]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.0.36pre2 2.0.36pre2
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:53 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:53 +0000 (15:11 -0500)
ftp://ftp.linux.org.uk/pub/linux/alan/..
This is a bit bigger than pre patch 1 but most of the bulk is the isdn driver
updates to reflect what everyone is actually using.
I don't have ISDN here - thats a hint to the ISDN using people to test this ok ;)

Lesser items:
o       Tlan 1.0 driver
o       >64Mb memory recognition
o       Full cyrix and other CPU recognition (should fix the TI problems)
o       Syscall return trap fix
o       Delay slightly more stable
o       IDE floppy knows about Iomega zip firmware 23.D
o       Cyclades update
o       Traffic Shaper
o       Etherexpress should now handle Compaq LTE base stations
o       EATA update
o       SCSI blacklist update
o       SCSI medium changers recognized
o       Ultrastor 14f/34f update
o       MPU401 DMA reporting
o       Sequencer busy fix
o       ISOfs boundary case fix
o       NFS unload fix
o       SMBfs time saving fix
o       mmap append only file fix
o       Socket leak fix

99 files changed:
Documentation/isdn/README.HiSax
Documentation/isdn/README.TimRu.De [new file with mode: 0644]
arch/i386/boot/compressed/misc.c
arch/i386/boot/setup.S
arch/i386/kernel/Makefile
arch/i386/kernel/setup.c
arch/i386/kernel/traps.c
arch/i386/lib/delay.S
drivers/block/ide-floppy.c
drivers/char/cyclades.c
drivers/isdn/Config.in
drivers/isdn/avmb1/b1capi.c
drivers/isdn/avmb1/b1lli.c
drivers/isdn/avmb1/b1pci.c
drivers/isdn/avmb1/capidrv.c
drivers/isdn/avmb1/capidrv.h
drivers/isdn/hisax/Makefile
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/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_ser.c [new file with mode: 0644]
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/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/s0box.c [new file with mode: 0644]
drivers/isdn/hisax/sedlbauer.c [new file with mode: 0644]
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/teles3.c
drivers/isdn/hisax/teles3c.c [new file with mode: 0644]
drivers/isdn/hisax/telespci.c [new file with mode: 0644]
drivers/isdn/icn/icn.c
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_tty.c
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/net/3c59x.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/eexpress.c
drivers/net/shaper.c [new file with mode: 0644]
drivers/scsi/eata.c
drivers/scsi/eata.h
drivers/scsi/scsi.c
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.h
drivers/sound/sb_common.c
drivers/sound/sequencer.c
fs/isofs/inode.c
fs/nfs/inode.c
fs/nfs/nfsiod.c
fs/proc/array.c
fs/smbfs/proc.c
include/asm-i386/processor.h
include/asm-i386/smp.h
include/linux/b1lli.h
include/linux/cyclades.h
include/linux/if_shaper.h [new file with mode: 0644]
include/linux/isdn.h
include/linux/isdnif.h
include/linux/serial.h
include/linux/skbuff.h
init/main.c
kernel/ksyms.c
mm/mmap.c

index 20b578d8322172d8a96f610210685631f323fbd2..593994f1767a83e0fd5156705a2c22c89f356ee2 100644 (file)
@@ -23,24 +23,45 @@ Supported cards
 ---------------
 
 Teles 8.0/16.0/16.3 and compatible ones
+Teles 16.3c
 Teles S0/PCMCIA
+Teles PCI
+Teles S0Box
+Creatix S0Box
 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 Quickstep 3000PCI
 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
+      Teles PCI is EXPERIMENTAL
+      Teles S0Box 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,13 +134,30 @@ 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
+   21   Teles PCI                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
+   25   Teles S0Box              irq, io (of the used lpt port)
+
         
-At the moment IRQ sharing is not possible. Please make sure that your IRQ
-is free and enabled for ISA use.
+At the moment IRQ sharing is only possible with PCI cards. Please make sure
+that your IRQ is free and enabled for ISA use.
 Note: For using the ELSA PCMCIA you need the cardmanager under MSDOS for
 enabling in the moment, then boot linux with loadlin.
 
@@ -181,17 +219,32 @@ 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   Teles PCI               no parameter
+   22   Sedlbauer Speed Star (PCMCIA)  pa=irq, pb=io  (set with card manager)
+   24   Dr. Neuhaus Niccy PnP   ONLY WORKS AS A MODULE !
+   24   Dr. Neuhaus Niccy PCI    no parameter
+   25   Teles S0Box              irq, io (of the used lpt port)
 
 Running the driver
 ------------------
@@ -200,7 +253,7 @@ When you insmod isdn.o and hisax.o (or with the in-kernel version, during
 boot time), a few lines should appear in your syslog. Look for something like:
 
 Apr 13 21:01:59 kke01 kernel: HiSax: Driver for Siemens chip set ISDN cards
-Apr 13 21:01:59 kke01 kernel: HiSax: Version 2.1
+Apr 13 21:01:59 kke01 kernel: HiSax: Version 2.9
 Apr 13 21:01:59 kke01 kernel: HiSax: Revisions 1.14/1.9/1.10/1.25/1.8
 Apr 13 21:01:59 kke01 kernel: HiSax: Total 1 card defined
 Apr 13 21:01:59 kke01 kernel: HiSax: Card 1 Protocol EDSS1 Id=HiSax1 (0)
@@ -215,8 +268,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 +279,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 +324,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 +344,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 +361,22 @@ 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
+       Enrik Berkhan (enrik@starfleet.inka.de) for S0BOX specific stuff
+       Ton van Rosmalen for Teles PCI
         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 +393,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.TimRu.De b/Documentation/isdn/README.TimRu.De
new file mode 100644 (file)
index 0000000..e3f86ac
--- /dev/null
@@ -0,0 +1,296 @@
+--( Version: 11.10.1997 )--
+
+TimRu-Erweiterungen:
+====================
+
+1. erfolglose Anwahlversuche per ICMP zurueckmelden
+---------------------------------------------------
+
+isdnctrl dialtimeout <name> <timeout>
+    name:    Name des Interfaces
+    timeout: -1: kein Waehl-Timeout
+              0: jede Telefonnummer dialmax-mal probieren
+             >0: Zeitraum in Sekunden, in dem die Anwahl versucht wird
+
+    isdnctrl dialtimeout bewirkt, dass die Anwahl der Gegenstelle im Fehler-
+    fall nicht unbegrenzt versucht wird, sondern entweder nach einer bestimmten
+    Anzahl von Versuchen oder nach einem bestimmten Zeitraum abgebrochen wird
+    und alle ausstehenden Pakete fuer den durch isdnctrl dialwait bestimmten
+    Zeitraum mit ICMP_NET_UNREACHABLE beantwortet werden.
+
+
+isdnctrl dialwait <name> <seconds>
+    name:    Name des Interfaces
+    seconds:  0: keine Waehl-Unterdrueckung im Fehlerfall
+             >0: Zeit in Sekunden, in der nach einem erfolglosen Anwahl-
+                 versuch Pakete mit ICMP_NET_UNREACHABLE beantwortet werden
+
+
+1.1 einzelne Interfaces stoppen / starten
+-----------------------------------------
+
+isdnctrl status <name> <status>
+    name:   Name des Interfaces
+    status: on:  Interface einschalten
+            off: Interface ausschalten
+
+    Dieser Befehl wirkt wie 'isdnctrl system on/off' auf Interface-Ebene.
+
+
+2. bessere Kontrolle ueber Aufbau und Hangup einer Verbindung
+-------------------------------------------------------------
+
+isdnctrl <cmd> <name> bringup <seconds> <rule>
+isdnctrl <cmd> <name> keepup in <seconds> <rule>
+isdnctrl <cmd> <name> keepup out <seconds> <rule>
+isdnctrl <cmd> <name> keepup both <seconds> <rule>
+    cmd:     addrule:        Regel am Ende der Regelliste anfuegen
+             insrule:        Regel am Anfang der Regelliste einfuegen
+             delrule:        Regel loeschen
+             default:        Was tun, wenn keine Regel passt?
+             showrules:      alle Regeln anzeigen
+             flushrules:     alle Regeln einer Art loeschen (bringup, ...)
+             flushallrules:  alle Regeln loeschen
+
+    name:    Name des Interfaces
+    seconds: Mindester Hangup-Timeout ab jetzt
+    rule:    Regel, auf die ein Paket passen muss, damit die Verbindung
+             aufgebaut oder der Hangup-Timeout verlaengert wird
+
+
+    Eine passende Bringup-Regel erlaubt den Aufbau der Verbindung,
+    wenn ihr Timeout > 0 ist. Eine Bringup-Regel mit einen Timeout == 0
+    verhindert einen Verbindungsaufbau. Dieser Timeout muss eigentlich nur
+    so gross sein, dass die Verbindung zum Gegenrechner erfolgreich
+    zustande kommt, da das ausloesende Datenpaket danach durch die
+    Keepup-Logik 'geht' und der Hangup-Timeout erneut berechnet wird.
+
+    Eine passende Keepup-Regel verlaengert den Hangup-Timeout, wobei
+    nach eingehenden und ausgehenden Paketen unterschieden werden kann.
+
+    Die Kontrolle eines Paketes stoppt bei der ersten passenden Regel, falls
+    keine Regel anwendbar ist, gilt die Default-Regel.
+
+    Die Regeln haben folgenden Aufbau:
+        ip/icmp <src>/<mask> <type> <dst>/<mask>
+        ip/tcp  <src>/<mask> <port> <dst>/<mask> <port>
+        ip/udp  <src>/<mask> <port> <dst>/<mask> <port>
+        ip/*    <src>/<mask>        <dst>/<mask>
+        ip/any  <src>/<mask>        <dst>/<mask>
+
+        ipx/*
+        ipx/any
+
+        ppp/ipcp
+        ppp/ipxcp
+        ppp/ccp
+        ppp/lcp
+        ppp/chap
+        ppp/pap
+        ppp/lqr
+        ppp/*
+        ppp/any
+
+        */*
+        any
+
+
+        src:    Absender-Adresse des Paketes als Nummer oder Name
+        dst:    Empfaenger-Adresse des Paketes als Nummer oder Name
+        mask:   Subnet-Maske als Anzahl Bits oder als Maske
+        type:   ICMP-Message-Type als Nummer
+        port:   Portnummer als Nummer oder Name
+
+
+       Wildcards ('*', 'any') sind ueberall erlaubt.
+
+        Fuer <src> und <dst> gilt:
+            <host>:           Host-Adresse als Nummer oder Name,
+                              Subnet-Mask /32
+            <host>/<mask>:    Host-Adresse als Nummer oder Name,
+                              Subnet-Mask als Anzahl Bits oder Maske
+            <network>:        Netzwerk-Adresse als Nummer oder Name,
+                              Subnet-Mask /32
+            <network>/<mask>: Host-Adresse als Nummer oder Name,
+                              Subnet-Mask als Anzahl Bits oder Maske
+            0.0.0.0/0
+            0/0
+            *
+            any:              Wildcard, passt auf jede Adresse.
+
+       Fuer <ports> gilt:
+            <from>-<to>: alle Ports von <from> bis <to>, numerische Angabe
+            <from>-:     alle Ports von <from> bis 65535, numerische Angabe
+            -<to>:       alle Ports von 0 bis <to>, numerische Angabe
+            <port>:      ein Port als Nummer oder Name
+            -, *
+            oder any:    alle Ports
+
+       Beginnt die Regel mit einem '!' oder mit 'not', so dreht sich ihre Aussage um:
+        falls sie NICHT passt, wird die Verbindung aufgebaut, bzw. der
+        Hangup-Timeout verlaengert.
+
+
+    Default-Regeln werden folgendermassen angegeben:
+
+        isdnctrl default <name> bringup <timeout>
+            name:    Name des Interfaces
+            timeout:  0: Verbindung wird nicht aufgebaut
+                     >0: Verbindung wird aufgebaut, anfaenglicher Timeout
+                         ist <timeout>.
+
+        isdnctrl default <name> keepup in <seconds>
+        isdnctrl default <name> keepup out <seconds>
+        isdnctrl default <name> keepup both <seconds>
+            name:    Name des Interfaces
+            seconds: Mindester Hangup-Timeout
+
+
+3. Budget-Erweiterungen
+-----------------------
+
+Diese Erweiterung erlaubt es, bestimmte 'Verbrauchswerte' pro
+Zeitraum zu limitieren. Falls ein Budget aufgebraucht ist, findet
+keine Anwahl mehr statt und eine bestehende Verbindung wird unterbrochen.
+Sobald wieder alle Budgets verfuegbar sind, werden wieder Verbindungen
+zugelassen.
+Die Gebuehrenimpuls-Zaehlung setzt momentan auf der Uebertragung der
+CINF-Pakete, also der Gebuehreninformation waehrend der Verbindung auf.
+Unmittelbar nach Aufbau der Verbindung wird der erste Gebuehrenimpuls
+'angenommen'.
+Fuer ISDN-Anschluesse, bei denen die Gebuehren erst am Ende der Ver-
+bindung uebertragen werden, faellt uns bestimmt auch noch was ein ;-).
+
+isdnctrl budget <name> <budget-type> <amount> <period>
+    setzt die Werte eines bestimmten Budgets. Ein aufgebrauchtes
+    Budget wird unmittelbar wieder aktiviert.
+
+       budget-type: dial:    Anzahl der Anwahlversuche (erfolgreich oder
+                          erfolglos) pro Periode
+                 charge:  Anzahl der Gebuehreneinheiten pro Periode
+                 online:  Online-Zeit pro Periode
+
+    amount:      Hoehe des Budgets. Bei <budget-type> 'dial' oder 'charge'
+                 ist das die Anzahl Anwahlen oder Einheiten, bei 'online'
+                 eine Zeitangabe (s.u.)
+
+    period:      Dauer der Periode in folgendem Format (<n> steht fuer eine
+                 natuerliche Zahl):
+
+                 <n>
+                 <n>s
+                 <n>sec,    <n> Sekunden
+
+                 <n>m
+                 <n>min,    <n> Minuten
+
+                 <n>h
+                 <n>hour,   <n> Stunden
+
+                 <n>d
+                 <n>day,    <n> Tage
+
+                 <n>w
+                 <n>week,   <n> Wochen (a 7 Tage)
+
+                 <n>M
+                 <n>month,  <n> Monate (a 30 Tage)
+
+                 <n>y
+                 <n>year,   <n> Jahre (a 365 Tage)
+
+                 Diese Angaben koennen miteinander kombiniert werden, z.B.:
+
+                     2h30m15
+                     2hour,30min,15sec
+                     1M2week,1day,8h
+
+
+isdnctrl budget <name> <budget-type> off
+    schaltet die Kontrolle des entsprechenden Budgets aus
+
+isdnctrl budget <name> showbudgets
+    zeigt die momentaten Budgets an
+
+isdnctrl budget <name> savebudgets
+    gibt die momentaten Budgets in einen Format aus, das vom Befehl 'restore-
+    budgets' wieder eingelesen kann
+
+isdnctrl budget <name> restorebudgets <saved-budget> ...
+    setzt die Budgets wieder auf die vorher mit 'savebudgets' ausgegebenen
+    Werte. Damit koennen Budgets auch ueber den Reboot der Maschine hinaus
+    Gueltigkeit haben.
+
+
+Hier ein Beispiel fuer die TimRu-Erweiterung:
+
+    # Alle Regeln loeschen
+    isdnctrl flushallrules ippp0
+
+    # Default: jeder Datenverkehr setzt den Hangup-Timeout auf 60 Sek.
+    isdnctrl default ippp0 keepup both 60
+
+    # FTP und Telnet erhoehen den Timeout auf 5 Minuten
+    isdnctrl addrule ippp0 keepup both 300 ip/tcp 0/0 20-23 0/0 -
+
+    # Anzeige der Regeln:
+    isdnctrl showrules ippp0
+
+    # ... erzeugt folgende Ausgabe:
+
+Timeout rules for interface ippp0:
+Default bringup policy: true
+Default huptimeout for incoming packets: 60 sec.
+Default huptimeout for outgoing packets: 60 sec.
+
+Current huptimeout: 60 sec.
+Time until hangup: 45 sec.
+
+Keepup-rules for incoming ip-packets:
+1-1-0 keepup_in 300 ip/tcp 0/0 20-23 0/0 * 
+
+Keepup-rules for outgoing ip-packets:
+2-1-0 keepup_out 300 ip/tcp 0/0 * 0/0 20-23 
+
+
+Hier ein Beispiel fuer die Budget-Erweiterung:
+
+    # Hoechstens 60 Anwahlversuche pro Stunde
+    isdnctrl budget ippp0 dial 60 1h
+
+    # Hoechstens 3000 Einheiten pro Monat
+    isdnctrl budget ippp0 charge 3000 1M
+
+    # Hoechstens 8 Stunden online pro Tag
+    isdnctrl budget ippp0 online 8h 1d
+
+    # Anzeige der Budgets:
+    isdnctrl showbudgets ippp0
+
+    # ... erzeugt nach kurzer Zeit folgende Ausgabe:
+
+
+Budgets for interface ippp0:
+
+TYPE    AMOUNT     PERIOD     USED       SINCE
+dial    60         1h         1          01.07.1997, 17:43:40
+charge  3000       1M         2          01.07.1997, 17:43:49
+online  8h         1d         2m26s      01.07.1997, 17:43:57
+
+
+Zum Nachfuehren der Budgets ueber einen laengeren Zeitraum koennte man
+folgende Methode verwenden:
+
+beim Herunterfahren oder per 'cron' jede Minute: 
+
+    INTERFACES="ippp0 ippp1 ippp2"
+    for i in $INTERFACES; do
+        isdnctrl savebudgets $i > /var/isdn/saved-budgets/$i
+    done
+
+
+und dann beim Neustart:
+
+    for f in /var/isdn/saved-budgets/*; do
+        isdnctrl restorebudgets ${f##*/} `cat $f`
+    done
index 5d9676ecffa9cdd53d54b3724b85d5513090e7bd..c5e31878aecc84106f0ce612f5a3fc3ce62d7149 100644 (file)
@@ -97,6 +97,9 @@ struct screen_info {
  * This is set up by the setup-routine at boot-time
  */
 #define EXT_MEM_K (*(unsigned short *)0x90002)
+#ifndef STANDARD_MEMORY_BIOS_CALL
+#define ALT_MEM_K (*(unsigned long *) 0x901e0)
+#endif
 #define DRIVE_INFO (*(struct drive_info *)0x90080)
 #define SCREEN_INFO (*(struct screen_info *)0x90000)
 #define RAMDISK_SIZE (*(unsigned short *)0x901F8)
@@ -313,7 +316,11 @@ struct {
 
 void setup_normal_output_buffer()
 {
+#ifdef STANDARD_MEMORY_BIOS_CALL
        if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
+#else
+       if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory.\n");
+#endif
        output_data = (char *)0x100000; /* Points to 1M */
 }
 
@@ -325,7 +332,11 @@ struct moveparams {
 void setup_output_buffer_if_we_run_high(struct moveparams *mv)
 {
        high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
+#ifdef STANDARD_MEMORY_BIOS_CALL
        if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n");
+#else
+       if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory.\n");
+#endif
        mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
        high_loaded = 1;
        free_mem_end_ptr = (long)high_buffer_start;
index 201a2936b25c8927b951fa31f6259ce48782d91d..f6afafc39063c6d015162f09ce13fb86b7bd4642 100644 (file)
@@ -232,6 +232,29 @@ loader_panic_mess:
 loader_ok:
 ! Get memory size (extended mem, kB)
 
+#ifndef STANDARD_MEMORY_BIOS_CALL
+       push    ebx
+
+        xor     ebx,ebx                ! preload new memory slot with 0k
+        mov    [0x1e0], ebx
+
+        mov     ax,#0xe801
+       int     0x15
+       jc      oldstylemem
+
+       and     ebx, #0xffff    ! clear sign extend
+       shl     ebx, 6          ! and go from 64k to 1k chunks
+       mov     [0x1e0],ebx     ! store extended memory size
+
+       and     eax, #0xffff    ! clear sign extend
+       add     [0x1e0],eax     ! and add lower memory into total size.
+  
+       ! and fall into the old memory detection code to populate the
+       ! compatability slot.
+
+oldstylemem:
+       pop     ebx
+#endif
        mov     ah,#0x88
        int     0x15
        mov     [2],ax
index 123dd120778641ac6c8e5f7d0ad9d35ed4252ad2..1aca286047f9ce86950a0f7b324a9b8cfd16dc84 100644 (file)
@@ -62,6 +62,6 @@ trampoline32.s: trampoline32.S $(CONFIGURE) $(TOPDIR)/include/linux/config.h Mak
        $(CPP) -D__SMP__ -traditional $< -o $@
 
 clean:
-       rm -f trampoline hexify
+       rm -f trampoline trampoline.hex hexify
 
 include $(TOPDIR)/Rules.make
index 084cd21a1f46024fbf241b0776a7f69b0b6553d0..923e1aa7ef8ab225b8eb007f5f15af7557b6df20 100644 (file)
@@ -42,15 +42,21 @@ char x86 = 0;                       /* set by kernel/head.S to 3..6 */
 char x86_model = 0;            /* set by kernel/head.S */
 char x86_mask = 0;             /* set by kernel/head.S */
 int x86_capability = 0;                /* set by kernel/head.S */
+int x86_ext_capability = 0;    /* newer CPUs have this */
 int fdiv_bug = 0;              /* set if Pentium(TM) with FP bug */
 int pentium_f00f_bug = 0;      /* set if Pentium(TM) with F00F bug */
 int have_cpuid = 0;             /* set if CPUID instruction works */
+int ext_cpuid = 0;             /* if != 0, highest available CPUID value */
 
-char x86_vendor_id[13] = "unknown";
+char x86_vendor_id[13] = "GenuineIntel";/* default */
 
-unsigned char Cx86_step = 0;
-static const char *Cx86_type[] = {
-       "unknown", "1.3", "1.4", "1.5", "1.6", "2.4", "2.5", "2.6", "2.7 or 3.7", "4.2"
+static char *Cx86_step = "unknown";    /* stepping info for Cyrix CPUs */
+
+static unsigned char Cx86_mult = 0;    /* clock multiplier for Cyrix CPUs */
+
+static const char *x86_clkmult[] = {
+       "unknown", "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5", "5.5",
+       "6", "6.5", "7", "7.5", "8"
        };
 
 char ignore_irq13 = 0;         /* set if exception 16 works */
@@ -89,6 +95,9 @@ extern char empty_zero_page[PAGE_SIZE];
  */
 #define PARAM  empty_zero_page
 #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
+#ifndef STANDARD_MEMORY_BIOS_CALL
+#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
+#endif
 #ifdef CONFIG_APM
 #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
 #endif
@@ -116,6 +125,9 @@ void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
        unsigned long memory_start, memory_end;
+#ifndef STANDARD_MEMORY_BIOS_CALL
+       unsigned long memory_alt_end;
+#endif
        char c = ' ', *to = command_line, *from = COMMAND_LINE;
        int len = 0;
        static unsigned char smptrap=0;
@@ -134,6 +146,15 @@ void setup_arch(char **cmdline_p,
 #endif
        aux_device_present = AUX_DEVICE_INFO;
        memory_end = (1<<20) + (EXT_MEM_K<<10);
+#ifndef STANDARD_MEMORY_BIOS_CALL
+       memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
+       if (memory_alt_end > memory_end) {
+           printk("Memory: sized by int13 0e801h\n");
+           memory_end = memory_alt_end;
+       }
+       else
+           printk("Memory: sized by int13 088h\n");
+#endif
        memory_end &= PAGE_MASK;
 #ifdef CONFIG_BLK_DEV_RAM
        rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
@@ -211,95 +232,107 @@ void setup_arch(char **cmdline_p,
        request_region(0xf0,0x10,"npu");
 }
 
-static const char * i486model(unsigned int nr)
-{
-       static const char *model[] = {
-               "0","DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB",
-               "10","11","12","13","Am5x86-WT","Am5x86-WB"
-       };
-       if (nr < sizeof(model)/sizeof(char *))
-               return model[nr];
-       return NULL;
-}
-
-static const char * i586model(unsigned int nr)
+static const char * IDTmodel(void)
+/* Right now IDT has a single CPU model in production: the C6.
+ * Adjust this when IDT/Centaur comes out with a new CPU model.
+ * Stepping information is correctly reported in x86_mask.
+ */
 {
        static const char *model[] = {
-               "0", "Pentium 60/66","Pentium 75+","OverDrive PODP5V83",
-               "Pentium MMX", NULL, NULL, "Mobile Pentium 75+",
-               "Mobile Pentium MMX"
+               "C6", "C6-3D"
        };
-       if (nr < sizeof(model)/sizeof(char *))
-               return model[nr];
-       return NULL;
+       return model[0];
 }
 
 static const char * Cx86model(void)
+/* We know our CPU is a Cyrix now (see bugs.h), so we can use the DIR0/DIR1
+ * mechanism to figure out the model, bus clock multiplier and stepping.
+ * For the newest CPUs (GXm and MXi) we use the Extended CPUID function.
+ */
 {
-       unsigned char nr6x86 = 0;
-       static const char *model[] = {
-               "unknown", "6x86", "6x86L", "6x86MX", "MII"
-       };
-       switch (x86) {
-               case 5:
-                       nr6x86 = ((x86_capability & (1 << 8)) ? 2 : 1); /* cx8 flag only on 6x86L */
-                       break;
-               case 6:
-                       nr6x86 = 3;
-                       break;
-               default:
-                       nr6x86 = 0;
+    unsigned char nr6x86 = 0;
+    unsigned char cx_dir0 = 0; /* Model and bus clock multiplier */
+    unsigned char cx_dir1 = 0; /* Stepping info */
+    unsigned int flags;
+    static const char *model[] = {
+       "unknown", "Cx486", "5x86", "MediaGX", "6x86", "6x86L", "6x86MX",
+       "M II"
+    };
+    
+    if (x86_model == -1) {     /* is this an old Cx486 without DIR0/DIR1? */
+       nr6x86 = 1;             /* Cx486 */
+       Cx86_mult = 0;          /* unknown multiplier */
+    }
+    else {
+
+       /* Get DIR0, DIR1 since all other Cyrix CPUs have them */
+    
+       save_flags(flags);
+       cli();
+       cx_dir0 = getCx86(CX86_DIR0);   /* we use the access macros */
+       cx_dir1 = getCx86(CX86_DIR1);   /* defined in processor.h */
+       restore_flags(flags);
+                                       
+       /* Now cook; the recipe is by Channing Corn, from Cyrix.
+        * We do the same thing for each generation: we work out
+        * the model, multiplier and stepping.
+        */
+        
+       if (cx_dir0 < 0x20) {
+               nr6x86 = 1;                             /* Cx486 */
+               Cx86_mult = 0;                          /* unknown multiplier */
+               sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
        }
-
-       /* We must get the stepping number by reading DIR1 */
-       outb(0xff, 0x22); x86_mask=inb(0x23);
-
-       switch (x86_mask) {
-               case 0x03:
-                       Cx86_step =  1; /* 6x86MX Rev 1.3 */
-                       break;
-               case 0x04:
-                       Cx86_step =  2; /* 6x86MX Rev 1.4 */
-                       break;
-               case 0x05:
-                       Cx86_step =  3; /* 6x86MX Rev 1.5 */
-                       break;
-               case 0x06:
-                       Cx86_step =  4; /* 6x86MX Rev 1.6 */
-                       break;
-               case 0x14:
-                       Cx86_step =  5; /* 6x86 Rev 2.4 */
-                       break;
-               case 0x15:
-                       Cx86_step =  6; /* 6x86 Rev 2.5 */
-                       break;
-               case 0x16:
-                       Cx86_step =  7; /* 6x86 Rev 2.6 */
+        
+        if ((cx_dir0 > 0x20) && (cx_dir0 < 0x30)) {
+               nr6x86 = 2;                             /* 5x86 */
+               Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */
+               sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
+       }
+        
+        if ((cx_dir0 >= 0x30) && (cx_dir0 < 0x38)) {
+               nr6x86 = ((x86_capability & (1 << 8)) ? 5 : 4); /* 6x86(L) */
+               Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */
+               sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 3), cx_dir1 & 0x0f);
+       }
+        
+        if ((cx_dir0 >= 0x40) && (cx_dir0 < 0x50)) {
+           if (x86 == 4) { /* MediaGX */
+               nr6x86 = 3;
+               Cx86_mult = ((cx_dir0 & 0x01) ? 5 : 7); /* either 3x or 4x */
+               switch (cx_dir1 >> 4) {
+                       case (0) :
+                       case (1) :
+                               sprintf(Cx86_step, "2.%d", cx_dir1 & 0x0f);
                        break;
-               case 0x17:
-                       Cx86_step =  8; /* 6x86 Rev 2.7 or 3.7 */
+                       case (2) :
+                               sprintf(Cx86_step, "1.%d", cx_dir1 & 0x0f);
                        break;
-               case 0x22:
-                       Cx86_step =  9; /* 6x86L Rev 4.2 */
+                        default  :
                        break;
-               default:
-                       Cx86_step = 0;
+                }
+            } /* endif MediaGX */
+            if (x86 == 5) { /* GXm */
+                char GXm_mult[8] = {7,11,7,11,13,15,13,9}; /* 4 to 8 */
+               ext_cpuid = 0x80000005; /* available */
+               Cx86_mult = GXm_mult[cx_dir0 & 0x0f];
+               sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) - 1, cx_dir1 & 0x0f);
+            } /* endif GXm */
+        }
+        
+        if ((cx_dir0 >= 0x50) && (cx_dir0 < 0x60)) {
+               nr6x86 = ((cx_dir1 > 7) ? 7 : 6);       /* 6x86Mx or M II */
+               Cx86_mult = (cx_dir0 & 0x07) + 2;       /* 2 to 5 in 0.5 steps */
+               if (((cx_dir1 & 0x0f) > 4) || ((cx_dir1 >> 4) == 2)) cx_dir1 += 0x10;
+               sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
        }
-       return model[nr6x86];
-}
-
-static const char * i686model(unsigned int nr)
-{
-       static const char *model[] = {
-               "PPro A-step", "Pentium Pro"
-       };
-       if (nr < sizeof(model)/sizeof(char *))
-               return model[nr];
-       return NULL;
+    }
+    x86_mask = 1;      /* we don't use it, but has to be set to something */
+    return model[nr6x86];
 }
 
 struct cpu_model_info {
-       int x86;
+       int cpu_x86;
        char *model_names[16];
 };
 
@@ -308,10 +341,7 @@ static struct cpu_model_info amd_models[] = {
          { NULL, NULL, NULL, "DX/2", NULL, NULL, NULL, "DX/2-WB", "DX/4",
            "DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }},
        { 5,
-         { "K5/SSA5 (PR-75, PR-90, PR-100)", "K5 (PR-120, PR-133)",
-           "K5 (PR-166)", "K5 (PR-200)", NULL, NULL,
-           "K6 (166 - 266)", "K6 (166 - 300)", "K6-2 (200 - 450)",
-           "K6-3D-Plus (200 - 450)", NULL, NULL, NULL, NULL, NULL, NULL }},
+         { "K5/SSA5 (PR-75, PR-90, PR-100)"}},
 };
 
 static const char * AMDmodel(void)
@@ -319,41 +349,81 @@ static const char * AMDmodel(void)
        const char *p=NULL;
        int i;
        
-       if (x86_model < 16)
+       if ((x86_model == 0) || (x86 == 4)) {
                for (i=0; i<sizeof(amd_models)/sizeof(struct cpu_model_info); i++)
-                       if (amd_models[i].x86 == x86) {
+                       if (amd_models[i].cpu_x86 == x86) {
                                p = amd_models[i].model_names[(int)x86_model];
                                break;
                        }
+       }
+       else ext_cpuid = 0x80000005;            /* available */
+       return p;
+}
+
+static struct cpu_model_info intel_models[] = {
+       { 4,
+         { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", 
+           "486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, 
+           NULL, NULL, NULL, NULL, NULL }},
+       { 5,
+         { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75+",
+           "OverDrive PODP5V83", "Pentium MMX", NULL, NULL,
+           "Mobile Pentium 75+", "Mobile Pentium MMX", NULL, NULL, NULL,
+           NULL, NULL, NULL, NULL }},
+       { 6,
+         { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
+           NULL, "Pentium II (Deschutes)", NULL, NULL, NULL, NULL, NULL, NULL,
+           NULL, NULL, NULL, NULL }},
+};
+
+static const char * Intelmodel(void)
+{
+       const char *p = "386 SX/DX";    /* default to a 386 */
+       int i;
+       
+       for (i=0; i<sizeof(intel_models)/sizeof(struct cpu_model_info); i++)
+               if (intel_models[i].cpu_x86 == x86) {
+                       p = intel_models[i].model_names[(int)x86_model];
+                       break;
+               }
        return p;
 }
+       
+/* Recent Intel CPUs have an EEPROM and a ROM with CPU information. We'll use
+ * this information in future versions of this code.
+ * AMD and more recently Cyrix have decided to standardize on an extended
+ * cpuid mechanism for their CPUs.
+ */
+static const char * get_cpu_mkt_name(void)
+{
+        static char mktbuf[48];
+        int dummy;
+       unsigned int *v;
+       v = (unsigned int *) mktbuf;
+       cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);  /* name, flags */
+       cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+       cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+       cpuid(0x80000001, &dummy, &dummy, &dummy, &x86_ext_capability);
+       return mktbuf;
+}
 
-static const char * getmodel(int x86, int model)
+static const char * getmodel()
+/* Default is Intel. We disregard Nexgen and UMC processors. */
 {
         const char *p = NULL;
-        static char nbuf[12];
-       if (strncmp(x86_vendor_id, "Cyrix", 5) == 0)
-               p = Cx86model();
-       else if(strcmp(x86_vendor_id, "AuthenticAMD")==0)
+       if      (strncmp(x86_vendor_id, "Au", 2) == 0)  /* AuthenticAMD */
                p = AMDmodel();
-       else {
-               switch (x86) {
-                       case 4:
-                               p = i486model(model);
-                               break;
-                       case 5:
-                               p = i586model(model);
-                               break;
-                       case 6:
-                               p = i686model(model);
-                               break;
-               }
-       }
-        if (p)
+       else if (strncmp(x86_vendor_id, "Cy", 2) == 0)  /* CyrixInstead */
+               p = Cx86model();
+       else if (strncmp(x86_vendor_id, "Ce", 2) == 0)  /* CentaurHauls */
+               p = IDTmodel();
+       else /* default */
+               p = Intelmodel();
+       if (ext_cpuid)
+               return get_cpu_mkt_name();
+        else
                 return p;
-
-        sprintf(nbuf, "%d", model);
-        return nbuf;
 }
 
 int get_cpuinfo(char * buffer)
@@ -365,7 +435,13 @@ int get_cpuinfo(char * buffer)
                 "16", "17", "18", "19", "20", "21", "22", "mmx",
                 "24", "25", "26", "27", "28", "29", "30", "31"
         };
-        
+       static const char *x86_ext_cap_flags[] = {
+                  "fpu","vme", "de",   "pse", "tsc", "msr",  "6",   "mce",
+                  "cx8",  "9", "10", "syscr",  "12", "pge", "14",  "cmov",
+               "fpcmov", "17", "18",    "19",  "20",  "21", "22",   "mmx",
+                 "emmx", "25", "26",    "27",  "28",  "29", "30", "3dnow"
+       };
+         
 #ifdef __SMP__
         int n;
 
@@ -385,25 +461,30 @@ int get_cpuinfo(char * buffer)
 
                         len += sprintf(buffer+len,"processor\t: %d\n"
                                        "cpu\t\t: %c86\n"
-                                       "model\t\t: %s\n"
-                                       "vendor_id\t: %s\n",
+                                       "model\t\t: %s",
                                        CPUN,
                                        CD(x86)+'0',
-                                       CD(have_cpuid) ? 
-                                         getmodel(CD(x86), CD(x86_model)) :
-                                         "unknown",
-                                       CD(x86_vendor_id));
+                                       getmodel());
+                       len += sprintf(buffer+len,
+                                       "\nvendor_id\t: %s\n",
+                                       x86_vendor_id);
         
-                        if (CD(x86_mask))
-                                if (strncmp(x86_vendor_id, "Cyrix", 5) != 0) {
+                        if (CD(x86_mask) || have_cpuid)
+                                if      ((strncmp(x86_vendor_id, "Au", 2) == 0)
+                                       && (x86_model >= 6)) {
                                        len += sprintf(buffer+len,
-                                                      "stepping\t: %d\n",
-                                                      CD(x86_mask));
+                                                      "stepping\t: %c\n",
+                                                      x86_mask + 'A');
                                 }
-                                else {                         /* we have a Cyrix */
+                                else if (strncmp(x86_vendor_id, "Cy", 2) == 0) {
                                        len += sprintf(buffer+len,
-                                                      "stepping\t: %s\n",
-                                                      Cx86_type[Cx86_step]);
+                                                       "stepping\t: %s, core/bus clock ratio: %sx\n",
+                                                       Cx86_step, x86_clkmult[Cx86_mult]);
+                                }
+                                else {         
+                                       len += sprintf(buffer+len,
+                                                      "stepping\t: %d\n",
+                                                      CD(x86_mask));
                                 }
                         else
                                 len += sprintf(buffer+len, 
@@ -432,6 +513,10 @@ int get_cpuinfo(char * buffer)
                                         len += sprintf(buffer+len, " %s",
                                                        x86_cap_flags[i]);
                                 }
+                                else if ( CD(x86_ext_capability) & (1 << i) ) {
+                                        len += sprintf(buffer+len, " %s",
+                                                       x86_ext_cap_flags[i]);
+                                }
                         }
                         len += sprintf(buffer+len,
                                        "\nbogomips\t: %lu.%02lu\n",
index 19cbf8a1c373d74036d1b3529a88bac75ee7f389..b7cd6470da9d94d2457abccf75b9af8fb7a585cf 100644 (file)
@@ -192,9 +192,9 @@ DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
 DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
 DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
 
-/* signal_return is directly after ret_from_sys_call in entry.S */
+/* divide_error is after ret_from_sys_call in entry.S */
 asmlinkage void ret_from_sys_call(void)        __asm__("ret_from_sys_call");
-asmlinkage void signal_return(void)    __asm__("signal_return");
+asmlinkage void divide_error(void)     __asm__("divide_error");
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
@@ -210,7 +210,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
         */
        if ((regs->cs & 3) != 3) {
                if (regs->eip >= (unsigned long)ret_from_sys_call &&
-                   regs->eip < (unsigned long)signal_return) {
+                   regs->eip < (unsigned long)divide_error) {
                        static int moancount = 0;
                        if (moancount < 5) {
                                printk(KERN_INFO "Ignoring GPF attempt from program \"%s\" (pid %d).\n",
index c6079a74efea78ebb74bb2afa773e8d727e6b782..9d36420e195585a53cb7f17f3ccb3c584e0a47ce 100644 (file)
@@ -6,8 +6,12 @@
  */
 
 ENTRY(__do_delay)
-1:     decl %eax
-       jns 1b
+       jmp 1f
+.align 16
+1:     jmp 2f
+.align 16
+2:     decl %eax
+       jns 2b
        ret
 
 
index d4622cee4ee9ff13b655477efb5f7c889545c71c..5c1710576898081e1ab73ee2e03add05e08bf530 100644 (file)
@@ -28,6 +28,7 @@
  *                       Issue START cmd only if TEST_UNIT_READY fails
  *                       Add CDROMEJECT ioctl
  *                       Clean up error messages a bit
+ * Ver 0.72  Jul  8 98   Limit max sectors only on IOMEGA ZIP 23.D
  */
 
 #include <linux/config.h>
@@ -1376,7 +1377,8 @@ void idefloppy_setup (ide_drive_t *drive)
        if (gcw.drq_type == 1)
                set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
        if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 &&
-           strcmp(drive->id->fw_rev, "21.D") == 0)
+           ((strcmp(drive->id->fw_rev, "21.D") == 0) ||
+            (strcmp(drive->id->fw_rev, "23.D") == 0)))
                floppy->max_sectors = 64;
        else
                floppy->max_sectors = IDEFLOPPY_MAX_SECTORS;
index 235b33e4e93e882735b2db3fbe0e67ac92a28bec..77603e60b420490dbb52d041806869538b589108 100644 (file)
@@ -1,13 +1,17 @@
+#define BLOCKMOVE
+#define        Z_WAKE
 static char rcsid[] =
-"$Revision: 1.36.3.9 $$Date: 1996/10/07 19:47:13 $";
+"$Revision: 2.1.1.4 $$Date: 1998/06/01 18:01:19 $";
+
 /*
  *  linux/drivers/char/cyclades.c
  *
  * This file contains the driver for the Cyclades Cyclom-Y multiport
  * serial boards.
  *
- * Maintained by Marcio Saito (marcio@cyclades.com) and
- * Randolph Bentson (bentson@grieg.seaslug.org)
+ * Maintained by Ivan Passos (ivan@cyclades.com),
+ * Marcio Saito (marcio@cyclades.com) and 
+ * Randolph Bentson (bentson@grieg.seaslug.org).
  *
  * For Technical support and installation problems, please send e-mail
  * to support@cyclades.com.
@@ -22,11 +26,212 @@ static char rcsid[] =
  * This module exports the following rs232 io functions:
  *   int cy_init(void);
  *   int cy_open(struct tty_struct *tty, struct file *filp);
+ * and the following functions for modularization.
+ *   int init_module(void);
+ *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
- * Revision 1.36.3.9  1996/10/07 19:47:13  bentson
- * add MOD_DEC_USE_COUNT in one return from cy_close (as
- * noted by Jon Lewis <jlewis@INORGANIC5.FDT.NET>)
+ * Revision 2.1.1.4  1998/06/01 18:01:19 ivan
+ * data loss prevention revisited (cy_wait_until_sent created);
+ * MOD_COUNT bug (which caused the usage decrementing not to work 
+ * properly) fixed.
+ *
+ * Revision 2.1.1.3b  1998/05/14 10:14:00 ivan
+ * temporary workaround for losing SIGHUPs in PPP connections
+ * (Cyclom-Y only).
+ *
+ * Revision 2.1.1.3a  1998/03/16 18:01:12 ivan
+ * cleaned up the data loss fix;
+ * fixed XON/XOFF handling once more (Cyclades-Z);
+ * general revision in the driver routines;
+ * introduction of a mechanism to prevent data loss with slow 
+ * printers, by forcing a delay before closing the port.
+ *
+ * Revision 2.1.1.2a  1998/02/17 16:50:00 ivan
+ * fixed detection/handling of new CD1400 in Ye boards;
+ * fixed XON/XOFF handling (Cyclades-Z);
+ * fixed data loss caused by a premature port close;
+ * introduction of a flag that holds the CD1400 version ID per port
+ * (used by the CYGETCD1400VER new ioctl).
+ *
+ * Revision 2.1.1.1a  1997/12/03 17:31:19 ivan
+ * Code review for the module cleanup routine;
+ * fixed RTS and DTR status report for new CD1400's in get_modem_info;
+ * includes anonymous changes regarding signal_pending.
+ * 
+ * Revision 2.1  1997/11/01 17:42:41 ivan
+ * Changes in the driver to support Alpha systems (except 8Zo V_1);
+ * BREAK fix for the Cyclades-Z boards;
+ * driver inactivity control by FW implemented;
+ * introduction of flag that allows driver to take advantage of 
+ * a special CD1400 feature related to HW flow control;
+ * added support for the CD1400  rev. J (Cyclom-Y boards);
+ * introduction of ioctls to:
+ *  - control the rtsdtr_inv flag (Cyclom-Y);
+ *  - control the rflow flag (Cyclom-Y);
+ *  - adjust the polling interval (Cyclades-Z);
+ *
+ * Revision 1.36.4.33  1997/06/27 19:00:00  ivan
+ * Fixes related to kernel version conditional 
+ * compilation.
+ *  
+ * Revision 1.36.4.32  1997/06/14 19:30:00  ivan
+ * Compatibility issues between kernels 2.0.x and 
+ * 2.1.x (mainly related to clear_bit function).
+ *  
+ * Revision 1.36.4.31  1997/06/03 15:30:00  ivan
+ * Changes to define the memory window according to the 
+ * board type.
+ *  
+ * Revision 1.36.4.30  1997/05/16 15:30:00  daniel
+ * Changes to suport new cycladesZ boards.
+ *
+ * Revision 1.36.4.29  1997/05/12 11:30:00  daniel
+ * Merge of Bentson's and Daniel's version 1.36.4.28.
+ * Corrects bug in cy_detect_pci: check if there are more
+ * ports than the number of static structs allocated.
+ * Warning message during initialization if this driver is
+ * used with the new generation of cycladesZ boards.  Those
+ * will be supported only in next release of the driver.
+ * Corrects bug in cy_detect_pci and cy_detect_isa that
+ * returned wrong number of VALID boards, when a cyclomY
+ * was found with no serial modules connected.
+ * Changes to use current (2.1.x) kernel subroutine names
+ * and created macros for compilation with 2.0.x kernel,
+ * instead of the other way around.
+ *
+ * Revision 1.36.4.28  1997/05/?? ??:00:00  bentson
+ * Change queue_task_irq_off to queue_task_irq.
+ * The inline function queue_task_irq_off (tqueue.h)
+ * was removed from latest releases of 2.1.x kernel.
+ * Use of macro __initfunc to mark the initialization
+ * routines, so memory can be reused.
+ * Also incorporate implementation of critical region
+ * in function cleanup_module() created by anonymous
+ * linuxer.
+ *
+ * Revision 1.36.4.28  1997/04/25 16:00:00  daniel
+ * Change to support new firmware that solves DCD problem:
+ * application could fail to receive SIGHUP signal when DCD
+ * varying too fast.
+ *
+ * Revision 1.36.4.27  1997/03/26 10:30:00  daniel
+ * Changed for suport linux versions 2.1.X.
+ * Backward compatible with linux versions 2.0.X.
+ * Corrected illegal use of filler field in
+ * CH_CTRL struct.
+ * Deleted some debug messages.
+ *
+ * Revision 1.36.4.26  1997/02/27 12:00:00  daniel
+ * Included check for NULL tty pointer in cyz_poll.
+ *
+ * Revision 1.36.4.25  1997/02/26 16:28:30  bentson
+ * Bill Foster at Blarg! Online services noticed that
+ * some of the switch elements of -Z modem control
+ * lacked a closing "break;"
+ *
+ * Revision 1.36.4.24  1997/02/24 11:00:00  daniel
+ * Changed low water threshold for buffer xmit_buf
+ *
+ * Revision 1.36.4.23  1996/12/02 21:50:16  bentson
+ * Marcio provided fix to modem status fetch for -Z
+ *
+ * Revision 1.36.4.22  1996/10/28 22:41:17  bentson
+ * improve mapping of -Z control page (thanks to Steve
+ * Price <stevep@fa.tdktca.com> for help on this)
+ *
+ * Revision 1.36.4.21  1996/09/10 17:00:10  bentson
+ * shift from cpu-bound to memcopy in cyz_polling operation
+ *
+ * Revision 1.36.4.20  1996/09/09 18:30:32  Bentson
+ * Added support to set and report higher speeds.
+ *
+ * Revision 1.36.4.19c  1996/08/09 10:00:00  Marcio Saito
+ * Some fixes in the HW flow control for the BETA release.
+ * Don't try to register the IRQ.
+ *
+ * Revision 1.36.4.19  1996/08/08 16:23:18  Bentson
+ * make sure "cyc" appears in all kernel messages; all soft interrupts
+ * handled by same routine; recognize out-of-band reception; comment
+ * out some diagnostic messages; leave RTS/CTS flow control to hardware;
+ * fix race condition in -Z buffer management; only -Y needs to explictly
+ * flush chars; tidy up some startup messages;
+ *
+ * Revision 1.36.4.18  1996/07/25 18:57:31  bentson
+ * shift MOD_INC_USE_COUNT location to match
+ * serial.c; purge some diagnostic messages;
+ *
+ * Revision 1.36.4.17  1996/07/25 18:01:08  bentson
+ * enable modem status messages and fetch & process them; note
+ * time of last activity type for each port; set_line_char now
+ * supports more than line 0 and treats 0 baud correctly;
+ * get_modem_info senses rs_status;
+ *
+ * Revision 1.36.4.16  1996/07/20 08:43:15  bentson
+ * barely works--now's time to turn on
+ * more features 'til it breaks
+ *
+ * Revision 1.36.4.15  1996/07/19 22:30:06  bentson
+ * check more -Z board status; shorten boot message
+ *
+ * Revision 1.36.4.14  1996/07/19 22:20:37  bentson
+ * fix reference to ch_ctrl in startup; verify return
+ * values from cyz_issue_cmd and cyz_update_channel;
+ * more stuff to get modem control correct;
+ *
+ * Revision 1.36.4.13  1996/07/11 19:53:33  bentson
+ * more -Z stuff folded in; re-order changes to put -Z stuff
+ * after -Y stuff (to make changes clearer)
+ *
+ * Revision 1.36.4.12  1996/07/11 15:40:55  bentson
+ * Add code to poll Cyclades-Z.  Add code to get & set RS-232 control.
+ * Add code to send break.  Clear firmware ID word at startup (so
+ * that other code won't talk to inactive board).
+ *
+ * Revision 1.36.4.11  1996/07/09 05:28:29  bentson
+ * add code for -Z in set_line_char
+ *
+ * Revision 1.36.4.10  1996/07/08 19:28:37  bentson
+ * fold more -Z stuff (or in some cases, error messages)
+ * into driver; add text to "don't know what to do" messages.
+ *
+ * Revision 1.36.4.9  1996/07/08 18:38:38  bentson
+ * moved compile-time flags near top of file; cosmetic changes
+ * to narrow text (to allow 2-up printing); changed many declarations
+ * to "static" to limit external symbols; shuffled code order to
+ * coalesce -Y and -Z specific code, also to put internal functions
+ * in order of tty_driver structure; added code to recognize -Z
+ * ports (and for moment, do nothing or report error); add cy_startup
+ * to parse boot command line for extra base addresses for ISA probes;
+ *
+ * Revision 1.36.4.8  1996/06/25 17:40:19  bentson
+ * reorder some code, fix types of some vars (int vs. long),
+ * add cy_setup to support user declared ISA addresses
+ *
+ * Revision 1.36.4.7  1996/06/21 23:06:18  bentson
+ * dump ioctl based firmware load (it's now a user level
+ * program); ensure uninitialzed ports cannot be used
+ *
+ * Revision 1.36.4.6  1996/06/20 23:17:19  bentson
+ * rename vars and restructure some code
+ *
+ * Revision 1.36.4.5  1996/06/14 15:09:44  bentson
+ * get right status back after boot load
+ *
+ * Revision 1.36.4.4  1996/06/13 19:51:44  bentson
+ * successfully loads firmware
+ *
+ * Revision 1.36.4.3  1996/06/13 06:08:33  bentson
+ * add more of the code for the boot/load ioctls
+ *
+ * Revision 1.36.4.2  1996/06/11 21:00:51  bentson
+ * start to add Z functionality--starting with ioctl
+ * for loading firmware
+ *
+ * Revision 1.36.4.1  1996/06/10 18:03:02  bentson
+ * added code to recognize Z/PCI card at initialization; report
+ * presence, but card is not initialized (because firmware needs
+ * to be loaded)
  *
  * Revision 1.36.3.8  1996/06/07 16:29:00  bentson
  * starting minor number at zero; added missing verify_area
@@ -261,6 +466,63 @@ static char rcsid[] =
  *
  */
 
+/* If you need to install more boards than NR_CARDS, change the constant
+   in the definition below. No other change is necessary to support up to
+   eight boards. Beyond that you'll have to extend cy_isa_addresses. */
+
+#define NR_CARDS        4
+
+/*
+   If the total number of ports is larger than NR_PORTS, change this
+   constant in the definition below. No other change is necessary to
+   support more boards/ports. */
+
+#define NR_PORTS        128
+
+#define ZE_V1_NPORTS   64
+#define ZO_V1  0
+#define ZO_V2  1
+#define ZE_V1  2
+
+#define        SERIAL_PARANOIA_CHECK
+#undef CY_DEBUG_OPEN
+#undef CY_DEBUG_THROTTLE
+#undef CY_DEBUG_OTHER
+#undef CY_DEBUG_IO
+#undef CY_DEBUG_COUNT
+#undef CY_DEBUG_DTR
+#undef CY_DEBUG_WAIT_UNTIL_SENT
+#undef CY_16Y_HACK
+#undef CY_ENABLE_MONITORING
+#undef CY_PCI_DEBUG
+
+#if 0
+#define PAUSE __asm__("nop");
+#else
+#define PAUSE ;
+#endif
+
+#define cy_min(a,b) (((a)<(b))?(a):(b))
+
+#if 0
+/******** 
+ * For the next two macros, it is assumed that the buffer size is a 
+ * power of 2 
+ ********/
+
+#define CHARS_IN_BUF(buf_ctrl) \
+    ((cy_readl(&buf_ctrl->rx_put) - \
+      cy_readl(&buf_ctrl->rx_get) + \
+      cy_readl(&buf_ctrl->rx_bufsize)) & \
+                 (cy_readl(&buf_ctrl->rx_bufsize) - 1))
+
+#define SPACE_IN_BUF(buf_ctrl) \
+    ((cy_readl(&buf_ctrl->tx_get) - \
+      cy_readl(&buf_ctrl->tx_put) + \
+      cy_readl(&buf_ctrl->tx_bufsize) - 1) & \
+                 (cy_readl(&buf_ctrl->tx_bufsize) - 1))
+#endif
+
 #include <linux/module.h>
 
 #include <linux/errno.h>
@@ -289,31 +551,38 @@ static char rcsid[] =
 #include <linux/bios32.h>
 #include <linux/pci.h>
 
-#define small_delay(x) for(j=0;j<x;j++)k++;
-
+#include <linux/version.h>
 
-#define SERIAL_PARANOIA_CHECK
-#undef  SERIAL_DEBUG_OPEN
-#undef  SERIAL_DEBUG_THROTTLE
-#undef  SERIAL_DEBUG_OTHER
-#undef  SERIAL_DEBUG_IO
-#undef  SERIAL_DEBUG_COUNT
-#undef  SERIAL_DEBUG_DTR
-#undef  CYCLOM_16Y_HACK
-#undef  CYCLOM_ENABLE_MONITORING
+#define __initfunc(__arginit)  __arginit
+#define copy_from_user         memcpy_fromfs
+#define copy_to_user           memcpy_tofs
+#define cy_get_user            get_fs_long
+#define cy_put_user            put_fs_long
+#define ioremap                        vremap
 
 #ifndef MIN
-#define MIN(a,b)       ((a) < (b) ? (a) : (b))
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
 #endif
 
-#define WAKEUP_CHARS 256
+#define IS_CYC_Z(card) ((card).num_chips == 1)
+
+#define Z_FPGA_CHECK(card) \
+    ((cy_readl(&((struct RUNTIME_9060 *) \
+                ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
+
+#define ISZLOADED(card)        (((ZO_V1==cy_readl(&((struct RUNTIME_9060 *) \
+                       ((card).ctl_addr))->mail_box_0)) || \
+                       Z_FPGA_CHECK(card)) && \
+                       (ZFIRM_ID==cy_readl(&((struct FIRM_ID *) \
+                       ((card).base_addr+ID_ADDRESS))->signature)))
+
+#define WAKEUP_CHARS (SERIAL_XMIT_SIZE-256)
 
 #define STD_COM_FLAGS (0)
 
 #define SERIAL_TYPE_NORMAL  1
 #define SERIAL_TYPE_CALLOUT 2
 
-
 DECLARE_TASK_QUEUE(tq_cyclades);
 
 struct tty_driver cy_serial_driver, cy_callout_driver;
@@ -321,75 +590,42 @@ struct tty_driver cy_serial_driver, cy_callout_driver;
 static volatile int cy_irq_triggered;
 static volatile int cy_triggered;
 static int cy_wild_int_mask;
-static unsigned char *intr_base_addr;
+static volatile ucchar *intr_base_addr;
 
 
-/* This is the address lockup table. The driver will probe for Cyclom-Y/ISA
-   boards at all addresses in here. If you want the driver to probe addresses
-   in a different address, add it to this table.
-   If the driver is probing some other board and causing problems, remove the
-   address from this table.  */
+/* This is the address lookup table. The driver will probe for
+   Cyclom-Y/ISA boards at all addresses in here. If you want the
+   driver to probe addresses at a different address, add it to
+   this table.  If the driver is probing some other board and
+   causing problems, remove the offending address from this table.
+   The cy_setup function extracts additional addresses from the
+   boot options line.  The form is "cyclades=address,address..."
+*/
 
 static unsigned char *cy_isa_addresses[] = {
-       (unsigned char *) 0xD0000,
-       (unsigned char *) 0xD2000,
-       (unsigned char *) 0xD4000,
-       (unsigned char *) 0xD6000,
-       (unsigned char *) 0xD8000,
-       (unsigned char *) 0xDA000,
-       (unsigned char *) 0xDC000,
-       (unsigned char *) 0xDE000,
+        (unsigned char *) 0xD0000,
+        (unsigned char *) 0xD2000,
+        (unsigned char *) 0xD4000,
+        (unsigned char *) 0xD6000,
+        (unsigned char *) 0xD8000,
+        (unsigned char *) 0xDA000,
+        (unsigned char *) 0xDC000,
+        (unsigned char *) 0xDE000,
+        0,0,0,0,0,0,0,0
 };
-#define        NR_ISA_ADDRESSES        (sizeof(cy_isa_addresses)/sizeof(unsigned char *))
+#define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
 
 /* This is the per-card data structure containing address, irq, number of
-   channels, etc. This driver supports a maximum of NR_CARDS cards. If
-   you need to install more boards, change this constant in the definition
-   below. No other change is necessary to support more boards. */
-
-#define NR_CARDS       4
-
+   channels, etc. This driver supports a maximum of NR_CARDS cards.
+*/
 static struct cyclades_card cy_card[NR_CARDS];
 
 /* This is the per-channel data structure containing pointers, flags
-   and variables for the port. This driver supports a maximum of NR_PORTS.
-   If the total number of ports is larger than NR_PORTS, change this
-   constant in the definition below. No other change is necessary to
-   support more boards/ports. */
-
-#define NR_PORTS        64
-
+ and variables for the port. This driver supports a maximum of NR_PORTS.
+*/
 static struct cyclades_port cy_port[NR_PORTS];
 
-/*  The Cyclom-Ye has placed the sequential chips in non-sequential
- *  address order.  This look-up table overcomes that problem.
- */
-static int cy_chip_offset [] =
-    { 0x0000,
-      0x0400,
-      0x0800,
-      0x0C00,
-      0x0200,
-      0x0600,
-      0x0A00,
-      0x0E00
-    };
-
-/* PCI related definitions */
-
-static unsigned short  cy_pci_nboard = 0;
-static unsigned short  cy_isa_nboard = 0;
-static unsigned short  cy_nboard = 0;
-static unsigned short  cy_pci_dev_id[] = {
-                               PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */
-                               PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */
-                               0                       /* end of table */
-                       };
-
-int                    cy_detect_isa(void);
-int                    cy_detect_pci(void);
-
-static int             cy_next_channel = 0;    /* next minor available */
+static int cy_next_channel = 0; /* next minor available */
 
 static int serial_refcount;
 
@@ -400,17 +636,18 @@ static struct termios *serial_termios_locked[NR_PORTS];
 /* This is the per-irq data structure,
    it maps an irq to the corresponding card */
 
-struct cyclades_card   *IRQ_cards[16];
+static struct cyclades_card     *IRQ_cards[16];
 
 
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * lock it in case the copy_from_user blocks while swapping in a page,
  * and some other program tries to do a serial write at the same time.
  * Since the lock will only come under contention when the system is
  * swapping and available memory is low, it makes sense to share one
  * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
+ * memory if large numbers of serial ports are open.  This buffer is
+ * allocated when the first cy_open occurs.
  */
 static unsigned char *tmp_buf = 0;
 static struct semaphore tmp_buf_sem = MUTEX;
@@ -419,83 +656,157 @@ static struct semaphore tmp_buf_sem = MUTEX;
  * This is used to look up the divisor speeds and the timeouts
  * We're normally limited to 15 distinct baud rates.  The extra
  * are accessed via settings in info->flags.
- *         0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
- *        10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
- *                                                  HI            VHI
+ *      0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
+ *     10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
+ *                                               HI            VHI
+ *     20
  */
 static int baud_table[] = {
-           0,    50,    75,   110,   134,   150,   200,   300,   600,  1200,
-        1800,  2400,  4800,  9600, 19200, 38400, 57600, 76800,115200,150000,
-        0};
+       0,    50,    75,   110,   134,   150,   200,   300,   600,  1200,
+    1800,  2400,  4800,  9600, 19200, 38400, 57600, 76800,115200,150000,
+  230400,     0};
+
+static char baud_co_25[] = {  /* 25 MHz clock option table */
+    /* value =>    00    01   02    03    04 */
+    /* divide by    8    32   128   512  2048 */
+    0x00,  0x04,  0x04,  0x04,  0x04,  0x04,  0x03,  0x03,  0x03,  0x02,
+    0x02,  0x02,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00};
+
+static char baud_bpr_25[] = {  /* 25 MHz baud rate period table */
+    0x00,  0xf5,  0xa3,  0x6f,  0x5c,  0x51,  0xf5,  0xa3,  0x51,  0xa3,
+    0x6d,  0x51,  0xa3,  0x51,  0xa3,  0x51,  0x36,  0x29,  0x1b,  0x15};
+
+static char baud_co_60[] = {  /* 60 MHz clock option table (CD1400 J) */
+    /* value =>    00    01   02    03    04 */
+    /* divide by    8    32   128   512  2048 */
+    0x00,  0x00,  0x00,  0x04,  0x04,  0x04,  0x04,  0x04,  0x03,  0x03,
+    0x03,  0x02,  0x02,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00};
+
+static char baud_bpr_60[] = {  /* 60 MHz baud rate period table (CD1400 J) */
+    0x00,  0x82,  0x21,  0xff,  0xdb,  0xc3,  0x92,  0x62,  0xc3,  0x62,
+    0x41,  0xc3,  0x62,  0xc3,  0x62,  0xc3,  0x82,  0x62,  0x41,  0x32,
+    0x21};
 
-static char baud_co[] = {  /* 25 MHz clock option table */
-        /* value =>    00    01   02    03    04 */
-        /* divide by    8    32   128   512  2048 */
-        0x00,  0x04,  0x04,  0x04,  0x04,  0x04,  0x03,  0x03,  0x03,  0x02,
-        0x02,  0x02,  0x01,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00};
+static char baud_cor3[] = {  /* receive threshold */
+    0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,
+    0x0a,  0x0a,  0x0a,  0x09,  0x09,  0x08,  0x08,  0x08,  0x08,  0x07,
+    0x07};
 
-static char baud_bpr[] = {  /* 25 MHz baud rate period table */
-        0x00,  0xf5,  0xa3,  0x6f,  0x5c,  0x51,  0xf5,  0xa3,  0x51,  0xa3,
-        0x6d,  0x51,  0xa3,  0x51,  0xa3,  0x51,  0x36,  0x29,  0x1b,  0x15};
+/*
+ * The Cyclades driver implements HW flow control as any serial driver.
+ * The cyclades_port structure member rflow and the vector rflow_thr 
+ * allows us to take advantage of a special feature in the CD1400 to avoid 
+ * data loss even when the system interrupt latency is too high. These flags 
+ * are to be used only with very special applications. Setting these flags 
+ * requires the use of a special cable (DTR and RTS reversed). In the new 
+ * CD1400-based boards (rev. 6.00 or later), there is no need for special 
+ * cables.
+ */
 
-static char baud_cor3[] = {  /* receive threshold */
-        0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,
-        0x0a,  0x0a,  0x0a,  0x09,  0x09,  0x08,  0x08,  0x08,  0x08,  0x07};
+static char rflow_thr[] = {  /* rflow threshold */
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,  0x0a,
+    0x0a};
 
+/*  The Cyclom-Ye has placed the sequential chips in non-sequential
+ *  address order.  This look-up table overcomes that problem.
+ */
+static int cy_chip_offset [] =
+    { 0x0000,
+      0x0400,
+      0x0800,
+      0x0C00,
+      0x0200,
+      0x0600,
+      0x0A00,
+      0x0E00
+    };
 
+/* PCI related definitions */
 
-static void shutdown(struct cyclades_port *);
-static int startup (struct cyclades_port *);
-static void cy_throttle(struct tty_struct *);
-static void cy_unthrottle(struct tty_struct *);
-static void config_setup(struct cyclades_port *);
-#ifdef CYCLOM_SHOW_STATUS
+static unsigned short   cy_pci_nboard = 0;
+static unsigned short   cy_isa_nboard = 0;
+static unsigned short   cy_nboard = 0;
+static unsigned short   cy_pci_dev_id[] = {
+                           PCI_DEVICE_ID_CYCLOM_Y_Lo,/* PCI below 1Mb */
+                           PCI_DEVICE_ID_CYCLOM_Y_Hi,/* PCI above 1Mb */
+                           PCI_DEVICE_ID_CYCLOM_Z_Lo,/* PCI below 1Mb */
+                           PCI_DEVICE_ID_CYCLOM_Z_Hi,/* PCI above 1Mb */
+                           0                       /* end of table */
+                        };
+
+
+static void cy_start(struct tty_struct *);
+static void set_line_char(struct cyclades_port *);
+static void cy_probe(int, void *, struct pt_regs *);
+static void cyz_poll(unsigned long);
+#ifdef CY_SHOW_STATUS
 static void show_status(int);
 #endif
 
+/* The Cyclades-Z polling cycle is defined by this variable */
+static long cyz_polling_cycle = CZ_DEF_POLL;
+
+static int cyz_timeron = 0;
+static struct timer_list
+cyz_timerlist = {
+    NULL, NULL, 0, 0, cyz_poll
+};
+
+/**************************************************
+error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+copy_to_user  (to, from, count);
+***************************************************************
+error = verify_area(VERIFY_READ,  (void *) arg, sizeof(unsigned long *));
+copy_from_user(to, from, count);
+**************************************************/
+
 
 static inline int
 serial_paranoia_check(struct cyclades_port *info,
-                       kdev_t device, const char *routine)
+                        kdev_t device, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
     static const char *badmagic =
-       "Warning: bad magic number for serial struct (%s) in %s\n";
+        "cyc Warning: bad magic number for serial struct (%s) in %s\n";
     static const char *badinfo =
-       "Warning: null cyclades_port for (%s) in %s\n";
+        "cyc Warning: null cyclades_port for (%s) in %s\n";
     static const char *badrange =
-       "Warning: cyclades_port out of range for (%s) in %s\n";
+        "cyc Warning: cyclades_port out of range for (%s) in %s\n";
 
     if (!info) {
-       printk(badinfo, kdevname(device), routine);
-       return 1;
+        printk(badinfo, kdevname(device), routine);
+        return 1;
     }
 
     if( (long)info < (long)(&cy_port[0])
     || (long)(&cy_port[NR_PORTS]) < (long)info ){
-       printk(badrange, kdevname(device), routine);
-       return 1;
+        printk(badrange, kdevname(device), routine);
+        return 1;
     }
 
     if (info->magic != CYCLADES_MAGIC) {
-       printk(badmagic, kdevname(device), routine);
-       return 1;
+        printk(badmagic, kdevname(device), routine);
+        return 1;
     }
 #endif
-       return 0;
+        return 0;
 } /* serial_paranoia_check */
 
+
 /* The following diagnostic routines allow the driver to spew
    information on the screen, even (especially!) during interrupts.
  */
-void
+static void
 SP(char *data){
   unsigned long flags;
     save_flags(flags); cli();
         console_print(data);
     restore_flags(flags);
-}
-void
+}/* SP */
+
+static void
 CP(char data){
   unsigned long flags;
   char scrn[2];
@@ -506,111 +817,17 @@ CP(char data){
     restore_flags(flags);
 }/* CP */
 
-void CP1(int data) { (data<10)?  CP(data+'0'): CP(data+'A'-10); }/* CP1 */
-void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */
-void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */
-void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */
-
-/* This routine waits up to 1000 micro-seconds for the previous
-   command to the Cirrus chip to complete and then issues the
-   new command.  An error is returned if the previous command
-   didn't finish within the time limit.
- */
-u_short
-write_cy_cmd(u_char *base_addr, u_char cmd, int index)
-{
-  unsigned long flags;
-  volatile int  i;
-
-    save_flags(flags); cli();
-       /* Check to see that the previous command has completed */
-       for(i = 0 ; i < 100 ; i++){
-           if (base_addr[CyCCR<<index] == 0){
-               break;
-           }
-           udelay(10L);
-       }
-       /* if the CCR never cleared, the previous command
-           didn't finish within the "reasonable time" */
-       if ( i == 100 ) {
-           restore_flags(flags);
-           return (-1);
-       }
-
-       /* Issue the new command */
-       base_addr[CyCCR<<index] = cmd;
-    restore_flags(flags);
-    return(0);
-} /* write_cy_cmd */
-
-
-/* cy_start and cy_stop provide software output flow control as a
-   function of XON/XOFF, software CTS, and other such stuff. */
-
-static void
-cy_stop(struct tty_struct *tty)
-{
-  struct cyclades_card *cinfo;
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned char *base_addr;
-  int chip,channel,index;
-  unsigned long flags;
-
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_stop ttyC%d\n", info->line); /* */
-#endif
-
-    if (serial_paranoia_check(info, tty->device, "cy_stop"))
-       return;
-       
-    cinfo = &cy_card[info->card];
-    index = cinfo->bus_index;
-    channel = info->line - cinfo->first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    base_addr = (unsigned char*)
-                   (cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index));
-
-    save_flags(flags); cli();
-        base_addr[CyCAR<<index] = (u_char)(channel & 0x0003); /* index channel */
-        base_addr[CySRER<<index] &= ~CyTxMpty;
-    restore_flags(flags);
-
-    return;
-} /* cy_stop */
-
-static void
-cy_start(struct tty_struct *tty)
-{
-  struct cyclades_card *cinfo;
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned char *base_addr;
-  int chip,channel,index;
-  unsigned long flags;
-
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_start ttyC%d\n", info->line); /* */
+static void CP4(int data)
+    { (data<10)?  CP(data+'0'): CP(data+'A'-10); }/* CP4 */
+static void CP8(int data)
+    { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */
+#if 0
+static void CP16(int data)
+    { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */
+static void CP32(long data)
+    { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */
 #endif
 
-    if (serial_paranoia_check(info, tty->device, "cy_start"))
-       return;
-       
-    cinfo = &cy_card[info->card];
-    index = cinfo->bus_index;
-    channel = info->line - cinfo->first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    base_addr = (unsigned char*)
-                   (cy_card[info->card].base_addr + (cy_chip_offset[chip]<<index));
-
-    save_flags(flags); cli();
-        base_addr[CyCAR<<index] = (u_char)(channel & 0x0003);
-        base_addr[CySRER<<index] |= CyTxMpty;
-    restore_flags(flags);
-
-    return;
-} /* cy_start */
-
 
 /*
  * This routine is used by the interrupt handler to schedule
@@ -622,64 +839,319 @@ static inline void
 cy_sched_event(struct cyclades_port *info, int event)
 {
     info->event |= 1 << event; /* remember what kind of event and who */
-    queue_task_irq_off(&info->tqueue, &tq_cyclades); /* it belongs to */
+    queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */
     mark_bh(CYCLADES_BH);                       /* then trigger event */
 } /* cy_sched_event */
 
 
-static int probe_ready;
-
 /*
- * This interrupt routine is used
- * while we are probing for submarines.
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using cy_sched_event(), and they get done here.
+ *
+ * This is done through one level of indirection--the task queue.
+ * When a hardware interrupt service routine wants service by the
+ * driver's bottom half, it enqueues the appropriate tq_struct (one
+ * per port) to the tq_cyclades work queue and sets a request flag
+ * via mark_bh for processing that queue.  When the time is right,
+ * do_cyclades_bh is called (because of the mark_bh) and it requests
+ * that the work queue be processed.
+ *
+ * Although this may seem unwieldy, it gives the system a way to
+ * pass an argument (in this case the pointer to the cyclades_port
+ * structure) to the bottom half of the driver.  Previous kernels
+ * had to poll every port to see if that port needed servicing.
  */
 static void
-cy_probe(int irq, void *dev_id, struct pt_regs *regs)
+do_cyclades_bh(void)
 {
-  int save_xir, save_car;
-  int index = 0;       /* probing interrupts is only for ISA */
+    run_task_queue(&tq_cyclades);
+} /* do_cyclades_bh */
 
-    if (!probe_ready) {
-       *(intr_base_addr + (Cy_ClrIntr<<index)) = 0;
+static void
+do_softint(void *private_)
+{
+  struct cyclades_port *info = (struct cyclades_port *) private_;
+  struct tty_struct    *tty;
+
+    tty = info->tty;
+    if (!tty)
         return;
+
+    if (clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+        tty_hangup(info->tty);
+        wake_up_interruptible(&info->open_wait);
+        info->flags &= ~(ASYNC_NORMAL_ACTIVE|
+                             ASYNC_CALLOUT_ACTIVE);
+    }
+    if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
+        wake_up_interruptible(&info->open_wait);
+    }
+    if (clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
+        if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
+        && tty->ldisc.write_wakeup){
+            (tty->ldisc.write_wakeup)(tty);
+        }
+        wake_up_interruptible(&tty->write_wait);
     }
+#ifdef Z_WAKE
+    if (clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
+        wake_up_interruptible(&info->shutdown_wait);
+    }
+#endif
+} /* do_softint */
 
-    cy_irq_triggered = irq;
-    cy_triggered |= 1 << irq;
 
-       if(intr_base_addr[CySVRR<<index] != 0) {
-           save_xir = (u_char) intr_base_addr[CyTIR<<index];
-           save_car = intr_base_addr[CyCAR<<index];
-           if ((save_xir & 0x3) != 0){
-               SP("channel ");
-               CP2(save_xir);
-               SP(" requesting unexpected interrupt\n");
-           }
-           intr_base_addr[CyCAR<<index] = (save_xir & 0x3);
-           intr_base_addr[CySRER<<index] &= ~CyTxMpty;
-           intr_base_addr[CyTIR<<index] = (save_xir & 0x3f);
-           intr_base_addr[CyCAR<<index] = (save_car);
-       }
-       *(intr_base_addr + (Cy_ClrIntr<<index)) = 0; /* Cy_ClrIntr is 0x1800 */
-    return;
-} /* cy_probe */
+/***********************************************************/
+/********* Start of block of Cyclom-Y specific code ********/
 
-/* The real interrupt service routine is called
-   whenever the card wants its hand held--chars
-   received, out buffer empty, modem change, etc.
+/* This routine waits up to 1000 micro-seconds for the previous
+   command to the Cirrus chip to complete and then issues the
+   new command.  An error is returned if the previous command
+   didn't finish within the time limit.
  */
-static void
-cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static int
+cyy_issue_cmd(volatile ucchar *base_addr, u_char cmd, int index)
 {
-  struct tty_struct *tty;
-  int status;
-  struct cyclades_card *cinfo;
-  struct cyclades_port *info;
-  volatile unsigned char *base_addr, *card_base_addr;
-  int chip;
-  int save_xir, channel, save_car;
-  char data;
-  int char_count;
+  unsigned long flags;
+  volatile int  i;
+
+    save_flags(flags); cli();
+        /* Check to see that the previous command has completed */
+        for(i = 0 ; i < 100 ; i++){
+            if (cy_readb(base_addr+(CyCCR<<index)) == 0){
+                break;
+            }
+            udelay(10L);
+        }
+        /* if the CCR never cleared, the previous command
+            didn't finish within the "reasonable time" */
+        if ( i == 100 ) {
+            restore_flags(flags);
+            return (-1);
+        }
+
+        /* Issue the new command */
+        cy_writeb((u_long)base_addr+(CyCCR<<index), cmd);
+    restore_flags(flags);
+    return(0);
+} /* cyy_issue_cmd */
+
+static int probe_ready;
+
+/*
+ * Grab all interrupts in preparation for doing an automatic irq
+ * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
+ * mask of irq's which were grabbed and should therefore be freed
+ * using free_all_interrupts().
+ */
+static int
+grab_all_interrupts(int dontgrab)
+{
+  int irq_lines = 0;
+  int i, mask;
+    
+    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
+        if (!(mask & dontgrab)
+        && !request_irq(i, cy_probe,
+                    SA_INTERRUPT, "serial probe", NULL)) {
+            irq_lines |= mask;
+        }
+    }
+    return irq_lines;
+} /* grab_all_interrupts */
+
+/*
+ * Release all interrupts grabbed by grab_all_interrupts
+ */
+static void
+free_all_interrupts(int irq_lines)
+{
+  int i;
+    
+    for (i = 0; i < 16; i++) {
+        if (irq_lines & (1 << i)) {
+            free_irq(i,NULL);
+       }
+    }
+} /* free_all_interrupts */
+
+/*
+ * This routine returns a bitfield of "wild interrupts".  Basically,
+ * any unclaimed interrupts which is flapping around.
+ */
+static int
+check_wild_interrupts(void)
+{
+  int   i, mask;
+  int   wild_interrupts = 0;
+  int   irq_lines;
+  unsigned long timeout;
+  unsigned long flags;
+        
+    /*Turn on interrupts (they may be off) */
+    save_flags(flags); sti();
+
+        irq_lines = grab_all_interrupts(0);
+       
+        /*
+         * Delay for 0.1 seconds -- we use a busy loop since this may 
+         * occur during the bootup sequence
+         */
+        timeout = jiffies+(HZ/10);
+        while (timeout >= jiffies)
+            ;
+        
+        cy_triggered = 0;       /* Reset after letting things settle */
+
+        timeout = jiffies+(HZ/10);
+        while (timeout >= jiffies)
+                ;
+        
+        for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
+            if ((cy_triggered & (1 << i)) &&
+                (irq_lines & (1 << i))) {
+                    wild_interrupts |= mask;
+            }
+        }
+        free_all_interrupts(irq_lines);
+    restore_flags(flags);
+    return wild_interrupts;
+} /* check_wild_interrupts */
+
+/*
+ * This routine is called by do_auto_irq(); it attempts to determine
+ * which interrupt a serial port is configured to use.  It is not
+ * fool-proof, but it works a large part of the time.
+ */
+static int
+get_auto_irq(volatile ucchar *address)
+{
+  unsigned long        timeout;
+  volatile ucchar      *base_addr;
+  int                  index;
+  unsigned long                flags;
+
+    index = 0;  /* IRQ probing is only for ISA */
+    base_addr = address;
+    intr_base_addr = address;
+        
+    /*
+     * Enable interrupts and see who answers
+     */
+    cy_irq_triggered = 0;
+    save_flags(flags); cli();
+        cy_writeb((u_long)base_addr+(CyCAR<<index), 0);
+        cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
+        cy_writeb((u_long)base_addr+(CySRER<<index), 
+             cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
+        probe_ready = 1;
+    restore_flags(flags);
+    
+    timeout = jiffies+(HZ/50);
+    while (timeout >= jiffies) {
+        if (cy_irq_triggered)
+            break;
+    }
+    probe_ready = 0;
+    return(cy_irq_triggered);
+} /* get_auto_irq */
+
+/*
+ * Calls get_auto_irq() multiple times, to make sure we don't get
+ * faked out by random interrupts
+ */
+static int
+do_auto_irq(volatile ucchar *address)
+{
+  int                   irq_lines = 0;
+  int                   irq_try_1 = 0, irq_try_2 = 0;
+  int                   retries;
+  unsigned long                flags;
+
+    /* Turn on interrupts (they may be off) */
+    save_flags(flags); sti();
+
+        probe_ready = 0;
+
+        cy_wild_int_mask = check_wild_interrupts();
+
+        irq_lines = grab_all_interrupts(cy_wild_int_mask);
+        
+        for (retries = 0; retries < 5; retries++) {
+            if (!irq_try_1)
+                irq_try_1 = get_auto_irq(address);
+            if (!irq_try_2)
+                irq_try_2 = get_auto_irq(address);
+            if (irq_try_1 && irq_try_2) {
+                if (irq_try_1 == irq_try_2)
+                    break;
+                irq_try_1 = irq_try_2 = 0;
+            }
+        }
+    restore_flags(flags);
+    free_all_interrupts(irq_lines);
+    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
+} /* do_auto_irq */
+
+
+/*
+ * This interrupt routine is used
+ * while we are probing for submarines.
+ */
+static void
+cy_probe(int irq, void *dev_id, struct pt_regs *regs)
+{
+  int save_xir, save_car;
+  int index = 0;        /* probing interrupts is only for ISA */
+
+    if (!probe_ready) {
+        cy_writeb((u_long)intr_base_addr+(Cy_ClrIntr<<index), 0);
+        return;
+    }
+
+    cy_irq_triggered = irq;
+    cy_triggered |= 1 << irq;
+
+        if(cy_readb(intr_base_addr+(CySVRR<<index)) != 0) {
+            save_xir = (u_char) cy_readb(intr_base_addr+(CyTIR<<index));
+            save_car = cy_readb(intr_base_addr+(CyCAR<<index));
+            if ((save_xir & 0x3) != 0){
+                SP("channel ");
+                CP8(save_xir);
+                SP(" requesting unexpected interrupt\n");
+            }
+            cy_writeb((u_long)intr_base_addr+(CyCAR<<index), (save_xir & 0x3));
+            cy_writeb((u_long)intr_base_addr+(CySRER<<index),
+                cy_readb(intr_base_addr+(CySRER<<index)) & ~CyTxMpty);
+            cy_writeb((u_long)intr_base_addr+(CyTIR<<index), (save_xir & 0x3f));
+            cy_writeb((u_long)intr_base_addr+(CyCAR<<index), (save_car));
+        }
+        cy_writeb((u_long)intr_base_addr+(Cy_ClrIntr<<index), 0);
+                                 /* Cy_ClrIntr is 0x1800 */
+    return;
+} /* cy_probe */
+
+/* The real interrupt service routine is called
+   whenever the card wants its hand held--chars
+   received, out buffer empty, modem change, etc.
+ */
+static void
+cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct tty_struct *tty;
+  int status;
+  struct cyclades_card *cinfo;
+  struct cyclades_port *info;
+  volatile unsigned char *base_addr, *card_base_addr;
+  int chip;
+  int save_xir, channel, save_car;
+  char data;
+  volatile int char_count;
   int outch;
   int i,j,index;
   int too_many;
@@ -688,12 +1160,16 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
   int mdm_status;
 
     if((cinfo = IRQ_cards[irq]) == 0){
+#ifdef CY_DEBUG_INTERRUPTS
+printk("cy_interrupt: spurious interrupt %d\n\r", irq);
+#endif
         return; /* spurious interrupt */
     }
 
     card_base_addr = (unsigned char *)cinfo->base_addr;
     index = cinfo->bus_index;
 
+
     /* This loop checks all chips in the card.  Make a note whenever
        _any_ chip had some work to do, as this is considered an
        indication that there will be more to do.  Only when no chip
@@ -702,224 +1178,255 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     do{
         had_work = 0;
         for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) {
-           base_addr = (unsigned char *)
-                          (cinfo->base_addr + (cy_chip_offset[chip]<<index));
+            base_addr = (unsigned char *)
+                      (cinfo->base_addr + (cy_chip_offset[chip]<<index));
             too_many = 0;
-            while ( (status = base_addr[CySVRR<<index]) != 0x00) {
+            while ( (status = cy_readb(base_addr+(CySVRR<<index))) != 0x00) {
                 had_work++;
                 /* The purpose of the following test is to ensure that
                    no chip can monopolize the driver.  This forces the
                    chips to be checked in a round-robin fashion (after
                    draining each of a bunch (1000) of characters).
-                */
+                 */
                 if(1000<too_many++){
                     break;
                 }
-                if (status & CySRReceive) {      /* reception interrupt */
-                    /* determine the channel and change to that context */
-                    save_xir = (u_char) base_addr[CyRIR<<index];
+                if (status & CySRReceive) { /* reception interrupt */
+#ifdef CY_DEBUG_INTERRUPTS
+printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
+#endif
+                    /* determine the channel & change to that context */
+                    save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index));
                     channel = (u_short ) (save_xir & CyIRChannel);
                     i = channel + chip * 4 + cinfo->first_line;
                     info = &cy_port[i];
                     info->last_active = jiffies;
-                    save_car = base_addr[CyCAR<<index];
-                    base_addr[CyCAR<<index] = save_xir;
+                    save_car = cy_readb(base_addr+(CyCAR<<index));
+                    cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
 
                     /* if there is nowhere to put the data, discard it */
                     if(info->tty == 0){
-                        j = (base_addr[CyRIVR<<index] & CyIVRMask);
+                        j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask);
                         if ( j == CyIVRRxEx ) { /* exception */
-                            data = base_addr[CyRDSR<<index];
+                            data = cy_readb(base_addr+(CyRDSR<<index));
                         } else { /* normal character reception */
-                            char_count = base_addr[CyRDCR<<index];
+                            char_count = cy_readb(base_addr+(CyRDCR<<index));
                             while(char_count--){
-                                data = base_addr[CyRDSR<<index];
+                                data = cy_readb(base_addr+(CyRDSR<<index));
                             }
                         }
                     }else{ /* there is an open port for this data */
                         tty = info->tty;
-                        j = (base_addr[CyRIVR<<index] & CyIVRMask);
+                        j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask);
                         if ( j == CyIVRRxEx ) { /* exception */
-                            data = base_addr[CyRDSR<<index];
+                            data = cy_readb(base_addr+(CyRDSR<<index));
                             if(data & info->ignore_status_mask){
                                 continue;
                             }
                             if (tty->flip.count < TTY_FLIPBUF_SIZE){
-                               tty->flip.count++;
-                               if (data & info->read_status_mask){
-                                   if(data & CyBREAK){
-                                       *tty->flip.flag_buf_ptr++ =
-                                                               TTY_BREAK;
-                                       *tty->flip.char_buf_ptr++ =
-                                                       base_addr[CyRDSR<<index];
-                                       if (info->flags & ASYNC_SAK){
-                                           do_SAK(tty);
-                                       }
-                                   }else if(data & CyFRAME){
-                                       *tty->flip.flag_buf_ptr++ =
-                                                               TTY_FRAME;
-                                       *tty->flip.char_buf_ptr++ =
-                                                       base_addr[CyRDSR<<index];
-                                   }else if(data & CyPARITY){
-                                       *tty->flip.flag_buf_ptr++ =
-                                                               TTY_PARITY;
-                                       *tty->flip.char_buf_ptr++ =
-                                                       base_addr[CyRDSR<<index];
-                                   }else if(data & CyOVERRUN){
-                                       *tty->flip.flag_buf_ptr++ =
-                                                               TTY_OVERRUN;
-                                       *tty->flip.char_buf_ptr++ = 0;
-                                       /* If the flip buffer itself is
-                                          overflowing, we still loose
-                                          the next incoming character.
-                                        */
-                                       if(tty->flip.count < TTY_FLIPBUF_SIZE){
-                                           tty->flip.count++;
-                                           *tty->flip.flag_buf_ptr++ =
-                                                                TTY_NORMAL;
-                                           *tty->flip.char_buf_ptr++ =
-                                                       base_addr[CyRDSR<<index];
-                                       }
-                                   /* These two conditions may imply */
-                                   /* a normal read should be done. */
-                                   /* }else if(data & CyTIMEOUT){ */
-                                   /* }else if(data & CySPECHAR){ */
-                                   }else{
-                                       *tty->flip.flag_buf_ptr++ = 0;
-                                       *tty->flip.char_buf_ptr++ = 0;
-                                   }
-                               }else{
-                                   *tty->flip.flag_buf_ptr++ = 0;
-                                   *tty->flip.char_buf_ptr++ = 0;
-                               }
+                                tty->flip.count++;
+                                if (data & info->read_status_mask){
+                                    if(data & CyBREAK){
+                                        *tty->flip.flag_buf_ptr++ =
+                                                           TTY_BREAK;
+                                        *tty->flip.char_buf_ptr++ =
+                                         cy_readb(base_addr+(CyRDSR<<index));
+                                        if (info->flags & ASYNC_SAK){
+                                            do_SAK(tty);
+                                        }
+                                    }else if(data & CyFRAME){
+                                        *tty->flip.flag_buf_ptr++ =
+                                                           TTY_FRAME;
+                                        *tty->flip.char_buf_ptr++ =
+                                         cy_readb(base_addr+(CyRDSR<<index));
+                                    }else if(data & CyPARITY){
+                                        *tty->flip.flag_buf_ptr++ =
+                                                           TTY_PARITY;
+                                        *tty->flip.char_buf_ptr++ =
+                                         cy_readb(base_addr+(CyRDSR<<index));
+                                    }else if(data & CyOVERRUN){
+                                        *tty->flip.flag_buf_ptr++ =
+                                                           TTY_OVERRUN;
+                                        *tty->flip.char_buf_ptr++ = 0;
+                                        /* If the flip buffer itself is
+                                           overflowing, we still loose
+                                           the next incoming character.
+                                         */
+                                        if(tty->flip.count
+                                                  < TTY_FLIPBUF_SIZE){
+                                            tty->flip.count++;
+                                            *tty->flip.flag_buf_ptr++ =
+                                                            TTY_NORMAL;
+                                           *tty->flip.char_buf_ptr++ =
+                                           cy_readb(base_addr+(CyRDSR<<index));
+                                        }
+                                    /* These two conditions may imply */
+                                    /* a normal read should be done. */
+                                    /* }else if(data & CyTIMEOUT){ */
+                                    /* }else if(data & CySPECHAR){ */
+                                    }else{
+                                        *tty->flip.flag_buf_ptr++ = 0;
+                                        *tty->flip.char_buf_ptr++ = 0;
+                                    }
+                                }else{
+                                    *tty->flip.flag_buf_ptr++ = 0;
+                                    *tty->flip.char_buf_ptr++ = 0;
+                                }
                             }else{
-                                /* there was a software buffer overrun
-                                   and nothing could be done about it!!! */
+                                /* there was a software buffer
+                                  overrun and nothing could be
+                                  done about it!!! */
                             }
                         } else { /* normal character reception */
-                            /* load # characters available from the chip */
-                            char_count = base_addr[CyRDCR<<index];
-
-#ifdef CYCLOM_ENABLE_MONITORING
-                           ++info->mon.int_count;
-                           info->mon.char_count += char_count;
-                           if (char_count > info->mon.char_max)
-                              info->mon.char_max = char_count;
-                           info->mon.char_last = char_count;
+                            /* load # chars available from the chip */
+                            char_count = cy_readb(base_addr+(CyRDCR<<index));
+
+#ifdef CY_ENABLE_MONITORING
+                            ++info->mon.int_count;
+                            info->mon.char_count += char_count;
+                            if (char_count > info->mon.char_max)
+                               info->mon.char_max = char_count;
+                            info->mon.char_last = char_count;
 #endif
                             while(char_count--){
-                               if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+                                if (tty->flip.count >= TTY_FLIPBUF_SIZE){
                                         break;
                                 }
-                               tty->flip.count++;
-                                data = base_addr[CyRDSR<<index];
-                               *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-                               *tty->flip.char_buf_ptr++ = data;
-#ifdef CYCLOM_16Y_HACK
-                               udelay(10L);
+                                tty->flip.count++;
+                                data = cy_readb(base_addr+(CyRDSR<<index));
+                                *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+                                *tty->flip.char_buf_ptr++ = data;
+#ifdef CY_16Y_HACK
+                                udelay(10L);
 #endif
                             }
                         }
-                        queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+                        queue_task(&tty->flip.tqueue, &tq_timer);
                     }
                     /* end of service */
-                    base_addr[CyRIR<<index] = (save_xir & 0x3f);
-                    base_addr[CyCAR<<index] = (save_car);
+                    cy_writeb((u_long)base_addr+(CyRIR<<index), (save_xir & 0x3f));
+                    cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car));
                 }
 
 
-                if (status & CySRTransmit) {     /* transmission interrupt */
-                    /* Since we only get here when the transmit buffer is empty,
-                        we know we can always stuff a dozen characters. */
+                if (status & CySRTransmit) { /* transmission interrupt */
+                    /* Since we only get here when the transmit buffer
+                       is empty, we know we can always stuff a dozen
+                       characters. */
+#ifdef CY_DEBUG_INTERRUPTS
+printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
+#endif
 
-                    /* determine the channel and change to that context */
-                    save_xir = (u_char) base_addr[CyTIR<<index];
+                    /* determine the channel & change to that context */
+                    save_xir = (u_char) cy_readb(base_addr+(CyTIR<<index));
                     channel = (u_short ) (save_xir & CyIRChannel);
                     i = channel + chip * 4 + cinfo->first_line;
-                    save_car = base_addr[CyCAR<<index];
-                    base_addr[CyCAR<<index] = save_xir;
+                    save_car = cy_readb(base_addr+(CyCAR<<index));
+                    cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
 
-                    /* validate the port number (as configured and open) */
+                    /* validate the port# (as configured and open) */
                     if( (i < 0) || (NR_PORTS <= i) ){
-                        base_addr[CySRER<<index] &= ~CyTxMpty;
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                             cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
                         goto txend;
                     }
                     info = &cy_port[i];
                     info->last_active = jiffies;
                     if(info->tty == 0){
-                        base_addr[CySRER<<index] &= ~CyTxMpty;
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                             cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
                         goto txdone;
                     }
 
-                    /* load the on-chip space available for outbound data */
+                    /* load the on-chip space for outbound data */
                     char_count = info->xmit_fifo_size;
 
 
                     if(info->x_char) { /* send special char */
                         outch = info->x_char;
-                        base_addr[CyTDR<<index] = outch;
+                        cy_writeb((u_long)base_addr+(CyTDR<<index), outch);
                         char_count--;
                         info->x_char = 0;
                     }
 
-                   if (info->x_break){
-                       /*  The Cirrus chip requires the "Embedded Transmit
-                           Commands" of start break, delay, and end break
-                           sequences to be sent.  The duration of the
-                           break is given in TICs, which runs at HZ
-                           (typically 100) and the PPR runs at 200 Hz,
-                           so the delay is duration * 200/HZ, and thus a
-                           break can run from 1/100 sec to about 5/4 sec.
-                        */
-                       base_addr[CyTDR<<index] = 0; /* start break */
-                       base_addr[CyTDR<<index] = 0x81;
-                       base_addr[CyTDR<<index] = 0; /* delay a bit */
-                       base_addr[CyTDR<<index] = 0x82;
-                       base_addr[CyTDR<<index] = info->x_break*200/HZ;
-                       base_addr[CyTDR<<index] = 0; /* terminate break */
-                       base_addr[CyTDR<<index] = 0x83;
-                       char_count -= 7;
-                       info->x_break = 0;
-                   }
+                    if (info->x_break){
+                        /*  The Cirrus chip requires the "Embedded
+                           Transmit Commands" of start break, delay,
+                           and end break sequences to be sent.  The
+                           duration of the break is given in TICs,
+                           which runs at HZ (typically 100) and the
+                           PPR runs at 200 Hz, so the delay is
+                           duration * 200/HZ, and thus a break can
+                           run from 1/100 sec to about 5/4 sec.
+                           For CD1400 J or later, replace the 200 Hz
+                           by 500 Hz.
+                         */
+                       /* start break */
+                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
+                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0x81);
+                       /* delay a bit */
+                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
+                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0x82);
+                        if (info->chip_rev >= CD1400_REV_J ) {
+                           /* It is a CD1400 rev. J or later */
+                            cy_writeb((u_long)base_addr + (CyTDR<<index), 
+                                     info->x_break*500/HZ);
+                       } else {
+                            cy_writeb((u_long)base_addr + (CyTDR<<index), 
+                                     info->x_break*200/HZ);
+                       }
+                       /* finish break */
+                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
+                        cy_writeb((u_long)base_addr + (CyTDR<<index), 0x83);
+                        char_count -= 7;
+                        info->x_break = 0;
+                    }
 
+                    if (!info->xmit_cnt){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        goto txdone;
+                    }
+                    if (info->xmit_buf == 0){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        goto txdone;
+                    }
+                    if (info->tty->stopped || info->tty->hw_stopped){
+                        cy_writeb((u_long)base_addr+(CySRER<<index),
+                           cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+                        goto txdone;
+                    }
                     while (char_count-- > 0){
                         if (!info->xmit_cnt){
-                           base_addr[CySRER<<index] &= ~CyTxMpty;
-                           goto txdone;
+                            goto txdone;
                         }
-                       if (info->xmit_buf == 0){
-                           base_addr[CySRER<<index] &= ~CyTxMpty;
-                           goto txdone;
-                       }
-                       if (info->tty->stopped || info->tty->hw_stopped){
-                           base_addr[CySRER<<index] &= ~CyTxMpty;
-                           goto txdone;
-                       }
-                        /* Because the Embedded Transmit Commands have been
-                           enabled, we must check to see if the escape
-                           character, NULL, is being sent.  If it is, we
-                           must ensure that there is room for it to be
-                           doubled in the output stream.  Therefore we
-                           no longer advance the pointer when the character
-                           is fetched, but rather wait until after the check
-                           for a NULL output character. (This is necessary
-                           because there may not be room for the two chars
-                           needed to send a NULL.
-                        */
+                        /* Because the Embedded Transmit Commands have
+                           been enabled, we must check to see if the
+                          escape character, NULL, is being sent.  If it
+                          is, we must ensure that there is room for it
+                          to be doubled in the output stream.  Therefore
+                          we no longer advance the pointer when the
+                          character is fetched, but rather wait until
+                          after the check for a NULL output character.
+                          This is necessary because there may not be
+                          room for the two chars needed to send a NULL.)
+                         */
                         outch = info->xmit_buf[info->xmit_tail];
                         if( outch ){
-                           info->xmit_cnt--;
-                           info->xmit_tail = (info->xmit_tail + 1)
-                                                     & (PAGE_SIZE - 1);
-                           base_addr[CyTDR<<index] = outch;
+                            info->xmit_cnt--;
+                            info->xmit_tail = (info->xmit_tail + 1)
+                                                      & (SERIAL_XMIT_SIZE - 1);
+                            cy_writeb((u_long)base_addr+(CyTDR<<index), outch);
                         }else{
                             if(char_count > 1){
-                               info->xmit_cnt--;
-                               info->xmit_tail = (info->xmit_tail + 1)
-                                                         & (PAGE_SIZE - 1);
-                               base_addr[CyTDR<<index] = outch;
-                               base_addr[CyTDR<<index] = 0;
-                               char_count--;
+                                info->xmit_cnt--;
+                                info->xmit_tail = (info->xmit_tail + 1)
+                                                     & (SERIAL_XMIT_SIZE - 1);
+                                cy_writeb((u_long)base_addr+(CyTDR<<index), 
+                                         outch);
+                                cy_writeb((u_long)base_addr+(CyTDR<<index), 0);
+                                char_count--;
                             }else{
                             }
                         }
@@ -929,52 +1436,64 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                     if (info->xmit_cnt < WAKEUP_CHARS) {
                         cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
                     }
-
         txend:
                     /* end of service */
-                    base_addr[CyTIR<<index] = (save_xir & 0x3f);
-                    base_addr[CyCAR<<index] = (save_car);
+                    cy_writeb((u_long)base_addr+(CyTIR<<index), 
+                             (save_xir & 0x3f));
+                    cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car));
                 }
 
                 if (status & CySRModem) {        /* modem interrupt */
 
-                    /* determine the channel and change to that context */
-                    save_xir = (u_char) base_addr[CyMIR<<index];
+                    /* determine the channel & change to that context */
+                    save_xir = (u_char) cy_readb(base_addr+(CyMIR<<index));
                     channel = (u_short ) (save_xir & CyIRChannel);
-                    info = &cy_port[channel + chip * 4 + cinfo->first_line];
+                    info = &cy_port[channel + chip * 4
+                                          + cinfo->first_line];
                     info->last_active = jiffies;
-                    save_car = base_addr[CyCAR<<index];
-                    base_addr[CyCAR<<index] = save_xir;
+                    save_car = cy_readb(base_addr+(CyCAR<<index));
+                    cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
 
-                    mdm_change = base_addr[CyMISR<<index];
-                    mdm_status = base_addr[CyMSVR1<<index];
+                    mdm_change = cy_readb(base_addr+(CyMISR<<index));
+                    mdm_status = cy_readb(base_addr+(CyMSVR1<<index));
 
-                    if(info->tty == 0){ /* nowhere to put the data, ignore it */
+                    if(info->tty == 0){/* no place for data, ignore it*/
                         ;
                     }else{
                         if((mdm_change & CyDCD)
                         && (info->flags & ASYNC_CHECK_CD)){
                             if(mdm_status & CyDCD){
-                                cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
-                            }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE)
-                                     &&(info->flags & ASYNC_CALLOUT_NOHUP))){
-                                cy_sched_event(info, Cy_EVENT_HANGUP);
+                                cy_sched_event(info,
+                                   Cy_EVENT_OPEN_WAKEUP);
+                            }else if(!((info->flags
+                                       & ASYNC_CALLOUT_ACTIVE)
+                                &&(info->flags
+                                   & ASYNC_CALLOUT_NOHUP))){
+                                cy_sched_event(info,
+                                   Cy_EVENT_HANGUP);
                             }
                         }
                         if((mdm_change & CyCTS)
                         && (info->flags & ASYNC_CTS_FLOW)){
                             if(info->tty->hw_stopped){
                                 if(mdm_status & CyCTS){
-                                    /* !!! cy_start isn't used because... */
+                                    /* cy_start isn't used
+                                        because... !!! */
                                     info->tty->hw_stopped = 0;
-                                   base_addr[CySRER<<index] |= CyTxMpty;
-                                   cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+                                  cy_writeb((u_long)base_addr+(CySRER<<index),
+                                       cy_readb(base_addr+(CySRER<<index)) | 
+                                       CyTxMpty);
+                                    cy_sched_event(info,
+                                       Cy_EVENT_WRITE_WAKEUP);
                                 }
                             }else{
                                 if(!(mdm_status & CyCTS)){
-                                    /* !!! cy_stop isn't used because... */
+                                    /* cy_stop isn't used
+                                        because ... !!! */
                                     info->tty->hw_stopped = 1;
-                                   base_addr[CySRER<<index] &= ~CyTxMpty;
+                                  cy_writeb((u_long)base_addr+(CySRER<<index),
+                                       cy_readb(base_addr+(CySRER<<index)) & 
+                                       ~CyTxMpty);
                                 }
                             }
                         }
@@ -984,225 +1503,424 @@ cy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                         }
                     }
                     /* end of service */
-                    base_addr[CyMIR<<index] = (save_xir & 0x3f);
-                    base_addr[CyCAR<<index] = save_car;
+                    cy_writeb((u_long)base_addr+(CyMIR<<index), 
+                             (save_xir & 0x3f));
+                    cy_writeb((u_long)base_addr+(CyCAR<<index), save_car);
                 }
             }          /* end while status != 0 */
         }            /* end loop for chips... */
     } while(had_work);
 
    /* clear interrupts */
-   *(card_base_addr + (Cy_ClrIntr<<index)) = 0; /* Cy_ClrIntr is 0x1800 */
+   cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<<index), 0);
+                                /* Cy_ClrIntr is 0x1800 */
+} /* cyy_interrupt */
 
-} /* cy_interrupt */
+/***********************************************************/
+/********* End of block of Cyclom-Y specific code **********/
+/******** Start of block of Cyclades-Z specific code *********/
+/***********************************************************/
 
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * cy_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using cy_sched_event(), and they get done here.
- *
- * This is done through one level of indirection--the task queue.
- * When a hardware interrupt service routine wants service by the
- * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the tq_cyclades work queue and sets a request flag
- * via mark_bh for processing that queue.  When the time is right,
- * do_cyclades_bh is called (because of the mark_bh) and it requests
- * that the work queue be processed.
- *
- * Although this may seem unwieldy, it gives the system a way to
- * pass an argument (in this case the pointer to the cyclades_port
- * structure) to the bottom half of the driver.  Previous kernels
- * had to poll every port to see if that port needed servicing.
- */
-static void
-do_cyclades_bh(void)
-{
-    run_task_queue(&tq_cyclades);
-} /* do_cyclades_bh */
 
-static void
-do_softint(void *private_)
+static int
+cyz_fetch_msg( struct cyclades_card *cinfo,
+           uclong *channel, ucchar *cmd, uclong *param)
 {
-  struct cyclades_port *info = (struct cyclades_port *) private_;
-  struct tty_struct    *tty;
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  unsigned long loc_doorbell;
+
+    firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+    if (!ISZLOADED(*cinfo)){
+       return (-1);
+    }
+    zfw_ctrl = (struct ZFW_CTRL *)
+              (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
+    board_ctrl = &zfw_ctrl->board_ctrl;
+
+    loc_doorbell = cy_readl(&((struct RUNTIME_9060 *)
+                     (cinfo->ctl_addr))->loc_doorbell);
+    if (loc_doorbell){
+       *cmd = (char)(0xff & loc_doorbell);
+       *channel = cy_readl(&board_ctrl->fwcmd_channel);
+       *param = (uclong)cy_readl(&board_ctrl->fwcmd_param);
+       cy_writel(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->loc_doorbell, 
+                 0xffffffff);
+       return 1;
+    }
+    return 0;
+} /* cyz_fetch_msg */
 
-    tty = info->tty;
-    if (!tty)
-       return;
 
-    if (clear_bit(Cy_EVENT_HANGUP, &info->event)) {
-       tty_hangup(info->tty);
-       wake_up_interruptible(&info->open_wait);
-       info->flags &= ~(ASYNC_NORMAL_ACTIVE|
-                            ASYNC_CALLOUT_ACTIVE);
-    }
-    if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
-       wake_up_interruptible(&info->open_wait);
+static int
+cyz_issue_cmd( struct cyclades_card *cinfo,
+           uclong channel, ucchar cmd, uclong param)
+{
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  volatile uclong *pci_doorbell;
+  int index;
+
+    firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+    if (!ISZLOADED(*cinfo)){
+       return (-1);
     }
-    if (clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
-       if((tty->flags & (1<< TTY_DO_WRITE_WAKEUP))
-       && tty->ldisc.write_wakeup){
-           (tty->ldisc.write_wakeup)(tty);
-       }
-       wake_up_interruptible(&tty->write_wait);
+    zfw_ctrl = (struct ZFW_CTRL *)
+              (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
+    board_ctrl = &zfw_ctrl->board_ctrl;
+
+    index = 0;
+    pci_doorbell = (uclong *)(&((struct RUNTIME_9060 *)
+                               (cinfo->ctl_addr))->pci_doorbell);
+    while( (cy_readl(pci_doorbell) & 0xff) != 0){
+        if (index++ == 1000){
+            return(-1);
+        }
+       udelay(50L);
     }
-} /* do_softint */
+    cy_writel((u_long)&board_ctrl->hcmd_channel, channel);
+    cy_writel((u_long)&board_ctrl->hcmd_param , param);
+    cy_writel((u_long)pci_doorbell, (long)cmd);
 
+    return(0);
+} /* cyz_issue_cmd */
 
-/*
- * Grab all interrupts in preparation for doing an automatic irq
- * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
- * mask of irq's which were grabbed and should therefore be freed
- * using free_all_interrupts().
- */
+
+#if 0
 static int
-grab_all_interrupts(int dontgrab)
-{
-  int irq_lines = 0;
-  int i, mask;
-    
-    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
-       if (!(mask & dontgrab)
-       && !request_irq(i, cy_probe, SA_INTERRUPT, "serial probe", NULL)) {
-           irq_lines |= mask;
-       }
+cyz_update_channel( struct cyclades_card *cinfo,
+           u_long channel, u_char mode, u_char cmd)
+{ 
+  struct FIRM_ID *firm_id =
+      (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+  struct ZFW_CTRL *zfw_ctrl;
+  struct CH_CTRL *ch_ctrl;
+
+    if (!ISZLOADED(*cinfo)){
+       return (-1);
     }
-    return irq_lines;
-} /* grab_all_interrupts */
+    zfw_ctrl = (struct ZFW_CTRL *)
+              (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
+    ch_ctrl = zfw_ctrl->ch_ctrl;
+
+    cy_writel(&ch_ctrl[channel].op_mode, (uclong)mode);
+
+    return cyz_issue_cmd(cinfo, channel, cmd, 0L);
+
+} /* cyz_update_channel */
+#endif
+
 
-/*
- * Release all interrupts grabbed by grab_all_interrupts
- */
 static void
-free_all_interrupts(int irq_lines)
+cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-  int i;
-    
-    for (i = 0; i < 16; i++) {
-       if (irq_lines & (1 << i))
-           free_irq(i,NULL);
-    }
-} /* free_all_interrupts */
+} /* cyz_interrupt */
 
-/*
- * This routine returns a bitfield of "wild interrupts".  Basically,
- * any unclaimed interrupts which is flapping around.
- */
-static int
-check_wild_interrupts(void)
-{
-  int  i, mask;
-  int  wild_interrupts = 0;
-  int  irq_lines;
-  unsigned long timeout;
-  unsigned long flags;
-       
-    /*Turn on interrupts (they may be off) */
-    save_flags(flags); sti();
 
-       irq_lines = grab_all_interrupts(0);
-       
-       /*
-        * Delay for 0.1 seconds -- we use a busy loop since this may 
-        * occur during the bootup sequence
-        */
-       timeout = jiffies+10;
-       while (timeout >= jiffies)
-           ;
-       
-       cy_triggered = 0;       /* Reset after letting things settle */
-
-       timeout = jiffies+10;
-       while (timeout >= jiffies)
-               ;
-       
-       for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
-           if ((cy_triggered & (1 << i)) &&
-               (irq_lines & (1 << i))) {
-                   wild_interrupts |= mask;
+static void
+cyz_poll(unsigned long arg)
+{
+  static volatile struct FIRM_ID *firm_id;
+  static volatile struct ZFW_CTRL *zfw_ctrl;
+  static volatile struct BOARD_CTRL *board_ctrl;
+  static volatile struct CH_CTRL *ch_ctrl;
+  static volatile struct BUF_CTRL *buf_ctrl;
+  struct cyclades_card *cinfo;
+  struct cyclades_port *info;
+  struct tty_struct *tty;
+  int card, port;
+  int char_count;
+#ifdef BLOCKMOVE
+  int small_count;
+#endif
+  char data;
+  uclong channel;
+  ucchar cmd;
+  uclong param;
+  uclong hw_ver, fw_ver;
+  volatile uclong tx_put, tx_get, tx_bufsize;
+  volatile uclong rx_put, rx_get, rx_bufsize;
+
+    cyz_timerlist.expires = jiffies + (HZ);
+    for (card = 0 ; card < NR_CARDS ; card++){
+       cinfo = &cy_card[card];
+       if (!IS_CYC_Z(*cinfo)) continue;
+
+
+       firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
+        if (!ISZLOADED(*cinfo)) {
+           cinfo->inact_ctrl = 0;
+           continue;
+       }
+
+       zfw_ctrl = (struct ZFW_CTRL *)
+                  (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
+       board_ctrl = &(zfw_ctrl->board_ctrl);
+       fw_ver = cy_readl(&board_ctrl->fw_version);
+       hw_ver = cy_readl(&((struct RUNTIME_9060 *)
+                            (cinfo->ctl_addr))->mail_box_0);
+
+       /* Enables the firmware inactivity control */
+       if ((fw_ver > 0x00000310L) && (!cinfo->inact_ctrl)) {
+           param = cyz_issue_cmd( &cy_card[card], 0L, C_CM_TINACT, 0L);
+           cinfo->inact_ctrl = 1;
+       }
+
+       while(cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1){
+           char_count = 0;
+           info = &cy_port[ channel + cinfo->first_line ];
+            if((tty = info->tty) == 0) continue;
+           ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+           buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+           info->jiffies[0] = jiffies;
+
+           switch(cmd){
+           case C_CM_PR_ERROR:
+               tty->flip.count++;
+               *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+               *tty->flip.char_buf_ptr++ = 0;
+               char_count++;
+               break;
+           case C_CM_FR_ERROR:
+               tty->flip.count++;
+               *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+               *tty->flip.char_buf_ptr++ = 0;
+               char_count++;
+               break;
+           case C_CM_RXBRK:
+               tty->flip.count++;
+               *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+               *tty->flip.char_buf_ptr++ = 0;
+               char_count++;
+               break;
+           case C_CM_MDCD:
+               if (info->flags & ASYNC_CHECK_CD){
+                   if ((fw_ver > 241 ? 
+                          ((u_long)param) : 
+                          cy_readl(&ch_ctrl[channel].rs_status)) & C_RS_DCD) {
+                       /* SP("Open Wakeup\n"); */
+                       cy_sched_event(info,
+                           Cy_EVENT_OPEN_WAKEUP);
+                   }else if(!((info->flags
+                               & ASYNC_CALLOUT_ACTIVE)
+                        &&(info->flags
+                           & ASYNC_CALLOUT_NOHUP))){
+                       /* SP("Hangup\n"); */
+                       cy_sched_event(info,
+                           Cy_EVENT_HANGUP);
+                   }
+               }
+               break;
+           case C_CM_MCTS:
+               if (info->flags & ASYNC_CTS_FLOW) {
+                   if(info->tty->hw_stopped){
+                       if( cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD){
+                           /* cy_start isn't used because... 
+                              HW flow is handled by the board */
+                           /* SP("Write Wakeup\n"); */
+                           cy_sched_event(info,
+                               Cy_EVENT_WRITE_WAKEUP);
+                       }
+                   }else{
+                       if(!(cy_readl(&ch_ctrl[channel].rs_status) & C_RS_CTS)){
+                           /* cy_stop isn't used because 
+                              HW flow is handled by the board */
+                           /* SP("Write stop\n"); */
+                       }
+                   }
+               }
+               break;
+           case C_CM_MRI:
+               break;
+           case C_CM_MDSR:
+               break;
+#ifdef Z_WAKE
+           case C_CM_IOCTLW:
+               cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+               break;
+#endif
+           case C_CM_FATAL:
+               /* should do something with this !!! */
+               break;
+           }
+           if(char_count){
+               queue_task(&tty->flip.tqueue, &tq_timer);
            }
        }
-       free_all_interrupts(irq_lines);
-    restore_flags(flags);
-    return wild_interrupts;
-} /* check_wild_interrupts */
+       for (port = 0; port < cy_readl(&board_ctrl->n_channel); port++){
+           info = &cy_port[ port + cinfo->first_line ];
+            tty = info->tty;
+           ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
+           buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
+
+/* Removed due to compilation problems in Alpha systems */
+//         if ((char_count = CHARS_IN_BUF(buf_ctrl))){
+
+           rx_get = cy_readl(&buf_ctrl->rx_get);
+           rx_put = cy_readl(&buf_ctrl->rx_put);
+           rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
+           if (rx_put >= rx_get)
+               char_count = rx_put - rx_get;
+           else
+               char_count = rx_put - rx_get + rx_bufsize;
+
+           if ( char_count ){
+
+               info->last_active = jiffies;
+               info->jiffies[1] = jiffies;
+
+#ifdef CY_ENABLE_MONITORING
+               info->mon.int_count++;
+               info->mon.char_count += char_count;
+               if (char_count > info->mon.char_max)
+                  info->mon.char_max = char_count;
+               info->mon.char_last = char_count;
+#endif
+               if( tty == 0){
+                   /* flush received characters */
+                   rx_get = (rx_get + char_count) & (rx_bufsize - 1);
+                   /* SP("-"); */
+                   info->rflush_count++;
+               }else{
+#ifdef BLOCKMOVE
+               /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
+                  for performance, but because of buffer boundaries, there
+                  may be several steps to the operation */
+                   while(0 < (small_count
+                       = cy_min((rx_bufsize - rx_get),
+                                cy_min((TTY_FLIPBUF_SIZE - tty->flip.count),
+                                       char_count)))){
+
+                       memcpy_fromio(tty->flip.char_buf_ptr,
+                                     (char *)(cinfo->base_addr
+                                      + cy_readl(&buf_ctrl->rx_bufaddr)
+                                      + rx_get),
+                                     small_count);
+
+                       tty->flip.char_buf_ptr += small_count;
+                       memset(tty->flip.flag_buf_ptr,
+                              TTY_NORMAL,
+                              small_count);
+                       tty->flip.flag_buf_ptr += small_count;
+                       rx_get = (rx_get + small_count) & (rx_bufsize - 1);
+                       char_count -= small_count;
+                       tty->flip.count += small_count;
+                   }
+#else
+                   while(char_count--){
+                       if (tty->flip.count >= TTY_FLIPBUF_SIZE){
+                               break;
+                       }
+                       data = cy_readb(cinfo->base_addr +
+                                  cy_readl(&buf_ctrl->rx_bufaddr) + rx_get);
+                       rx_get = (rx_get + 1) & (rx_bufsize - 1);
+                       tty->flip.count++;
+                       *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+                       *tty->flip.char_buf_ptr++ = data;
+                   }
+#endif
+                   queue_task(&tty->flip.tqueue, &tq_timer);
+               }
+               /* Update rx_get */
+               cy_writel(&buf_ctrl->rx_get, rx_get);
+           }
 
-/*
- * This routine is called by do_auto_irq(); it attempts to determine
- * which interrupt a serial port is configured to use.  It is not
- * fool-proof, but it works a large part of the time.
- */
-static int
-get_auto_irq(unsigned char *address)
-{
-  unsigned long timeout;
-  unsigned char *base_addr;
-  int          index;
+/* Removed due to compilation problems in Alpha systems */
+//         if ((char_count = SPACE_IN_BUF(buf_ctrl))){
 
-    index = 0; /* IRQ probing is only for ISA */
-    base_addr = address;
-    intr_base_addr = address;
-       
-    /*
-     * Enable interrupts and see who answers
-     */
-    cy_irq_triggered = 0;
-    cli();
-       base_addr[CyCAR<<index] = 0;
-       write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
-       base_addr[CySRER<<index] |= CyTxMpty;
-       probe_ready = 1;
-    sti();
-    
-    timeout = jiffies+2;
-    while (timeout >= jiffies) {
-       if (cy_irq_triggered)
-           break;
-    }
-    probe_ready = 0;
-    return(cy_irq_triggered);
-} /* get_auto_irq */
+           tx_get = cy_readl(&buf_ctrl->tx_get);
+           tx_put = cy_readl(&buf_ctrl->tx_put);
+           tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+           if (tx_put >= tx_get)
+               char_count = tx_get - tx_put - 1 + tx_bufsize;
+           else
+               char_count = tx_get - tx_put - 1;
 
-/*
- * Calls get_auto_irq() multiple times, to make sure we don't get
- * faked out by random interrupts
- */
-static int
-do_auto_irq(unsigned char *address)
-{
-  int                  irq_lines = 0;
-  int                  irq_try_1 = 0, irq_try_2 = 0;
-  int                  retries;
-  unsigned long flags;
+           if ( char_count ){
 
-    /* Turn on interrupts (they may be off) */
-    save_flags(flags); sti();
+               if( tty == 0 ){
+                   goto ztxdone;
+               }
 
-       probe_ready = 0;
+               if(info->x_char) { /* send special char */
+                   data = info->x_char;
 
-        cy_wild_int_mask = check_wild_interrupts();
+                   cy_writeb((cinfo->base_addr +
+                             cy_readl(&buf_ctrl->tx_bufaddr) + tx_put), data);
+                   tx_put = (tx_put + 1) & (tx_bufsize - 1);
+                   info->x_char = 0;
+                   char_count--;
+                   info->last_active = jiffies;
+                   info->jiffies[2] = jiffies;
+               }
+               if (info->x_break){
+                   printk("cyc cyz_poll shouldn't see x_break\n");
+                   info->x_break = 0;
+                   info->last_active = jiffies;
+                   info->jiffies[2] = jiffies;
+               }
+#ifdef BLOCKMOVE
+               while(0 < (small_count
+                   = cy_min((tx_bufsize - tx_put),
+                            cy_min ((SERIAL_XMIT_SIZE - info->xmit_tail),
+                                    cy_min(info->xmit_cnt, char_count))))){
+
+                   memcpy_toio((char *)(cinfo->base_addr
+                                + cy_readl(&buf_ctrl->tx_bufaddr) + tx_put),
+                               &info->xmit_buf[info->xmit_tail],
+                               small_count);
+
+                   tx_put = (tx_put + small_count) & (tx_bufsize - 1);
+                   char_count -= small_count;
+                   info->xmit_cnt -= small_count;
+                   info->xmit_tail =
+                      (info->xmit_tail + small_count) & (SERIAL_XMIT_SIZE - 1);
+                   info->last_active = jiffies;
+                   info->jiffies[2] = jiffies;
+               }
+#else
+               while (info->xmit_cnt && char_count){
+                   data = info->xmit_buf[info->xmit_tail];
+                   info->xmit_cnt--;
+                   info->xmit_tail =
+                       (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+
+                   cy_writeb(cinfo->base_addr +
+                             cy_readl(&buf_ctrl->tx_bufaddr) + tx_put, 
+                             data);
+                   tx_put = (tx_put + 1) & (tx_bufsize - 1);
+                   char_count--;
+                   info->last_active = jiffies;
+                   info->jiffies[2] = jiffies;
+               }
 
-       irq_lines = grab_all_interrupts(cy_wild_int_mask);
-       
-       for (retries = 0; retries < 5; retries++) {
-           if (!irq_try_1)
-               irq_try_1 = get_auto_irq(address);
-           if (!irq_try_2)
-               irq_try_2 = get_auto_irq(address);
-           if (irq_try_1 && irq_try_2) {
-               if (irq_try_1 == irq_try_2)
-                   break;
-               irq_try_1 = irq_try_2 = 0;
+#endif
+           ztxdone:
+               if (info->xmit_cnt < WAKEUP_CHARS) {
+                   cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+               }
+               /* Update tx_put */
+               cy_writel(&buf_ctrl->tx_put, tx_put);
            }
        }
-    restore_flags(flags);
-    free_all_interrupts(irq_lines);
-    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
-} /* do_auto_irq */
+       /* poll every 40 ms */
+       cyz_timerlist.expires = jiffies + cyz_polling_cycle;
+
+       /* refresh inactivity counter */
+       if (cinfo->inact_ctrl) {
+               cy_writel(&board_ctrl->inactivity, (uclong) ZF_TINACT);
+       }
+    }
+    add_timer(&cyz_timerlist);
+
+    return;
+} /* cyz_poll */
+
+
+/********** End of block of Cyclades-Z specific code *********/
+/***********************************************************/
 
 
 /* This is called whenever a port becomes active;
@@ -1216,72 +1934,137 @@ startup(struct cyclades_port * info)
   int card,chip,channel,index;
 
     if (info->flags & ASYNC_INITIALIZED){
-       return 0;
+        return 0;
     }
 
     if (!info->type){
-       if (info->tty){
-           set_bit(TTY_IO_ERROR, &info->tty->flags);
-       }
-       return 0;
+        if (info->tty){
+            set_bit(TTY_IO_ERROR, &info->tty->flags);
+        }
+        return 0;
     }
     if (!info->xmit_buf){
-       info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
-       if (!info->xmit_buf){
-           return -ENOMEM;
-       }
+        info->xmit_buf = (unsigned char *) get_free_page (GFP_KERNEL);
+        if (!info->xmit_buf){
+            return -ENOMEM;
+        }
     }
 
-    config_setup(info);
+    set_line_char(info);
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
                   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
 
 #ifdef SERIAL_DEBUG_OPEN
-    printk("startup card %d, chip %d, channel %d, base_addr %lx",
-        card, chip, channel, (long)base_addr);/**/
+       printk("cyc startup card %d, chip %d, channel %d, base_addr %lx\n",
+            card, chip, channel, (long)base_addr);/**/
 #endif
 
-    save_flags(flags); cli();
-       base_addr[CyCAR<<index] = (u_char)channel;
+       save_flags(flags); cli();
+           cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
 
-       base_addr[CyRTPR<<index] = (info->default_timeout
-                            ? info->default_timeout
-                            : 0x02); /* 10ms rx timeout */
+           cy_writeb((ulong)base_addr+(CyRTPR<<index), (info->default_timeout
+                                ? info->default_timeout
+                                : 0x02)); /* 10ms rx timeout */
 
-       write_cy_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+           cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
 
-       base_addr[CyCAR<<index] = (u_char)channel; /* !!! Is this needed? */
-       base_addr[CyMSVR1<<index] = CyRTS;
-       base_addr[CyMSVR2<<index] = CyDTR;
+           cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
+           cy_writeb((ulong)base_addr+(CyMSVR1<<index), CyRTS);
+           cy_writeb((ulong)base_addr+(CyMSVR2<<index), CyDTR);
 
 #ifdef SERIAL_DEBUG_DTR
-        printk("cyc: %d: raising DTR\n", __LINE__);
-        printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+           printk("cyc:startup raising DTR\n");
+           printk("     status: 0x%x, 0x%x\n",
+                  cy_readb(base_addr+(CyMSVR1<<index)), 
+                   cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
 
-       base_addr[CySRER<<index] |= CyRxData;
-       info->flags |= ASYNC_INITIALIZED;
+           cy_writeb((u_long)base_addr+(CySRER<<index),
+               cy_readb(base_addr+(CySRER<<index)) | CyRxData);
+           info->flags |= ASYNC_INITIALIZED;
+
+           if (info->tty){
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+           }
+           info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+       restore_flags(flags);
+    } else {
+      struct FIRM_ID *firm_id;
+      struct ZFW_CTRL *zfw_ctrl;
+      struct BOARD_CTRL *board_ctrl;
+      struct CH_CTRL *ch_ctrl;
+      int retval;
+
+       base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+        firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+        if (!ISZLOADED(cy_card[card])){
+           return -ENODEV;
+       }
+
+       zfw_ctrl =
+           (struct ZFW_CTRL *)
+               (cy_card[card].base_addr + cy_readl(&firm_id->zfwctrl_addr));
+       board_ctrl = &zfw_ctrl->board_ctrl;
+       ch_ctrl = zfw_ctrl->ch_ctrl;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
+            card, channel, (long)base_addr);/**/
+#endif
 
+       cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
+#ifdef Z_WAKE
+       cy_writel(&ch_ctrl[channel].intr_enable, 
+                 C_IN_MDCD|C_IN_MCTS|C_IN_IOCTLW);
+#else
+       cy_writel(&ch_ctrl[channel].intr_enable, 
+                 C_IN_MDCD|C_IN_MCTS);
+#endif
+       retval = cyz_issue_cmd( &cy_card[card],
+           channel, C_CM_IOCTL, 0L);   /* was C_CM_RESET */
+       if (retval != 0){
+           printk("cyc:startup(1) retval was %x\n", retval);
+       }
+
+       /* set timeout !!! */
+       /* set RTS and DTR !!! */
+       cy_writel(&ch_ctrl[channel].rs_control,
+             cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR) ;
+       retval = cyz_issue_cmd(&cy_card[info->card],
+           channel, C_CM_IOCTLM, 0L);
+       if (retval != 0){
+           printk("cyc:startup(2) retval was %x\n", retval);
+       }
+#ifdef SERIAL_DEBUG_DTR
+           printk("cyc:startup raising Z DTR\n");
+#endif
+
+       /* enable send, recv, modem !!! */
+
+       info->flags |= ASYNC_INITIALIZED;
        if (info->tty){
            clear_bit(TTY_IO_ERROR, &info->tty->flags);
        }
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
-    restore_flags(flags);
+    }
 
 #ifdef SERIAL_DEBUG_OPEN
-    printk(" done\n");
+       printk(" cyc startup done\n");
 #endif
-    return 0;
+       return 0;
 } /* startup */
 
-void
+
+static void
 start_xmit( struct cyclades_port *info )
 {
   unsigned long flags;
@@ -1290,18 +2073,25 @@ start_xmit( struct cyclades_port *info )
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
 
-    save_flags(flags); cli();
-       base_addr[CyCAR<<index] = channel;
-       base_addr[CySRER<<index] |= CyTxMpty;
-    restore_flags(flags);
+       save_flags(flags); cli();
+           cy_writeb((u_long)base_addr+(CyCAR<<index), channel);
+           cy_writeb((u_long)base_addr+(CySRER<<index), 
+               cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
+       restore_flags(flags);
+    } else {
+       /* Don't have to do anything at this time */
+    }
 } /* start_xmit */
 
+
 /*
  * This routine shuts down a serial port; interrupts are disabled,
  * and DTR is dropped if the hangup on close termio flag is on.
@@ -1314,326 +2104,658 @@ shutdown(struct cyclades_port * info)
   int card,chip,channel,index;
 
     if (!(info->flags & ASYNC_INITIALIZED)){
-       return;
+        return;
     }
 
     card = info->card;
     channel = info->line - cy_card[card].first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
 
 #ifdef SERIAL_DEBUG_OPEN
-    printk("shutdown card %d, chip %d, channel %d, base_addr %lx\n",
-           card, chip, channel, (long)base_addr);
+    printk("cyc shutdown Y card %d, chip %d, channel %d, base_addr %lx\n",
+               card, chip, channel, (long)base_addr);
 #endif
 
-    /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
-       SENT BEFORE DROPPING THE LINE !!!  (Perhaps
-       set some flag that is read when XMTY happens.)
-       Other choices are to delay some fixed interval
-       or schedule some later processing.
-     */
-    save_flags(flags); cli();
-       if (info->xmit_buf){
-            unsigned char * temp;
-            temp = info->xmit_buf;
-            info->xmit_buf = 0;
-           free_page((unsigned long) temp);
-       }
+       save_flags(flags); cli();
 
-       base_addr[CyCAR<<index] = (u_char)channel;
-       if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
-           base_addr[CyMSVR1<<index] = ~CyRTS;
-           base_addr[CyMSVR2<<index] = ~CyDTR;
+           if (info->xmit_buf){
+               unsigned char * temp;
+               temp = info->xmit_buf;
+               info->xmit_buf = 0;
+               free_page((unsigned long) temp);
+           }
+           cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+           if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+               cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
+               cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
 #ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+               printk("cyc shutdown dropping DTR\n");
+               printk("     status: 0x%x, 0x%x\n",
+                   cy_readb(base_addr+(CyMSVR1<<index)), 
+                    cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-        }
-       write_cy_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
-         /* it may be appropriate to clear _XMIT at
-           some later date (after testing)!!! */
+           }
+           cyy_issue_cmd(base_addr,CyCHAN_CTL|CyDIS_RCVR,index);
+            /* it may be appropriate to clear _XMIT at
+              some later date (after testing)!!! */
 
-       if (info->tty){
-           set_bit(TTY_IO_ERROR, &info->tty->flags);
+           if (info->tty){
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+           }
+           info->flags &= ~ASYNC_INITIALIZED;
+       restore_flags(flags);
+    } else {
+      struct FIRM_ID *firm_id;
+      struct ZFW_CTRL *zfw_ctrl;
+      struct BOARD_CTRL *board_ctrl;
+      struct CH_CTRL *ch_ctrl;
+      int retval;
+
+       base_addr = (unsigned char*) (cy_card[card].base_addr);
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
+               card, channel, (long)base_addr);
+#endif
+
+        firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+        if (!ISZLOADED(cy_card[card])) {
+           return;
        }
-       info->flags &= ~ASYNC_INITIALIZED;
-    restore_flags(flags);
+
+       zfw_ctrl =
+           (struct ZFW_CTRL *)
+               (cy_card[card].base_addr + cy_readl(&firm_id->zfwctrl_addr));
+       board_ctrl = &(zfw_ctrl->board_ctrl);
+       ch_ctrl = zfw_ctrl->ch_ctrl;
+
+       save_flags(flags); cli();
+
+           if (info->xmit_buf){
+               unsigned char * temp;
+               temp = info->xmit_buf;
+               info->xmit_buf = 0;
+               free_page((unsigned long) temp);
+           }
+           
+           if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+               cy_writel((u_long)&ch_ctrl[channel].rs_control,
+                   (uclong)(cy_readl(&ch_ctrl[channel].rs_control) & 
+                   ~(C_RS_RTS | C_RS_DTR)));
+               retval = cyz_issue_cmd(&cy_card[info->card],
+                       channel, C_CM_IOCTLM, 0L);
+               if (retval != 0){
+                   printk("cyc:shutdown retval (2) was %x\n", retval);
+               }
+#ifdef SERIAL_DEBUG_DTR
+               printk("cyc:shutdown dropping Z DTR\n");
+#endif
+           }
+           
+           if (info->tty){
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+           }
+           info->flags &= ~ASYNC_INITIALIZED;
+
+       restore_flags(flags);
+    }
 
 #ifdef SERIAL_DEBUG_OPEN
-    printk(" done\n");
+    printk(" cyc shutdown done\n");
 #endif
     return;
 } /* shutdown */
 
+
 /*
- * This routine finds or computes the various line characteristics.
+ * ------------------------------------------------------------
+ * cy_open() and friends
+ * ------------------------------------------------------------
  */
-static void
-config_setup(struct cyclades_port * info)
+
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+                           struct cyclades_port *info)
 {
+  struct wait_queue wait = { current, NULL };
+  struct cyclades_card *cinfo;
   unsigned long flags;
-  unsigned char *base_addr;
-  int card,chip,channel,index;
-  unsigned cflag;
-  int   i;
+  int chip, channel,index;
+  int retval;
+  char *base_addr;
 
-    if (!info->tty || !info->tty->termios){
-        return;
-    }
-    if (info->line == -1){
-        return;
+    /*
+     * If the device is in the middle of being closed, then block
+     * until it's done, and then try again.
+     */
+    if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+       if (info->flags & ASYNC_CLOSING) {
+            interruptible_sleep_on(&info->close_wait);
+       }
+        if (info->flags & ASYNC_HUP_NOTIFY){
+            return -EAGAIN;
+        }else{
+            return -ERESTARTSYS;
+        }
     }
-    cflag = info->tty->termios->c_cflag;
 
-    /* baud rate */
-    i = cflag & CBAUD;
-#ifdef CBAUDEX
-/* Starting with kernel 1.1.65, there is direct support for
-   higher baud rates.  The following code supports those
-   changes.  The conditional aspect allows this driver to be
-   used for earlier as well as later kernel versions.  (The
-   mapping is slightly different from serial.c because there
-   is still the possibility of supporting 75 kbit/sec with
-   the Cyclades board.)
- */
-    if (i & CBAUDEX) {
-       if (i == B57600)
-           i = 16;
-       else if(i == B115200) 
-           i = 18;
-#ifdef B78600
-       else if(i == B78600) 
-           i = 17;
-#endif
-       else
-           info->tty->termios->c_cflag &= ~CBAUDEX;
-    }
-#endif
-    if (i == 15) {
-           if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-                   i += 1;
-           if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-                   i += 3;
-    }
-    info->tbpr = baud_bpr[i]; /* Tx BPR */
-    info->tco = baud_co[i]; /* Tx CO */
-    info->rbpr = baud_bpr[i]; /* Rx BPR */
-    info->rco = baud_co[i]; /* Rx CO */
-    if (baud_table[i] == 134) {
-        info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
-        /* get it right for 134.5 baud */
-    } else if (baud_table[i]) {
-        info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
-        /* this needs to be propagated into the card info */
-    } else {
-        info->timeout = 0;
-    }
-    /* By tradition (is it a standard?) a baud rate of zero
-       implies the line should be/has been closed.  A bit
-       later in this routine such a test is performed. */
-
-    /* byte size and parity */
-    info->cor5 = 0;
-    info->cor4 = 0;
-    info->cor3 = (info->default_threshold
-                 ? info->default_threshold
-                 : baud_cor3[i]); /* receive threshold */
-    info->cor2 = CyETC;
-    switch(cflag & CSIZE){
-    case CS5:
-        info->cor1 = Cy_5_BITS;
-        break;
-    case CS6:
-        info->cor1 = Cy_6_BITS;
-        break;
-    case CS7:
-        info->cor1 = Cy_7_BITS;
-        break;
-    case CS8:
-        info->cor1 = Cy_8_BITS;
-        break;
-    }
-    if(cflag & CSTOPB){
-        info->cor1 |= Cy_2_STOP;
-    }
-    if (cflag & PARENB){
-        if (cflag & PARODD){
-            info->cor1 |= CyPARITY_O;
-        }else{
-            info->cor1 |= CyPARITY_E;
+    /*
+     * If this is a callout device, then just make sure the normal
+     * device isn't being used.
+     */
+    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+        if (info->flags & ASYNC_NORMAL_ACTIVE){
+            return -EBUSY;
         }
-    }else{
-        info->cor1 |= CyPARITY_NONE;
+        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+            (info->flags & ASYNC_SESSION_LOCKOUT) &&
+            (info->session != current->session)){
+            return -EBUSY;
+        }
+        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+            (info->flags & ASYNC_PGRP_LOCKOUT) &&
+            (info->pgrp != current->pgrp)){
+            return -EBUSY;
+        }
+        info->flags |= ASYNC_CALLOUT_ACTIVE;
+        return 0;
     }
-       
-    /* CTS flow control flag */
-    if (cflag & CRTSCTS){
-       info->flags |= ASYNC_CTS_FLOW;
-       info->cor2 |= CyCtsAE;
-    }else{
-       info->flags &= ~ASYNC_CTS_FLOW;
-       info->cor2 &= ~CyCtsAE;
-    }
-    if (cflag & CLOCAL)
-       info->flags &= ~ASYNC_CHECK_CD;
-    else
-       info->flags |= ASYNC_CHECK_CD;
-
-     /***********************************************
-       The hardware option, CyRtsAO, presents RTS when
-       the chip has characters to send.  Since most modems
-       use RTS as reverse (inbound) flow control, this
-       option is not used.  If inbound flow control is
-       necessary, DTR can be programmed to provide the
-       appropriate signals for use with a non-standard
-       cable.  Contact Marcio Saito for details.
-     ***********************************************/
 
-    card = info->card;
-    channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    /*
+     * If non-blocking mode is set, then make the check up front
+     * and then exit.
+     */
+    if ((filp->f_flags & O_NONBLOCK) ||
+       (tty->flags & (1 << TTY_IO_ERROR))) {
+        if (info->flags & ASYNC_CALLOUT_ACTIVE){
+            return -EBUSY;
+        }
+        info->flags |= ASYNC_NORMAL_ACTIVE;
+        return 0;
+    }
 
+    /*
+     * Block waiting for the carrier detect and the line to become
+     * free (i.e., not in use by the callout).  While we are in
+     * this loop, info->count is dropped by one, so that
+     * cy_close() knows when to free things.  We restore it upon
+     * exit, either normal or abnormal.
+     */
+    retval = 0;
+    add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
+           info->line, info->count);/**/
+#endif
     save_flags(flags); cli();
-       base_addr[CyCAR<<index] = (u_char)channel;
+    if (!tty_hung_up_p(filp))
+       info->count--;
+    restore_flags(flags);
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc block_til_ready: (%d): decrementing count to %d\n",
+        current->pid, info->count);
+#endif
+    info->blocked_open++;
 
-       /* tx and rx baud rate */
-
-       base_addr[CyTCOR<<index] = info->tco;
-       base_addr[CyTBPR<<index] = info->tbpr;
-       base_addr[CyRCOR<<index] = info->rco;
-       base_addr[CyRBPR<<index] = info->rbpr;
-
-       /* set line characteristics  according configuration */
+    cinfo = &cy_card[info->card];
+    channel = info->line - cinfo->first_line;
+    if (!IS_CYC_Z(*cinfo)) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cinfo->bus_index;
+       base_addr = (char *)(cinfo->base_addr
+                           + (cy_chip_offset[chip]<<index));
+
+       while (1) {
+           save_flags(flags); cli();
+               if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
+                   cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+                   cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
+                   cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
+#ifdef SERIAL_DEBUG_DTR
+                   printk("cyc:block_til_ready raising DTR\n");
+                   printk("     status: 0x%x, 0x%x\n",
+                       cy_readb(base_addr+(CyMSVR1<<index)), 
+                        cy_readb(base_addr+(CyMSVR2<<index)));
+#endif
+               }
+           restore_flags(flags);
+           current->state = TASK_INTERRUPTIBLE;
+           if (tty_hung_up_p(filp)
+           || !(info->flags & ASYNC_INITIALIZED) ){
+               if (info->flags & ASYNC_HUP_NOTIFY) {
+                   retval = -EAGAIN;
+               }else{
+                   retval = -ERESTARTSYS;
+               }
+               break;
+           }
+           save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+               if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
+               && !(info->flags & ASYNC_CLOSING)
+               && (C_CLOCAL(tty)
+                   || (cy_readb(base_addr+(CyMSVR1<<index)) & CyDCD))) {
+                       restore_flags(flags);
+                       break;
+               }
+           restore_flags(flags);
+           if (current->signal & ~current->blocked) {
+               retval = -ERESTARTSYS;
+               break;
+           }
+#ifdef SERIAL_DEBUG_OPEN
+           printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
+                  info->line, info->count);/**/
+#endif
+           schedule();
+       }
+    } else {
+      struct FIRM_ID *firm_id;
+      struct ZFW_CTRL *zfw_ctrl;
+      struct BOARD_CTRL *board_ctrl;
+      struct CH_CTRL *ch_ctrl;
+      int retval;
+
+       base_addr = (char *)(cinfo->base_addr);
+       firm_id = (struct FIRM_ID *)
+                       (base_addr + ID_ADDRESS);
+        if (!ISZLOADED(*cinfo)){
+           return -EINVAL;
+       }
 
-       base_addr[CySCHR1<<index] = START_CHAR(info->tty);
-       base_addr[CySCHR2<<index] = STOP_CHAR(info->tty);
-       base_addr[CyCOR1<<index] = info->cor1;
-       base_addr[CyCOR2<<index] = info->cor2;
-       base_addr[CyCOR3<<index] = info->cor3;
-       base_addr[CyCOR4<<index] = info->cor4;
-       base_addr[CyCOR5<<index] = info->cor5;
+       zfw_ctrl =
+           (struct ZFW_CTRL *)
+               (base_addr + cy_readl(&firm_id->zfwctrl_addr));
+       board_ctrl = &zfw_ctrl->board_ctrl;
+       ch_ctrl = zfw_ctrl->ch_ctrl;
+
+       while (1) {
+           cy_writel(&ch_ctrl[channel].rs_control,
+               cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR);
+           retval = cyz_issue_cmd(&cy_card[info->card],
+                   channel, C_CM_IOCTLM, 0L);
+           if (retval != 0){
+               printk("cyc:block_til_ready retval was %x\n", retval);
+           }
+#ifdef SERIAL_DEBUG_DTR
+                   printk("cyc:block_til_ready raising Z DTR\n");
+#endif
 
-       write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
+           current->state = TASK_INTERRUPTIBLE;
+           if (tty_hung_up_p(filp)
+           || !(info->flags & ASYNC_INITIALIZED) ){
+               if (info->flags & ASYNC_HUP_NOTIFY) {
+                   retval = -EAGAIN;
+               }else{
+                   retval = -ERESTARTSYS;
+               }
+               break;
+           }
+           if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
+           && !(info->flags & ASYNC_CLOSING)
+           && (C_CLOCAL(tty)
+             || (cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD))) {
+               break;
+           }
+           if (current->signal & ~current->blocked) {
+               retval = -ERESTARTSYS;
+               break;
+           }
+#ifdef SERIAL_DEBUG_OPEN
+           printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
+                  info->line, info->count);/**/
+#endif
+           schedule();
+       }
+    }
+    current->state = TASK_RUNNING;
+    remove_wait_queue(&info->open_wait, &wait);
+    if (!tty_hung_up_p(filp)){
+       info->count++;
+#ifdef SERIAL_DEBUG_COUNT
+       printk("cyc:block_til_ready (%d): incrementing count to %d\n",
+           current->pid, info->count);
+#endif
+    }
+    info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
+          info->line, info->count);/**/
+#endif
+    if (retval)
+       return retval;
+    info->flags |= ASYNC_NORMAL_ACTIVE;
+    return 0;
+} /* block_til_ready */
 
-       base_addr[CyCAR<<index] = (u_char)channel; /* !!! Is this needed? */
 
-       base_addr[CyRTPR<<index] = (info->default_timeout
-                            ? info->default_timeout
-                            : 0x02); /* 10ms rx timeout */
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * performs the serial-specific initialization for the tty structure.
+ */
+int
+cy_open(struct tty_struct *tty, struct file * filp)
+{
+  struct cyclades_port  *info;
+  int retval, line;
 
-       if (C_CLOCAL(info->tty)) {
-           base_addr[CySRER<<index] |= CyMdmCh; /* without modem intr */
-                                   /* act on 1->0 modem transitions */
-           base_addr[CyMCOR1<<index] = CyCTS;
-                                   /* act on 0->1 modem transitions */
-           base_addr[CyMCOR2<<index] = CyCTS;
-       } else {
-           base_addr[CySRER<<index] |= CyMdmCh; /* with modem intr */
-                                   /* act on 1->0 modem transitions */
-           base_addr[CyMCOR1<<index] = CyDSR|CyCTS|CyRI|CyDCD;
-                                   /* act on 0->1 modem transitions */
-           base_addr[CyMCOR2<<index] = CyDSR|CyCTS|CyRI|CyDCD;
+    line = MINOR(tty->device) - tty->driver.minor_start;
+    if ((line < 0) || (NR_PORTS <= line)){
+        return -ENODEV;
+    }
+    info = &cy_port[line];
+    if (info->line < 0){
+        return -ENODEV;
+    }
+    
+    /* If the card's firmware hasn't been loaded,
+       treat it as absent from the system.  This
+       will make the user pay attention.
+    */
+    if (IS_CYC_Z(cy_card[info->card])) {
+        if (!ISZLOADED(cy_card[info->card])) {
+           if (((ZE_V1 ==cy_readl(&((struct RUNTIME_9060 *)
+               ((cy_card[info->card]).ctl_addr))->mail_box_0)) &&
+               Z_FPGA_CHECK(cy_card[info->card])) &&
+               (ZFIRM_HLT==cy_readl(&((struct FIRM_ID *)
+               ((cy_card[info->card]).base_addr+ID_ADDRESS))->signature)))
+           {
+               printk ("Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n");
+           } else {
+               printk("Cyclades-Z firmware not yet loaded\n");
+           }
+           return -ENODEV;
        }
-
-       if(i == 0){ /* baud rate is zero, turn off line */
-           base_addr[CyMSVR2<<index] = ~CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+    }
+#ifdef SERIAL_DEBUG_OTHER
+    printk("cyc:cy_open ttyC%d\n", info->line); /* */
 #endif
-       }else{
-           base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: raising DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+    if (serial_paranoia_check(info, tty->device, "cy_open")){
+        return -ENODEV;
+    }
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc:cy_open ttyC%d, count = %d\n",
+        info->line, info->count);/**/
 #endif
-       }
+    info->count++;
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc:cy_open (%d): incrementing count to %d\n",
+        current->pid, info->count);
+#endif
+    tty->driver_data = info;
+    info->tty = tty;
 
-       if (info->tty){
-           clear_bit(TTY_IO_ERROR, &info->tty->flags);
-       }
+    /* Some drivers have (incorrect/incomplete) code to test
+       against a race condition.  Should add good code here!!! */
+    if (!tmp_buf) {
+        tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+        if (!tmp_buf){
+            return -ENOMEM;
+        }
+    }
 
-    restore_flags(flags);
+    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+        if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+            *tty->termios = info->normal_termios;
+        else 
+            *tty->termios = info->callout_termios;
+    }
+    /*
+     * Start up serial port
+     */
+    retval = startup(info);
+    if (retval){
+        return retval;
+    }
 
-} /* config_setup */
+    MOD_INC_USE_COUNT;
 
+    retval = block_til_ready(tty, filp, info);
+    if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+        printk("cyc:cy_open returning after block_til_ready with %d\n",
+               retval);
+#endif
+        return retval;
+    }
 
-static void
-cy_put_char(struct tty_struct *tty, unsigned char ch)
-{
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
+    info->session = current->session;
+    info->pgrp = current->pgrp;
 
-#ifdef SERIAL_DEBUG_IO
-    printk("cy_put_char ttyC%d\n", info->line);
+#ifdef SERIAL_DEBUG_OPEN
+    printk(" cyc:cy_open done\n");/**/
 #endif
 
-    if (serial_paranoia_check(info, tty->device, "cy_put_char"))
-       return;
+    return 0;
+} /* cy_open */
 
-    if (!tty || !info->xmit_buf)
+/*
+ * cy_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+  unsigned char *base_addr;
+  int card,chip,channel,index;
+  unsigned long orig_jiffies, char_time;
+
+    if (serial_paranoia_check(info, tty->device, "cy_wait_until_sent"))
        return;
 
-    save_flags(flags); cli();
-       if (info->xmit_cnt >= PAGE_SIZE - 1) {
-           restore_flags(flags);
-           return;
+    orig_jiffies = jiffies;
+    /*
+     * Set the check interval to be 1/5 of the estimated time to
+     * send a single character, and make it at least 1.  The check
+     * interval should also be less than the timeout.
+     *
+     * Note: we have to use pretty tight timings here to satisfy
+     * the NIST-PCTS.
+     */
+    char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+    char_time = char_time / 5;
+    if (char_time == 0)
+       char_time = 1;
+    if (timeout < 0)
+       timeout = 0;
+    if (timeout)
+       char_time = MIN(char_time, timeout);
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+    printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
+    printk("jiff=%lu...", jiffies);
+#endif
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char *)
+               (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+       while (cy_readb(base_addr+(CySRER<<index)) & CyTxMpty) {
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+           printk("Not clean (jiff=%lu)...", jiffies);
+#endif
+           current->state = TASK_INTERRUPTIBLE;
+           current->counter = 0;       /* make us low-priority */
+           current->timeout = jiffies + char_time;
+           schedule();
+           if (current->signal & ~current->blocked)
+               break;
+           if (timeout && ((orig_jiffies + timeout) < jiffies))
+               break;
        }
+       current->state = TASK_RUNNING;
+    } else {
+       // Nothing to do!
+    }
+    /* Run one more char cycle */
+    current->state = TASK_INTERRUPTIBLE;
+    current->counter = 0;       /* make us low-priority */
+    current->timeout = jiffies + (char_time * 5);
+    schedule();
+    current->state = TASK_RUNNING;
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+    printk("Clean (jiff=%lu)...done\n", jiffies);
+#endif
+}
 
-       info->xmit_buf[info->xmit_head++] = ch;
-       info->xmit_head &= PAGE_SIZE - 1;
-       info->xmit_cnt++;
-    restore_flags(flags);
-} /* cy_put_char */
-
-
+/*
+ * This routine is called when a particular tty device is closed.
+ */
 static void
-cy_flush_chars(struct tty_struct *tty)
+cy_close(struct tty_struct * tty, struct file * filp)
 {
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
   unsigned long flags;
-  unsigned char *base_addr;
-  int card,chip,channel,index;
-                               
-#ifdef SERIAL_DEBUG_IO
-    printk("cy_flush_chars ttyC%d\n", info->line); /* */
+
+#ifdef SERIAL_DEBUG_OTHER
+    printk("cyc:cy_close ttyC%d\n", info->line);
 #endif
 
-    if (serial_paranoia_check(info, tty->device, "cy_flush_chars"))
-       return;
+    if (!info
+    || serial_paranoia_check(info, tty->device, "cy_close")){
+        return;
+    }
+#ifdef SERIAL_DEBUG_OPEN
+    printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+#endif
 
-    if (info->xmit_cnt <= 0 || tty->stopped
-    || tty->hw_stopped || !info->xmit_buf)
-       return;
+    save_flags(flags); cli();
 
-    card = info->card;
-    channel = info->line - cy_card[card].first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    /* If the TTY is being hung up, nothing to do */
+    if (tty_hung_up_p(filp)) {
+        MOD_DEC_USE_COUNT;
+        restore_flags(flags);
+        return;
+    }
+        
+    if ((tty->count == 1) && (info->count != 1)) {
+        /*
+         * Uh, oh.  tty->count is 1, which means that the tty
+         * structure will be freed.  Info->count should always
+         * be one in these conditions.  If it's greater than
+         * one, we've got real problems, since it means the
+         * serial port won't be shutdown.
+         */
+        printk("cyc:cy_close: bad serial port count; tty->count is 1, "
+           "info->count is %d\n", info->count);
+        info->count = 1;
+    }
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc:cy_close at (%d): decrementing count to %d\n",
+        current->pid, info->count - 1);
+#endif
+    if (--info->count < 0) {
+#ifdef SERIAL_DEBUG_COUNT
+    printk("cyc:cyc_close setting count to 0\n");
+#endif
+        info->count = 0;
+    }
+    if (info->count) {
+        MOD_DEC_USE_COUNT;
+        restore_flags(flags);
+        return;
+    }
+    info->flags |= ASYNC_CLOSING;
+    /*
+     * Save the termios structure, since this port may have
+     * separate termios for callout and dialin.
+     */
+    if (info->flags & ASYNC_NORMAL_ACTIVE)
+        info->normal_termios = *tty->termios;
+    if (info->flags & ASYNC_CALLOUT_ACTIVE)
+        info->callout_termios = *tty->termios;
 
-    save_flags(flags); cli();
-       base_addr[CyCAR<<index] = channel;
-       base_addr[CySRER<<index] |= CyTxMpty;
+    /*
+    * Now we wait for the transmit buffer to clear; and we notify
+    * the line discipline to only process XON/XOFF characters.
+    */
+    tty->closing = 1;
+    if (info->closing_wait != CY_CLOSING_WAIT_NONE)
+       tty_wait_until_sent(tty, info->closing_wait);
+
+    if (!IS_CYC_Z(cy_card[info->card])) {
+        unsigned char *base_addr = (unsigned char *)
+                                        cy_card[info->card].base_addr;
+        int index = cy_card[info->card].bus_index;
+        /* Stop accepting input */
+        cy_writeb((u_long)base_addr+(CySRER<<index),
+                        cy_readb(base_addr+(CySRER<<index)) & ~CyRxData);
+        if (info->flags & ASYNC_INITIALIZED) {
+            /* Waiting for on-board buffers to be empty before closing
+               the port */
+            cy_wait_until_sent(tty, info->timeout);
+        }
+    } else {
+#ifdef Z_WAKE
+       /* Waiting for on-board buffers to be empty before closing the port */
+       unsigned char *base_addr = (unsigned char *) 
+                                       cy_card[info->card].base_addr;
+       struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+       struct ZFW_CTRL *zfw_ctrl = 
+           (struct ZFW_CTRL *) (base_addr + cy_readl(&firm_id->zfwctrl_addr));
+       struct CH_CTRL *ch_ctrl = zfw_ctrl->ch_ctrl;
+       int channel = info->line - cy_card[info->card].first_line;
+       int retval;
+
+       if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+           retval = cyz_issue_cmd(&cy_card[info->card], channel, 
+                                  C_CM_IOCTLW, 0L);
+           if (retval != 0){
+               printk("cyc:shutdown retval (1) was %x\n", retval);
+           }
+           interruptible_sleep_on(&info->shutdown_wait);
+       }
+#endif
+    }
+
+    shutdown(info);
+    if (tty->driver.flush_buffer)
+        tty->driver.flush_buffer(tty);
+    if (tty->ldisc.flush_buffer)
+        tty->ldisc.flush_buffer(tty);
+    info->event = 0;
+    info->tty = 0;
+    if (info->blocked_open) {
+        if (info->close_delay) {
+            current->state = TASK_INTERRUPTIBLE;
+            current->timeout = jiffies + info->close_delay;
+            schedule();
+        }
+        wake_up_interruptible(&info->open_wait);
+    }
+    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+                     ASYNC_CLOSING);
+    wake_up_interruptible(&info->close_wait);
+
+#ifdef SERIAL_DEBUG_OTHER
+    printk(" cyc:cy_close done\n");
+#endif
+
+    MOD_DEC_USE_COUNT;
     restore_flags(flags);
-} /* cy_flush_chars */
+    return;
+} /* cy_close */
 
 
 /* This routine gets called when tty_write has put something into
-    the write_queue.  If the port is not already transmitting stuff,
-    start it off by enabling interrupts.  The interrupt service
-    routine will then ensure that the characters are sent.  If the
-    port is already active, there is no need to kick it.
+ * the write_queue.  The characters may come from user space or
+ * kernel space.
+ *
+ * This routine will return the number of characters actually
+ * accepted for writing.
+ *
+ * If the port is not already transmitting stuff, start it off by
+ * enabling interrupts.  The interrupt service routine will then
+ * ensure that the characters are sent.
+ * If the port is already active, there is no need to kick it.
+ *
  */
 static int
 cy_write(struct tty_struct * tty, int from_user,
@@ -1643,69 +2765,162 @@ cy_write(struct tty_struct * tty, int from_user,
   unsigned long flags;
   int c, total = 0;
 
-#ifdef SERIAL_DEBUG_IO
-    printk("cy_write ttyC%d\n", info->line); /* */
+#ifdef CY_DEBUG_IO
+    printk("cyc:cy_write ttyC%d\n", info->line); /* */
 #endif
 
     if (serial_paranoia_check(info, tty->device, "cy_write")){
-       return 0;
+        return 0;
     }
-       
+        
     if (!tty || !info->xmit_buf || !tmp_buf){
         return 0;
     }
 
+    if (from_user)
+       down(&tmp_buf_sem);
+    save_flags(flags);               
     while (1) {
-        save_flags(flags); cli();              
-       c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                          SERIAL_XMIT_SIZE - info->xmit_head));
-       if (c <= 0){
-           restore_flags(flags);
-           break;
-       }
+        cli();               
+        c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                           SERIAL_XMIT_SIZE - info->xmit_head));
+        if (c <= 0)
+            break;
 
-       if (from_user) {
-           down(&tmp_buf_sem);
-           memcpy_fromfs(tmp_buf, buf, c);
-           c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                      SERIAL_XMIT_SIZE - info->xmit_head));
-           memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-           up(&tmp_buf_sem);
-       } else
-           memcpy(info->xmit_buf + info->xmit_head, buf, c);
-       info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
-       info->xmit_cnt += c;
-       restore_flags(flags);
-       buf += c;
-       count -= c;
-       total += c;
+        if (from_user) {
+            copy_from_user(tmp_buf, buf, c);
+            c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                       SERIAL_XMIT_SIZE - info->xmit_head));
+            memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+        } else
+            memcpy(info->xmit_buf + info->xmit_head, buf, c);
+        info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+        info->xmit_cnt += c;
+        restore_flags(flags);
+        buf += c;
+        count -= c;
+        total += c;
+#if 0
+        SP("CW");
+       CP16(c);
+       SP(" ");
+#endif
     }
-
-
-    if (info->xmit_cnt
-    && !tty->stopped
-    && !tty->hw_stopped ) {
+    if (from_user)
+       up(&tmp_buf_sem);
+    if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
         start_xmit(info);
     }
+    restore_flags(flags);
     return total;
 } /* cy_write */
 
 
-static int
-cy_write_room(struct tty_struct *tty)
+/*
+ * This routine is called by the kernel to write a single
+ * character to the tty device.  If the kernel uses this routine,
+ * it must call the flush_chars() routine (if defined) when it is
+ * done stuffing characters into the driver.  If there is no room
+ * in the queue, the character is ignored.
+ */
+static void
+cy_put_char(struct tty_struct *tty, unsigned char ch)
+{
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned long flags;
+
+#ifdef CY_DEBUG_IO
+    printk("cyc:cy_put_char ttyC%d\n", info->line);
+#endif
+
+    if (serial_paranoia_check(info, tty->device, "cy_put_char"))
+        return;
+
+    if (!tty || !info->xmit_buf)
+        return;
+
+    save_flags(flags); cli();
+        if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+            restore_flags(flags);
+            return;
+        }
+
+        info->xmit_buf[info->xmit_head++] = ch;
+        info->xmit_head &= SERIAL_XMIT_SIZE - 1;
+        info->xmit_cnt++;
+    restore_flags(flags);
+#if 0
+       SP("+");
+#endif
+} /* cy_put_char */
+
+
+/*
+ * This routine is called by the kernel after it has written a
+ * series of characters to the tty device using put_char().  
+ */
+static void
+cy_flush_chars(struct tty_struct *tty)
+{
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned long flags;
+  unsigned char *base_addr;
+  int card,chip,channel,index;
+                                
+#ifdef CY_DEBUG_IO
+    printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
+#endif
+
+    if (serial_paranoia_check(info, tty->device, "cy_flush_chars"))
+        return;
+
+    if (info->xmit_cnt <= 0 || tty->stopped
+    || tty->hw_stopped || !info->xmit_buf)
+        return;
+
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
+
+       save_flags(flags); cli();
+           cy_writeb((u_long)base_addr+(CyCAR<<index), channel);
+           cy_writeb((u_long)base_addr+(CySRER<<index),
+               cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
+       restore_flags(flags);
+    } else {
+       /* Since polling is already in place,
+           nothing further need be done.  */
+    }
+} /* cy_flush_chars */
+
+
+/*
+ * This routine returns the numbers of characters the tty driver
+ * will accept for queuing to be written.  This number is subject
+ * to change as output buffers get emptied, or if the output flow
+ * control is activated.
+ */
+static int
+cy_write_room(struct tty_struct *tty)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  int  ret;
-                               
-#ifdef SERIAL_DEBUG_IO
-    printk("cy_write_room ttyC%d\n", info->line); /* */
+  int   ret;
+                                
+#ifdef CY_DEBUG_IO
+    printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
 #endif
 
     if (serial_paranoia_check(info, tty->device, "cy_write_room"))
-       return 0;
-    ret = PAGE_SIZE - info->xmit_cnt - 1;
+        return 0;
+    ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
     if (ret < 0)
-       ret = 0;
+        ret = 0;
     return ret;
 } /* cy_write_room */
 
@@ -1714,126 +2929,464 @@ static int
 cy_chars_in_buffer(struct tty_struct *tty)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-                               
-#ifdef SERIAL_DEBUG_IO
-    printk("cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
-#endif
-
+  int card, channel;
+                                
     if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer"))
-       return 0;
-
-    return info->xmit_cnt;
-} /* cy_chars_in_buffer */
+        return 0;
 
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
 
-static void
-cy_flush_buffer(struct tty_struct *tty)
-{
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
-                               
-#ifdef SERIAL_DEBUG_IO
-    printk("cy_flush_buffer ttyC%d\n", info->line); /* */
+    if (!IS_CYC_Z(cy_card[card])) {
+#ifdef CY_DEBUG_IO
+       printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+               info->line, info->xmit_cnt); /* */
 #endif
+       return info->xmit_cnt;
+    } else {
+       static volatile struct FIRM_ID *firm_id;
+       static volatile struct ZFW_CTRL *zfw_ctrl;
+       static volatile struct CH_CTRL *ch_ctrl;
+       static volatile struct BUF_CTRL *buf_ctrl;
+       int char_count;
+       volatile uclong tx_put, tx_get, tx_bufsize;
+
+       firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
+       zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
+                               cy_readl(&firm_id->zfwctrl_addr));
+       ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+       buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+       tx_get = cy_readl(&buf_ctrl->tx_get);
+       tx_put = cy_readl(&buf_ctrl->tx_put);
+       tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+       if (tx_put >= tx_get)
+           char_count = tx_put - tx_get;
+       else
+           char_count = tx_put - tx_get + tx_bufsize;
+#ifdef CY_DEBUG_IO
+       printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+               info->line, info->xmit_cnt + char_count); /* */
+#endif
+       return (info->xmit_cnt + char_count);
+    }
+} /* cy_chars_in_buffer */
 
-    if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
-       return;
-    save_flags(flags); cli();
-       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-    restore_flags(flags);
-    wake_up_interruptible(&tty->write_wait);
-    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
-    && tty->ldisc.write_wakeup)
-       (tty->ldisc.write_wakeup)(tty);
-} /* cy_flush_buffer */
+
+/*
+ * ------------------------------------------------------------
+ * cy_ioctl() and friends
+ * ------------------------------------------------------------
+ */
 
 
-/* This routine is called by the upper-layer tty layer to signal
-   that incoming characters should be throttled or that the
-   throttle should be released.
+/*
+ * This routine finds or computes the various line characteristics.
+ * It used to be called config_setup
  */
 static void
-cy_throttle(struct tty_struct * tty)
+set_line_char(struct cyclades_port * info)
 {
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
   unsigned long flags;
   unsigned char *base_addr;
   int card,chip,channel,index;
+  unsigned cflag, iflag;
+  unsigned short chip_number;
+  int   i;
 
-#ifdef SERIAL_DEBUG_THROTTLE
-  char buf[64];
-       
-    printk("throttle %s: %d....\n", _tty_name(tty, buf),
-          tty->ldisc.chars_in_buffer(tty));
-    printk("cy_throttle ttyC%d\n", info->line);
-#endif
 
-    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
-           return;
+    if (!info->tty || !info->tty->termios){
+        return;
     }
-
-    if (I_IXOFF(tty)) {
-       info->x_char = STOP_CHAR(tty);
-           /* Should use the "Send Special Character" feature!!! */
+    if (info->line == -1){
+        return;
     }
+    cflag = info->tty->termios->c_cflag;
+    iflag = info->tty->termios->c_iflag;
 
     card = info->card;
-    channel = info->line - cy_card[card].first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    channel = (info->line) - (cy_card[card].first_line);
+    chip_number = channel / 4;
 
-    save_flags(flags); cli();
-       base_addr[CyCAR<<index] = (u_char)channel;
-       base_addr[CyMSVR1<<index] = ~CyRTS;
-    restore_flags(flags);
+    if (!IS_CYC_Z(cy_card[card])) {
 
-    return;
-} /* cy_throttle */
+       index = cy_card[card].bus_index;
 
+       /* baud rate */
+       i = cflag & CBAUD;
+     
+       if (i & CBAUDEX) {
+           if (i == B57600)
+               i = 16;
+#ifdef B76800
+           else if(i == B76800) 
+               i = 17;
+#endif
+           else if(i == B115200) 
+               i = 18;
+           else if(i == B230400 && (info->chip_rev >= CD1400_REV_J)) {
+               /* It is a CD1400 rev. J or later */
+               i = 20;
+           }
+           else
+               info->tty->termios->c_cflag &= ~CBAUDEX;
+       }
 
-static void
-cy_unthrottle(struct tty_struct * tty)
-{
-  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
-  unsigned char *base_addr;
-  int card,chip,channel,index;
+       if (i == 15) {
+           if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+               i += 1;
+           if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+               i += 3;
+                   if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
+                switch(info->baud) {
+                   case 57600:
+                       i += 1; break;
+#ifdef B76800
+                   case 76800: 
+                       i += 2; break;
+#endif
+                   case 115200:
+                       i += 3; break;
+                   case 230400:
+                       i += 5; break;
+                   default:
+                       break;
+               }
+            }
+       }
+       if(info->chip_rev >= CD1400_REV_J) {
+           /* It is a CD1400 rev. J or later */
+           info->tbpr = baud_bpr_60[i]; /* Tx BPR */
+           info->tco = baud_co_60[i]; /* Tx CO */
+           info->rbpr = baud_bpr_60[i]; /* Rx BPR */
+           info->rco = baud_co_60[i]; /* Rx CO */
+       } else {
+           info->tbpr = baud_bpr_25[i]; /* Tx BPR */
+           info->tco = baud_co_25[i]; /* Tx CO */
+           info->rbpr = baud_bpr_25[i]; /* Rx BPR */
+           info->rco = baud_co_25[i]; /* Rx CO */
+       }
+       if (baud_table[i] == 134) {
+           info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+           /* get it right for 134.5 baud */
+       } else if (baud_table[i]) {
+           info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
+           /* this needs to be propagated into the card info */
+       } else {
+           info->timeout = 0;
+       }
+       /* By tradition (is it a standard?) a baud rate of zero
+          implies the line should be/has been closed.  A bit
+          later in this routine such a test is performed. */
+
+       /* byte size and parity */
+       info->cor5 = 0;
+       info->cor4 = 0;
+       info->cor3 = (info->default_threshold
+                     ? info->default_threshold
+                     : baud_cor3[i]); /* receive threshold */
+       info->cor2 = CyETC;
+       switch(cflag & CSIZE){
+       case CS5:
+           info->cor1 = Cy_5_BITS;
+           break;
+       case CS6:
+           info->cor1 = Cy_6_BITS;
+           break;
+       case CS7:
+           info->cor1 = Cy_7_BITS;
+           break;
+       case CS8:
+           info->cor1 = Cy_8_BITS;
+           break;
+       }
+       if(cflag & CSTOPB){
+           info->cor1 |= Cy_2_STOP;
+       }
+       if (cflag & PARENB){
+           if (cflag & PARODD){
+               info->cor1 |= CyPARITY_O;
+           }else{
+               info->cor1 |= CyPARITY_E;
+           }
+       }else{
+           info->cor1 |= CyPARITY_NONE;
+       }
+           
+       /* CTS flow control flag */
+       if (cflag & CRTSCTS){
+           info->flags |= ASYNC_CTS_FLOW;
+           info->cor2 |= CyCtsAE;
+       }else{
+           info->flags &= ~ASYNC_CTS_FLOW;
+           info->cor2 &= ~CyCtsAE;
+       }
+       if (cflag & CLOCAL)
+           info->flags &= ~ASYNC_CHECK_CD;
+       else
+           info->flags |= ASYNC_CHECK_CD;
+
+        /***********************************************
+           The hardware option, CyRtsAO, presents RTS when
+           the chip has characters to send.  Since most modems
+           use RTS as reverse (inbound) flow control, this
+           option is not used.  If inbound flow control is
+           necessary, DTR can be programmed to provide the
+           appropriate signals for use with a non-standard
+           cable.  Contact Marcio Saito for details.
+        ***********************************************/
+
+       chip = channel>>2;
+       channel &= 0x03;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
 
-#ifdef SERIAL_DEBUG_THROTTLE
-  char buf[64];
-       
-    printk("throttle %s: %d....\n", _tty_name(tty, buf),
-          tty->ldisc.chars_in_buffer(tty));
-    printk("cy_unthrottle ttyC%d\n", info->line);
+       save_flags(flags); cli();
+           cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+
+          /* tx and rx baud rate */
+
+           cy_writeb((u_long)base_addr+(CyTCOR<<index), info->tco);
+           cy_writeb((u_long)base_addr+(CyTBPR<<index), info->tbpr);
+           cy_writeb((u_long)base_addr+(CyRCOR<<index), info->rco);
+           cy_writeb((u_long)base_addr+(CyRBPR<<index), info->rbpr);
+
+           /* set line characteristics  according configuration */
+
+           cy_writeb((u_long)base_addr+(CySCHR1<<index), 
+                     START_CHAR(info->tty));
+           cy_writeb((u_long)base_addr+(CySCHR2<<index), 
+                     STOP_CHAR(info->tty));
+           cy_writeb((u_long)base_addr+(CyCOR1<<index), info->cor1);
+           cy_writeb((u_long)base_addr+(CyCOR2<<index), info->cor2);
+           cy_writeb((u_long)base_addr+(CyCOR3<<index), info->cor3);
+           cy_writeb((u_long)base_addr+(CyCOR4<<index), info->cor4);
+           cy_writeb((u_long)base_addr+(CyCOR5<<index), info->cor5);
+
+           cyy_issue_cmd(base_addr,
+                    CyCOR_CHANGE|CyCOR1ch|CyCOR2ch|CyCOR3ch,index);
+
+           cy_writeb((u_long)base_addr+(CyCAR<<index), 
+                     (u_char)channel); /* !!! Is this needed? */
+           cy_writeb((u_long)base_addr+(CyRTPR<<index), (info->default_timeout
+                                                ? info->default_timeout
+                                                : 0x02)); /* 10ms rx timeout */
+
+           if (C_CLOCAL(info->tty)) {
+               /* without modem intr */
+               cy_writeb((u_long)base_addr+(CySRER<<index),
+                   cy_readb(base_addr+(CySRER<<index)) | CyMdmCh); 
+                                       /* act on 1->0 modem transitions */
+                if ((cflag & CRTSCTS) && info->rflow) {
+                        cy_writeb((u_long)base_addr+(CyMCOR1<<index), 
+                                  (CyCTS|rflow_thr[i]));
+                } else {
+                        cy_writeb((u_long)base_addr+(CyMCOR1<<index), CyCTS);
+                }
+                                       /* act on 0->1 modem transitions */
+               cy_writeb((u_long)base_addr+(CyMCOR2<<index), CyCTS);
+           } else {
+               /* without modem intr */
+               cy_writeb((u_long)base_addr+(CySRER<<index),
+                   cy_readb(base_addr+(CySRER<<index)) | CyMdmCh); 
+                                       /* act on 1->0 modem transitions */
+                if ((cflag & CRTSCTS) && info->rflow) {
+                       cy_writeb((u_long)base_addr+(CyMCOR1<<index), 
+                                 (CyDSR|CyCTS|CyRI|CyDCD|rflow_thr[i]));
+                } else {
+                       cy_writeb((u_long)base_addr+(CyMCOR1<<index), 
+                                  CyDSR|CyCTS|CyRI|CyDCD);
+                }
+                                       /* act on 0->1 modem transitions */
+               cy_writeb((u_long)base_addr+(CyMCOR2<<index), 
+                         CyDSR|CyCTS|CyRI|CyDCD);
+           }
+
+           if(i == 0){ /* baud rate is zero, turn off line */
+               if (info->rtsdtr_inv) {
+                       cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
+               } else {
+                        cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
+               }
+#ifdef CY_DEBUG_DTR
+               printk("cyc:set_line_char dropping DTR\n");
+               printk("     status: 0x%x,
+                   0x%x\n", cy_readb(base_addr+(CyMSVR1<<index)),
+                   cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
+           }else{
+                if (info->rtsdtr_inv) {
+                       cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
+                } else {
+                       cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
+                }
+#ifdef CY_DEBUG_DTR
+               printk("cyc:set_line_char raising DTR\n");
+               printk("     status: 0x%x, 0x%x\n",
+                   cy_readb(base_addr+(CyMSVR1<<index)),
+                   cy_readb(base_addr+(CyMSVR2<<index)));
+#endif
+           }
 
-    if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+           if (info->tty){
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+           }
+
+       restore_flags(flags);
+    } else {
+      struct FIRM_ID *firm_id;
+      struct ZFW_CTRL *zfw_ctrl;
+      struct BOARD_CTRL *board_ctrl;
+      struct CH_CTRL *ch_ctrl;
+      struct BUF_CTRL *buf_ctrl;
+      int retval;
+
+        firm_id = (struct FIRM_ID *)
+                       (cy_card[card].base_addr + ID_ADDRESS);
+        if (!ISZLOADED(cy_card[card])) {
            return;
-    }
+       }
 
-    if (I_IXOFF(tty)) {
-       info->x_char = START_CHAR(tty);
-       /* Should use the "Send Special Character" feature!!! */
-    }
+       zfw_ctrl = (struct ZFW_CTRL *)
+                (cy_card[card].base_addr + cy_readl(&firm_id->zfwctrl_addr));
+       board_ctrl = &zfw_ctrl->board_ctrl;
+       ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+       buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
 
-    card = info->card;
-    channel = info->line - cy_card[card].first_line;
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+       /* baud rate */
+       switch(i = cflag & CBAUD){
+       /*
+        case B0: cy_writel(&ch_ctrl->comm_baud , 0); break;
+       */
+        case B50: cy_writel(&ch_ctrl->comm_baud , 50); break;
+        case B75: cy_writel(&ch_ctrl->comm_baud , 75); break;
+        case B110: cy_writel(&ch_ctrl->comm_baud , 110); break;
+        case B134: cy_writel(&ch_ctrl->comm_baud , 134); break;
+        case B150: cy_writel(&ch_ctrl->comm_baud , 150); break;
+        case B200: cy_writel(&ch_ctrl->comm_baud , 200); break;
+        case B300: cy_writel(&ch_ctrl->comm_baud , 300); break;
+        case B600: cy_writel(&ch_ctrl->comm_baud , 600); break;
+        case B1200: cy_writel(&ch_ctrl->comm_baud , 1200); break;
+        case B1800: cy_writel(&ch_ctrl->comm_baud , 1800); break;
+        case B2400: cy_writel(&ch_ctrl->comm_baud , 2400); break;
+        case B4800: cy_writel(&ch_ctrl->comm_baud , 4800); break;
+        case B9600: cy_writel(&ch_ctrl->comm_baud , 9600); break;
+        case B19200: cy_writel(&ch_ctrl->comm_baud , 19200); break;
+        case B38400:
+            if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI){
+                cy_writel(&ch_ctrl->comm_baud , 57600);
+            }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI){
+                cy_writel(&ch_ctrl->comm_baud , 115200);
+            }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
+                cy_writel(&ch_ctrl->comm_baud , info->baud);
+            }else{
+                cy_writel(&ch_ctrl->comm_baud , 38400);
+            }
+            break;
+        case B57600: cy_writel(&ch_ctrl->comm_baud , 57600); break;
+#ifdef B76800
+        case B76800: cy_writel(&ch_ctrl->comm_baud , 76800); break;
+#endif
+        case B115200: cy_writel(&ch_ctrl->comm_baud , 115200); break;
+        case B230400: cy_writel(&ch_ctrl->comm_baud , 230400); break;
+        case B460800: cy_writel(&ch_ctrl->comm_baud , 460800); break;
+       }
 
-    save_flags(flags); cli();
-       base_addr[CyCAR<<index] = (u_char)channel;
-       base_addr[CyMSVR1<<index] = CyRTS;
-    restore_flags(flags);
+       if ((i = cy_readl(&ch_ctrl->comm_baud)) == 134) {
+           info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+           /* get it right for 134.5 baud */
+       } else if (i) {
+           info->timeout = (info->xmit_fifo_size*HZ*15/i) + 2;
+           /* this needs to be propagated into the card info */
+       } else {
+           info->timeout = 0;
+       }
+
+       /* byte size and parity */
+       switch(cflag & CSIZE){
+       case CS5: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS5); break;
+       case CS6: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS6); break;
+       case CS7: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS7); break;
+       case CS8: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS8); break;
+       }
+       if(cflag & CSTOPB){
+           cy_writel(&ch_ctrl->comm_data_l,
+               cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
+       }else{
+           cy_writel(&ch_ctrl->comm_data_l,
+               cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
+       }
+       if (cflag & PARENB){
+           if (cflag & PARODD){
+               cy_writel(&ch_ctrl->comm_parity , C_PR_ODD);
+           }else{
+               cy_writel(&ch_ctrl->comm_parity , C_PR_EVEN);
+           }
+       }else{
+           cy_writel(&ch_ctrl->comm_parity , C_PR_NONE);
+       }
+
+       /* CTS flow control flag */
+       if (cflag & CRTSCTS){
+           info->flags |= ASYNC_CTS_FLOW;
+           cy_writel(&ch_ctrl->hw_flow,
+               cy_readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
+       }else{
+           info->flags &= ~ASYNC_CTS_FLOW;
+           cy_writel(&ch_ctrl->hw_flow,
+               cy_readl(&ch_ctrl->hw_flow) & ~(C_RS_CTS | C_RS_RTS));
+       }
+
+       retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+       if (retval != 0){
+           printk("cyc:set_line_char retval at %d was %x\n",
+               __LINE__, retval);
+       }
+
+       /* CD sensitivity */
+       if (cflag & CLOCAL){
+           info->flags &= ~ASYNC_CHECK_CD;
+       }else{
+           info->flags |= ASYNC_CHECK_CD;
+       }
+
+       if (iflag & IXON){
+           cy_writel(&ch_ctrl->sw_flow, 
+               cy_readl(&ch_ctrl->sw_flow) | C_FL_OXX);
+       } else {
+           cy_writel(&ch_ctrl->sw_flow, 
+               cy_readl(&ch_ctrl->sw_flow) & ~C_FL_OXX);
+       }
+
+       if(i == 0){ /* baud rate is zero, turn off line */
+           cy_writel(&ch_ctrl->rs_control,
+               cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
+#ifdef CY_DEBUG_DTR
+           printk("cyc:set_line_char dropping Z DTR\n");
+#endif
+       }else{
+           cy_writel(&ch_ctrl->rs_control,
+               cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
+#ifdef CY_DEBUG_DTR
+           printk("cyc:set_line_char raising Z DTR\n");
+#endif
+       }
+
+       retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTLM, 0L);
+       if (retval != 0){
+           printk("cyc:set_line_char retval at %d was %x\n",
+               __LINE__, retval);
+       }
+       cy_readl(&ch_ctrl->comm_baud);
+
+       if (info->tty){
+           clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       }
+    }
+
+} /* set_line_char */
 
-    return;
-} /* cy_unthrottle */
 
 static int
 get_serial_info(struct cyclades_port * info,
@@ -1850,14 +3403,15 @@ get_serial_info(struct cyclades_port * info,
     tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
     tmp.irq = cinfo->irq;
     tmp.flags = info->flags;
-    tmp.baud_base = 0;          /*!!!*/
     tmp.close_delay = info->close_delay;
+    tmp.baud_base = info->baud;
     tmp.custom_divisor = 0;     /*!!!*/
     tmp.hub6 = 0;               /*!!!*/
-    memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
+    copy_to_user(retinfo,&tmp,sizeof(*retinfo));
     return 0;
 } /* get_serial_info */
 
+
 static int
 set_serial_info(struct cyclades_port * info,
                            struct serial_struct * new_info)
@@ -1866,18 +3420,20 @@ set_serial_info(struct cyclades_port * info,
   struct cyclades_port old_info;
 
     if (!new_info)
-           return -EFAULT;
-    memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
+            return -EFAULT;
+    copy_from_user(&new_serial,new_info,sizeof(new_serial));
     old_info = *info;
 
     if (!suser()) {
-           if ((new_serial.close_delay != info->close_delay) ||
+            if ((new_serial.close_delay != info->close_delay) ||
+               (new_serial.baud_base != info->baud) ||
                ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
                 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
-                   return -EPERM;
-           info->flags = ((info->flags & ~ASYNC_USR_MASK) |
-                          (new_serial.flags & ASYNC_USR_MASK));
-           goto check_and_exit;
+                    return -EPERM;
+            info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+                           (new_serial.flags & ASYNC_USR_MASK));
+            info->baud = new_serial.baud_base;
+            goto check_and_exit;
     }
 
 
@@ -1886,20 +3442,23 @@ set_serial_info(struct cyclades_port * info,
      * At this point, we start making changes.....
      */
 
+    info->baud = new_serial.baud_base;
     info->flags = ((info->flags & ~ASYNC_FLAGS) |
-                   (new_serial.flags & ASYNC_FLAGS));
-    info->close_delay = new_serial.close_delay;
-
+                    (new_serial.flags & ASYNC_FLAGS));
+    info->close_delay = new_serial.close_delay * HZ/100;
+    info->closing_wait = new_serial.closing_wait * HZ/100;
 
 check_and_exit:
     if (info->flags & ASYNC_INITIALIZED){
-       config_setup(info);
-       return 0;
+        set_line_char(info);
+        return 0;
     }else{
         return startup(info);
     }
 } /* set_serial_info */
 
+
 static int
 get_modem_info(struct cyclades_port * info, unsigned int *value)
 {
@@ -1907,32 +3466,73 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
   unsigned char *base_addr;
   unsigned long flags;
   unsigned char status;
+  unsigned long lstatus;
   unsigned int result;
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  struct CH_CTRL *ch_ctrl;
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
 
-    save_flags(flags); cli();
-        base_addr[CyCAR<<index] = (u_char)channel;
-        status = base_addr[CyMSVR1<<index];
-       status |= base_addr[CyMSVR2<<index];
-    restore_flags(flags);
+       save_flags(flags); cli();
+           cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+           status = cy_readb(base_addr+(CyMSVR1<<index));
+           status |= cy_readb(base_addr+(CyMSVR2<<index));
+       restore_flags(flags);
+
+
+        if (info->rtsdtr_inv) {
+           result =  ((status  & CyRTS) ? TIOCM_DTR : 0)
+                   | ((status  & CyDTR) ? TIOCM_RTS : 0);
+       } else {
+           result =  ((status  & CyRTS) ? TIOCM_RTS : 0)
+                   | ((status  & CyDTR) ? TIOCM_DTR : 0);
+       }
+       result |=  ((status  & CyDCD) ? TIOCM_CAR : 0)
+                | ((status  & CyRI) ? TIOCM_RNG : 0)
+                | ((status  & CyDSR) ? TIOCM_DSR : 0)
+                | ((status  & CyCTS) ? TIOCM_CTS : 0);
+    } else {
+       base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+        if (cy_card[card].num_chips != 1){
+           return -EINVAL;
+       }
 
-    result =  ((status  & CyRTS) ? TIOCM_RTS : 0)
-            | ((status  & CyDTR) ? TIOCM_DTR : 0)
-            | ((status  & CyDCD) ? TIOCM_CAR : 0)
-            | ((status  & CyRI) ? TIOCM_RNG : 0)
-            | ((status  & CyDSR) ? TIOCM_DSR : 0)
-            | ((status  & CyCTS) ? TIOCM_CTS : 0);
-    put_fs_long(result,(unsigned long *) value);
+       firm_id = (struct FIRM_ID *)
+                   (cy_card[card].base_addr + ID_ADDRESS);
+        if (ISZLOADED(cy_card[card])) {
+           zfw_ctrl = (struct ZFW_CTRL *)
+               (cy_card[card].base_addr + cy_readl(&firm_id->zfwctrl_addr));
+           board_ctrl = &zfw_ctrl->board_ctrl;
+           ch_ctrl = zfw_ctrl->ch_ctrl;
+           lstatus = cy_readl(&ch_ctrl[channel].rs_status);
+           result =  ((lstatus  & C_RS_RTS) ? TIOCM_RTS : 0)
+                   | ((lstatus  & C_RS_DTR) ? TIOCM_DTR : 0)
+                   | ((lstatus  & C_RS_DCD) ? TIOCM_CAR : 0)
+                   | ((lstatus  & C_RS_RI) ? TIOCM_RNG : 0)
+                   | ((lstatus  & C_RS_DSR) ? TIOCM_DSR : 0)
+                   | ((lstatus  & C_RS_CTS) ? TIOCM_CTS : 0);
+       }else{
+           result = 0;
+           return -ENODEV;
+       }
+
+    }
+    cy_put_user(result,(unsigned long *) value);
     return 0;
 } /* get_modem_info */
 
+
 static int
 set_modem_info(struct cyclades_port * info, unsigned int cmd,
                           unsigned int *value)
@@ -1940,221 +3540,398 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
   int card,chip,channel,index;
   unsigned char *base_addr;
   unsigned long flags;
-  unsigned int arg = get_fs_long((unsigned long *) value);
+  unsigned int arg = cy_get_user((unsigned long *) value);
+  struct FIRM_ID *firm_id;
+  struct ZFW_CTRL *zfw_ctrl;
+  struct BOARD_CTRL *board_ctrl;
+  struct CH_CTRL *ch_ctrl;
+  int retval;
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
-    chip = channel>>2;
-    channel &= 0x03;
-    index = cy_card[card].bus_index;
-    base_addr = (unsigned char*)
-                   (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-
-    switch (cmd) {
-    case TIOCMBIS:
-       if (arg & TIOCM_RTS){
-           save_flags(flags); cli();
-               base_addr[CyCAR<<index] = (u_char)channel;
-               base_addr[CyMSVR1<<index] = CyRTS;
-           restore_flags(flags);
-       }
-       if (arg & TIOCM_DTR){
-           save_flags(flags); cli();
-           base_addr[CyCAR<<index] = (u_char)channel;
-           base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: raising DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
+
+       switch (cmd) {
+       case TIOCMBIS:
+           if (arg & TIOCM_RTS){
+               save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+                if (info->rtsdtr_inv) {
+                   cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
+                } else {
+                   cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
+                }
+               restore_flags(flags);
+           }
+           if (arg & TIOCM_DTR){
+               save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+                if (info->rtsdtr_inv) {
+                   cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
+                } else {
+                   cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
+                }
+#ifdef CY_DEBUG_DTR
+               printk("cyc:set_modem_info raising DTR\n");
+               printk("     status: 0x%x, 0x%x\n",
+                   cy_readb(base_addr+(CyMSVR1<<index)), 
+                    cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-           restore_flags(flags);
-       }
-       break;
-    case TIOCMBIC:
-       if (arg & TIOCM_RTS){
-           save_flags(flags); cli();
-               base_addr[CyCAR<<index] = (u_char)channel;
-               base_addr[CyMSVR1<<index] = ~CyRTS;
-           restore_flags(flags);
-       }
-       if (arg & TIOCM_DTR){
-           save_flags(flags); cli();
-           base_addr[CyCAR<<index] = (u_char)channel;
-           base_addr[CyMSVR2<<index] = ~CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+               restore_flags(flags);
+           }
+           break;
+       case TIOCMBIC:
+           if (arg & TIOCM_RTS){
+               save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), 
+                          (u_char)channel);
+                if (info->rtsdtr_inv) {
+                       cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
+                } else {
+                       cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
+                }
+               restore_flags(flags);
+           }
+           if (arg & TIOCM_DTR){
+               save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+                if (info->rtsdtr_inv) {
+                       cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
+                } else {
+                       cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
+                }
+#ifdef CY_DEBUG_DTR
+               printk("cyc:set_modem_info dropping DTR\n");
+               printk("     status: 0x%x, 0x%x\n",
+                   cy_readb(base_addr+(CyMSVR1<<index)), 
+                    cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-           restore_flags(flags);
-       }
-       break;
-    case TIOCMSET:
-       if (arg & TIOCM_RTS){
-           save_flags(flags); cli();
-               base_addr[CyCAR<<index] = (u_char)channel;
-               base_addr[CyMSVR1<<index] = CyRTS;
-           restore_flags(flags);
-       }else{
-           save_flags(flags); cli();
-               base_addr[CyCAR<<index] = (u_char)channel;
-               base_addr[CyMSVR1<<index] = ~CyRTS;
-           restore_flags(flags);
-       }
-       if (arg & TIOCM_DTR){
-           save_flags(flags); cli();
-           base_addr[CyCAR<<index] = (u_char)channel;
-           base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: raising DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+               restore_flags(flags);
+           }
+           break;
+       case TIOCMSET:
+           if (arg & TIOCM_RTS){
+               save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+                if (info->rtsdtr_inv) {
+                       cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
+                } else {
+                       cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
+                }
+               restore_flags(flags);
+           }else{
+               save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+                if (info->rtsdtr_inv) {
+                       cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
+                } else {
+                       cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
+                }
+               restore_flags(flags);
+           }
+           if (arg & TIOCM_DTR){
+               save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+                if (info->rtsdtr_inv) {
+                       cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
+                } else {
+                       cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
+                }
+#ifdef CY_DEBUG_DTR
+               printk("cyc:set_modem_info raising DTR\n");
+               printk("     status: 0x%x, 0x%x\n",
+                   cy_readb(base_addr+(CyMSVR1<<index)), 
+                    cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-           restore_flags(flags);
-       }else{
-           save_flags(flags); cli();
-           base_addr[CyCAR<<index] = (u_char)channel;
-           base_addr[CyMSVR2<<index] = ~CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-            printk("cyc: %d: dropping DTR\n", __LINE__);
-            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
+               restore_flags(flags);
+           }else{
+               save_flags(flags); cli();
+               cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+                if (info->rtsdtr_inv) {
+                       cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
+                } else {
+                       cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
+                }
+
+#ifdef CY_DEBUG_DTR
+               printk("cyc:set_modem_info dropping DTR\n");
+               printk("     status: 0x%x, 0x%x\n",
+                   cy_readb(base_addr+(CyMSVR1<<index)), 
+                    cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-           restore_flags(flags);
+               restore_flags(flags);
+           }
+           break;
+       default:
+           return -EINVAL;
        }
-       break;
-    default:
+    } else {
+       base_addr = (unsigned char*) (cy_card[card].base_addr);
+
+       firm_id = (struct FIRM_ID *)
+                   (cy_card[card].base_addr + ID_ADDRESS);
+        if (ISZLOADED(cy_card[card])) {
+           zfw_ctrl = (struct ZFW_CTRL *)
+               (cy_card[card].base_addr + cy_readl(&firm_id->zfwctrl_addr));
+           board_ctrl = &zfw_ctrl->board_ctrl;
+           ch_ctrl = zfw_ctrl->ch_ctrl;
+
+           switch (cmd) {
+           case TIOCMBIS:
+               if (arg & TIOCM_RTS){
+                   cy_writel(&ch_ctrl[channel].rs_control,
+                       cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
+               }
+               if (arg & TIOCM_DTR){
+                   cy_writel(&ch_ctrl[channel].rs_control,
+                       cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
+#ifdef CY_DEBUG_DTR
+                   printk("cyc:set_modem_info raising Z DTR\n");
+#endif
+               }
+               break;
+           case TIOCMBIC:
+               if (arg & TIOCM_RTS){
+                   cy_writel(&ch_ctrl[channel].rs_control,
+                       cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
+               }
+               if (arg & TIOCM_DTR){
+                   cy_writel(&ch_ctrl[channel].rs_control,
+                       cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
+#ifdef CY_DEBUG_DTR
+                   printk("cyc:set_modem_info clearing Z DTR\n");
+#endif
+               }
+               break;
+           case TIOCMSET:
+               if (arg & TIOCM_RTS){
+                   cy_writel(&ch_ctrl[channel].rs_control,
+                       cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
+               }else{
+                   cy_writel(&ch_ctrl[channel].rs_control,
+                       cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
+               }
+               if (arg & TIOCM_DTR){
+                   cy_writel(&ch_ctrl[channel].rs_control,
+                       cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
+#ifdef CY_DEBUG_DTR
+                   printk("cyc:set_modem_info raising Z DTR\n");
+#endif
+               }else{
+                   cy_writel(&ch_ctrl[channel].rs_control,
+                       cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
+#ifdef CY_DEBUG_DTR
+                   printk("cyc:set_modem_info clearing Z DTR\n");
+#endif
+               }
+               break;
+           default:
                return -EINVAL;
-        }
+           }
+       }else{
+           return -ENODEV;
+       }
+        retval = cyz_issue_cmd(&cy_card[info->card],
+                                   channel, C_CM_IOCTLM,0L);
+       if (retval != 0){
+           printk("cyc:set_modem_info retval at %d was %x\n",
+               __LINE__, retval);
+       }
+    }
     return 0;
 } /* set_modem_info */
 
+
 static void
 send_break( struct cyclades_port * info, int duration)
-{ /* Let the transmit ISR take care of this (since it
-     requires stuffing characters into the output stream).
-   */
-    info->x_break = duration;
-    if (!info->xmit_cnt ) {
-       start_xmit(info);
+{
+
+    if (!IS_CYC_Z(cy_card[info->card])) {
+        /* Let the transmit ISR take care of this (since it
+          requires stuffing characters into the output stream).
+        */
+       info->x_break = duration;
+       if (!info->xmit_cnt ) {
+           start_xmit(info);
+       }
+    } else {
+       /* For the moment we ignore the duration parameter!!!
+          A better implementation will use C_CM_SET_BREAK
+          and C_CM_CLR_BREAK with the appropriate delay.
+        */
+#if 1
+// this appears to wedge the output data stream
+int retval;
+        retval = cyz_issue_cmd(&cy_card[info->card],
+               (info->line) - (cy_card[info->card].first_line),
+               C_CM_SENDBRK, 0L);
+       if (retval != 0){
+           printk("cyc:send_break retval at %d was %x\n",
+               __LINE__, retval);
+       }
+#endif
     }
 } /* send_break */
 
+
 static int
 get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
 {
 
-   memcpy_tofs(mon, &info->mon, sizeof(struct cyclades_monitor));
-   info->mon.int_count  = 0;
-   info->mon.char_count = 0;
-   info->mon.char_max   = 0;
-   info->mon.char_last  = 0;
-   return 0;
-}
+    copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor));
+    info->mon.int_count  = 0;
+    info->mon.char_count = 0;
+    info->mon.char_max   = 0;
+    info->mon.char_last  = 0;
+    return 0;
+}/* get_mon_info */
+
 
 static int
 set_threshold(struct cyclades_port * info, unsigned long value)
 {
-   unsigned char *base_addr;
-   int card,channel,chip,index;
+  unsigned char *base_addr;
+  int card,channel,chip,index;
    
-   card = info->card;
-   channel = info->line - cy_card[card].first_line;
-   chip = channel>>2;
-   channel &= 0x03;
-   index = cy_card[card].bus_index;
-   base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
+
+       info->cor3 &= ~CyREC_FIFO;
+       info->cor3 |= value & CyREC_FIFO;
+       cy_writeb((u_long)base_addr+(CyCOR3<<index), info->cor3);
+       cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
+    } else {
+       // Nothing to do!
+    }
+    return 0;
+}/* set_threshold */
 
-   info->cor3 &= ~CyREC_FIFO;
-   info->cor3 |= value & CyREC_FIFO;
-   base_addr[CyCOR3<<index] = info->cor3;
-   write_cy_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
-   return 0;
-}
 
 static int
 get_threshold(struct cyclades_port * info, unsigned long *value)
 {
-   unsigned char *base_addr;
-   int card,channel,chip,index;
-   unsigned long tmp;
+  unsigned char *base_addr;
+  int card,channel,chip,index;
+  unsigned long tmp;
    
-   card = info->card;
-   channel = info->line - cy_card[card].first_line;
-   chip = channel>>2;
-   channel &= 0x03;
-   index = cy_card[card].bus_index;
-   base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
+
+       tmp = cy_readb(base_addr+(CyCOR3<<index)) & CyREC_FIFO;
+       cy_put_user(tmp,value);
+    } else {
+       // Nothing to do!
+    }
+    return 0;
+}/* get_threshold */
 
-   tmp = base_addr[CyCOR3<<index] & CyREC_FIFO;
-   put_fs_long(tmp,value);
-   return 0;
-}
 
 static int
 set_default_threshold(struct cyclades_port * info, unsigned long value)
 {
-   info->default_threshold = value & 0x0f;
-   return 0;
-}
+    info->default_threshold = value & 0x0f;
+    return 0;
+}/* set_default_threshold */
+
 
 static int
 get_default_threshold(struct cyclades_port * info, unsigned long *value)
 {
-   put_fs_long(info->default_threshold,value);
-   return 0;
-}
+    cy_put_user(info->default_threshold,value);
+    return 0;
+}/* get_default_threshold */
+
 
 static int
 set_timeout(struct cyclades_port * info, unsigned long value)
 {
-   unsigned char *base_addr;
-   int card,channel,chip,index;
+  unsigned char *base_addr;
+  int card,channel,chip,index;
    
-   card = info->card;
-   channel = info->line - cy_card[card].first_line;
-   chip = channel>>2;
-   channel &= 0x03;
-   index = cy_card[card].bus_index;
-   base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
+
+       cy_writeb((u_long)base_addr+(CyRTPR<<index), value & 0xff);
+    } else {
+       // Nothing to do!
+    }
+    return 0;
+}/* set_timeout */
 
-   base_addr[CyRTPR<<index] = value & 0xff;
-   return 0;
-}
 
 static int
 get_timeout(struct cyclades_port * info, unsigned long *value)
 {
-   unsigned char *base_addr;
-   int card,channel,chip,index;
-   unsigned long tmp;
+  unsigned char *base_addr;
+  int card,channel,chip,index;
+  unsigned long tmp;
    
-   card = info->card;
-   channel = info->line - cy_card[card].first_line;
-   chip = channel>>2;
-   channel &= 0x03;
-   index = cy_card[card].bus_index;
-   base_addr = (unsigned char*)
-                  (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
+
+       tmp = cy_readb(base_addr+(CyRTPR<<index));
+       cy_put_user(tmp,value);
+    } else {
+       // Nothing to do!
+    }
+    return 0;
+}/* get_timeout */
 
-   tmp = base_addr[CyRTPR<<index];
-   put_fs_long(tmp,value);
-   return 0;
-}
 
 static int
 set_default_timeout(struct cyclades_port * info, unsigned long value)
 {
-   info->default_timeout = value & 0xff;
-   return 0;
-}
+    info->default_timeout = value & 0xff;
+    return 0;
+}/* set_default_timeout */
+
 
 static int
 get_default_timeout(struct cyclades_port * info, unsigned long *value)
 {
-   put_fs_long(info->default_timeout,value);
-   return 0;
-}
+    cy_put_user(info->default_timeout,value);
+    return 0;
+}/* get_default_timeout */
 
+/*
+ * This routine allows the tty driver to implement device-
+ * specific ioctl's.  If the ioctl number passed in cmd is
+ * not recognized by the driver, it should return ENOIOCTLCMD.
+ */
 static int
 cy_ioctl(struct tty_struct *tty, struct file * file,
             unsigned int cmd, unsigned long arg)
@@ -2163,8 +3940,9 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
   struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
   int ret_val = 0;
 
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
+#ifdef CY_DEBUG_OTHER
+    printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
+        info->line, cmd, arg); /* */
 #endif
 
     switch (cmd) {
@@ -2176,7 +3954,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
                 break;
             }
             ret_val = get_mon_info(info, (struct cyclades_monitor *)arg);
-           break;
+            break;
         case CYGETTHRESH:
             error = verify_area(VERIFY_WRITE, (void *) arg
                                 ,sizeof(unsigned long));
@@ -2184,11 +3962,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
                 ret_val = error;
                 break;
             }
-           ret_val = get_threshold(info, (unsigned long *)arg);
-           break;
+            ret_val = get_threshold(info, (unsigned long *)arg);
+            break;
         case CYSETTHRESH:
             ret_val = set_threshold(info, (unsigned long)arg);
-           break;
+            break;
         case CYGETDEFTHRESH:
             error = verify_area(VERIFY_WRITE, (void *) arg
                                 ,sizeof(unsigned long));
@@ -2196,11 +3974,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
                 ret_val = error;
                 break;
             }
-           ret_val = get_default_threshold(info, (unsigned long *)arg);
-           break;
+            ret_val = get_default_threshold(info, (unsigned long *)arg);
+            break;
         case CYSETDEFTHRESH:
             ret_val = set_default_threshold(info, (unsigned long)arg);
-           break;
+            break;
         case CYGETTIMEOUT:
             error = verify_area(VERIFY_WRITE, (void *) arg
                                 ,sizeof(unsigned long));
@@ -2208,11 +3986,11 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
                 ret_val = error;
                 break;
             }
-           ret_val = get_timeout(info, (unsigned long *)arg);
-           break;
+            ret_val = get_timeout(info, (unsigned long *)arg);
+            break;
         case CYSETTIMEOUT:
             ret_val = set_timeout(info, (unsigned long)arg);
-           break;
+            break;
         case CYGETDEFTIMEOUT:
             error = verify_area(VERIFY_WRITE, (void *) arg
                                 ,sizeof(unsigned long));
@@ -2220,23 +3998,62 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
                 ret_val = error;
                 break;
             }
-           ret_val = get_default_timeout(info, (unsigned long *)arg);
-           break;
+            ret_val = get_default_timeout(info, (unsigned long *)arg);
+            break;
         case CYSETDEFTIMEOUT:
             ret_val = set_default_timeout(info, (unsigned long)arg);
+            break;
+       case CYSETRFLOW:
+           info->rflow = (int)arg;
+           ret_val = 0;
+           break;
+       case CYGETRFLOW:
+           ret_val = info->rflow;
+           break;
+       case CYSETRTSDTR_INV:
+           info->rtsdtr_inv = (int)arg;
+           ret_val = 0;
+           break;
+       case CYGETRTSDTR_INV:
+           ret_val = info->rtsdtr_inv;
+           break;
+       case CYGETCARDINFO:
+            error = verify_area(VERIFY_WRITE, (void *) arg
+                                ,sizeof(struct cyclades_card));
+            if (error){
+                ret_val = error;
+                break;
+            }
+            copy_to_user((void *)arg, (void *)&cy_card[info->card], 
+                        sizeof (struct cyclades_card));
+           ret_val = 0;
+            break;
+       case CYGETCD1400VER:
+           ret_val = info->chip_rev;
+           break;
+       case CYZPOLLCYCLE:
+            cyz_polling_cycle = (HZ * arg) / 1000;
+           ret_val = 0;
+           break;
+       case CYSETWAIT:
+           info->closing_wait = (unsigned short)arg * HZ/100;
+           ret_val = 0;
+           break;
+       case CYGETWAIT:
+           ret_val = info->closing_wait / (HZ/100);
            break;
         case TCSBRK:    /* SVID version: non-zero arg --> no break */
-           ret_val = tty_check_change(tty);
-           if (ret_val)
-               return ret_val;
+            ret_val = tty_check_change(tty);
+            if (ret_val)
+                return ret_val;
             tty_wait_until_sent(tty,0);
             if (!arg)
                 send_break(info, HZ/4); /* 1/4 second */
             break;
         case TCSBRKP:   /* support for POSIX tcsendbreak() */
-           ret_val = tty_check_change(tty);
-           if (ret_val)
-               return ret_val;
+            ret_val = tty_check_change(tty);
+            if (ret_val)
+                return ret_val;
             tty_wait_until_sent(tty,0);
             send_break(info, arg ? arg*(HZ/10) : HZ/4);
             break;
@@ -2254,18 +4071,18 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
                 ret_val = error;
                 break;
             }
-            put_fs_long(C_CLOCAL(tty) ? 1 : 0,
+            cy_put_user(C_CLOCAL(tty) ? 1 : 0,
                         (unsigned long *) arg);
             break;
         case TIOCSSOFTCAR:
-            error = verify_area(VERIFY_READ, (void *) arg
-                                 ,sizeof(unsigned long *));
-            if (error) {
-                 ret_val = error;
-                 break;
-            }
+           error = verify_area(VERIFY_READ, (void *) arg
+                                ,sizeof(unsigned long *));
+           if (error) {
+                ret_val = error;
+                break;
+           }
 
-            arg = get_fs_long((unsigned long *) arg);
+            arg = cy_get_user((unsigned long *) arg);
             tty->termios->c_cflag =
                     ((tty->termios->c_cflag & ~CLOCAL) |
                      (arg ? CLOCAL : 0));
@@ -2300,31 +4117,35 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
                                    (struct serial_struct *) arg);
             break;
         default:
-           ret_val = -ENOIOCTLCMD;
+            ret_val = -ENOIOCTLCMD;
     }
 
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_ioctl done\n");
+#ifdef CY_DEBUG_OTHER
+    printk(" cyc:cy_ioctl done\n");
 #endif
 
     return ret_val;
 } /* cy_ioctl */
 
 
-
-
+/*
+ * This routine allows the tty driver to be notified when
+ * device's termios settings have changed.  Note that a
+ * well-designed tty driver should be prepared to accept the case
+ * where old == NULL, and try to do something rational.
+ */
 static void
 cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
 
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_set_termios ttyC%d\n", info->line);
+#ifdef CY_DEBUG_OTHER
+    printk("cyc:cy_set_termios ttyC%d\n", info->line);
 #endif
 
     if (tty->termios->c_cflag == old_termios->c_cflag)
         return;
-    config_setup(info);
+    set_line_char(info);
 
     if ((old_termios->c_cflag & CRTSCTS) &&
         !(tty->termios->c_cflag & CRTSCTS)) {
@@ -2341,353 +4162,281 @@ cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
 } /* cy_set_termios */
 
 
+/*
+ * void (*set_ldisc)(struct tty_struct *tty);
+ *
+ *     This routine allows the tty driver to be notified when the
+ *     device's termios settings have changed.
+ * 
+ */
+
+
+/* This routine is called by the upper-layer tty layer to signal
+   that incoming characters should be throttled because the input
+   buffers are close to full.
+ */
 static void
-cy_close(struct tty_struct * tty, struct file * filp)
+cy_throttle(struct tty_struct * tty)
 {
-  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
   unsigned long flags;
+  unsigned char *base_addr;
+  int card,chip,channel,index;
 
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_close ttyC%d\n", info->line);
-#endif
+#ifdef CY_DEBUG_THROTTLE
+  char buf[64];
 
-    if (!info
-    || serial_paranoia_check(info, tty->device, "cy_close")){
-        return;
-    }
-#ifdef SERIAL_DEBUG_OPEN
-    printk("cy_close ttyC%d, count = %d\n", info->line, info->count);
+    printk("cyc:throttle %s: %d....ttyC%d\n", 
+          _tty_name(tty, buf),
+           tty->ldisc.chars_in_buffer(tty), info->line);
 #endif
 
-    save_flags(flags); cli();
-
-    /* If the TTY is being hung up, nothing to do */
-    if (tty_hung_up_p(filp)) {
-       MOD_DEC_USE_COUNT;
-       restore_flags(flags);
-       return;
+    if (serial_paranoia_check(info, tty->device, "cy_throttle")){
+            return;
     }
-       
-    if ((tty->count == 1) && (info->count != 1)) {
-       /*
-        * Uh, oh.  tty->count is 1, which means that the tty
-        * structure will be freed.  Info->count should always
-        * be one in these conditions.  If it's greater than
-        * one, we've got real problems, since it means the
-        * serial port won't be shutdown.
-        */
-       printk("cy_close: bad serial port count; tty->count is 1, "
-          "info->count is %d\n", info->count);
-       info->count = 1;
-    }
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count - 1);
-#endif
-    if (--info->count < 0) {
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: setting count to 0\n", __LINE__);
-#endif
-       info->count = 0;
-    }
-    if (info->count)
-    {
-        MOD_DEC_USE_COUNT;
-       restore_flags(flags);
-       return;
+
+    if (I_IXOFF(tty)) {
+        info->x_char = STOP_CHAR(tty);
+            /* Should use the "Send Special Character" feature!!! */
     }
-    info->flags |= ASYNC_CLOSING;
-    /*
-     * Save the termios structure, since this port may have
-     * separate termios for callout and dialin.
-     */
-    if (info->flags & ASYNC_NORMAL_ACTIVE)
-       info->normal_termios = *tty->termios;
-    if (info->flags & ASYNC_CALLOUT_ACTIVE)
-       info->callout_termios = *tty->termios;
-    if (info->flags & ASYNC_INITIALIZED)
-       tty_wait_until_sent(tty, 30*HZ); /* 30 seconds timeout */
-    shutdown(info);
-    if (tty->driver.flush_buffer)
-       tty->driver.flush_buffer(tty);
-    if (tty->ldisc.flush_buffer)
-       tty->ldisc.flush_buffer(tty);
-    info->event = 0;
-    info->tty = 0;
-    if (info->blocked_open) {
-       if (info->close_delay) {
-           current->state = TASK_INTERRUPTIBLE;
-           current->timeout = jiffies + info->close_delay;
-           schedule();
+
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
+
+       save_flags(flags); cli();
+       cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+       if (info->rtsdtr_inv) {
+               cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
+       } else {
+               cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
        }
-       wake_up_interruptible(&info->open_wait);
+       restore_flags(flags);
+    } else {
+       // Nothing to do!
     }
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-                    ASYNC_CLOSING);
-    wake_up_interruptible(&info->close_wait);
-
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_close done\n");
-#endif
 
-    MOD_DEC_USE_COUNT;
-    restore_flags(flags);
     return;
-} /* cy_close */
+} /* cy_throttle */
+
 
 /*
- * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
+ * This routine notifies the tty driver that it should signal
+ * that characters can now be sent to the tty without fear of
+ * overrunning the input buffers of the line disciplines.
  */
-void
-cy_hangup(struct tty_struct *tty)
+static void
+cy_unthrottle(struct tty_struct * tty)
 {
-  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-       
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_hangup ttyC%d\n", info->line); /* */
-#endif
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned long flags;
+  unsigned char *base_addr;
+  int card,chip,channel,index;
 
-    if (serial_paranoia_check(info, tty->device, "cy_hangup"))
-       return;
-    
-    shutdown(info);
-    info->event = 0;
-    info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): setting count to 0\n", __LINE__, current->pid);
+#ifdef CY_DEBUG_THROTTLE
+  char buf[64];
+        
+    printk("cyc:unthrottle %s: %d....ttyC%d\n", 
+          _tty_name(tty, buf),
+           tty->ldisc.chars_in_buffer(tty), info->line);
 #endif
-    info->tty = 0;
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
-    wake_up_interruptible(&info->open_wait);
-} /* cy_hangup */
 
+    if (serial_paranoia_check(info, tty->device, "cy_unthrottle")){
+            return;
+    }
 
+    if (I_IXOFF(tty)) {
+       if (info->x_char)
+           info->x_char = 0;
+       else
+           info->x_char = START_CHAR(tty);
+            /* Should use the "Send Special Character" feature!!! */
+    }
 
-/*
- * ------------------------------------------------------------
- * cy_open() and friends
- * ------------------------------------------------------------
- */
+    card = info->card;
+    channel = info->line - cy_card[card].first_line;
+    if (!IS_CYC_Z(cy_card[card])) {
+       chip = channel>>2;
+       channel &= 0x03;
+       index = cy_card[card].bus_index;
+       base_addr = (unsigned char*)
+                      (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
 
-static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
-                           struct cyclades_port *info)
+       save_flags(flags); cli();
+       cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
+       if (info->rtsdtr_inv) {
+               cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
+       } else {
+               cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
+       }
+       restore_flags(flags);
+    }else{
+       // Nothing to do!
+    }
+
+    return;
+} /* cy_unthrottle */
+
+
+/* cy_start and cy_stop provide software output flow control as a
+   function of XON/XOFF, software CTS, and other such stuff.
+*/
+static void
+cy_stop(struct tty_struct *tty)
 {
-  struct wait_queue wait = { current, NULL };
   struct cyclades_card *cinfo;
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned char *base_addr;
+  int chip,channel,index;
   unsigned long flags;
-  int chip, channel,index;
-  int retval;
-  char *base_addr;
 
-    /*
-     * If the device is in the middle of being closed, then block
-     * until it's done, and then try again.
-     */
-    if (info->flags & ASYNC_CLOSING) {
-       interruptible_sleep_on(&info->close_wait);
-       if (info->flags & ASYNC_HUP_NOTIFY){
-           return -EAGAIN;
-       }else{
-           return -ERESTARTSYS;
-       }
-    }
+#ifdef CY_DEBUG_OTHER
+    printk("cyc:cy_stop ttyC%d\n", info->line); /* */
+#endif
 
-    /*
-     * If this is a callout device, then just make sure the normal
-     * device isn't being used.
-     */
-    if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
-       if (info->flags & ASYNC_NORMAL_ACTIVE){
-           return -EBUSY;
-       }
-       if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-           (info->flags & ASYNC_SESSION_LOCKOUT) &&
-           (info->session != current->session)){
-           return -EBUSY;
-       }
-       if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-           (info->flags & ASYNC_PGRP_LOCKOUT) &&
-           (info->pgrp != current->pgrp)){
-           return -EBUSY;
-       }
-       info->flags |= ASYNC_CALLOUT_ACTIVE;
-       return 0;
+    if (serial_paranoia_check(info, tty->device, "cy_stop"))
+        return;
+        
+    cinfo = &cy_card[info->card];
+    channel = info->line - cinfo->first_line;
+    if (!IS_CYC_Z(*cinfo)) {
+        index = cinfo->bus_index;
+        chip = channel>>2;
+        channel &= 0x03;
+        base_addr = (unsigned char*)
+                   (cy_card[info->card].base_addr
+                           + (cy_chip_offset[chip]<<index));
+
+        save_flags(flags); cli();
+            cy_writeb((u_long)base_addr+(CyCAR<<index),
+              (u_char)(channel & 0x0003)); /* index channel */
+            cy_writeb((u_long)base_addr+(CySRER<<index), 
+               cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+        restore_flags(flags);
+    } else {
+       // Nothing to do!
     }
 
-    /*
-     * If non-blocking mode is set, then make the check up front
-     * and then exit.
-     */
-    if (filp->f_flags & O_NONBLOCK) {
-       if (info->flags & ASYNC_CALLOUT_ACTIVE){
-           return -EBUSY;
-       }
-       info->flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
-    }
+    return;
+} /* cy_stop */
 
-    /*
-     * Block waiting for the carrier detect and the line to become
-     * free (i.e., not in use by the callout).  While we are in
-     * this loop, info->count is dropped by one, so that
-     * cy_close() knows when to free things.  We restore it upon
-     * exit, either normal or abnormal.
-     */
-    retval = 0;
-    add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
-    printk("block_til_ready before block: ttyC%d, count = %d\n",
-          info->line, info->count);/**/
-#endif
-    info->count--;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): decrementing count to %d\n", __LINE__, current->pid, info->count);
+
+static void
+cy_start(struct tty_struct *tty)
+{
+  struct cyclades_card *cinfo;
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  unsigned char *base_addr;
+  int chip,channel,index;
+  unsigned long flags;
+
+#ifdef CY_DEBUG_OTHER
+    printk("cyc:cy_start ttyC%d\n", info->line); /* */
 #endif
-    info->blocked_open++;
 
+    if (serial_paranoia_check(info, tty->device, "cy_start"))
+        return;
+        
     cinfo = &cy_card[info->card];
     channel = info->line - cinfo->first_line;
-    chip = channel>>2;
-    channel &= 0x03;
     index = cinfo->bus_index;
-    base_addr = (char *) (cinfo->base_addr + (cy_chip_offset[chip]<<index));
-
-    while (1) {
-       save_flags(flags); cli();
-           if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
-               base_addr[CyCAR<<index] = (u_char)channel;
-               base_addr[CyMSVR1<<index] = CyRTS;
-               base_addr[CyMSVR2<<index] = CyDTR;
-#ifdef SERIAL_DEBUG_DTR
-                printk("cyc: %d: raising DTR\n", __LINE__);
-                printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1<<index], base_addr[CyMSVR2<<index]);
-#endif
-           }
-       restore_flags(flags);
-       current->state = TASK_INTERRUPTIBLE;
-       if (tty_hung_up_p(filp)
-       || !(info->flags & ASYNC_INITIALIZED) ){
-           if (info->flags & ASYNC_HUP_NOTIFY) {
-               retval = -EAGAIN;
-           }else{
-               retval = -ERESTARTSYS;
-           }
-           break;
-       }
-       save_flags(flags); cli();
-           base_addr[CyCAR<<index] = (u_char)channel;
-           if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
-           && !(info->flags & ASYNC_CLOSING)
-           && (C_CLOCAL(tty)
-               || (base_addr[CyMSVR1<<index] & CyDCD))) {
-                   restore_flags(flags);
-                   break;
-           }
-       restore_flags(flags);
-       if (current->signal & ~current->blocked) {
-           retval = -ERESTARTSYS;
-           break;
-       }
-#ifdef SERIAL_DEBUG_OPEN
-       printk("block_til_ready blocking: ttyC%d, count = %d\n",
-              info->line, info->count);/**/
-#endif
-       schedule();
-    }
-    current->state = TASK_RUNNING;
-    remove_wait_queue(&info->open_wait, &wait);
-    if (!tty_hung_up_p(filp)){
-       info->count++;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
-#endif
+    if (!IS_CYC_Z(*cinfo)) {
+        chip = channel>>2;
+        channel &= 0x03;
+        base_addr = (unsigned char*)
+                       (cy_card[info->card].base_addr
+                      + (cy_chip_offset[chip]<<index));
+
+        save_flags(flags); cli();
+            cy_writeb((u_long)base_addr+(CyCAR<<index),
+              (u_char)(channel & 0x0003)); /* index channel */
+            cy_writeb((u_long)base_addr+(CySRER<<index), 
+               cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
+        restore_flags(flags);
+    } else {
+       // Nothing to do!
     }
-    info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-    printk("block_til_ready after blocking: ttyC%d, count = %d\n",
-          info->line, info->count);/**/
-#endif
-    if (retval)
-           return retval;
-    info->flags |= ASYNC_NORMAL_ACTIVE;
-    return 0;
-} /* block_til_ready */
 
-/*
- * This routine is called whenever a serial port is opened.  It
- * performs the serial-specific initialization for the tty structure.
- */
-int
-cy_open(struct tty_struct *tty, struct file * filp)
-{
-  struct cyclades_port  *info;
-  int retval, line;
+    return;
+} /* cy_start */
 
-    line = MINOR(tty->device) - tty->driver.minor_start;
-    if ((line < 0) || (NR_PORTS <= line)){
-        return -ENODEV;
-    }
-    info = &cy_port[line];
-    if (info->line < 0){
-        return -ENODEV;
-    }
-#ifdef SERIAL_DEBUG_OTHER
-    printk("cy_open ttyC%d\n", info->line); /* */
-#endif
-    if (serial_paranoia_check(info, tty->device, "cy_open")){
-        return -ENODEV;
-    }
-#ifdef SERIAL_DEBUG_OPEN
-    printk("cy_open ttyC%d, count = %d\n", info->line, info->count);/**/
-#endif
-    info->count++;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d(%d): incrementing count to %d\n", __LINE__, current->pid, info->count);
+
+static void
+cy_flush_buffer(struct tty_struct *tty)
+{
+  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+  int card, channel;
+  unsigned long flags;
+                                
+#ifdef CY_DEBUG_IO
+    printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
 #endif
-    tty->driver_data = info;
-    info->tty = tty;
 
-    if (!tmp_buf) {
-       tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
-       if (!tmp_buf){
-           return -ENOMEM;
-        }
-    }
+    if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
+        return;
+    save_flags(flags); cli();
+    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+    restore_flags(flags);
+
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
 
-    if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-       if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
-           *tty->termios = info->normal_termios;
-       else 
-           *tty->termios = info->callout_termios;
-    }
-    /*
-     * Start up serial port
-     */
-    retval = startup(info);
-    if (retval){
-       return retval;
+    if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board 
+                                     buffers as well */
+       static volatile struct FIRM_ID *firm_id;
+       static volatile struct ZFW_CTRL *zfw_ctrl;
+       static volatile struct CH_CTRL *ch_ctrl;
+       static volatile struct BUF_CTRL *buf_ctrl;
+
+       firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
+       zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
+                               cy_readl(&firm_id->zfwctrl_addr));
+       ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+       buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+       while (cy_readl(&buf_ctrl->tx_get) != cy_readl(&buf_ctrl->tx_put))
+               cy_writel(&buf_ctrl->tx_put, cy_readl(&buf_ctrl->tx_get));
     }
+    wake_up_interruptible(&tty->write_wait);
+    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+       && tty->ldisc.write_wakeup)
+           (tty->ldisc.write_wakeup)(tty);
+} /* cy_flush_buffer */
 
-    MOD_INC_USE_COUNT;
 
-    retval = block_til_ready(tty, filp, info);
-    if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-       printk("cy_open returning after block_til_ready with %d\n",
-              retval);
+/*
+ * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void
+cy_hangup(struct tty_struct *tty)
+{
+  struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+        
+#ifdef CY_DEBUG_OTHER
+    printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
 #endif
-       return retval;
-    }
 
-    info->session = current->session;
-    info->pgrp = current->pgrp;
+    if (serial_paranoia_check(info, tty->device, "cy_hangup"))
+        return;
 
-#ifdef SERIAL_DEBUG_OPEN
-    printk("cy_open done\n");/**/
+    cy_flush_buffer(tty);
+    shutdown(info);
+    info->event = 0;
+    info->count = 0;
+#ifdef CY_DEBUG_COUNT
+    printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
 #endif
-    return 0;
-} /* cy_open */
-
+    info->tty = 0;
+    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+    wake_up_interruptible(&info->open_wait);
+} /* cy_hangup */
 
 
 /*
@@ -2698,33 +4447,25 @@ cy_open(struct tty_struct *tty, struct file * filp)
  * ---------------------------------------------------------------------
  */
 
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static void
-show_version(void)
-{
-    printk("Cyclom driver %s\n",rcsid);
-} /* show_version */
-
-/* initialize chips on card -- return number of valid
+/* initialize chips on Cyclom-Y card -- return number of valid
    chips (which is number of ports/4) */
-int
-cy_init_card(unsigned char *true_base_addr,int index)
+__initfunc(static unsigned short
+cyy_init_card(volatile ucchar *true_base_addr,int index))
 {
   unsigned int chip_number;
-  unsigned char* base_addr;
+  volatile ucchar* base_addr;
 
-    true_base_addr[Cy_HwReset<<index] = 0; /* Cy_HwReset is 0x1400 */
-    true_base_addr[Cy_ClrIntr<<index] = 0; /* Cy_ClrIntr is 0x1800 */
+    cy_writeb((u_long)true_base_addr+(Cy_HwReset<<index), 0); 
+                                               /* Cy_HwReset is 0x1400 */
+    cy_writeb((u_long)true_base_addr+(Cy_ClrIntr<<index), 0); 
+                                               /* Cy_ClrIntr is 0x1800 */
     udelay(500L);
 
-    for(chip_number=0; chip_number<CyMaxChipsPerCard; chip_number++){
-        base_addr = true_base_addr + (cy_chip_offset[chip_number]<<index);
+    for(chip_number=0; chip_number<CyMAX_CHIPS_PER_CARD; chip_number++){
+        base_addr = true_base_addr
+                      + (cy_chip_offset[chip_number]<<index);
         udelay(1000L);
-        if(base_addr[CyCCR<<index] != 0x00){
+        if(cy_readb(base_addr+(CyCCR<<index)) != 0x00){
             /*************
             printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
                chip_number, (unsigned long)base_addr);
@@ -2732,7 +4473,7 @@ cy_init_card(unsigned char *true_base_addr,int index)
             return chip_number;
         }
 
-        base_addr[CyGFRCR<<index] = 0;
+        cy_writeb((u_long)base_addr+(CyGFRCR<<index), 0);
         udelay(10L);
 
         /* The Cyclom-16Y does not decode address bit 9 and therefore
@@ -2742,39 +4483,558 @@ cy_init_card(unsigned char *true_base_addr,int index)
            and this must be a Cyclom-16Y, not a Cyclom-32Ye.
         */
         if (chip_number == 4
-        && *(true_base_addr + (cy_chip_offset[0]<<index) + (CyGFRCR<<index)) == 0){
-           return chip_number;
+        && cy_readb(true_base_addr
+           + (cy_chip_offset[0]<<index)
+           + (CyGFRCR<<index)) == 0){
+            return chip_number;
         }
 
-        base_addr[CyCCR<<index] = CyCHIP_RESET;
+        cy_writeb((u_long)base_addr+(CyCCR<<index), CyCHIP_RESET);
         udelay(1000L);
 
-        if(base_addr[CyGFRCR<<index] == 0x00){
-           /*
-            printk(" chip #%d at %#6lx is not responding (GFRCR stayed 0)\n",
+        if(cy_readb(base_addr+(CyGFRCR<<index)) == 0x00){
+            /*
+            printk(" chip #%d at %#6lx is not responding ",
                chip_number, (unsigned long)base_addr);
-           */
+            printk("(GFRCR stayed 0)\n",
+            */
             return chip_number;
         }
-        if((0xf0 & base_addr[CyGFRCR<<index]) != 0x40){
-           /*
+        if((0xf0 & (cy_readb(base_addr+(CyGFRCR<<index)))) != 0x40){
+            /*
             printk(" chip #%d at %#6lx is not valid (GFRCR == %#2x)\n",
-               chip_number, (unsigned long)base_addr, base_addr[CyGFRCR<<index]);
-           */
+               chip_number, (unsigned long)base_addr,
+              base_addr[CyGFRCR<<index]);
+            */
             return chip_number;
         }
-        base_addr[CyGCR<<index] = CyCH0_SERIAL;
-        base_addr[CyPPR<<index] = 244; /* better value than CyCLOCK_25_1MS * 5
-                                                  to run clock at 200 Hz */
+        cy_writeb((u_long)base_addr+(CyGCR<<index), CyCH0_SERIAL);
+        if (cy_readb(base_addr+(CyGFRCR<<index)) >= CD1400_REV_J){
+           /* It is a CD1400 rev. J or later */
+           /* Impossible to reach 5ms with this chip. 
+              Changed to 2ms instead (f = 500 Hz). */
+           cy_writeb((u_long)base_addr+(CyPPR<<index), CyCLOCK_60_2MS);
+       } else {
+           /* f = 200 Hz */
+           cy_writeb((u_long)base_addr+(CyPPR<<index), CyCLOCK_25_5MS);
+       }
 
-       /*
+    /*
         printk(" chip #%d at %#6lx is rev 0x%2x\n",
-               chip_number, (unsigned long)base_addr, base_addr[CyGFRCR<<index]);
-       */
+               chip_number, (unsigned long)base_addr,
+              cy_readb(base_addr+(CyGFRCR<<index)));
+    */
     }
-
     return chip_number;
-} /* cy_init_card */
+} /* cyy_init_card */
+
+/*
+ * ---------------------------------------------------------------------
+ * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
+ * sets global variables and return the number of ISA boards found.
+ * ---------------------------------------------------------------------
+ */
+__initfunc(static int
+cy_detect_isa(void))
+{
+  unsigned short       cy_isa_irq,nboard;
+  volatile ucchar      *cy_isa_address;
+  unsigned short       i,j,cy_isa_nchan;
+
+        nboard = 0;
+
+        /* scan the address table probing for Cyclom-Y/ISA boards */
+        for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
+                cy_isa_address = cy_isa_addresses[i];
+                if (cy_isa_address  == 0x0000) {
+                        return(nboard);
+                }
+
+                /* probe for CD1400... */
+
+                cy_isa_nchan = CyPORTS_PER_CHIP * 
+                     cyy_init_card(cy_isa_address,0);
+                if (cy_isa_nchan == 0) {
+                        continue;
+                }
+
+                /* find out the board's irq by probing */
+                cy_isa_irq = do_auto_irq(cy_isa_address);
+                if (cy_isa_irq == 0) {
+                        printk("Cyclom-Y/ISA found at 0x%lx ",
+                                (unsigned long) cy_isa_address);
+                        printk("but the IRQ could not be detected.\n");
+                        continue;
+                }
+
+                if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
+                        printk("Cyclom-Y/ISA found at 0x%lx ",
+                                (unsigned long) cy_isa_address);
+                        printk("but no more channels are available.\n");
+                        printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
+                        return(nboard);
+                }
+                /* fill the next cy_card structure available */
+                for (j = 0 ; j < NR_CARDS ; j++) {
+                        if (cy_card[j].base_addr == 0)  break;
+                }
+                if (j == NR_CARDS) {    /* no more cy_cards available */
+                        printk("Cyclom-Y/ISA found at 0x%lx ",
+                                (unsigned long) cy_isa_address);
+                        printk("but no more cards can be used .\n");
+                        printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+                        return(nboard);
+                }
+
+                /* allocate IRQ */
+                if(request_irq(cy_isa_irq, cyy_interrupt,
+                                  SA_INTERRUPT, "cyclomY", NULL))
+                {
+                        printk("Cyclom-Y/ISA found at 0x%lx ",
+                                (unsigned long) cy_isa_address);
+                        printk("but could not allocate IRQ#%d.\n",
+                                cy_isa_irq);
+                        return(nboard);
+                }
+
+                /* set cy_card */
+                cy_card[j].base_addr = (u_long) cy_isa_address;
+                cy_card[j].ctl_addr = 0;
+                cy_card[j].irq = (int) cy_isa_irq;
+                cy_card[j].bus_index = 0;
+                cy_card[j].first_line = cy_next_channel;
+                cy_card[j].num_chips = cy_isa_nchan/4;
+                IRQ_cards[cy_isa_irq] = &cy_card[j];
+                nboard++;
+                        
+                /* print message */
+                printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
+                    j+1, (unsigned long) cy_isa_address,
+                    (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
+                   cy_isa_irq);
+                printk("%d channels starting from port %d.\n",
+                        cy_isa_nchan, cy_next_channel);
+                cy_next_channel += cy_isa_nchan;
+        }
+        return(nboard);
+
+} /* cy_detect_isa */
+
+/*
+ * ---------------------------------------------------------------------
+ * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
+ * sets global variables and return the number of PCI boards found.
+ * ---------------------------------------------------------------------
+ */
+__initfunc(static int
+cy_detect_pci(void))
+{
+#ifdef CONFIG_PCI
+  unsigned char         cyy_bus, cyy_dev_fn, cyy_rev_id;
+  unsigned long         pci_intr_ctrl;
+  unsigned char         cy_pci_irq;
+  uclong                cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
+  unsigned short        i,j,cy_pci_nchan;
+  unsigned short        device_id,dev_index = 0,board_index = 0;
+  uclong               mailbox;
+  uclong               Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
+
+        if(pcibios_present() == 0) {    /* PCI bus not present */
+                return(0);
+        }
+        for (i = 0; i < NR_CARDS; i++) {
+                /* look for a Cyclades card by vendor and device id */
+                while((device_id = cy_pci_dev_id[dev_index]) != 0) {
+                        if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
+                                        device_id,board_index,
+                                        &cyy_bus, &cyy_dev_fn) != 0)
+                        {
+                                dev_index++;    /* try next device id */
+                                board_index = 0;
+                        } else {
+                                board_index++;
+                                break;          /* found a board */
+                        }
+                }
+
+               if (device_id == 0)
+                   break;
+
+                /* read PCI configuration area */
+                pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+                                 PCI_INTERRUPT_LINE, &cy_pci_irq);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_0, 
+                                 (unsigned int *) &cy_pci_addr0);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_1, 
+                                 (unsigned int *) &cy_pci_addr1);
+                pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
+                                  PCI_BASE_ADDRESS_2, 
+                                 (unsigned int *) &cy_pci_addr2);
+                pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
+                                  PCI_REVISION_ID, &cyy_rev_id);
+
+    if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
+          || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
+#ifdef CY_PCI_DEBUG
+            printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+               cyy_bus, cyy_dev_fn);
+            printk("rev_id=%d) IRQ%d\n",
+               cyy_rev_id, (int)cy_pci_irq);
+            printk("Cyclom-Y/PCI:found  winaddr=0x%lx ioaddr=0x%lx\n",
+               (ulong)cy_pci_addr2, (ulong)cy_pci_addr1);
+#endif
+                cy_pci_addr1  &= PCI_BASE_ADDRESS_IO_MASK;
+                cy_pci_addr2  &= PCI_BASE_ADDRESS_MEM_MASK;
+
+#if defined(__alpha__)
+                if (device_id  == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
+                   printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+                       cyy_bus, cyy_dev_fn);
+                   printk("rev_id=%d) IRQ%d\n",
+                       cyy_rev_id, (int)cy_pci_irq);
+                    printk("Cyclom-Y/PCI:found  winaddr=0x%lx ioaddr=0x%lx\n",
+                       (ulong)cy_pci_addr2, (ulong)cy_pci_addr1);
+                   printk("Cyclom-Y/PCI not supported for low addresses in "
+                           "Alpha systems.\n");
+                   i--;
+                   continue;
+                }
+#else
+                if ((ulong)cy_pci_addr2 >= 0x100000)  /* above 1M? */
+                    cy_pci_addr2 = (ulong) ioremap(cy_pci_addr2, CyPCI_Ywin);
+#endif
+
+#ifdef CY_PCI_DEBUG
+            printk("Cyclom-Y/PCI: relocate winaddr=0x%lx ioaddr=0x%lx\n",
+               (u_long)cy_pci_addr2, (u_long)cy_pci_addr1);
+#endif
+                cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP * 
+                       cyy_init_card((volatile ucchar *)cy_pci_addr2, 1));
+                if(cy_pci_nchan == 0) {
+                        printk("Cyclom-Y PCI host card with ");
+                        printk("no Serial-Modules at 0x%lx.\n",
+                           (ulong) cy_pci_addr2);
+                        i--;
+                        continue;
+                }
+                if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
+                        printk("Cyclom-Y/PCI found at 0x%lx ",
+                           (ulong) cy_pci_addr2);
+                        printk("but no channels are available.\n");
+                        printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
+                        return(i);
+                }
+                /* fill the next cy_card structure available */
+                for (j = 0 ; j < NR_CARDS ; j++) {
+                        if (cy_card[j].base_addr == 0)  break;
+                }
+                if (j == NR_CARDS) {    /* no more cy_cards available */
+                        printk("Cyclom-Y/PCI found at 0x%lx ",
+                           (ulong) cy_pci_addr2);
+                        printk("but no more cards can be used.\n");
+                        printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+                        return(i);
+                }
+
+                /* allocate IRQ */
+                if(request_irq(cy_pci_irq, cyy_interrupt,
+                       SA_INTERRUPT, "cyclomY", NULL))
+                {
+                        printk("Cyclom-Y/PCI found at 0x%lx ",
+                           (ulong) cy_pci_addr2);
+                        printk("but could not allocate IRQ%d.\n",
+                           cy_pci_irq);
+                        return(i);
+                }
+
+                /* set cy_card */
+                cy_card[j].base_addr = (ulong)cy_pci_addr2;
+                cy_card[j].ctl_addr = 0;
+                cy_card[j].irq = (int) cy_pci_irq;
+                cy_card[j].bus_index = 1;
+                cy_card[j].first_line = cy_next_channel;
+                cy_card[j].num_chips = cy_pci_nchan/4;
+                IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+                /* enable interrupts in the PCI interface */
+                outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68);
+                pci_intr_ctrl = (unsigned long)
+                               (inw(cy_pci_addr1+0x68)
+                               | inw(cy_pci_addr1+0x6a)<<16);
+
+                /* print message */
+                printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
+                      j+1, 
+                      (ulong)cy_pci_addr2, 
+                      (ulong)(cy_pci_addr2 + CyPCI_Ywin - 1),
+                      (int)cy_pci_irq);
+                printk("%d channels starting from port %d.\n",
+                   cy_pci_nchan, cy_next_channel);
+
+                cy_next_channel += cy_pci_nchan;
+    }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
+           /* print message */
+               printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+                   cyy_bus, cyy_dev_fn);
+               printk("rev_id=%d) IRQ%d\n",
+                   cyy_rev_id, (int)cy_pci_irq);
+               printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
+                   (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
+           printk("Cyclades-Z/PCI not supported for low addresses\n");
+           break;
+    }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
+#ifdef CY_PCI_DEBUG
+            printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+               cyy_bus, cyy_dev_fn);
+            printk("rev_id=%d) IRQ%d\n",
+               cyy_rev_id, (int)cy_pci_irq);
+            printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
+                (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
+#endif
+                cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK;
+#if !defined(__alpha__)
+                cy_pci_addr0 = (unsigned int) ioremap(
+                               cy_pci_addr0 & PAGE_MASK,
+                               PAGE_ALIGN(CyPCI_Zctl))
+                               + (cy_pci_addr0 & (PAGE_SIZE-1));
+#endif
+               mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) 
+                          cy_pci_addr0)->mail_box_0);
+                cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
+               if (mailbox == ZE_V1) {
+#if !defined(__alpha__)
+                           cy_pci_addr2 = (unsigned int) ioremap(
+                       cy_pci_addr2 & PAGE_MASK,
+                       PAGE_ALIGN(CyPCI_Ze_win))
+                       + (cy_pci_addr2 & (PAGE_SIZE-1));
+#endif
+                   if (ZeIndex == NR_CARDS) {
+                       printk("Cyclades-Ze/PCI found at 0x%lx ",
+                               (ulong)cy_pci_addr2);
+                       printk("but no more cards can be used.\n");
+                        printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+                   } else {
+                       Ze_addr0[ZeIndex] = cy_pci_addr0;
+                       Ze_addr2[ZeIndex] = cy_pci_addr2;
+                       ZeIndex++;
+                   }
+                   i--;
+                   continue;
+               } else {
+#if !defined(__alpha__)
+                    cy_pci_addr2 = (unsigned int) ioremap(
+                       cy_pci_addr2 & PAGE_MASK,
+                       PAGE_ALIGN(CyPCI_Zwin))
+                       + (cy_pci_addr2 & (PAGE_SIZE-1));
+#endif
+               }
+
+#ifdef CY_PCI_DEBUG
+            printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
+                (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
+           if (mailbox == ZO_V1) {
+               cy_writel(&((struct RUNTIME_9060 *)
+                         (cy_pci_addr0))->loc_addr_base, WIN_CREG);
+               PAUSE
+               printk("Cyclades-8Zo/PCI: FPGA id %lx, ver %lx\n",
+                      (ulong)(0xff & cy_readl(&((struct CUSTOM_REG *)
+                       (cy_pci_addr2))->fpga_id)),
+                      (ulong)(0xff & cy_readl(&((struct CUSTOM_REG *)
+                       (cy_pci_addr2))->fpga_version)));
+               cy_writel(&((struct RUNTIME_9060 *)
+                         (cy_pci_addr0))->loc_addr_base, WIN_RAM);
+           } else {
+               printk("Cyclades-Z/PCI: New Cyclades-Z board.  FPGA not loaded\n");
+           }
+#endif
+           /* The following clears the firmware id word.  This ensures
+              that the driver will not attempt to talk to the board
+              until it has been properly initialized.
+            */
+               PAUSE
+               if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
+                   cy_writel((ulong)(cy_pci_addr2+ID_ADDRESS), 0L);
+
+                /* This must be a Cyclades-8Zo/PCI.  The extendable
+                   version will have a different device_id and will
+                   be allocated its maximum number of ports. */
+                cy_pci_nchan = 8;
+
+                if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
+                        printk("Cyclades-8Zo/PCI found at 0x%lx ",
+                           (ulong)cy_pci_addr2);
+                        printk("but no channels are available.\n");
+                        printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
+                        return(i);
+                }
+
+                /* fill the next cy_card structure available */
+                for (j = 0 ; j < NR_CARDS ; j++) {
+                        if (cy_card[j].base_addr == 0)  break;
+                }
+                if (j == NR_CARDS) {    /* no more cy_cards available */
+                   printk("Cyclades-8Zo/PCI found at 0x%lx ",
+                       (ulong)cy_pci_addr2);
+                   printk("but no more cards can be used.\n");
+                    printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+                   return(i);
+                }
+
+                /* allocate IRQ only if board has an IRQ */
+               if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
+                   if(request_irq(cy_pci_irq,cyz_interrupt,
+                       SA_INTERRUPT,"cyclomZ",NULL))
+                   {
+                       printk("Could not allocate IRQ%d ",
+                           cy_pci_irq);
+                       printk("for Cyclades-8Zo/PCI at 0x%lx.\n",
+                           (ulong)cy_pci_addr2);
+                       return(i);
+                   }
+               }
+
+
+                /* set cy_card */
+                cy_card[j].base_addr = cy_pci_addr2;
+                cy_card[j].ctl_addr = cy_pci_addr0;
+                cy_card[j].irq = (int) cy_pci_irq;
+                cy_card[j].bus_index = 1;
+                cy_card[j].first_line = cy_next_channel;
+                cy_card[j].num_chips = 1;
+                IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+                /* print message */
+               /* don't report IRQ if board is no IRQ */
+               if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
+                   printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
+                       j+1,(ulong)cy_pci_addr2,
+                       (ulong)(cy_pci_addr2 + CyPCI_Zwin - 1),
+                       (int)cy_pci_irq);
+               }else{
+                   printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
+                       j+1,(ulong)cy_pci_addr2,
+                       (ulong)(cy_pci_addr2 + CyPCI_Zwin - 1));
+               }
+                printk("%d channels starting from port %d.\n",
+                   cy_pci_nchan,cy_next_channel);
+                cy_next_channel += cy_pci_nchan;
+    }
+        }
+
+        for (; ZeIndex != 0 && i < NR_CARDS; i++) {
+           cy_pci_addr0 = Ze_addr0[0];
+           cy_pci_addr2 = Ze_addr2[0];
+           for (j = 0 ; j < ZeIndex-1 ; j++) {
+               Ze_addr0[j] = Ze_addr0[j+1];
+               Ze_addr2[j] = Ze_addr2[j+1];
+           }
+           ZeIndex--;
+               mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) 
+                                          cy_pci_addr0)->mail_box_0);
+#ifdef CY_PCI_DEBUG
+            printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
+                (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
+           printk("Cyclades-Z/PCI: New Cyclades-Z board.  FPGA not loaded\n");
+#endif
+           /* The following clears the firmware id word.  This ensures
+              that the driver will not attempt to talk to the board
+              until it has been properly initialized.
+            */
+               PAUSE
+                /* This must be the new Cyclades-Ze/PCI. */
+                cy_pci_nchan = ZE_V1_NPORTS;
+
+                if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
+                        printk("Cyclades-Ze/PCI found at 0x%lx ",
+                           (ulong)cy_pci_addr2);
+                        printk("but no channels are available.\n");
+                        printk("Change NR_PORTS in cyclades.c and recompile kernel.\n");
+                        return(i);
+                }
+
+                /* fill the next cy_card structure available */
+                for (j = 0 ; j < NR_CARDS ; j++) {
+                        if (cy_card[j].base_addr == 0)  break;
+                }
+                if (j == NR_CARDS) {    /* no more cy_cards available */
+                   printk("Cyclades-Ze/PCI found at 0x%lx ",
+                       (ulong)cy_pci_addr2);
+                   printk("but no more cards can be used.\n");
+                    printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+                   return(i);
+                }
+
+                /* allocate IRQ only if board has an IRQ */
+               if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) {
+                   if(request_irq(cy_pci_irq,cyz_interrupt,
+                       SA_INTERRUPT,"cyclomZ",NULL))
+                   {
+                       printk("Could not allocate IRQ%d ",
+                           cy_pci_irq);
+                       printk("for Cyclades-Ze/PCI at 0x%lx.\n",
+                           (ulong) cy_pci_addr2);
+                       return(i);
+                   }
+               }
+
+                /* set cy_card */
+                cy_card[j].base_addr = cy_pci_addr2;
+                cy_card[j].ctl_addr = cy_pci_addr0;
+                cy_card[j].irq = (int) cy_pci_irq;
+                cy_card[j].bus_index = 1;
+                cy_card[j].first_line = cy_next_channel;
+                cy_card[j].num_chips = 1;
+                IRQ_cards[cy_pci_irq] = &cy_card[j];
+
+                /* print message */
+               /* don't report IRQ if board is no IRQ */
+               if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) {
+                   printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
+                       j+1,(ulong)cy_pci_addr2,
+                       (ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1),
+                       (int)cy_pci_irq);
+               }else{
+                   printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
+                       j+1,(ulong)cy_pci_addr2,
+                       (ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1));
+               }
+                printk("%d channels starting from port %d.\n",
+                   cy_pci_nchan,cy_next_channel);
+                cy_next_channel += cy_pci_nchan;
+        }
+       if (ZeIndex != 0) {
+           printk("Cyclades-Ze/PCI found at 0x%x ",
+               (unsigned int) Ze_addr2[0]);
+           printk("but no more cards can be used.\n");
+            printk("Change NR_CARDS in cyclades.c and recompile kernel.\n");
+       }
+        return(i);
+#else
+        return(0);
+#endif /* ifdef CONFIG_PCI */
+} /* cy_detect_pci */
+
+
+/*
+ * This routine prints out the appropriate serial driver version number
+ * and identifies which options were configured into this driver.
+ */
+static inline void
+show_version(void)
+{
+  char *rcsvers, *rcsdate, *tmp;
+    rcsvers = strchr(rcsid, ' '); rcsvers++;
+    tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
+    rcsdate = strchr(tmp, ' '); rcsdate++;
+    tmp = strrchr(rcsdate, ' '); *tmp = '\0';
+    printk("Cyclades driver %s %s\n",
+        rcsvers, rcsdate);
+    printk("        built %s %s\n",
+       __DATE__, __TIME__);
+} /* show_version */
+
 
 /* The serial driver boot-time initialization code!
     Hardware I/O ports are mapped to character special devices on a
@@ -2789,15 +5049,21 @@ cy_init_card(unsigned char *true_base_addr,int index)
     device driver because the Cyclom is more properly a multiplexer,
     not just an aggregation of serial ports on one card.
 
-    If there are more cards with more ports than have been statically
-    allocated above, a warning is printed and the extra ports are ignored.
+    If there are more cards with more ports than have been
+    statically allocated above, a warning is printed and the
+    extra ports are ignored.
  */
-int
-cy_init(void)
+
+__initfunc(int
+cy_init(void))
 {
-  struct cyclades_port *info;
+  struct cyclades_port  *info;
   struct cyclades_card *cinfo;
-  int                  board,port,i;
+  int number_z_boards = 0;
+  int board,port,i,index;
+  unsigned long mailbox;
+  unsigned short chip_number;
+  int nports;
 
     show_version();
 
@@ -2813,7 +5079,7 @@ cy_init(void)
     cy_serial_driver.subtype = SERIAL_TYPE_NORMAL;
     cy_serial_driver.init_termios = tty_std_termios;
     cy_serial_driver.init_termios.c_cflag =
-           B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+            B9600 | CS8 | CREAD | HUPCL | CLOCAL;
     cy_serial_driver.flags = TTY_DRIVER_REAL_RAW;
     cy_serial_driver.refcount = &serial_refcount;
     cy_serial_driver.table = serial_table;
@@ -2845,31 +5111,31 @@ cy_init(void)
     cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 
     if (tty_register_driver(&cy_serial_driver))
-           panic("Couldn't register Cyclom serial driver\n");
+            panic("Couldn't register Cyclades serial driver\n");
     if (tty_register_driver(&cy_callout_driver))
-           panic("Couldn't register Cyclom callout driver\n");
+            panic("Couldn't register Cyclades callout driver\n");
 
     init_bh(CYCLADES_BH, do_cyclades_bh);
 
     for (i = 0; i < 16; i++) {
-           IRQ_cards[i] = 0;
+            IRQ_cards[i] = 0;
     }
 
     for (i = 0; i < NR_CARDS; i++) {
-           /* base_addr=0 indicates board not found */
-           cy_card[i].base_addr = 0;
+            /* base_addr=0 indicates board not found */
+            cy_card[i].base_addr = 0;
     }
 
     /* the code below is responsible to find the boards. Each different
        type of board has its own detection routine. If a board is found,
        the next cy_card structure available is set by the detection
-       routine. These functions are responsible for checking the availability
-       of cy_card and cy_port data structures and updating the
-       cy_next_channel. */
+       routine. These functions are responsible for checking the
+       availability of cy_card and cy_port data structures and updating
+       the cy_next_channel. */
 
     /* look for isa boards */
     cy_isa_nboard = cy_detect_isa();
-
+    
     /* look for pci boards */
     cy_pci_nboard = cy_detect_pci();
 
@@ -2877,288 +5143,225 @@ cy_init(void)
 
     /* invalidate remaining cy_card structures */
     for (i = 0 ; i < NR_CARDS ; i++) {
-       if (cy_card[i].base_addr == 0) {
-               cy_card[i].first_line = -1;
-       }
+        if (cy_card[i].base_addr == 0) {
+                cy_card[i].first_line = -1;
+                cy_card[i].ctl_addr = 0;
+                cy_card[i].irq = 0;
+                cy_card[i].bus_index = 0;
+                cy_card[i].first_line = 0;
+                cy_card[i].num_chips = 0;
+        }
     }
     /* invalidate remaining cy_port structures */
     for (i = cy_next_channel ; i < NR_PORTS ; i++) {
-       cy_port[i].line = -1;
-       cy_port[i].magic = -1;
+        cy_port[i].line = -1;
+        cy_port[i].magic = -1;
     }
 
     /* initialize per-port data structures for each valid board found */
     for (board = 0 ; board < cy_nboard ; board++) {
-           cinfo = &cy_card[board];
-           for (port = cinfo->first_line ;
-                port < cinfo->first_line + 4*cinfo->num_chips ;
-                port++)
-           {
-               info = &cy_port[port];
-               info->magic = CYCLADES_MAGIC;
-               info->type = PORT_CIRRUS;
-               info->card = board;
-               info->line = port;
-               info->flags = STD_COM_FLAGS;
-               info->tty = 0;
-               info->xmit_fifo_size = 12;
-               info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
-               info->cor2 = CyETC;
-               info->cor3 = 0x08; /* _very_ small receive threshold */
-               info->cor4 = 0;
-               info->cor5 = 0;
-               info->tbpr = baud_bpr[13]; /* Tx BPR */
-               info->tco = baud_co[13]; /* Tx CO */
-               info->rbpr = baud_bpr[13]; /* Rx BPR */
-               info->rco = baud_co[13]; /* Rx CO */
-               info->close_delay = 0;
-               info->x_char = 0;
-               info->event = 0;
-               info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
-    printk("cyc: %d: setting count to 0\n", __LINE__);
-#endif
-               info->blocked_open = 0;
-               info->default_threshold = 0;
-               info->default_timeout = 0;
-               info->tqueue.routine = do_softint;
-               info->tqueue.data = info;
-               info->callout_termios =cy_callout_driver.init_termios;
-               info->normal_termios = cy_serial_driver.init_termios;
-               info->open_wait = 0;
-               info->close_wait = 0;
-               /* info->session */
-               /* info->pgrp */
-               info->read_status_mask = CyTIMEOUT| CySPECHAR| CyBREAK
-                                       | CyPARITY| CyFRAME| CyOVERRUN;
-               /* info->timeout */
-           }
+            cinfo = &cy_card[board];
+            if (cinfo->num_chips == 1){ /* Cyclades-Z */
+               number_z_boards++;
+               mailbox = cy_readl(&((struct RUNTIME_9060 *)
+                            cy_card[board].ctl_addr)->mail_box_0);
+               nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
+                for (port = cinfo->first_line ;
+                     port < cinfo->first_line + nports;
+                     port++)
+                {
+                    info = &cy_port[port];
+                    info->magic = CYCLADES_MAGIC;
+                    info->type = PORT_STARTECH;
+                    info->card = board;
+                    info->line = port;
+                   info->chip_rev = 0;
+                    info->flags = STD_COM_FLAGS;
+                    info->tty = 0;
+                   if (mailbox == ZO_V1)
+                       info->xmit_fifo_size = CYZ_FIFO_SIZE;
+                   else
+                       info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
+                    info->cor1 = 0;
+                    info->cor2 = 0;
+                    info->cor3 = 0;
+                    info->cor4 = 0;
+                    info->cor5 = 0;
+                    info->tbpr = 0;
+                    info->tco = 0;
+                    info->rbpr = 0;
+                    info->rco = 0;
+                    info->close_delay = 5*HZ/10;
+                   info->closing_wait = CLOSING_WAIT_DELAY;
+                    info->x_char = 0;
+                    info->event = 0;
+                    info->count = 0;
+#ifdef CY_DEBUG_COUNT
+//        printk("cyc:cy_init(1) setting Z count to 0\n");
+#endif
+                    info->blocked_open = 0;
+                    info->default_threshold = 0;
+                    info->default_timeout = 0;
+                    info->tqueue.routine = do_softint;
+                    info->tqueue.data = info;
+                    info->callout_termios =
+                               cy_callout_driver.init_termios;
+                    info->normal_termios =
+                               cy_serial_driver.init_termios;
+                    info->open_wait = 0;
+                    info->close_wait = 0;
+                    info->shutdown_wait = 0;
+                    /* info->session */
+                    /* info->pgrp */
+                    info->read_status_mask = 0;
+                    /* info->timeout */
+                   /* Bentson's vars */
+                    info->jiffies[0] = 0;
+                    info->jiffies[1] = 0;
+                    info->jiffies[2] = 0;
+                    info->rflush_count = 0;
+                }
+                continue;
+            }else{ /* Cyclom-Y of some kind*/
+                index = cinfo->bus_index;
+                for (port = cinfo->first_line ;
+                     port < cinfo->first_line + 4*cinfo->num_chips ;
+                     port++)
+                {
+                    info = &cy_port[port];
+                    info->magic = CYCLADES_MAGIC;
+                    info->type = PORT_CIRRUS;
+                    info->card = board;
+                    info->line = port;
+                    info->flags = STD_COM_FLAGS;
+                    info->tty = 0;
+                    info->xmit_fifo_size = CyMAX_CHAR_FIFO;
+                    info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
+                    info->cor2 = CyETC;
+                    info->cor3 = 0x08; /* _very_ small rcv threshold */
+                    info->cor4 = 0;
+                    info->cor5 = 0;
+                    info->close_delay = 5*HZ/10;
+                   info->closing_wait = CLOSING_WAIT_DELAY;
+                   chip_number = (port - cinfo->first_line) / 4;
+                    if ((info->chip_rev = cy_readb(cinfo->base_addr +
+                                (cy_chip_offset[chip_number]<<index) +
+                                (CyGFRCR<<index))) >= CD1400_REV_J) {
+                        /* It is a CD1400 rev. J or later */
+                        info->tbpr = baud_bpr_60[13]; /* Tx BPR */
+                        info->tco = baud_co_60[13]; /* Tx CO */
+                        info->rbpr = baud_bpr_60[13]; /* Rx BPR */
+                        info->rco = baud_co_60[13]; /* Rx CO */
+                        info->rflow = 0;
+                        info->rtsdtr_inv = 1;
+                    } else {
+                        info->tbpr = baud_bpr_25[13]; /* Tx BPR */
+                        info->tco = baud_co_25[13]; /* Tx CO */
+                        info->rbpr = baud_bpr_25[13]; /* Rx BPR */
+                        info->rco = baud_co_25[13]; /* Rx CO */
+                        info->rflow = 0;
+                        info->rtsdtr_inv = 0;
+                    }
+                    info->x_char = 0;
+                    info->event = 0;
+                    info->count = 0;
+#ifdef CY_DEBUG_COUNT
+//        printk("cyc:cy_init(2) setting Y count to 0\n");
+#endif
+                    info->blocked_open = 0;
+                    info->default_threshold = 0;
+                    info->default_timeout = 0;
+                    info->tqueue.routine = do_softint;
+                    info->tqueue.data = info;
+                    info->callout_termios =
+                              cy_callout_driver.init_termios;
+                    info->normal_termios =
+                              cy_serial_driver.init_termios;
+                    info->open_wait = 0;
+                    info->close_wait = 0;
+                    info->shutdown_wait = 0;
+                    /* info->session */
+                    /* info->pgrp */
+                    info->read_status_mask =
+                                 CyTIMEOUT| CySPECHAR| CyBREAK
+                                  | CyPARITY| CyFRAME| CyOVERRUN;
+                    /* info->timeout */
+                }
+            }
+    }
+    
+    if ( number_z_boards && !cyz_timeron){
+        cyz_timeron++;
+       cyz_timerlist.expires = jiffies + 1;
+       add_timer(&cyz_timerlist);
+#ifdef CY_PCI_DEBUG
+       printk("Cyclades-Z polling initialized\n");
+#endif
     }
+
     return 0;
     
 } /* cy_init */
 
 #ifdef MODULE
+/* See linux/drivers/char/riscom.c for ideas on how to
+   pass additional base addresses to the driver!!! */
 int
 init_module(void)
 {
    return(cy_init());
-}
+} /* init_module */
 
 void
 cleanup_module(void)
 {
     int i;
+    unsigned long flags;
+
+    if (cyz_timeron){
+       cyz_timeron = 0;
+       del_timer(&cyz_timerlist);
+    }
 
+    save_flags(flags); cli();
 
+    free_page((unsigned long)tmp_buf);
     if (tty_unregister_driver(&cy_callout_driver))
-           printk("Couldn't unregister Cyclom callout driver\n");
+            printk("Couldn't unregister Cyclades callout driver\n");
     if (tty_unregister_driver(&cy_serial_driver))
-           printk("Couldn't unregister Cyclom serial driver\n");
+            printk("Couldn't unregister Cyclades serial driver\n");
+
+    restore_flags(flags);
 
     for (i = 0; i < NR_CARDS; i++) {
-        if (cy_card[i].base_addr != 0)
-       {
-           free_irq(cy_card[i].irq,NULL);
-       }
+        if (cy_card[i].base_addr != 0
+           && cy_card[i].irq)
+        {
+            free_irq(cy_card[i].irq,NULL);
+        }
     }
-}
-#endif
-
-/*
- * ---------------------------------------------------------------------
- * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
- * sets global variables and return the number of ISA boards found.
- * ---------------------------------------------------------------------
- */
-int
-cy_detect_isa()
-{
-  unsigned int         cy_isa_irq,nboard;
-  unsigned char                *cy_isa_address;
-  unsigned short       i,j,cy_isa_nchan;
-
-       nboard = 0;
-
-       /* scan the address table probing for Cyclom-Y/ISA boards */
-       for (i = 0 ; i < NR_ISA_ADDRESSES ; i++) {
-               cy_isa_address = cy_isa_addresses[i];
-               if (cy_isa_address  == 0x0000) {
-                       return(nboard);
-               }
-
-               /* probe for CD1400... */
-               cy_isa_nchan = 4 * cy_init_card(cy_isa_address,0);
-               if (cy_isa_nchan == 0) {
-                       continue;
-               }
-
-               /* find out the board's irq by probing */
-               cy_isa_irq = do_auto_irq(cy_isa_address);
-               if (cy_isa_irq == 0) {
-                       printk("Cyclom-Y/ISA found at 0x%x but the IRQ could not be detected.\n",
-                               (unsigned int) cy_isa_address);
-                       continue;
-               }
-
-               if((cy_next_channel+cy_isa_nchan) > NR_PORTS) {
-                       printk("Cyclom-Y/ISA found at 0x%x but no more channel structures are available.\n",
-                               (unsigned int) cy_isa_address);
-                       return(nboard);
-               }
-               /* fill the next cy_card structure available */
-               for (j = 0 ; j < NR_CARDS ; j++) {
-                       if (cy_card[j].base_addr == 0)  break;
-               }
-               if (j == NR_CARDS) {    /* no more cy_cards available */
-                       printk("Cyclom-Y/ISA found at 0x%x but no more card structures are available.\n",
-                               (unsigned int) cy_isa_address);
-                       return(nboard);
-               }
-
-               /* allocate IRQ */
-               if(request_irq(cy_isa_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL))
-               {
-                       printk("Cyclom-Y/ISA found at 0x%x but could not allocate interrupt IRQ#%d.\n",
-                               (unsigned int) cy_isa_address,cy_isa_irq);
-                       return(nboard);
-               }
-
-               /* set cy_card */
-               cy_card[j].base_addr = (int) cy_isa_address;
-               cy_card[j].irq = (int) cy_isa_irq;
-               cy_card[j].bus_index = 0;
-               cy_card[j].first_line = cy_next_channel;
-               cy_card[j].num_chips = cy_isa_nchan/4;
-               IRQ_cards[cy_isa_irq] = &cy_card[j];
-               nboard++;
-                       
-               /* print message */
-               printk("Cyclom-Y/ISA #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n",
-                       j+1,(unsigned int) cy_isa_address,
-                       (unsigned int)(cy_isa_address + 0x1fff),
-                       cy_isa_irq,cy_isa_nchan,cy_next_channel);
-               cy_next_channel += cy_isa_nchan;
-       }
-       return(nboard);
-
-}
-
-/*
- * ---------------------------------------------------------------------
- * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
- * sets global variables and return the number of PCI boards found.
- * ---------------------------------------------------------------------
- */
-int
-cy_detect_pci()
+} /* cleanup_module */
+#else
+/* called by linux/init/main.c to parse command line options */
+void
+cy_setup(char *str, int *ints)
 {
-#ifdef CONFIG_PCI
-  unsigned char                cyy_bus, cyy_dev_fn, cyy_rev_id;
-  unsigned long                pci_intr_ctrl;
-  unsigned char                cy_pci_irq;
-  unsigned int         cy_pci_address, cy_pci_io;
-  unsigned short       i,j,cy_pci_nchan;
-  unsigned short       device_id,dev_index = 0,board_index = 0;
-
-       if(pcibios_present() == 0) {    /* PCI bus not present */
-               return(0);
-       }
-       for (i = 0; i < NR_CARDS; i++) {
-               /* look for a Cyclom-Y card by vendor and device id */
-               while((device_id = cy_pci_dev_id[dev_index]) != 0) {
-                       if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
-                                       device_id,board_index,
-                                       &cyy_bus, &cyy_dev_fn) != 0)
-                       {
-                               dev_index++;    /* try next device id */
-                               board_index = 0;
-                       } else {
-                               board_index++;
-                               break;          /* found a board */
-                       }
-               }
-               if (device_id == 0)     break;
-
-               /* read PCI configuration area */
-               pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
-                                PCI_INTERRUPT_LINE, &cy_pci_irq);
-               pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
-                                 PCI_BASE_ADDRESS_1, &cy_pci_io);
-               pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
-                                 PCI_BASE_ADDRESS_2, &cy_pci_address);
-               pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
-                                 PCI_REVISION_ID, &cyy_rev_id);
-               cy_pci_address &= 0xfffffff0;
-               if ((ulong)cy_pci_address >= 0x100000) { /* above 1M? */
-                       cy_pci_address =
-                           (unsigned int) vremap(cy_pci_address,0x4000);
-               }
-               cy_pci_io  &= 0xfffffffc;
-               cy_pci_nchan = 4 * cy_init_card((unsigned char *)
-                                               cy_pci_address,1);
-               if(cy_pci_nchan == 0) {
-                       printk("Cyclom-Y PCI host card with no Serial-Modules at 0x%x.\n",
-                               (unsigned int) cy_pci_address);
-                       continue;
-               }
-               if((cy_next_channel+cy_pci_nchan) > NR_PORTS) {
-                       printk("Cyclom-Y/PCI found at 0x%x but no more channel structures are available.\n",
-                               (unsigned int) cy_pci_address);
-                       return(i);
-               }
-#ifdef CY_PCI_DEBUG
-               printk("Cyclom-Ye/PCI #%d (bus=0x0%x, pci_id=0x%x, rev_id=%d).\n",
-                       i+1,cyy_bus,cyy_dev_fn,cyy_rev_id);
-               printk("Cyclom-Ye/PCI: found at 0x%x, IRQ%d, ioaddr = 0x%lx.\n",
-                       cy_pci_address,(int)cy_pci_irq,cy_pci_io);
-#endif
-               /* fill the next cy_card structure available */
-               for (j = 0 ; j < NR_CARDS ; j++) {
-                       if (cy_card[j].base_addr == 0)  break;
-               }
-               if (j == NR_CARDS) {    /* no more cy_cards available */
-                       printk("Cyclom-Y/PCI found at 0x%x but no more card structures are available.\n",
-                               (unsigned int) cy_pci_address);
-                       return(i);
-               }
+  int i, j;
 
-               /* allocate IRQ */
-               if(request_irq(cy_pci_irq,cy_interrupt,SA_INTERRUPT,"cyclades",NULL))
-               {
-                       printk("Cyclom-Y/PCI found at 0x%x but could not allocate interrupt IRQ%d.\n",
-                               (unsigned int) cy_pci_address,cy_pci_irq);
-                       return(i);
-               }
+    for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
+        if (cy_isa_addresses[i] == 0) break;
+    }
+    for (j = 1; j <= ints[0]; j++){
+        if ( i < NR_ISA_ADDRS ){
+            cy_isa_addresses[i++] = (unsigned char *)(ints[j]);
+        }
+    }
 
-               /* set cy_card */
-               cy_card[j].base_addr = (int) cy_pci_address;
-               cy_card[j].irq = (int) cy_pci_irq;
-               cy_card[j].bus_index = 1;
-               cy_card[j].first_line = cy_next_channel;
-               cy_card[j].num_chips = cy_pci_nchan/4;
-               IRQ_cards[cy_pci_irq] = &cy_card[j];
-
-               /* enable interrupts in the PCI interface */
-               outw(inw(cy_pci_io+0x68)|0x0900,cy_pci_io+0x68);
-               pci_intr_ctrl = (unsigned long)(inw(cy_pci_io+0x68) | inw(cy_pci_io+0x6a)<<16);
-
-               /* print message */
-               printk("Cyclom-Y/PCI #%d: 0x%x-0x%x, IRQ%d, %d channels starting from port %d.\n",
-                       j+1,(unsigned int) cy_pci_address,
-                       (unsigned int)(cy_pci_address + 0x3fff),
-                       (int)cy_pci_irq,cy_pci_nchan,cy_next_channel);
-
-               cy_next_channel += cy_pci_nchan;
-       }
-       return(i);
-#else
-       return(0);
-#endif /* ifdef CONFIG_PCI */
-}
+} /* cy_setup */
+#endif
 
 
-#ifdef CYCLOM_SHOW_STATUS
+#ifdef CY_SHOW_STATUS
 static void
 show_status(int line_num)
 {
@@ -3183,7 +5386,8 @@ show_status(int line_num)
     printk(" cy_port\n");
     printk("  card line flags = %d %d %x\n",
                  info->card, info->line, info->flags);
-    printk("  *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
+    printk("  *tty read_status_mask timeout xmit_fifo_size ",
+    printk("= %lx %x %x %x\n",
                  (long)info->tty, info->read_status_mask,
                  info->timeout, info->xmit_fifo_size);
     printk("  cor1,cor2,cor3,cor4,cor5 = %x %x %x %x %x\n",
@@ -3200,59 +5404,60 @@ show_status(int line_num)
 
     save_flags(flags); cli();
 
-       base_addr = (unsigned char*)
-                      (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+        base_addr = (unsigned char*)
+                       (cy_card[card].base_addr
+                      + (cy_chip_offset[chip]<<index));
 
 /* Global Registers */
 
-       printk(" CyGFRCR %x\n", base_addr[CyGFRCR<<index]);
-       printk(" CyCAR %x\n", base_addr[CyCAR<<index]);
-       printk(" CyGCR %x\n", base_addr[CyGCR<<index]);
-       printk(" CySVRR %x\n", base_addr[CySVRR<<index]);
-       printk(" CyRICR %x\n", base_addr[CyRICR<<index]);
-       printk(" CyTICR %x\n", base_addr[CyTICR<<index]);
-       printk(" CyMICR %x\n", base_addr[CyMICR<<index]);
-       printk(" CyRIR %x\n", base_addr[CyRIR<<index]);
-       printk(" CyTIR %x\n", base_addr[CyTIR<<index]);
-       printk(" CyMIR %x\n", base_addr[CyMIR<<index]);
-       printk(" CyPPR %x\n", base_addr[CyPPR<<index]);
+        printk(" CyGFRCR %x\n", cy_readb(base_addr + CyGFRCR<<index));
+        printk(" CyCAR %x\n", cy_readb(base_addr + CyCAR<<index));
+        printk(" CyGCR %x\n", cy_readb(base_addr + CyGCR<<index));
+        printk(" CySVRR %x\n", cy_readb(base_addr + CySVRR<<index));
+        printk(" CyRICR %x\n", cy_readb(base_addr + CyRICR<<index));
+        printk(" CyTICR %x\n", cy_readb(base_addr + CyTICR<<index));
+        printk(" CyMICR %x\n", cy_readb(base_addr + CyMICR<<index));
+        printk(" CyRIR %x\n", cy_readb(base_addr + CyRIR<<index));
+        printk(" CyTIR %x\n", cy_readb(base_addr + CyTIR<<index));
+        printk(" CyMIR %x\n", cy_readb(base_addr + CyMIR<<index));
+        printk(" CyPPR %x\n", cy_readb(base_addr + CyPPR<<index));
 
-       base_addr[CyCAR<<index] = (u_char)channel;
+        cy_writeb(base_addr + CyCAR<<index, (u_char)channel);
 
 /* Virtual Registers */
 
-       printk(" CyRIVR %x\n", base_addr[CyRIVR<<index]);
-       printk(" CyTIVR %x\n", base_addr[CyTIVR<<index]);
-       printk(" CyMIVR %x\n", base_addr[CyMIVR<<index]);
-       printk(" CyMISR %x\n", base_addr[CyMISR<<index]);
+        printk(" CyRIVR %x\n", cy_readb(base_addr + CyRIVR<<index));
+        printk(" CyTIVR %x\n", cy_readb(base_addr + CyTIVR<<index));
+        printk(" CyMIVR %x\n", cy_readb(base_addr + CyMIVR<<index));
+        printk(" CyMISR %x\n", cy_readb(base_addr + CyMISR<<index));
 
 /* Channel Registers */
 
-       printk(" CyCCR %x\n", base_addr[CyCCR<<index]);
-       printk(" CySRER %x\n", base_addr[CySRER<<index]);
-       printk(" CyCOR1 %x\n", base_addr[CyCOR1<<index]);
-       printk(" CyCOR2 %x\n", base_addr[CyCOR2<<index]);
-       printk(" CyCOR3 %x\n", base_addr[CyCOR3<<index]);
-       printk(" CyCOR4 %x\n", base_addr[CyCOR4<<index]);
-       printk(" CyCOR5 %x\n", base_addr[CyCOR5<<index]);
-       printk(" CyCCSR %x\n", base_addr[CyCCSR<<index]);
-       printk(" CyRDCR %x\n", base_addr[CyRDCR<<index]);
-       printk(" CySCHR1 %x\n", base_addr[CySCHR1<<index]);
-       printk(" CySCHR2 %x\n", base_addr[CySCHR2<<index]);
-       printk(" CySCHR3 %x\n", base_addr[CySCHR3<<index]);
-       printk(" CySCHR4 %x\n", base_addr[CySCHR4<<index]);
-       printk(" CySCRL %x\n", base_addr[CySCRL<<index]);
-       printk(" CySCRH %x\n", base_addr[CySCRH<<index]);
-       printk(" CyLNC %x\n", base_addr[CyLNC<<index]);
-       printk(" CyMCOR1 %x\n", base_addr[CyMCOR1<<index]);
-       printk(" CyMCOR2 %x\n", base_addr[CyMCOR2<<index]);
-       printk(" CyRTPR %x\n", base_addr[CyRTPR<<index]);
-       printk(" CyMSVR1 %x\n", base_addr[CyMSVR1<<index]);
-       printk(" CyMSVR2 %x\n", base_addr[CyMSVR2<<index]);
-       printk(" CyRBPR %x\n", base_addr[CyRBPR<<index]);
-       printk(" CyRCOR %x\n", base_addr[CyRCOR<<index]);
-       printk(" CyTBPR %x\n", base_addr[CyTBPR<<index]);
-       printk(" CyTCOR %x\n", base_addr[CyTCOR<<index]);
+        printk(" CyCCR %x\n", cy_readb(base_addr + CyCCR<<index));
+        printk(" CySRER %x\n", cy_readb(base_addr + CySRER<<index));
+        printk(" CyCOR1 %x\n", cy_readb(base_addr + CyCOR1<<index));
+        printk(" CyCOR2 %x\n", cy_readb(base_addr + CyCOR2<<index));
+        printk(" CyCOR3 %x\n", cy_readb(base_addr + CyCOR3<<index));
+        printk(" CyCOR4 %x\n", cy_readb(base_addr + CyCOR4<<index));
+        printk(" CyCOR5 %x\n", cy_readb(base_addr + CyCOR5<<index));
+        printk(" CyCCSR %x\n", cy_readb(base_addr + CyCCSR<<index));
+        printk(" CyRDCR %x\n", cy_readb(base_addr + CyRDCR<<index));
+        printk(" CySCHR1 %x\n", cy_readb(base_addr + CySCHR1<<index));
+        printk(" CySCHR2 %x\n", cy_readb(base_addr + CySCHR2<<index));
+        printk(" CySCHR3 %x\n", cy_readb(base_addr + CySCHR3<<index));
+        printk(" CySCHR4 %x\n", cy_readb(base_addr + CySCHR4<<index));
+        printk(" CySCRL %x\n", cy_readb(base_addr + CySCRL<<index));
+        printk(" CySCRH %x\n", cy_readb(base_addr + CySCRH<<index));
+        printk(" CyLNC %x\n", cy_readb(base_addr + CyLNC<<index));
+        printk(" CyMCOR1 %x\n", cy_readb(base_addr + CyMCOR1<<index));
+        printk(" CyMCOR2 %x\n", cy_readb(base_addr + CyMCOR2<<index));
+        printk(" CyRTPR %x\n", cy_readb(base_addr + CyRTPR<<index));
+        printk(" CyMSVR1 %x\n", cy_readb(base_addr + CyMSVR1<<index));
+        printk(" CyMSVR2 %x\n", cy_readb(base_addr + CyMSVR2<<index));
+        printk(" CyRBPR %x\n", cy_readb(base_addr + CyRBPR<<index));
+        printk(" CyRCOR %x\n", cy_readb(base_addr + CyRCOR<<index));
+        printk(" CyTBPR %x\n", cy_readb(base_addr + CyTBPR<<index));
+        printk(" CyTCOR %x\n", cy_readb(base_addr + CyTCOR<<index));
 
     restore_flags(flags);
 } /* show_status */
index 2213ac6dc7d5cebe43cff3a2e178319353049b96..f7928f15030cf90ab70c063f440020575f12695a 100644 (file)
@@ -7,20 +7,40 @@ if [ "$CONFIG_INET" != "n" ]; then
     bool 'Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
     bool 'Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
   fi
+ # bool 'Support dynamic timeout-rules' CONFIG_ISDN_TIMEOUT_RULES
+ # if [ "$CONFIG_ISDN_TIMEOUT_RULES" != "n" ]; then
+ #   bool 'Use masqueraded addresses for rule-matching' CONFIG_ISDN_TIMRU_USE_MASQ
+ # fi
+ # bool 'Support budget-accounting' CONFIG_ISDN_BUDGET
 fi
 bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
 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 chargeinfo' 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 Teles PCI' CONFIG_HISAX_TELESPCI 
+    bool 'HiSax Support for Teles S0Box' CONFIG_HISAX_S0BOX 
     bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
-    bool 'HiSax Support for 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 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
 fi
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
        dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
index 84723ea1704ea22b2dd75170d34e562b63eb3294..d40addb0584dfb82285401caedcf26f1829578cb 100644 (file)
@@ -1,11 +1,71 @@
 /*
- * $Id: b1capi.c,v 1.4.2.1 1997/07/12 08:18:59 calle Exp $
+ * $Id: b1capi.c,v 1.4.2.18 1998/03/20 20:34:37 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.4.2.18  1998/03/20 20:34:37  calle
+ * port valid check now only for T1, because of the PCI and PCMCIA cards.
+ *
+ * Revision 1.4.2.17  1998/03/20 14:38:17  calle
+ * capidrv: prepared state machines for suspend/resume/hold
+ * capidrv: fix bug in state machine if B1/T1 is out of nccis
+ * b1capi: changed some errno returns.
+ * b1capi: detect if you try to add same T1 to different io address.
+ * b1capi: change number of nccis depending on number of channels.
+ * b1lli: cosmetics
+ *
+ * Revision 1.4.2.16  1998/03/20 09:01:08  calle
+ * Changes capi_register handling to get full support for 30 bchannels.
+ *
+ * Revision 1.4.2.15  1998/03/18 17:43:26  calle
+ * T1 with fastlink, bugfix for multicontroller support in capidrv.c
+ *
+ * Revision 1.4.2.14  1998/03/04 17:33:47  calle
+ * Changes for T1.
+ *
+ * Revision 1.4.2.13  1998/02/27 15:40:41  calle
+ * T1 running with slow link. bugfix in capi_release.
+ *
+ * Revision 1.4.2.12  1998/02/24 17:58:25  calle
+ * changes for T1.
+ *
+ * Revision 1.4.2.11  1998/01/27 16:12:49  calle
+ * Support for PCMCIA B1/M1/M2 ready.
+ *
+ * Revision 1.4.2.10  1998/01/26 14:53:30  calle
+ * interface change for pcmcia cards
+ *
+ * Revision 1.4.2.9  1998/01/23 16:49:27  calle
+ * added functions for pcmcia cards,
+ * avmb1_addcard returns now the controller number.
+ *
+ * Revision 1.4.2.8  1998/01/16 14:04:15  calle
+ * Decoding of manufacturer part of capi_profile, now show linetype and
+ * protocol if possible.
+ *
+ * Revision 1.4.2.7  1998/01/15 15:33:34  calle
+ * print cardtype, d2 protocol and linetype after load.
+ *
+ * Revision 1.4.2.6  1997/12/08 06:58:41  calle
+ * correct typo.
+ *
+ * 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.4.2.3  1997/11/26 10:46:52  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.4.2.2  1997/10/19 14:44:36  calle
+ * fixed capi_get_version.
+ *
  * Revision 1.4.2.1  1997/07/12 08:18:59  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.
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.4.2.1 $";
+static char *revision = "$Revision: 1.4.2.18 $";
 
 /* ------------------------------------------------------------- */
 
-int portbase = 0x150;
-int irq = 15;
 int showcapimsgs = 0;          /* used in lli.c */
 int loaddebug = 0;
 
 #ifdef HAS_NEW_SYMTAB
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-MODULE_PARM(portbase, "i");
-MODULE_PARM(irq, "2-15i");
-MODULE_PARM(showcapimsgs, "0-3i");
+MODULE_PARM(showcapimsgs, "0-5i");
 MODULE_PARM(loaddebug, "0-1i");
 #endif
 
@@ -99,7 +155,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";
 
@@ -111,7 +167,7 @@ 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)        (((cp)-cards)+1)
 
@@ -128,6 +184,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) {
@@ -271,7 +338,7 @@ void avmb1_handle_free_ncci(avmb1_card * card,
                        }
                }
                APPL(appl)->releasing--;
-               if (APPL(appl)->releasing == 0) {
+               if (APPL(appl)->releasing <= 0) {
                        APPL(appl)->signal = 0;
                        APPL_MARK_FREE(appl);
                        printk(KERN_INFO "b1capi: appl %d down\n", appl);
@@ -404,25 +471,36 @@ static void notify_handler(void *dummy)
 
 /* -------- card ready callback ------------------------------- */
 
+
 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;
+        int nbchan = profp->nbchannel;
 
        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) {
+                       int nconn, want = APPL(appl)->rparam.level3cnt;
+
+                       if (want > 0) nconn = want;
+                       else nconn = nbchan * -want;
+                       if (nconn == 0) nconn = nbchan;
+
                        B1_send_register(card->port, appl,
-                               1024 * (APPL(appl)->rparam.level3cnt+1),
-                               APPL(appl)->rparam.level3cnt,
+                               1024 * (nconn+1), nconn,
                                APPL(appl)->rparam.datablkcnt,
                                APPL(appl)->rparam.datablklen);
                }
@@ -430,10 +508,45 @@ void avmb1_card_ready(avmb1_card * card)
 
         set_bit(CARDNR(card), &notify_up_set);
         queue_task(&tq_state_notify, &tq_scheduler);
-        printk(KERN_NOTICE "b1capi: card %d ready.\n", CARDNR(card));
+
+        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)
+static void avmb1_card_down(avmb1_card * card, int notify)
 {
        __u16 appl;
 
@@ -460,52 +573,135 @@ static void avmb1_card_down(avmb1_card * 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;
 
 
-       card = &cards[ncards];
+       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[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;
+               return -EBUSY;
        }
+
+       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_probecard(int port, int irq)
+int avmb1_addcard(int port, int irq, int cardtype)
+{
+       return avmb1_registercard(port, irq, cardtype, 1);
+}
+
+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);
-               return -EIO;
+       if (!B1_valid_irq(irq, cardtype)) {
+               printk(KERN_WARNING "b1capi: irq %d not valid for %s-card.\n",
+                               irq, cardtype2str(cardtype));
+               return -EINVAL;
        }
-       if (!B1_valid_irq(irq)) {
-               printk(KERN_WARNING "b1capi: irq %d not valid.\n", irq);
-               return -EIO;
+       if (!B1_valid_port(port, cardtype)) {
+               printk(KERN_WARNING "b1capi: port 0x%x not valid for %s-card.\n",
+                               port, cardtype2str(cardtype));
+               return -EINVAL;
        }
-       if ((rc = B1_detect(port)) != 0) {
-               printk(KERN_NOTICE "b1capi: NO card at 0x%x (%d)\n", port, rc);
+       B1_reset(port);
+       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;
        }
        B1_reset(port);
-       printk(KERN_NOTICE "b1capi: AVM-B1-Controller detected at 0x%x\n", 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:
+                       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 -EBUSY;
+       }
+        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);
+
+       if (card->cardstate != CARD_FREE)
+               if (card->cardtype == AVM_CARDTYPE_T1)
+                       T1_reset(card->port);
+
+       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;
 }
@@ -517,7 +713,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;
        }
@@ -526,6 +722,7 @@ static int capi_installed(void)
 
 static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
 {
+       int nconn, want = rparam->level3cnt;
        int i;
        int appl;
 
@@ -544,14 +741,21 @@ 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++) {
+               struct capi_profile *profp =
+                       (struct capi_profile *)cards[i].version[VER_PROFILE];
+
                if (cards[i].cardstate != CARD_RUNNING)
                        continue;
+
+               if (want > 0) nconn = want;
+               else nconn = profp->nbchannel * -want;
+               if (nconn == 0) nconn = profp->nbchannel;
+
                B1_send_register(cards[i].port, appl,
-                              1024 * (APPL(appl)->rparam.level3cnt + 1),
-                                APPL(appl)->rparam.level3cnt,
-                                APPL(appl)->rparam.datablkcnt,
-                                APPL(appl)->rparam.datablklen);
+                       1024 * (nconn+1), nconn,
+                       APPL(appl)->rparam.datablkcnt,
+                       APPL(appl)->rparam.datablklen);
        }
        *applidp = appl;
        printk(KERN_INFO "b1capi: appl %d up\n", appl);
@@ -564,20 +768,18 @@ static __u16 capi_release(__u16 applid)
        struct sk_buff *skb;
        int i;
 
-       if (ncards == 0)
-               return CAPI_REGNOTINSTALLED;
        if (!VALID_APPLID(applid) || APPL(applid)->releasing)
                return CAPI_ILLAPPNR;
        while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
                kfree_skb(skb, FREE_READ);
-       for (i = 0; i < ncards; i++) {
+       for (i = 0; i < CAPI_MAXCONTR; i++) {
                if (cards[i].cardstate != CARD_RUNNING) {
                        continue;
                }
                APPL(applid)->releasing++;
                B1_send_release(cards[i].port, applid);
        }
-       if (APPL(applid)->releasing == 0) {
+       if (APPL(applid)->releasing <= 0) {
                APPL(applid)->signal = 0;
                APPL_MARK_FREE(applid);
                printk(KERN_INFO "b1capi: appl %d down\n", applid);
@@ -661,7 +863,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;
 }
@@ -698,33 +900,87 @@ 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);
+                if (cdef.cardtype == AVM_CARDTYPE_T1) {
+                       int i;
+                       for (i=0; i < CAPI_MAXCONTR; i++) {
+                               if (   cards[i].cardstate != CARD_FREE
+                                   && cards[i].cardtype == AVM_CARDTYPE_T1
+                                   && cards[i].cardnr == cdef.cardnr) {
+                                       printk(KERN_ERR
+                                               "b1capi: T1-HEMA-card-%d already at 0x%x\n",
+                                               cdef.cardnr, cards[i].port);
+                                       return -EBUSY;
+                               }
+                        }
+                       rc = T1_detectandinit(cdef.port,cdef.irq,cdef.cardnr);
+                       if (rc) {
+                               printk(KERN_NOTICE "b1capi: NO T1-HEMA-card-%d at 0x%x (%d)\n",
+                                         cdef.cardnr, cdef.port, rc);
+                               return -EIO;
+                        }
+                       printk(KERN_NOTICE "b1capi: T1-HEMA-card-%d at 0x%x\n",
+                                 cdef.cardnr, cdef.port);
+               }
+
+               rc = avmb1_addcard(cdef.port, cdef.irq, cdef.cardtype);
+               if (rc < 0)
+                       return rc;
+               /* don't want to change interface t
+                  addcard/probecard/registercard */
+                if (cdef.cardtype == AVM_CARDTYPE_T1) {
+                       int i;
+                       for (i=0; i < CAPI_MAXCONTR; i++) {
+                               if (cards[i].cnr == rc) {
+                                       cards[i].cardnr = cdef.cardnr;
+                                       break;
+                               }
+                        }
+               }
+               return rc;
 
        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 (loaddebug)
-                               printk(KERN_DEBUG "b1capi: load: invalid parameter contr=%d len=%d\n", ldef.contr, ldef.t4file.len);
+               if (ldef.t4file.len <= 0) {
+                       printk(KERN_DEBUG "b1capi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
                        return -EINVAL;
                }
 
@@ -746,13 +1002,34 @@ static int capi_manufacturer(unsigned int cmd, void *data)
                }
 
                B1_reset(card->port);
+
+               if (loaddebug) {
+                       printk(KERN_DEBUG "b1capi: loading contr %d\n",
+                               ldef.contr);
+               }
+
                if ((rc = B1_load_t4file(card->port, &ldef.t4file))) {
                        B1_reset(card->port);
                        printk(KERN_ERR "b1capi: failed to load t4file!!\n");
                        card->cardstate = CARD_DETECTED;
                        return rc;
                }
+
                B1_disable_irq(card->port);
+
+               if (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);
@@ -770,8 +1047,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_enable_irq(card->port);
+               B1_setinterrupt(card->port, card->irq, card->cardtype);
                restore_flags(flags);
 
                if (loaddebug) {
@@ -782,7 +1058,14 @@ static int capi_manufacturer(unsigned int cmd, void *data)
                /*
                 * init card
                 */
-               B1_send_init(card->port, AVM_NAPPS, AVM_NNCCI, card->cnr - 1);
+                if (card->cardtype == AVM_CARDTYPE_T1)
+                  B1_send_init(card->port, AVM_NAPPS,
+                                           AVM_NNCCI_PER_CHANNEL*30,
+                                           card->cnr - 1);
+               else
+                  B1_send_init(card->port, AVM_NAPPS,
+                                           AVM_NNCCI_PER_CHANNEL*2,
+                                           card->cnr - 1);
 
                if (loaddebug) {
                        printk(KERN_DEBUG "b1capi: load: waiting for init reply contr %d\n",
@@ -799,25 +1082,45 @@ 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);
 
-               card = CARD(rdef.contr);
+       case AVMB1_GET_CARDINFO:
+               if ((rc = copy_from_user((void *) &gdef, data,
+                                        sizeof(avmb1_getdef))))
+                       return rc;
 
-               if (card->cardstate == CARD_RUNNING)
-                       avmb1_card_down(card);
+               if (!VALID_CARD(gdef.contr))
+                       return -ESRCH;
 
-               card->cardstate = CARD_DETECTED;
+               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;
 
                return 0;
+       case AVMB1_REMOVECARD:
+               if ((rc = copy_from_user((void *) &rdef, data,
+                                        sizeof(avmb1_resetdef))))
+                       return rc;
+               if (!VALID_CARD(rdef.contr))
+                       return -ESRCH;
+
+               card = CARD(rdef.contr);
+
+               if (card->cardstate != CARD_DETECTED)
+                       return -EBUSY;
+
+               return avmb1_unregistercard(rdef.contr, 1);
        }
        return -EINVAL;
 }
@@ -855,6 +1158,7 @@ struct capi_interface *attach_capi_interface(struct capi_interface_user *userp)
        userp->next = capi_users;
        capi_users = userp;
        MOD_INC_USE_COUNT;
+       printk(KERN_NOTICE "b1capi: %s attached\n", userp->name);
 
        return &avmb1_interface;
 }
@@ -868,6 +1172,7 @@ int detach_capi_interface(struct capi_interface_user *userp)
                        *pp = userp->next;
                        userp->next = 0;
                        MOD_DEC_USE_COUNT;
+                       printk(KERN_NOTICE "b1capi: %s detached\n", userp->name);
                        return 0;
                }
        }
@@ -884,6 +1189,10 @@ EXPORT_SYMBOL(attach_capi_interface);
 EXPORT_SYMBOL(detach_capi_interface);
 EXPORT_SYMBOL(avmb1_addcard);
 EXPORT_SYMBOL(avmb1_probecard);
+EXPORT_SYMBOL(avmb1_registercard);
+EXPORT_SYMBOL(avmb1_unregistercard);
+EXPORT_SYMBOL(avmb1_resetcard);
+EXPORT_SYMBOL(avmb1_detectcard);
 #else
 static struct symbol_table capidev_syms =
 {
@@ -892,6 +1201,10 @@ static struct symbol_table capidev_syms =
        X(detach_capi_interface),
        X(avmb1_addcard),
        X(avmb1_probecard),
+       X(avmb1_registercard),
+       X(avmb1_unregistercard),
+       X(avmb1_resetcard),
+       X(avmb1_detectcard),
 #include <linux/symtab_end.h>
 };
 #endif
@@ -933,15 +1246,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
@@ -963,20 +1268,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 7028b5d399774ebd188595f0d094a938efe5ebe4..ae09ed9e0d54bf34a30152aff4df8885db00138f 100644 (file)
@@ -1,11 +1,45 @@
 /*
- * $Id: b1lli.c,v 1.1.2.1 1997/07/13 12:16:46 calle Exp $
+ * $Id: b1lli.c,v 1.1.2.10 1998/03/20 20:34:41 calle Exp $
  * 
  * ISDN lowlevel-module for AVM B1-card.
  * 
  * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1lli.c,v $
+ * Revision 1.1.2.10  1998/03/20 20:34:41  calle
+ * port valid check now only for T1, because of the PCI and PCMCIA cards.
+ *
+ * Revision 1.1.2.9  1998/03/20 14:38:20  calle
+ * capidrv: prepared state machines for suspend/resume/hold
+ * capidrv: fix bug in state machine if B1/T1 is out of nccis
+ * b1capi: changed some errno returns.
+ * b1capi: detect if you try to add same T1 to different io address.
+ * b1capi: change number of nccis depending on number of channels.
+ * b1lli: cosmetics
+ *
+ * Revision 1.1.2.8  1998/03/18 17:43:29  calle
+ * T1 with fastlink, bugfix for multicontroller support in capidrv.c
+ *
+ * Revision 1.1.2.7  1998/03/04 17:33:50  calle
+ * Changes for T1.
+ *
+ * Revision 1.1.2.6  1998/02/27 15:40:44  calle
+ * T1 running with slow link. bugfix in capi_release.
+ *
+ * Revision 1.1.2.5  1998/02/13 16:28:28  calle
+ * first step for T1
+ *
+ * Revision 1.1.2.4  1998/01/27 16:12:51  calle
+ * Support for PCMCIA B1/M1/M2 ready.
+ *
+ * Revision 1.1.2.3  1998/01/15 15:33:37  calle
+ * print cardtype, d2 protocol and linetype after load.
+ *
+ * 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.1.2.1  1997/07/13 12:16:46  calle
  * bug fix for more than one controller in connect_req.
  *
@@ -20,6 +54,7 @@
  *
  * 
  */
+/* #define FASTLINK_DEBUG */
 
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
@@ -34,6 +69,8 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
+extern int showcapimsgs;
+
 /*
  * LLI Messages to the ISDN-ControllerISDN Controller 
  */
                                           * B3Length data .... 
                                         */
 
+#define SEND_CONFIG            0x21    /*
+                                         */
+
+#define SEND_POLLACK           0x73    /* T1 Watchdog */
+
 /*
  * LLI Messages from the ISDN-ControllerISDN Controller 
  */
 #define RECEIVE_RELEASE                0x26    /*
                                           * int32 AppllID int32 0xffffffff 
                                         */
+#define RECEIVE_TASK_READY     0x31    /*
+                                          * int32 tasknr
+                                          * int32 Length Taskname ...
+                                        */
+
+#define WRITE_REGISTER         0x00
+#define READ_REGISTER          0x01
 
 /*
  * port offsets
 #define B1_RESET               0x10
 #define B1_ANALYSE             0x04
 
+/* Hema card T1 */
+
+#define T1_FASTLINK            0x00
+#define T1_SLOWLINK            0x08
+
+#define T1_READ                        B1_READ
+#define T1_WRITE               B1_WRITE
+#define T1_INSTAT              B1_INSTAT
+#define T1_OUTSTAT             B1_OUTSTAT
+#define T1_IRQENABLE           0x05
+#define T1_FIFOSTAT            0x06
+#define T1_RESETLINK           0x10
+#define T1_ANALYSE             0x11
+#define T1_IRQMASTER           0x12
+#define T1_IDENT               0x17
+#define T1_RESETBOARD          0x1f
+
+#define        T1F_IREADY              0x01
+#define        T1F_IHALF               0x02
+#define        T1F_IFULL               0x04
+#define        T1F_IEMPTY              0x08
+#define        T1F_IFLAGS              0xF0
+
+#define        T1F_OREADY              0x10
+#define        T1F_OHALF               0x20
+#define        T1F_OEMPTY              0x40
+#define        T1F_OFULL               0x80
+#define        T1F_OFLAGS              0xF0
+
+/* there are HEMA cards with 1k and 4k FIFO out */
+#define FIFO_OUTBSIZE          256
+#define FIFO_INPBSIZE          512
+
+#define HEMA_VERSION_ID                0
+#define HEMA_PAL_ID            0
+
+#define B1_STAT0(cardtype)  ((cardtype) == AVM_CARDTYPE_M1 ? 0x81200000l : 0x80A00000l)
+#define B1_STAT1(cardtype)  (0x80E00000l)
 
 
 static inline unsigned char b1outp(unsigned short base,
@@ -134,6 +221,191 @@ static inline unsigned char b1outp(unsigned short base,
        return inb(base + B1_ANALYSE);
 }
 
+static inline void t1outp(unsigned short base,
+                         unsigned short offset,
+                         unsigned char value)
+{
+       outb(value, base + offset);
+}
+
+static inline unsigned char t1inp(unsigned short base,
+                                 unsigned short offset)
+{
+       return inb(base + offset);
+}
+
+static inline int B1_isfastlink(unsigned short base)
+{
+       return (inb(base + T1_IDENT) & ~0x82) == 1;
+}
+static inline unsigned char B1_fifostatus(unsigned short base)
+{
+       return inb(base + T1_FIFOSTAT);
+}
+
+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 + 1 * HZ;     /* maximum wait time 1 sec */
+       while (!B1_rx_full(base) && i > jiffies);
+       if (B1_rx_full(base))
+               return inb(base + B1_READ);
+       printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base);
+       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;
+#ifdef FASTLINK_DEBUG
+       unsigned wcnt = 0, bcnt = 0;
+#endif
+
+       len = i = B1_get_word(base);
+        if (B1_isfastlink(base)) {
+               int status;
+               while (i > 0) {
+                       status = B1_fifostatus(base) & (T1F_IREADY|T1F_IHALF);
+                       if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
+
+                       switch (status) {
+                               case T1F_IREADY|T1F_IHALF|T1F_IFULL:
+                                       insb(base+B1_READ, dp, FIFO_INPBSIZE);
+                                       dp += FIFO_INPBSIZE;
+                                       i -= FIFO_INPBSIZE;
+#ifdef FASTLINK_DEBUG
+                                       wcnt += FIFO_INPBSIZE;
+#endif
+                                       break;
+                               case T1F_IREADY|T1F_IHALF: 
+                                       insb(base+B1_READ,dp, i);
+#ifdef FASTLINK_DEBUG
+                                       wcnt += i;
+#endif
+                                       dp += i;
+                                       i = 0;
+                                       if (i == 0)
+                                               break;
+                                       /* fall through */
+                               default:
+                                       *dp++ = B1_get_byte(base);
+                                       i--;
+#ifdef FASTLINK_DEBUG
+                                       bcnt++;
+#endif
+                                       break;
+                       }
+           }
+#ifdef FASTLINK_DEBUG
+           if (wcnt)
+           printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n",
+                               base, len, wcnt, bcnt);
+#endif
+       } else {
+               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)
+{
+       unsigned i = len;
+       B1_put_word(base, i);
+        if (B1_isfastlink(base)) {
+               int status;
+               while (i > 0) {
+                       status = B1_fifostatus(base) & (T1F_OREADY|T1F_OHALF);
+                       if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY;
+                       switch (status) {
+                               case T1F_OREADY|T1F_OHALF|T1F_OEMPTY: 
+                                       outsb(base+B1_WRITE, dp, FIFO_OUTBSIZE);
+                                       dp += FIFO_OUTBSIZE;
+                                       i -= FIFO_OUTBSIZE;
+                                       break;
+                               case T1F_OREADY|T1F_OHALF: 
+                                       outsb(base+B1_WRITE, dp, i);
+                                       dp += i;
+                                       i = 0;
+                                       break;
+                               default:
+                                       B1_put_byte(base, *dp++);
+                                       i--;
+                                       break;
+                       }
+               }
+       } else {
+               while (i-- > 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,
@@ -153,19 +425,79 @@ static int irq_table[16] =
  112,                          /* irq 15 */
 };
 
-int B1_valid_irq(unsigned irq)
+static int hema_irq_table[16] =
+{0,
+ 0,
+ 0,
+ 0x80,                         /* irq 3 */
+ 0,
+ 0x90,                         /* irq 5 */
+ 0,
+ 0xA0,                         /* irq 7 */
+ 0,
+ 0xB0,                         /* irq 9 */
+ 0xC0,                         /* irq 10 */
+ 0xD0,                         /* irq 11 */
+ 0xE0,                         /* irq 12 */
+ 0,
+ 0,
+ 0xF0,                         /* irq 15 */
+};
+
+
+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 & 0xf] != 0;
+          case AVM_CARDTYPE_T1:
+               return hema_irq_table[irq & 0xf] != 0;
+       }
 }
 
-unsigned char B1_assign_irq(unsigned short base, unsigned irq)
+int B1_valid_port(unsigned port, int cardtype)
 {
-       return b1outp(base, B1_RESET, irq_table[irq]);
+   switch (cardtype) {
+          default:
+          case AVM_CARDTYPE_M1:
+          case AVM_CARDTYPE_M2:
+          case AVM_CARDTYPE_B1:
+#if 0  /* problem with PCMCIA and PCI cards */
+               switch (port) {
+                       case 0x150:
+                       case 0x250:
+                       case 0x300:
+                       case 0x340:
+                               return 1;
+               }
+               return 0;
+#else
+               return 1;
+#endif
+          case AVM_CARDTYPE_T1:
+               return ((port & 0x7) == 0) && ((port & 0x30) != 0x30);
+   }
 }
 
-unsigned char B1_enable_irq(unsigned short base)
+void B1_setinterrupt(unsigned short base,
+                                unsigned irq, int cardtype)
 {
-       return b1outp(base, B1_INSTAT, 0x02);
+       switch (cardtype) {
+          case AVM_CARDTYPE_T1:
+              t1outp(base, B1_INSTAT, 0x00);
+              t1outp(base, B1_INSTAT, 0x02);
+             t1outp(base, T1_IRQMASTER, 0x08);
+          default:
+          case AVM_CARDTYPE_M1:
+          case AVM_CARDTYPE_M2:
+          case AVM_CARDTYPE_B1:
+             b1outp(base, B1_INSTAT, 0x00);
+             b1outp(base, B1_RESET, irq_table[irq]);
+             b1outp(base, B1_INSTAT, 0x02);
+        }
 }
 
 unsigned char B1_disable_irq(unsigned short base)
@@ -173,6 +505,11 @@ unsigned char B1_disable_irq(unsigned short base)
        return b1outp(base, B1_INSTAT, 0x00);
 }
 
+void T1_disable_irq(unsigned short base)
+{
+      t1outp(base, T1_IRQMASTER, 0x00);
+}
+
 void B1_reset(unsigned short base)
 {
        b1outp(base, B1_RESET, 0);
@@ -185,24 +522,39 @@ void B1_reset(unsigned short base)
        udelay(55 * 2 * 1000);  /* 2 TIC's */
 }
 
-int B1_detect(unsigned short base)
+void T1_reset(unsigned short base)
+{
+        /* reset T1 Controller */
+        B1_reset(base);
+        /* disable irq on HEMA */
+        t1outp(base, B1_INSTAT, 0x00);
+        t1outp(base, B1_OUTSTAT, 0x00);
+        t1outp(base, T1_IRQMASTER, 0x00);
+        /* reset HEMA board configuration */
+       t1outp(base, T1_RESETBOARD, 0xf);
+}
+
+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 
         */
@@ -211,71 +563,91 @@ 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)
+int T1_detectandinit(unsigned short base, unsigned irq, int cardnr)
 {
-       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);
-}
+       unsigned char cregs[8];
+       unsigned char reverse_cardnr;
+       unsigned long flags;
+       unsigned char dummy;
+       int i;
 
-static inline unsigned int B1_get_slice(unsigned short base,
-                                       unsigned char *dp)
-{
-       unsigned int len, i;
+       reverse_cardnr =   ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1)
+                        | ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3);
+       cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf);
+       cregs[1] = 0x00; /* fast & slow link connected to CON1 */
+       cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */
+       cregs[3] = 0;
+       cregs[4] = 0x11; /* zero wait state */
+       cregs[5] = hema_irq_table[irq & 0xf];
+       cregs[6] = 0;
+       cregs[7] = 0;
 
-       len = i = B1_get_word(base);
-       while (i-- > 0)
-               *dp++ = B1_get_byte(base);
-       return len;
-}
+       save_flags(flags);
+       cli();
+       /* board reset */
+       t1outp(base, T1_RESETBOARD, 0xf);
+       udelay(100 * 1000);
+       dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */
+
+       /* write config */
+       dummy = (base >> 4) & 0xff;
+       for (i=1;i<=0xf;i++) t1outp(base, i, dummy);
+       t1outp(base, HEMA_PAL_ID & 0xf, dummy);
+       t1outp(base, HEMA_PAL_ID >> 4, cregs[0]);
+       for(i=1;i<7;i++) t1outp(base, 0, cregs[i]);
+       t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
+       restore_flags(flags);
 
-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++);
+       udelay(100 * 1000);
+       t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
+       t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
+       udelay(10 * 1000);
+       t1outp(base, T1_FASTLINK+T1_RESETLINK, 1);
+       t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1);
+       udelay(100 * 1000);
+       t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
+       t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
+       udelay(10 * 1000);
+       t1outp(base, T1_FASTLINK+T1_ANALYSE, 0);
+       udelay(5 * 1000);
+       t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0);
+
+       if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */
+               return 1;
+       if (t1inp(base, T1_FASTLINK+T1_INSTAT) != 0x0) /* rx empty */
+               return 2;
+       if (t1inp(base, T1_FASTLINK+T1_IRQENABLE) != 0x0)
+               return 3;
+       if ((t1inp(base, T1_FASTLINK+T1_FIFOSTAT) & 0xf0) != 0x70)
+               return 4;
+       if ((t1inp(base, T1_FASTLINK+T1_IRQMASTER) & 0x0e) != 0)
+               return 5;
+       if ((t1inp(base, T1_FASTLINK+T1_IDENT) & 0x7d) != 1)
+               return 6;
+       if (t1inp(base, T1_SLOWLINK+T1_OUTSTAT) != 0x1) /* tx empty */
+               return 7;
+       if ((t1inp(base, T1_SLOWLINK+T1_IRQMASTER) & 0x0e) != 0)
+               return 8;
+       if ((t1inp(base, T1_SLOWLINK+T1_IDENT) & 0x7d) != 0)
+               return 9;
+        return 0;
 }
 
 extern int loaddebug;
@@ -319,6 +691,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;
@@ -331,7 +759,7 @@ int B1_loaded(unsigned short base)
                        break;
        }
        if (!B1_tx_empty(base)) {
-               printk(KERN_ERR "b1lli: B1_loaded: timeout tx\n");
+               printk(KERN_ERR "b1lli(0x%x): B1_loaded: timeout tx\n", base);
                return 0;
        }
        B1_put_byte(base, SEND_POLL);
@@ -343,11 +771,12 @@ int B1_loaded(unsigned short base)
                                        printk(KERN_DEBUG "b1capi: loaded: ok\n");
                                return 1;
                        }
-                       printk(KERN_ERR "b1lli: B1_loaded: got 0x%x ???\n", ans);
+                       printk(KERN_ERR "b1lli(0x%x): B1_loaded: got 0x%x ???\n",
+                               base, ans);
                        return 0;
                }
        }
-       printk(KERN_ERR "b1lli: B1_loaded: timeout rx\n");
+       printk(KERN_ERR "b1lli(0x%x): B1_loaded: timeout rx\n", base);
        return 0;
 }
 
@@ -411,8 +840,6 @@ void B1_send_release(unsigned short port,
        restore_flags(flags);
 }
 
-extern int showcapimsgs;
-
 void B1_send_message(unsigned short port, struct sk_buff *skb)
 {
        unsigned long flags;
@@ -479,6 +906,7 @@ void B1_handle_interrupt(avmb1_card * card)
        unsigned NCCI;
        unsigned WindowSize;
 
+t1retry:
        if (!B1_rx_full(card->port))
                return;
 
@@ -555,7 +983,7 @@ void B1_handle_interrupt(avmb1_card * card)
                WindowSize = B1_get_word(card->port);
 
                if (showcapimsgs)
-                       printk(KERN_DEBUG "b1lli: NEW_NCCI app %u ncci 0x%x\n", ApplId, NCCI);
+                       printk(KERN_DEBUG "b1lli(0x%x): NEW_NCCI app %u ncci 0x%x\n", card->port, ApplId, NCCI);
 
                avmb1_handle_new_ncci(card, ApplId, NCCI, WindowSize);
 
@@ -567,19 +995,23 @@ void B1_handle_interrupt(avmb1_card * card)
                NCCI = B1_get_word(card->port);
 
                if (showcapimsgs)
-                       printk(KERN_DEBUG "b1lli: FREE_NCCI app %u ncci 0x%x\n", ApplId, NCCI);
+                       printk(KERN_DEBUG "b1lli(0x%x): FREE_NCCI app %u ncci 0x%x\n", card->port, ApplId, NCCI);
 
                avmb1_handle_free_ncci(card, ApplId, NCCI);
                break;
 
        case RECEIVE_START:
+                if (card->cardtype == AVM_CARDTYPE_T1) {
+                  B1_put_byte(card->port, SEND_POLLACK);
+                  /* printk(KERN_DEBUG "b1lli: T1 watchdog\n"); */
+                }
                if (card->blocked)
-                       printk(KERN_DEBUG "b1lli: RESTART\n");
+                       printk(KERN_DEBUG "b1lli(0x%x): RESTART\n", card->port);
                card->blocked = 0;
                break;
 
        case RECEIVE_STOP:
-               printk(KERN_DEBUG "b1lli: STOP\n");
+               printk(KERN_DEBUG "b1lli(0x%x): STOP\n", card->port);
                card->blocked = 1;
                break;
 
@@ -588,14 +1020,24 @@ 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(0x%x): %s-card (%s) now active\n",
+                      card->port,
                       card->version[VER_CARDTYPE],
-                      card->version[VER_DRIVER],
-                      card->version[VER_PROTO]);
+                      card->version[VER_DRIVER]);
                avmb1_card_ready(card);
                break;
+        case RECEIVE_TASK_READY:
+               ApplId = (unsigned) B1_get_word(card->port);
+               MsgLen = B1_get_slice(card->port, card->msgbuf);
+               card->msgbuf[MsgLen] = 0;
+               printk(KERN_INFO "b1lli(0x%x): Task %d \"%s\" ready.\n",
+                               card->port, ApplId, card->msgbuf);
+               break;
        default:
-               printk(KERN_ERR "b1lli: B1_handle_interrupt: 0x%x ???\n", b1cmd);
+               printk(KERN_ERR "b1lli(0x%x): B1_handle_interrupt: 0x%x ???\n",
+                               card->port, b1cmd);
                break;
        }
+       if (card->cardtype == AVM_CARDTYPE_T1) 
+               goto t1retry;
 }
index af7b58407795f068684409382f4705833b51b3fb..585ad29030d4c4efe18656be13782f55ebdf04b2 100644 (file)
@@ -1,11 +1,20 @@
 /*
- * $Id: b1pci.c,v 1.2 1997/05/18 09:24:13 calle Exp $
+ * $Id: b1pci.c,v 1.2.2.2 1998/01/23 16:49:30 calle Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
  * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pci.c,v $
+ * Revision 1.2.2.2  1998/01/23 16:49:30  calle
+ * added functions for pcmcia cards,
+ * avmb1_addcard returns now the controller number.
+ *
+ * Revision 1.2.2.1  1997/11/26 10:46:57  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.2  1997/05/18 09:24:13  calle
  * added verbose disconnect reason reporting to avmb1.
  * some fixes in capi20 interface.
@@ -34,7 +43,7 @@
 #define PCI_DEVICE_ID_AVM_B1   0x700
 #endif
 
-static char *revision = "$Revision: 1.2 $";
+static char *revision = "$Revision: 1.2.2.2 $";
 
 /* ------------------------------------------------------------- */
 
@@ -98,13 +107,13 @@ int b1pci_init(void)
                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 b818a85a4e097b92a6b409a30830908208d1f57f..268a3826da85a7a6abeed16ae4a35c17d0ff2e92 100644 (file)
@@ -1,11 +1,46 @@
 /*
- * $Id: capidrv.c,v 1.3.2.1 1997/07/13 12:16:48 calle Exp $
+ * $Id: capidrv.c,v 1.3.2.11 1998/04/02 10:27:59 calle Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.c,v $
+ * Revision 1.3.2.11  1998/04/02 10:27:59  calle
+ * version check for D2 trace was wrong :-(
+ *
+ * Revision 1.3.2.10  1998/03/20 14:38:24  calle
+ * capidrv: prepared state machines for suspend/resume/hold
+ * capidrv: fix bug in state machine if B1/T1 is out of nccis
+ * b1capi: changed some errno returns.
+ * b1capi: detect if you try to add same T1 to different io address.
+ * b1capi: change number of nccis depending on number of channels.
+ * b1lli: cosmetics
+ *
+ * Revision 1.3.2.9  1998/03/20 09:01:12  calle
+ * Changes capi_register handling to get full support for 30 bchannels.
+ *
+ * Revision 1.3.2.8  1998/03/18 17:51:28  calle
+ * added controller number to error messages
+ *
+ * Revision 1.3.2.7  1998/02/27 15:40:47  calle
+ * T1 running with slow link. bugfix in capi_release.
+ *
+ * Revision 1.3.2.6  1998/02/02 19:51:13  calle
+ * Fixed vbox (audio) acceptb.
+ *
+ * Revision 1.3.2.5  1997/10/29 09:35:29  calle
+ * correct byteorder problem with new isdnlog interface.
+ *
+ * Revision 1.3.2.4  1997/10/26 15:04:24  calle
+ * prepared isdnlog interface for d2-trace in newer firmware.
+ *
+ * Revision 1.3.2.3  1997/10/24 06:37:00  calle
+ * changed LISTEN cipmask, now we can distinguish voice, fax und data calls.
+ *
+ * Revision 1.3.2.2  1997/10/08 05:42:25  calle
+ * Added isdnlog support. patch to isdnlog needed.
+ *
  * Revision 1.3.2.1  1997/07/13 12:16:48  calle
  * bug fix for more than one controller in connect_req.
  *
@@ -51,7 +86,7 @@
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.3.2.1 $";
+static char *revision = "$Revision: 1.3.2.11 $";
 int debugmode = 0;
 
 #ifdef HAS_NEW_SYMTAB
@@ -125,8 +160,15 @@ struct capidrv_contr {
        } *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;
@@ -144,6 +186,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)
@@ -170,9 +215,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;
        }
 }
 
@@ -338,8 +382,8 @@ static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
                        return;
                }
        }
-       printk(KERN_ERR "capidrv: free_plci %p (0x%x) not found, Huh?\n",
-              plcip, plcip->plci);
+       printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
+              card->contrnr, plcip, plcip->plci);
 }
 
 /* -------- ncci management ------------------------------------------ */
@@ -437,15 +481,15 @@ struct listenstatechange {
 
 static struct listenstatechange listentable[] =
 {
-       {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
-       {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
-       {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
-    {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
-       {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
-      {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
-       {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
-       {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
-       {},
+  {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
+  {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
+  {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
+  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
+  {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
+  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
+  {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
+  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
+  {},
 };
 
 static void listen_change_state(capidrv_contr * card, int event)
@@ -454,15 +498,15 @@ static void listen_change_state(capidrv_contr * card, int event)
        while (p->event) {
                if (card->state == p->actstate && p->event == event) {
                        if (debugmode)
-                               printk(KERN_DEBUG "capidrv: listen_change_state %d -> %d\n",
-                                      card->state, p->nextstate);
+                               printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
+                                      card->contrnr, card->state, p->nextstate);
                        card->state = p->nextstate;
                        return;
                }
                p++;
        }
-       printk(KERN_ERR "capidrv: listen_change_state state=%d event=%d ????\n",
-              card->state, event);
+       printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
+              card->contrnr, card->state, event);
 
 }
 
@@ -492,46 +536,57 @@ struct plcistatechange {
 static struct plcistatechange plcitable[] =
 {
   /* P-0 */
-       {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0},
-       {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0},
-       {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0},
+  {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0},
+  {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0},
+  {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0},
+  {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, 0},
   /* P-0.1 */
-       {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
-       {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
-    {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
- {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+  {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
+  {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
+  {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
 {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
   /* P-1 */
-      {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
-   {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
-{ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
-    {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
   /* P-ACT */
-      {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
-   {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
-       {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, 0},
+  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, 0},
   /* P-2 */
-    {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
-    {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0},
-       {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0},
-    {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
- {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
-     {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
+  {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0},
+  {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0},
+  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, 0},
   /* P-3 */
-{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
-{ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0},
-{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
-       {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
- {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
+  {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
 {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
   /* P-4 */
-      {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
-   {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
-{ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
-    {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
   /* P-5 */
-{ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+  {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
   /* P-6 */
-       {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
-       {},
+  {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
+  /* P-0.Res */
+  {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
+  {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, 0},
+  /* P-RES */
+  {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, 0},
+  /* P-HELD */
+  {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, 0},
+  {},
 };
 
 static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
@@ -540,8 +595,8 @@ static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int eve
        while (p->event) {
                if (plci->state == p->actstate && p->event == event) {
                        if (debugmode)
-                               printk(KERN_DEBUG "capidrv: plci_change_state:0x%x %d -> %d\n",
-                                 plci->plci, plci->state, p->nextstate);
+                               printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
+                                 card->contrnr, plci->plci, plci->state, p->nextstate);
                        plci->state = p->nextstate;
                        if (p->changefunc)
                                p->changefunc(card, plci);
@@ -549,8 +604,8 @@ static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int eve
                }
                p++;
        }
-       printk(KERN_ERR "capidrv: plci_change_state:0x%x state=%d event=%d ????\n",
-              plci->plci, plci->state, event);
+       printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
+              card->contrnr, plci->plci, plci->state, event);
 }
 
 /* ------------------------------------------------------------------ */
@@ -567,7 +622,7 @@ static void n0(capidrv_contr * card, capidrv_ncci * ncci)
                                 ncci->plcip->plci,
                                 0,     /* BChannelinformation */
                                 0,     /* Keypadfacility */
-                                0,     /* Useruserdata */
+                                0,     /* Useruserdata */   /* $$$$ */
                                 0      /* Facilitydataarray */
        );
        send_message(card, &cmsg);
@@ -592,34 +647,35 @@ struct nccistatechange {
 static struct nccistatechange nccitable[] =
 {
   /* N-0 */
-       {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0},
-       {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0},
+  {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0},
+  {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0},
   /* N-0.1 */
-    {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0},
-      {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, 0},
+  {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0},
+  {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
   /* N-1 */
- {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0},
-       {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0},
 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0},
+  {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0},
   {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
- {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
 {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
   /* N-2 */
-   {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0},
- {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
-{ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+  {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0},
 {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+  {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
   /* N-ACT */
-       {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0},
-    {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
-   {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+  {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
+  {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0},
+  {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+  {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
   /* N-3 */
-       {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
+  {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
   {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
- {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
 {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
   /* N-4 */
-       {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
-       {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, 0},
+  {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+  {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,0},
   /* N-5 */
-    {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
-       {},
+  {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
+  {},
 };
 
 static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
@@ -628,8 +684,8 @@ static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int eve
        while (p->event) {
                if (ncci->state == p->actstate && p->event == event) {
                        if (debugmode)
-                               printk(KERN_DEBUG "capidrv: ncci_change_state:0x%x %d -> %d\n",
-                                 ncci->ncci, ncci->state, p->nextstate);
+                               printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
+                                 card->contrnr, ncci->ncci, ncci->state, p->nextstate);
                        if (p->nextstate == ST_NCCI_PREVIOUS) {
                                ncci->state = ncci->oldstate;
                                ncci->oldstate = p->actstate;
@@ -643,8 +699,8 @@ static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int eve
                }
                p++;
        }
-       printk(KERN_ERR "capidrv: ncci_change_state:0x%x state=%d event=%d ????\n",
-              ncci->ncci, ncci->state, event);
+       printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
+              card->contrnr, ncci->ncci, ncci->state, event);
 }
 
 /* ------------------------------------------------------------------- */
@@ -677,8 +733,8 @@ static void handle_controller(_cmsg * cmsg)
 
        case CAPI_LISTEN_CONF:  /* Controller */
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
-                              cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
+                       printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
+                              card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
                if (cmsg->Info) {
                        listen_change_state(card, EV_LISTEN_CONF_ERROR);
                } else if (card->cipmask == 0) {
@@ -689,8 +745,55 @@ 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-%d: %s from controller 0x%x layer 0x%x, ignored\n",
+                        card->contrnr, 
+                       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-%d: %s from controller 0x%x function %d: %s\n",
+                       card->contrnr,
+                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+                       cmsg->adr.adrController,
+                       cmsg->Function, s);
+                  break;
+               }
                goto ignored;
        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
                goto ignored;
@@ -702,14 +805,16 @@ static void handle_controller(_cmsg * cmsg)
                goto ignored;
 
        default:
-               printk(KERN_ERR "capidrv: got %s from controller 0x%x ???",
+               printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
+                      card->contrnr,
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                       cmsg->adr.adrController);
        }
        return;
 
       ignored:
-       printk(KERN_INFO "capidrv: %s from controller 0x%x ignored\n",
+       printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
+              card->contrnr,
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
               cmsg->adr.adrController);
 }
@@ -722,12 +827,12 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
        int chan;
 
        if ((chan = new_bchan(card)) == -1) {
-               printk(KERN_ERR "capidrv: incoming call on not existing bchan ?\n");
+               printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
                return;
        }
        bchan = &card->bchans[chan];
        if ((plcip = new_plci(card, chan)) == 0) {
-               printk(KERN_ERR "capidrv: incoming call: no memory, sorry.\n");
+               printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
                return;
        }
        bchan->incoming = 1;
@@ -749,7 +854,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
        cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
        cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
 
-       printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s\n", 
+       printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n", 
+                       card->contrnr,
                        cmd.parm.setup.phone,
                        cmd.parm.setup.si1,
                        cmd.parm.setup.si2,
@@ -766,7 +872,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
                cmsg->Reject = 1;       /* ignore */
                send_message(card, cmsg);
                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
-               printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s ignored\n",
+               printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
+                       card->contrnr,
                        cmd.parm.setup.phone,
                        cmd.parm.setup.si1,
                        cmd.parm.setup.si2,
@@ -783,7 +890,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
                 * and CONNECT_RESP already sent.
                 */
                if (plcip->state == ST_PLCI_INCOMING) {
-                       printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s tty alerting\n",
+                       printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
+                               card->contrnr,
                                cmd.parm.setup.phone,
                                cmd.parm.setup.si1,
                                cmd.parm.setup.si2,
@@ -800,7 +908,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
                        plcip->msgid = cmsg->Messagenumber;
                        send_message(card, cmsg);
                } else {
-                       printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s on netdev\n",
+                       printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
+                               card->contrnr,
                                cmd.parm.setup.phone,
                                cmd.parm.setup.si1,
                                cmd.parm.setup.si2,
@@ -843,7 +952,8 @@ static void handle_plci(_cmsg * cmsg)
 
        case CAPI_DISCONNECT_IND:       /* plci */
                if (cmsg->Reason) {
-                       printk(KERN_INFO "capidrv: %s reason 0x%x (%s) for plci 0x%x\n",
+                       printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
+                          card->contrnr,
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                               cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
                }
@@ -861,7 +971,8 @@ static void handle_plci(_cmsg * cmsg)
 
        case CAPI_DISCONNECT_CONF:      /* plci */
                if (cmsg->Info) {
-                       printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+                       printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
+                          card->contrnr,
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                               cmsg->Info, capi_info2str(cmsg->Info), 
                               cmsg->adr.adrPLCI);
@@ -874,7 +985,8 @@ static void handle_plci(_cmsg * cmsg)
 
        case CAPI_ALERT_CONF:   /* plci */
                if (cmsg->Info) {
-                       printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+                       printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
+                          card->contrnr,
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                               cmsg->Info, capi_info2str(cmsg->Info), 
                               cmsg->adr.adrPLCI);
@@ -887,7 +999,8 @@ static void handle_plci(_cmsg * cmsg)
 
        case CAPI_CONNECT_CONF: /* plci */
                if (cmsg->Info) {
-                       printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+                       printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
+                          card->contrnr,
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                               cmsg->Info, capi_info2str(cmsg->Info), 
                               cmsg->adr.adrPLCI);
@@ -920,7 +1033,7 @@ static void handle_plci(_cmsg * cmsg)
                        nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
 
                        if (!nccip) {
-                               printk(KERN_ERR "capidrv: no mem for ncci, sorry\n");
+                               printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
                                break;  /* $$$$ */
                        }
                        capi_fill_CONNECT_B3_REQ(cmsg,
@@ -960,7 +1073,8 @@ static void handle_plci(_cmsg * cmsg)
                                break;
                        }
                }
-               printk(KERN_ERR "capidrv: %s\n", capi_cmsg2str(cmsg));
+               printk(KERN_ERR "capidrv-%d: %s\n",
+                               card->contrnr, capi_cmsg2str(cmsg));
                break;
 
        case CAPI_CONNECT_ACTIVE_CONF:          /* plci */
@@ -976,18 +1090,21 @@ static void handle_plci(_cmsg * cmsg)
                goto ignored;
 
        default:
-               printk(KERN_ERR "capidrv: got %s for plci 0x%x ???",
+               printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
+                      card->contrnr,
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                       cmsg->adr.adrPLCI);
        }
        return;
       ignored:
-       printk(KERN_INFO "capidrv: %s for plci 0x%x ignored\n",
+       printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
+              card->contrnr,
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
               cmsg->adr.adrPLCI);
        return;
       notfound:
-       printk(KERN_ERR "capidrv: %s: plci 0x%x not found\n",
+       printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
+              card->contrnr,
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
               cmsg->adr.adrPLCI);
        return;
@@ -1021,8 +1138,8 @@ static void handle_ncci(_cmsg * cmsg)
                cmd.arg = nccip->chan;
                card->interface.statcallb(&cmd);
 
-               printk(KERN_INFO "capidrv: chan %d up with ncci 0x%x\n",
-                      nccip->chan, nccip->ncci);
+               printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
+                      card->contrnr, nccip->chan, nccip->ncci);
                break;
 
        case CAPI_CONNECT_B3_ACTIVE_CONF:       /* ncci */
@@ -1046,9 +1163,10 @@ static void handle_ncci(_cmsg * cmsg)
                                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
                                break;
                        }
-                       printk(KERN_ERR "capidrv: no mem for ncci, sorry\n");
+                       printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n",                                                 card->contrnr);
                } else {
-                       printk(KERN_ERR "capidrv: %s: plci for ncci 0x%x not found\n",
+                       printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
+                          card->contrnr,
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                               cmsg->adr.adrNCCI);
                }
@@ -1071,7 +1189,8 @@ static void handle_ncci(_cmsg * cmsg)
 
                nccip->ncci = cmsg->adr.adrNCCI;
                if (cmsg->Info) {
-                       printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n",
+                       printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
+                          card->contrnr,
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                               cmsg->Info, capi_info2str(cmsg->Info), 
                               cmsg->adr.adrNCCI);
@@ -1118,7 +1237,8 @@ static void handle_ncci(_cmsg * cmsg)
                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
                        goto notfound;
                if (cmsg->Info) {
-                       printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n",
+                       printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
+                          card->contrnr,
                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                               cmsg->Info, capi_info2str(cmsg->Info), 
                               cmsg->adr.adrNCCI);
@@ -1127,6 +1247,9 @@ static void handle_ncci(_cmsg * cmsg)
                break;
 
        case CAPI_RESET_B3_IND: /* ncci */
+               if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+                       goto notfound;
+               ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
                capi_cmsg_answer(cmsg);
                send_message(card, cmsg);
                break;
@@ -1140,18 +1263,21 @@ static void handle_ncci(_cmsg * cmsg)
                goto ignored;
 
        default:
-               printk(KERN_ERR "capidrv: got %s for ncci 0x%x ???",
+               printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
+                      card->contrnr,
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                       cmsg->adr.adrNCCI);
        }
        return;
       ignored:
-       printk(KERN_INFO "capidrv: %s for ncci 0x%x ignored\n",
+       printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
+              card->contrnr,
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
               cmsg->adr.adrNCCI);
        return;
       notfound:
-       printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n",
+       printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
+              card->contrnr,
               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
               cmsg->adr.adrNCCI);
 }
@@ -1169,7 +1295,8 @@ static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
                return;
        }
        if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
-               printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n",
+               printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
+                      card->contrnr,
                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
                       cmsg->adr.adrNCCI);
                kfree_skb(skb, FREE_READ);
@@ -1190,7 +1317,8 @@ static void capidrv_signal(__u16 applid, __u32 dummy)
        while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) {
                capi_message2cmsg(&s_cmsg, skb->data);
                if (debugmode > 1)
-                       printk(KERN_DEBUG "capidrv_signal: %s\n", capi_cmsg2str(&s_cmsg));
+                       printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
+                                       applid, capi_cmsg2str(&s_cmsg));
 
                if (s_cmsg.Command == CAPI_DATA_B3
                    && s_cmsg.Subcommand == CAPI_IND) {
@@ -1209,13 +1337,69 @@ 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 "capidrv-%d: avmb1_q931_data: len == %d\n",
+                               card->contrnr, 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)
 {
        switch (c->arg) {
        default:
-               printk(KERN_DEBUG "capidrv: capidrv_ioctl(%ld) called ??\n", c->arg);
+               printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
+                               card->contrnr, c->arg);
                return -EINVAL;
        }
        return -EINVAL;
@@ -1236,7 +1420,8 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
                        __u8 called[ISDN_MSNLEN + 2];
 
                        if (debugmode)
-                               printk(KERN_DEBUG "capidrv: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
+                               printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
+                                       card->contrnr,
                                        c->arg,
                                        c->parm.setup.phone,
                                        c->parm.setup.si1,
@@ -1246,7 +1431,8 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
                        bchan = &card->bchans[c->arg % card->nbchan];
 
                        if (bchan->plcip) {
-                               printk(KERN_ERR "capidrv: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
+                               printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
+                                       card->contrnr,
                                        c->arg, 
                                        c->parm.setup.phone,
                                        c->parm.setup.si1,
@@ -1308,10 +1494,11 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
 
        case ISDN_CMD_ACCEPTD:
 
-               if (debugmode)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTD(ch=%ld)\n",
-                              c->arg);
                bchan = &card->bchans[c->arg % card->nbchan];
+               if (debugmode)
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
+                              card->contrnr,
+                              c->arg, bchan->l2, bchan->l3);
 
                capi_fill_CONNECT_RESP(&cmdcmsg,
                                       global.appid,
@@ -1339,19 +1526,22 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
 
        case ISDN_CMD_ACCEPTB:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTB(ch=%ld)\n",
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
+                              card->contrnr,
                               c->arg);
                return -ENOSYS;
 
        case ISDN_CMD_HANGUP:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_HANGUP(ch=%ld)\n",
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
+                              card->contrnr,
                               c->arg);
                bchan = &card->bchans[c->arg % card->nbchan];
 
                if (bchan->disconnecting) {
                        if (debugmode)
-                               printk(KERN_DEBUG "capidrv: chan %ld already disconnecting ...\n",
+                               printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
+                                      card->contrnr,
                                       c->arg);
                        return 0;
                }
@@ -1390,23 +1580,26 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
 
        case ISDN_CMD_SETL2:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: set L2 on chan %ld to %ld\n",
+                       printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
+                              card->contrnr,
                               (c->arg & 0xff), (c->arg >> 8));
-               bchan = &card->bchans[c->arg % card->nbchan];
+               bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
                bchan->l2 = (c->arg >> 8);
                return 0;
 
        case ISDN_CMD_SETL3:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: set L3 on chan %ld to %ld\n",
+                       printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
+                              card->contrnr,
                               (c->arg & 0xff), (c->arg >> 8));
-               bchan = &card->bchans[c->arg % card->nbchan];
+               bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
                bchan->l3 = (c->arg >> 8);
                return 0;
 
        case ISDN_CMD_SETEAZ:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: set EAZ \"%s\" on chan %ld\n",
+                       printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
+                              card->contrnr,
                               c->parm.num, c->arg);
                bchan = &card->bchans[c->arg % card->nbchan];
                strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
@@ -1414,46 +1607,54 @@ static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
 
        case ISDN_CMD_CLREAZ:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: clearing EAZ on chan %ld\n", c->arg);
+                       printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
+                                       card->contrnr, c->arg);
                bchan = &card->bchans[c->arg % card->nbchan];
                bchan->msn[0] = 0;
                return 0;
 
        case ISDN_CMD_LOCK:
                if (debugmode > 1)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_LOCK (%ld)\n", c->arg);
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_LOCK (%ld)\n", card->contrnr, c->arg);
                MOD_INC_USE_COUNT;
                break;
 
        case ISDN_CMD_UNLOCK:
                if (debugmode > 1)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_UNLOCK (%ld)\n", c->arg);
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_UNLOCK (%ld)\n",
+                                       card->contrnr, c->arg);
                MOD_DEC_USE_COUNT;
                break;
 
 /* never called */
        case ISDN_CMD_GETL2:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL2\n");
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL2\n",
+                                       card->contrnr);
                return -ENODEV;
        case ISDN_CMD_GETL3:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL3\n");
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETL3\n",
+                                       card->contrnr);
                return -ENODEV;
        case ISDN_CMD_GETEAZ:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_GETEAZ\n");
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETEAZ\n",
+                                       card->contrnr);
                return -ENODEV;
        case ISDN_CMD_SETSIL:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_SETSIL\n");
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_SETSIL\n",
+                                       card->contrnr);
                return -ENODEV;
        case ISDN_CMD_GETSIL:
                if (debugmode)
-                       printk(KERN_DEBUG "capidrv: ISDN_CMD_GETSIL\n");
+                       printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_GETSIL\n",
+                                       card->contrnr);
                return -ENODEV;
        default:
-               printk(KERN_ERR "capidrv: ISDN_CMD_%d, Huh?\n", c->command);
+               printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
+                                       card->contrnr, c->command);
                return -EINVAL;
        }
        return 0;
@@ -1467,8 +1668,8 @@ static int if_command(isdn_ctrl * c)
                return capidrv_command(c, card);
 
        printk(KERN_ERR
-            "capidrv: if_command %d called with invalid driverId %d!\n",
-              c->command, c->driver);
+            "capidrv-%d: if_command %d called with invalid driverId %d!\n",
+              card->contrnr, c->command, c->driver);
        return -ENODEV;
 }
 
@@ -1484,15 +1685,15 @@ static int if_sendbuf(int id, int channel, struct sk_buff *skb)
        __u16 errcode;
 
        if (!card) {
-               printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
-                      id);
+               printk(KERN_ERR "capidrv-%d: if_sendbuf called with invalid driverId %d!\n",
+                      card->contrnr, id);
                return 0;
        }
        bchan = &card->bchans[channel % card->nbchan];
        nccip = bchan->nccip;
        if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
-               printk(KERN_ERR "capidrv: if_sendbuf: %s:%d: chan not up!\n",
-                      card->name, channel);
+               printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
+                      card->contrnr, card->name, channel);
                return 0;
        }
        capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
@@ -1507,12 +1708,13 @@ static int if_sendbuf(int id, int channel, struct sk_buff *skb)
        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");
+                       printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
+                                       card->contrnr);
                        return 0;
                }
 #if 0
-               printk(KERN_DEBUG "capidrv: only %d bytes headroom\n",
-                      skb_headroom(skb));
+               printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom\n",
+                      card->contrnr, skb_headroom(skb));
 #endif
                 SET_SKB_FREE(nskb);
                memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen);
@@ -1542,6 +1744,82 @@ static int if_sendbuf(int id, int channel, struct sk_buff *skb)
        }
 }
 
+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-%d: if_readstat called with invalid driverId %d!\n",
+                      card->contrnr, 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)
 {
        capidrv_contr *card;
@@ -1571,7 +1849,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 |
@@ -1584,6 +1862,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;
@@ -1603,7 +1884,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,
@@ -1619,6 +1900,9 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
        printk(KERN_INFO "%s: now up (%d B channels)\n",
                card->name, card->nbchan);
 
+        if (card->nbchan == 2)  /* no T1 */
+               enable_dchannel_trace(card);
+
        return 0;
 }
 
@@ -1709,8 +1993,8 @@ int capidrv_init(void)
        } else
                strcpy(rev, " ??? ");
 
-       rparam.level3cnt = 2;
-       rparam.datablkcnt = 8;
+       rparam.level3cnt = -2;  /* number of bchannels twice */
+       rparam.datablkcnt = 16;
        rparam.datablklen = 2048;
        errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
        if (errcode) {
index f30c3f4dd1de6945b755e118a3b4b4b92c46a3e4..614010224b3a178e5246c5a1170b0f0a098a97cb 100644 (file)
@@ -1,11 +1,19 @@
 /*
- * $Id: capidrv.h,v 1.1 1997/03/04 21:50:33 calle Exp $
+ * $Id: capidrv.h,v 1.1.2.1 1998/03/20 14:38:28 calle Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.h,v $
+ * Revision 1.1.2.1  1998/03/20 14:38:28  calle
+ * capidrv: prepared state machines for suspend/resume/hold
+ * capidrv: fix bug in state machine if B1/T1 is out of nccis
+ * b1capi: changed some errno returns.
+ * b1capi: detect if you try to add same T1 to different io address.
+ * b1capi: change number of nccis depending on number of channels.
+ * b1lli: cosmetics
+ *
  * Revision 1.1  1997/03/04 21:50:33  calle
  * Frirst version in isdn4linux
  *
 #define ST_PLCI_ACCEPTING              6       /* P-4 */
 #define ST_PLCI_DISCONNECTING          7       /* P-5 */
 #define ST_PLCI_DISCONNECTED           8       /* P-6 */
+#define ST_PLCI_RESUMEING              9       /* P-0.Res */
+#define ST_PLCI_RESUME                 10      /* P-Res */
+#define ST_PLCI_HELD                   11      /* P-HELD */
 
-#define EV_PLCI_CONNECT_REQ            1       /* P-0 -> P-0.1 */
-#define EV_PLCI_CONNECT_CONF_ERROR     2       /* P-0.1 -> P-0 */
-#define EV_PLCI_CONNECT_CONF_OK                3       /* P-0.1 -> P-1 */
-#define EV_PLCI_FACILITY_IND_UP                4       /* P-0 -> P-1 */
-#define EV_PLCI_CONNECT_IND            5       /* P-0 -> P-2 */
-#define EV_PLCI_CONNECT_ACTIVE_IND     6       /* P-1 -> P-ACT */
+#define EV_PLCI_CONNECT_REQ            1       /* P-0 -> P-0.1
+                                                 */
+#define EV_PLCI_CONNECT_CONF_ERROR     2       /* P-0.1 -> P-0
+                                                 */
+#define EV_PLCI_CONNECT_CONF_OK                3       /* P-0.1 -> P-1
+                                                 */
+#define EV_PLCI_FACILITY_IND_UP                4       /* P-0 -> P-1
+                                                 */
+#define EV_PLCI_CONNECT_IND            5       /* P-0 -> P-2
+                                                 */
+#define EV_PLCI_CONNECT_ACTIVE_IND     6       /* P-1 -> P-ACT
+                                                 */
 #define EV_PLCI_CONNECT_REJECT         7       /* P-2 -> P-5
-                                                  P-3 -> P-5 */
+                                                  P-3 -> P-5
+                                                */
 #define EV_PLCI_DISCONNECT_REQ         8       /* P-1 -> P-5
                                                   P-2 -> P-5
                                                   P-3 -> P-5
                                                   P-4 -> P-5
-                                                  P-ACT -> P-5 */
+                                                  P-ACT -> P-5
+                                                  P-Res -> P-5 (*)
+                                                  P-HELD -> P-5 (*)
+                                                  */
 #define EV_PLCI_DISCONNECT_IND         9       /* P-1 -> P-6
                                                   P-2 -> P-6
                                                   P-3 -> P-6
                                                   P-4 -> P-6
                                                   P-5 -> P-6
-                                                  P-ACT -> P-6 */
+                                                  P-ACT -> P-6
+                                                  P-Res -> P-6 (*)
+                                                  P-HELD -> P-6 (*)
+                                                  */
 #define EV_PLCI_FACILITY_IND_DOWN      10      /* P-0.1 -> P-5
                                                   P-1 -> P-5
                                                   P-ACT -> P-5
                                                   P-2 -> P-5
                                                   P-3 -> P-5
-                                                  P-4 -> P-5 */
-#define EV_PLCI_DISCONNECT_RESP                11      /* P-6 -> P-0 */
-#define EV_PLCI_CONNECT_RESP           12      /* P-6 -> P-0 */
+                                                  P-4 -> P-5
+                                                  */
+#define EV_PLCI_DISCONNECT_RESP                11      /* P-6 -> P-0
+                                                   */
+#define EV_PLCI_CONNECT_RESP           12      /* P-6 -> P-0
+                                                   */
+
+#define EV_PLCI_RESUME_REQ             13      /* P-0 -> P-0.Res
+                                                 */
+#define EV_PLCI_RESUME_CONF_OK         14      /* P-0.Res -> P-Res
+                                                 */
+#define EV_PLCI_RESUME_CONF_ERROR      15      /* P-0.Res -> P-0
+                                                 */
+#define EV_PLCI_RESUME_IND             16      /* P-Res -> P-ACT
+                                                 */
+#define EV_PLCI_HOLD_IND               17      /* P-ACT -> P-HELD
+                                                 */
+#define EV_PLCI_RETRIEVE_IND           18      /* P-HELD -> P-ACT
+                                                 */
+#define EV_PLCI_SUSPEND_IND            19      /* P-ACT -> P-5
+                                                 */
+#define EV_PLCI_CD_IND                 20      /* P-2 -> P-5
+                                                 */
 
 /*
  * per ncci state machine
index 2cc325b1f24636a092d4ac2210402f170db2213b..65e1341ee18711bf578fa2f563689a6795e83333 100644 (file)
@@ -1,7 +1,7 @@
 L_OBJS :=
 M_OBJS :=
-O_OBJS := isdnl1.o config.o tei.o isdnl2.o isdnl3.o \
-          q931.o callc.o fsm.o
+O_OBJS := isdnl1.o tei.o isdnl2.o isdnl3.o \
+          lmgr.o q931.o callc.o fsm.o
 
 # EXTRA_CFLAGS += -S
 
@@ -17,31 +17,112 @@ ifeq ($(CONFIG_HISAX_1TR6),y)
         O_OBJS += l3_1tr6.o
 endif
 
+ISAC_OBJ :=
+ARCOFI_OBJ :=
+HSCX_OBJ :=
+HFC_OBJ :=
+HFC_2BDS0 :=
+
 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
+ifeq ($(CONFIG_HISAX_TELESPCI),y)
+        O_OBJS += telespci.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
 endif
 
-ifeq ($(CONFIG_HISAX_ELSA_PCC),y)
-        O_OBJS += elsa.o
+ifeq ($(CONFIG_HISAX_S0BOX),y)
+        O_OBJS += s0box.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_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_NICCY),y)
+        O_OBJS += niccy.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+
+O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(HFC_OBJ) $(HFC_2BDS0) $(ARCOFI_OBJ)
+OX_OBJS += config.o
+
 O_TARGET :=
+
 ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
   O_TARGET += hisax.o
 else
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
new file mode 100644 (file)
index 0000000..29c43dd
--- /dev/null
@@ -0,0 +1,75 @@
+/* $Id: arcofi.c,v 1.1.2.3 1998/05/27 18:04:48 keil Exp $
+
+ * arcofi.h   Ansteuerung ARCOFI 2165
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ *
+ * $Log: arcofi.c,v $
+ * Revision 1.1.2.3  1998/05/27 18:04:48  keil
+ * HiSax 3.0
+ *
+ * Revision 1.1.2.2  1998/04/11 18:45:13  keil
+ * New interface
+ *
+ * Revision 1.1.2.1  1997/11/15 18:57:37  keil
+ * ARCOFI 2165 support
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl1.h"
+#include "isac.h"
+
+int
+send_arcofi(struct IsdnCardState *cs, const u_char *msg, int bc, int receive) {
+       u_char val;
+       char tmp[32];
+       long flags;
+       int cnt=50;
+       
+       cs->mon_txp = 0;
+       cs->mon_txc = msg[0];
+       memcpy(cs->mon_tx, &msg[1], cs->mon_txc);
+       switch(bc) {
+               case 0: break;
+               case 1: cs->mon_tx[1] |= 0x40;
+                       break;
+               default: break;
+       }
+       cs->mocr &= 0x0f;
+       cs->mocr |= 0xa0;
+       test_and_clear_bit(HW_MON1_TX_END, &cs->HW_Flags);
+       if (receive)
+               test_and_clear_bit(HW_MON1_RX_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--;
+               udelay(500);
+#if 0
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+               schedule();
+#endif
+       }
+       if (receive) {
+               while (cnt && !test_bit(HW_MON1_RX_END, &cs->HW_Flags)) {
+                       cnt--;
+                       udelay(500);
+               }
+       }
+       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..2ad5ff3
--- /dev/null
@@ -0,0 +1,23 @@
+/* $Id: arcofi.h,v 1.1.2.3 1998/05/27 18:04:50 keil Exp $
+
+ * arcofi.h   Ansteuerung ARCOFI 2165
+ *
+ * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: arcofi.h,v $
+ * Revision 1.1.2.3  1998/05/27 18:04:50  keil
+ * HiSax 3.0
+ *
+ * Revision 1.1.2.2  1998/04/11 18:45:14  keil
+ * New interface
+ *
+ * Revision 1.1.2.1  1997/11/15 18:57:38  keil
+ * ARCOFI 2165 support
+ *
+ *
+ */
+#define ARCOFI_USE     1
+
+extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg, int bc, int receive);
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
new file mode 100644 (file)
index 0000000..d667cf7
--- /dev/null
@@ -0,0 +1,406 @@
+/* $Id: asuscom.c,v 1.1.2.3 1998/06/18 23:10:26 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.1.2.3  1998/06/18 23:10:26  keil
+ * Support for new IPAC card
+ *
+ * Revision 1.1.2.2  1998/04/08 21:58:37  keil
+ * New init code
+ *
+ * Revision 1.1.2.1  1998/01/27 22:34:02  keil
+ * dynalink ----> asuscom
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "ipac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *Asuscom_revision = "$Revision: 1.1.2.3 $";
+
+#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
+
+#define ASUS_IPAC_ALE  0
+#define ASUS_IPAC_DATA 1
+
+#define ASUS_ISACHSCX  1
+#define ASUS_IPAC      2
+
+/* 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
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80));
+}
+
+static void
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80, value);
+}
+
+static void
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
+{
+       readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
+}
+
+static void
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
+{
+       writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, 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);
+       }
+}
+
+static void
+asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char ista, val, icnt = 20;
+       char   tmp[64];
+
+       if (!cs) {
+               printk(KERN_WARNING "ISDNLink: Spurious interrupt!\n");
+               return;
+       }
+       ista = readreg(cs->hw.asus.adr, cs->hw.asus.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.asus.adr, cs->hw.asus.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.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80);
+               if (val) {
+                       isac_interrupt(cs, val);
+               }
+       }
+       if (ista & 0x10) {
+               val = 0x01;
+               isac_interrupt(cs, val);
+       }
+       ista  = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
+       if ((ista & 0x3f) && icnt) {
+               icnt--;
+               goto Start_IPAC;
+       }
+       if (!icnt)
+               printk(KERN_WARNING "ASUS IRQ LOOP\n");
+       writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF);
+       writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0);
+}
+
+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;
+
+       if (cs->subtyp == ASUS_IPAC)
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
+       else
+               byteout(cs->hw.asus.adr, ASUS_RESET);   /* Reset On */
+       save_flags(flags);
+       sti();
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 1;
+       schedule();
+       if (cs->subtyp == ASUS_IPAC)
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
+       else
+               byteout(cs->hw.asus.adr, 0);    /* Reset Off */
+       current->state = TASK_INTERRUPTIBLE;
+       current->timeout = jiffies + 1;
+       schedule();
+       if (cs->subtyp == ASUS_IPAC) {
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0);
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
+               writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
+       }
+       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:
+                       if (cs->subtyp == ASUS_IPAC)
+                               return(request_irq(cs->irq, &asuscom_interrupt_ipac,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+                       else
+                               return(request_irq(cs->irq, &asuscom_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       cs->debug |= L1_DEB_IPAC;
+                       inithscxisac(cs, 3);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+__initfunc(int
+setup_asuscom(struct IsdnCard *card))
+{
+       int bytecnt;
+       struct IsdnCardState *cs = card->cs;
+       u_char val;
+       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];
+       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);
+       cs->BC_Read_Reg = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Asus_card_msg;
+       val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, 
+               cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
+       if (val == 1) {
+               cs->subtyp = ASUS_IPAC;
+               cs->hw.asus.adr  = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
+               cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
+               cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
+               test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+               cs->readisac = &ReadISAC_IPAC;
+               cs->writeisac = &WriteISAC_IPAC;
+               cs->readisacfifo = &ReadISACfifo_IPAC;
+               cs->writeisacfifo = &WriteISACfifo_IPAC;
+               printk(KERN_INFO "Asus: IPAC version %x\n", val);
+       } else {
+               cs->subtyp = ASUS_ISACHSCX;
+               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;
+               cs->readisac = &ReadISAC;
+               cs->writeisac = &WriteISAC;
+               cs->readisacfifo = &ReadISACfifo;
+               cs->writeisacfifo = &WriteISACfifo;
+               ISACVersion(cs, "ISDNLink:");
+               if (HscxVersion(cs, "ISDNLink:")) {
+                       printk(KERN_WARNING
+                       "ISDNLink: wrong HSCX versions check IO address\n");
+                       release_io_asuscom(cs);
+                       return (0);
+               }
+       }
+       printk(KERN_INFO "ISDNLink: resetting card\n");
+       reset_asuscom(cs);
+       return (1);
+}
index 6f80ae8bcd850d6c10c67243e22bf695287b5648..42434c789308e15824a0ebfac9a3c2eb1c62c862 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 1.6.2.10 1998/05/27 18:04:50 keil Exp $
 
  * avm_a1.c     low level stuff for AVM A1 (Fritz) isdn cards
  *
@@ -6,6 +6,33 @@
  *
  *
  * $Log: avm_a1.c,v $
+ * Revision 1.6.2.10  1998/05/27 18:04:50  keil
+ * HiSax 3.0
+ *
+ * Revision 1.6.2.9  1998/04/08 21:58:39  keil
+ * New init code
+ *
+ * Revision 1.6.2.8  1998/01/27 22:37:49  keil
+ * fast io
+ *
+ * Revision 1.6.2.7  1998/01/13 23:06:11  keil
+ * really disable internal timer
+ *
+ * Revision 1.6.2.6  1998/01/02 06:49:01  calle
+ * Perodic timer of A1 now disabled, no need for linux driver.
+ *
+ * Revision 1.6.2.5  1997/11/15 18:50:41  keil
+ * new common init function
+ *
+ * Revision 1.6.2.4  1997/10/17 22:13:29  keil
+ * update to last hisax version
+ *
+ * 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: 1.6.2.10 $";
 
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
+#define         AVM_A1_STAT_ISAC       0x01
+#define         AVM_A1_STAT_HSCX       0x02
+#define         AVM_A1_STAT_TIMER      0x04
+
+#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 +85,302 @@ 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)
-{
-       printk(KERN_DEBUG "HSCX %d\n", hscx);
-       printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
-       printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
-       printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
-}
-
-void
-avm_a1_report(struct IsdnCardState *sp)
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-       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);
+       writereg(cs->hw.avm.isac, 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->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)
-{
-       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)
+WriteISACfifo(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 {
-                               dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
-                               hsp->count = 0;
-                               if (hsp->st->l4.l1writewakeup)
-                                       hsp->st->l4.l1writewakeup(hsp->st);
-                               hsp->tx_skb = NULL;
-                       }
-               if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
-                       hsp->count = 0;
-                       hscx_fill_fifo(hsp);
-               } else
-                       hscx_sched_event(hsp, HSCX_XMTBUFREADY);
-       }
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
-{
-       u_char *ptr;
-       long flags;
-
-       if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
-               if (sp->debug & L1_DEB_ISAC)
-                       debugl1(sp, "isac_empty_fifo");
-
-       if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
-               if (sp->debug & L1_DEB_WARN) {
-                       char tmp[40];
-                       sprintf(tmp, "isac_empty_fifo overrun %d",
-                               sp->rcvidx + count);
-                       debugl1(sp, tmp);
-               }
-               writereg(sp->isac, ISAC_CMDR, 0x80);
-               sp->rcvidx = 0;
-               return;
-       }
-       ptr = sp->rcvbuf + sp->rcvidx;
-       sp->rcvidx += count;
-       save_flags(flags);
-       cli();
-       read_fifo(sp->isac, ptr, count);
-       writereg(sp->isac, ISAC_CMDR, 0x80);
-       restore_flags(flags);
-       if (sp->debug & L1_DEB_ISAC_FIFO) {
-               char tmp[128];
-               char *t = tmp;
-
-               t += sprintf(t, "isac_empty_fifo cnt %d", count);
-               QuickHex(t, ptr, count);
-               debugl1(sp, tmp);
-       }
+       write_fifo(cs->hw.avm.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.avm.hscx[hscx], offset));
 }
 
 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)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-       u_char exval;
-       struct sk_buff *skb;
-       unsigned int count;
-       char tmp[32];
-
-       if (sp->debug & L1_DEB_ISAC) {
-               sprintf(tmp, "ISAC interrupt %x", val);
-               debugl1(sp, tmp);
-       }
-       if (val & 0x80) {       /* RME */
-               exval = readreg(sp->isac, ISAC_RSTA);
-               if ((exval & 0x70) != 0x20) {
-                       if (exval & 0x40)
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, "ISAC RDO");
-                       if (!(exval & 0x20))
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, "ISAC CRC error");
-                       writereg(sp->isac, ISAC_CMDR, 0x80);
-               } else {
-                       count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
-                       if (count == 0)
-                               count = 32;
-                       isac_empty_fifo(sp, count);
-                       if ((count = sp->rcvidx) > 0) {
-                               if (!(skb = alloc_skb(count, GFP_ATOMIC)))
-                                       printk(KERN_WARNING "AVM: D receive out of memory\n");
-                               else {
-                                       SET_SKB_FREE(skb);
-                                       memcpy(skb_put(skb, count), sp->rcvbuf, count);
-                                       skb_queue_tail(&sp->rq, skb);
-                               }
-                       }
-               }
-               sp->rcvidx = 0;
-               isac_sched_event(sp, ISAC_RCVBUFREADY);
-       }
-       if (val & 0x40) {       /* RPF */
-               isac_empty_fifo(sp, 32);
-       }
-       if (val & 0x20) {       /* RSC */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC RSC interrupt");
-       }
-       if (val & 0x10) {       /* XPR */
-               if (sp->tx_skb)
-                       if (sp->tx_skb->len) {
-                               isac_fill_fifo(sp);
-                               goto afterXPR;
-                       } else {
-                               dev_kfree_skb(sp->tx_skb, FREE_WRITE);
-                               sp->tx_cnt = 0;
-                               sp->tx_skb = NULL;
-                       }
-               if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
-                       sp->tx_cnt = 0;
-                       isac_fill_fifo(sp);
-               } else
-                       isac_sched_event(sp, ISAC_XMTBUFREADY);
-       }
-      afterXPR:
-       if (val & 0x04) {       /* CISQ */
-               sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
-                   & 0xf;
-               if (sp->debug & L1_DEB_ISAC) {
-                       sprintf(tmp, "l1state %d", sp->ph_state);
-                       debugl1(sp, tmp);
-               }
-               isac_new_ph(sp);
-       }
-       if (val & 0x02) {       /* SIN */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC SIN interrupt");
-       }
-       if (val & 0x01) {       /* EXI */
-               exval = readreg(sp->isac, ISAC_EXIR);
-               if (sp->debug & L1_DEB_WARN) {
-                       sprintf(tmp, "ISAC EXIR %02x", exval);
-                       debugl1(sp, tmp);
-               }
-       }
+       writereg(cs->hw.avm.hscx[hscx], offset, value);
 }
 
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
+/*
+ * fast interrupt HSCX stuff goes here
+ */
 
-       u_char exval;
-       struct HscxState *hsp;
-       char tmp[32];
+#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 *) irq2dev_map[intno];
-
-       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:
+                       inithscxisac(cs, 1);
+                       byteout(cs->hw.avm.cfg_reg, 0x16);
+                       byteout(cs->hw.avm.cfg_reg, 0x1E);
+                       inithscxisac(cs, 2);
+                       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.interrupts[sp->irq];
-       sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
-       debugl1(sp, tmp);
-       clear_pending_ints(sp);
-       ret = get_irq(sp->cardnr, &avm_a1_interrupt);
-       if (ret) {
-               initisac(sp);
-               sp->modehscx(sp->hs, 0, 0);
-               sp->modehscx(sp->hs + 1, 0, 0);
-               while (loop++ < 10) {
-                       /* At least 1-3 irqs must happen
-                        * (one from HSCX A, one from HSCX B, 3rd from ISAC)
-                        */
-                       if (kstat.interrupts[sp->irq] > sp->counter)
-                               break;
-                       current->state = TASK_INTERRUPTIBLE;
-                       current->timeout = jiffies + 1;
-                       schedule();
-               }
-               sprintf(tmp, "IRQ %d count %d", sp->irq,
-                       kstat.interrupts[sp->irq]);
-               debugl1(sp, tmp);
-               if (kstat.interrupts[sp->irq] == sp->counter) {
-                       printk(KERN_WARNING
-                              "AVM A1: IRQ(%d) getting no interrupts during init\n",
-                              sp->irq);
-                       irq2dev_map[sp->irq] = NULL;
-                       free_irq(sp->irq, NULL);
-                       return (0);
-               }
-       }
-       return (ret);
-}
-
-int
-setup_avm_a1(struct IsdnCard *card)
-{
-       u_char val, verA, verB;
-       struct IsdnCardState *sp = card->sp;
+       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);
+       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);
 }
index 91c8689420823f2459f7d2a61c8da45944637b84..3cb5f9ce7c4f30d8e36a92c6444a3d1180813bce 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 1.30 1997/05/29 10:40:43 keil Exp $
+/* $Id: callc.c,v 1.30.2.9 1998/05/27 18:04:53 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: callc.c,v $
- * Revision 1.30  1997/05/29 10:40:43  keil
- * chanp->impair was uninitialised
+ * Revision 1.30.2.9  1998/05/27 18:04:53  keil
+ * HiSax 3.0
  *
- * Revision 1.29  1997/04/23 20:09:49  fritz
- * Removed tmp, used by removed debugging code.
+ * Revision 1.30.2.8  1998/04/11 18:48:26  keil
+ * remove debug
  *
- * Revision 1.28  1997/04/21 13:42:25  keil
- * Remove unneeded debug
+ * Revision 1.30.2.7  1998/04/08 21:51:50  keil
+ * new debug
  *
- * Revision 1.27  1997/04/16 14:21:01  keil
- * remove unused variable
+ * Revision 1.30.2.6  1998/03/07 23:15:02  tsbogend
+ * made HiSax working on Linux/Alpha
  *
- * Revision 1.26  1997/04/13 19:55:21  keil
- * Changes in debugging code
+ * Revision 1.30.2.5  1998/02/09 11:24:17  keil
+ * New leased line support (Read README.HiSax!)
  *
- * Revision 1.25  1997/04/06 22:54:08  keil
- * Using SKB's
+ * Revision 1.30.2.4  1998/01/27 22:46:00  keil
+ * B-channel send delay now configurable
  *
- * Revision 1.24  1997/03/05 11:28:03  keil
- * fixed undefined l2tei procedure
- * a layer1 release delete now the drel timer
+ * Revision 1.30.2.3  1998/01/11 23:21:03  keil
+ * Missing callc state
  *
- * Revision 1.23  1997/03/04 23:07:42  keil
- * bugfix dial parameter
+ * Revision 1.30.2.2  1997/11/15 18:54:31  keil
+ * cosmetics
  *
- * Revision 1.22  1997/02/27 13:51:55  keil
- * Reset B-channel (dlc) statemachine in every release
+ * Revision 1.30.2.1  1997/10/17 22:13:32  keil
+ * update to last hisax version
  *
- * Revision 1.21  1997/02/19 09:24:27  keil
- * Bugfix: Hangup to LL if a ttyI rings
+ * Revision 2.6  1997/09/11 17:26:58  keil
+ * Open B-channel if here are incomming packets
  *
- * Revision 1.20  1997/02/17 00:32:47  keil
- * Bugfix: No Busy reported to LL
+ * Revision 2.5  1997/08/07 17:46:05  keil
+ * Fix Incomming Call without broadcast
  *
- * Revision 1.19  1997/02/14 12:23:10  fritz
- * Added support for new insmod parameter handling.
+ * Revision 2.4  1997/08/03 14:37:58  keil
+ * Activate Layer2 in PtP mode
  *
- * Revision 1.18  1997/02/11 01:36:58  keil
- * Changed setup-interface (incoming and outgoing), cause reporting
+ * Revision 2.3  1997/07/31 19:23:40  keil
+ * LAYER2_WATCHING for PtP
  *
- * 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.2  1997/07/31 11:48:18  keil
+ * experimental REJECT after ALERTING
  *
- * Revision 1.16  1997/01/27 23:17:03  keil
- * delete timers while unloading
+ * Revision 2.1  1997/07/30 17:12:59  keil
+ * more changes for 'One TEI per card'
  *
- * Revision 1.15  1997/01/27 16:00:38  keil
- * D-channel shutdown delay; improved callback
+ * Revision 2.0  1997/07/27 21:12:21  keil
+ * CRef based L3; new channel handling; many other stuff
  *
- * Revision 1.14  1997/01/21 22:16:39  keil
- * new statemachine; leased line support; cleanup for 2.0
+ * Revision 1.31  1997/06/26 11:09:23  keil
+ * New managment and minor changes
  *
- * 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
  *
  */
 
 #define __NO_VERSION__
 #include "hisax.h"
+#include "../avmb1/capicmd.h"  /* this should be moved in a common place */
 
 #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: 1.30.2.9 $";
 
 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};
-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
+#define  FLG_RESUME    16
 
 /*
  * 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 40000
 
 /*
  * Find card with given driverId
@@ -162,12 +135,25 @@ 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;
 }
 
+int
+discard_queue(struct sk_buff_head *q)
+{
+       struct sk_buff *skb;
+       int ret=0;
+
+       while ((skb = skb_dequeue(q))) {
+               dev_kfree_skb(skb, FREE_READ);
+               ret++;
+       }
+       return(ret);
+}
+
 static void
 link_debug(struct Channel *chanp, char *s, int direction)
 {
@@ -176,7 +162,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 +219,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 +249,7 @@ static char *strEvent[] =
        "EV_SETUP_CMPL_IND",
        "EV_BC_EST",
        "EV_WRITEBUF",
-       "EV_DATAIN",
+       "EV_ESTABLISH",
        "EV_HANGUP",
        "EV_BC_REL",
        "EV_CINF",
@@ -276,1105 +262,1045 @@ static char *strEvent[] =
        "EV_RELEASE_ERR",
 };
 
-enum {
-       ST_LC_NULL,
-       ST_LC_ACTIVATE_WAIT,
-       ST_LC_DELAY,
-       ST_LC_ESTABLISH_WAIT,
-       ST_LC_CONNECTED,
-       ST_LC_FLUSH_WAIT,
-       ST_LC_FLUSH_DELAY,
-       ST_LC_RELEASE_WAIT,
-};
-
-#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
-
-static char *strLcState[] =
-{
-       "ST_LC_NULL",
-       "ST_LC_ACTIVATE_WAIT",
-       "ST_LC_DELAY",
-       "ST_LC_ESTABLISH_WAIT",
-       "ST_LC_CONNECTED",
-       "ST_LC_FLUSH_WAIT",
-       "ST_LC_FLUSH_DELAY",
-       "ST_LC_RELEASE_WAIT",
-};
-
-enum {
-       EV_LC_ESTABLISH,
-       EV_LC_PH_ACTIVATE,
-       EV_LC_PH_DEACTIVATE,
-       EV_LC_DL_ESTABLISH,
-       EV_LC_TIMER,
-       EV_LC_DL_FLUSH,
-       EV_LC_DL_RELEASE,
-       EV_LC_FLUSH,
-       EV_LC_RELEASE,
-};
-
-#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
-
-static char *strLcEvent[] =
-{
-       "EV_LC_ESTABLISH",
-       "EV_LC_PH_ACTIVATE",
-       "EV_LC_PH_DEACTIVATE",
-       "EV_LC_DL_ESTABLISH",
-       "EV_LC_TIMER",
-       "EV_LC_DL_FLUSH",
-       "EV_LC_DL_RELEASE",
-       "EV_LC_FLUSH",
-       "EV_LC_RELEASE",
-};
-
-#define LC_D  0
-#define LC_B  1
-
 static inline void
-l4_deliver_cause(struct Channel *chanp)
+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 *) (long)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 *) (long)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;
-       switch (chanp->l2_active_protocol) {
-               case (ISDN_PROTO_L2_X75I):
-                       chanp->lc_b.l2_establish = !0;
-                       break;
-               case (ISDN_PROTO_L2_HDLC):
-               case (ISDN_PROTO_L2_TRANS):
-                       chanp->lc_b.l2_establish = 0;
-                       break;
-               default:
-                       printk(KERN_WARNING "l4_prep_dialout unknown protocol\n");
-                       break;
-       }
-       if (chanp->Flags & FLG_ESTAB_D) {
+       if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
                FsmEvent(fi, EV_DLEST, NULL);
        } else {
-               chanp->Flags = FLG_START_D;
-               if (chanp->leased) {
-                       chanp->lc_d.l2_establish = 0;
-               }
-               FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+               chanp->Flags = 0;
+               if (EV_RESUME == event)
+                       test_and_set_bit(FLG_RESUME, &chanp->Flags);
+               test_and_set_bit(FLG_START_D, &chanp->Flags);
+               chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, 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;
+       int ev;
 
        FsmChangeState(fi, ST_OUT_DIAL);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan);
+       if (test_and_clear_bit(FLG_RESUME, &chanp->Flags))
+               ev = CC_RESUME | REQUEST;
+       else
+               ev = CC_SETUP | REQUEST;
        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, ev, 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);
+       chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, 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 *) (long)chanp->chan);
 }
 
+/*
+ * RESUME
+ */
+
 /* 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))
+               chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, 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 *) (long)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 | REQUEST, 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);
+                                       chanp->d_st->lli.l4l3(chanp->d_st,
+                                               DL_ESTABLISH | REQUEST, 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 | REQUEST, chanp->proc);
+                               chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
                                FsmChangeState(fi, ST_NULL);
-                               chanp->Flags = FLG_ESTAB_D;
-                               FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
+                               if (test_bit(FLG_ESTAB_D, &chanp->Flags) &&
+                                       !test_bit(FLG_PTP, &chanp->d_st->l2.flag))
+                                       FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
                                break;
                }
        } else {
-               chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
+               chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
                FsmChangeState(fi, ST_NULL);
-               chanp->Flags = FLG_ESTAB_D;
-               FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
+               if (test_bit(FLG_ESTAB_D, &chanp->Flags) &&
+                       !test_bit(FLG_PTP, &chanp->d_st->l2.flag))
+                       FsmRestartTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
+       }
+}
+
+static void
+lli_establish_d(struct FsmInst *fi, int event, void *arg)
+{
+       /* This establish the D-channel for pending L3 messages 
+        * without blocking the 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);
+       chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, 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 | RESPONSE, 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 | REQUEST, 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 | REQUEST, chanp->proc);
+               test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
        }
 }
 
 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 | RESPONSE, 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;
-       switch (chanp->l2_active_protocol) {
-               case (ISDN_PROTO_L2_X75I):
-                       chanp->lc_b.l2_establish = !0;
-                       break;
-               case (ISDN_PROTO_L2_HDLC):
-               case (ISDN_PROTO_L2_TRANS):
-                       chanp->lc_b.l2_establish = 0;
-                       break;
-               default:
-                       printk(KERN_WARNING "r9 unknown protocol\n");
-                       break;
-       }
-       init_ds(chanp, !0);
-       SETBIT(chanp->Flags, FLG_START_B);
-       FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+       init_b_st(chanp, !0);
+       test_and_set_bit(FLG_START_B, &chanp->Flags);
+       chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
 }
 
-/* Call clearing */
+/* Call suspend */
 
 static void
-l4_reject_call(struct FsmInst *fi, int event, void *arg)
+lli_suspend(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);
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
 }
 
+/* Call clearing */
+
 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);
+               chanp->cs->iif.statcallb(&ic);
        }
-       if (chanp->Flags & FLG_START_B) {
-               release_ds(chanp);
-               RESBIT(chanp->Flags, FLG_START_B);
-       }
-       chanp->para.cause = 0x10;       /* Normal Call Clearing */
-       chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-       SETBIT(chanp->Flags, FLG_DISC_SEND);
+       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 | REQUEST, 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);
+       if (test_bit(FLG_PTP, &chanp->d_st->l2.flag)) {
+       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);
+       chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL);
+       }
 }
 
 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);
+       if (!test_bit(FLG_PTP, &chanp->d_st->l2.flag))
        FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)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 *) (long)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);
+       chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, 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);
+               chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, 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 | REQUEST, 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);
+       chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, 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->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, 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->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, 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_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 | REQUEST, 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);
+       chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, 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 | REQUEST, chanp->proc);
        chanp->Flags = 0;
        FsmChangeState(fi, ST_NULL);
-       FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+       chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, 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->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, 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->Flags = 0;
-       chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
-       FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-}
-/* *INDENT-OFF* */
-static struct FsmNode fnlist[] =
-{
-       {ST_NULL,               EV_DIAL,                l4_prep_dialout},
-       {ST_NULL,               EV_SETUP_IND,           l4_start_dchan},
-       {ST_NULL,               EV_SHUTDOWN_D,          l4_shutdown_d},
-       {ST_NULL,               EV_DLRL,                l4_go_null},
-       {ST_OUT_WAIT_D,         EV_DLEST,               l4_do_dialout},
-       {ST_OUT_WAIT_D,         EV_DLRL,                l4_no_dchan},
-       {ST_OUT_WAIT_D,         EV_HANGUP,              l4_no_dchan},
-       {ST_IN_WAIT_D,          EV_DLEST,               l4_deliver_call},
-       {ST_IN_WAIT_D,          EV_DLRL,                l4_no_dchan_in},
-       {ST_IN_WAIT_D,          EV_HANGUP,              l4_no_dchan_in},
-       {ST_OUT_DIAL,           EV_SETUP_CNF,           l4_init_bchan_out},
-       {ST_OUT_DIAL,           EV_HANGUP,              l4_cancel_call},
-       {ST_OUT_DIAL,           EV_DISCONNECT_IND,      l4_received_d_disc},
-       {ST_OUT_DIAL,           EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_OUT_DIAL,           EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_OUT_DIAL,           EV_NOSETUP_RSP,         l4_no_setup_rsp},
-       {ST_OUT_DIAL,           EV_SETUP_ERR,           l4_setup_err},
-       {ST_IN_WAIT_LL,         EV_SETUP_CMPL_IND,      l4_init_bchan_in},
-       {ST_IN_WAIT_LL,         EV_ACCEPTD,             l4_send_dconnect},
-       {ST_IN_WAIT_LL,         EV_HANGUP,              l4_reject_call},
-       {ST_IN_WAIT_LL,         EV_DISCONNECT_IND,      l4_received_d_disc},
-       {ST_IN_WAIT_LL,         EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_IN_WAIT_LL,         EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_IN_ALERT_SEND,      EV_SETUP_CMPL_IND,      l4_init_bchan_in},
-       {ST_IN_ALERT_SEND,      EV_ACCEPTD,             l4_send_dconnect},
-       {ST_IN_ALERT_SEND,      EV_HANGUP,              l4_send_d_disc},
-       {ST_IN_ALERT_SEND,      EV_DISCONNECT_IND,      l4_received_d_disc},
-       {ST_IN_ALERT_SEND,      EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_IN_ALERT_SEND,      EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_IN_WAIT_CONN_ACK,   EV_SETUP_CMPL_IND,      l4_init_bchan_in},
-       {ST_IN_WAIT_CONN_ACK,   EV_HANGUP,              l4_send_d_disc},
-       {ST_IN_WAIT_CONN_ACK,   EV_DISCONNECT_IND,      l4_received_d_disc},
-       {ST_IN_WAIT_CONN_ACK,   EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_IN_WAIT_CONN_ACK,   EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_IN_WAIT_CONN_ACK,   EV_CONNECT_ERR,         l4_connect_err},
-       {ST_WAIT_BCONN,         EV_BC_EST,              l4_go_active},
-       {ST_WAIT_BCONN,         EV_BC_REL,              l4_send_d_disc},
-       {ST_WAIT_BCONN,         EV_HANGUP,              l4_send_d_disc},
-       {ST_WAIT_BCONN,         EV_DISCONNECT_IND,      l4_received_d_disc},
-       {ST_WAIT_BCONN,         EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_WAIT_BCONN,         EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_ACTIVE,             EV_CINF,                l4_charge_info},
-       {ST_ACTIVE,             EV_BC_REL,              l4_released_bchan},
-       {ST_ACTIVE,             EV_HANGUP,              l4_disconn_bchan},
-       {ST_ACTIVE,             EV_DISCONNECT_IND,      l4_release_bchan},
-       {ST_ACTIVE,             EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_ACTIVE,             EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_ACTIVE,             EV_DLRL,                l4_active_dlrl},
-       {ST_WAIT_BRELEASE,      EV_BC_REL,              l4_send_d_disc},
-       {ST_WAIT_BRELEASE,      EV_DISCONNECT_IND,      l4_received_d_disc},
-       {ST_WAIT_BRELEASE,      EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_WAIT_BRELEASE,      EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_WAIT_BREL_DISC,     EV_BC_REL,              l4_received_d_disc},
-       {ST_WAIT_BREL_DISC,     EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_WAIT_BREL_DISC,     EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_WAIT_DCOMMAND,      EV_HANGUP,              l4_send_d_disc},
-       {ST_WAIT_DCOMMAND,      EV_DISCONNECT_IND,      l4_received_d_disc},
-       {ST_WAIT_DCOMMAND,      EV_RELEASE_CNF,         l4_received_d_relcnf},
-       {ST_WAIT_DCOMMAND,      EV_RELEASE_IND,         l4_received_d_rel},
-       {ST_WAIT_DRELEASE,      EV_RELEASE_IND,         l4_timeout_d},
-       {ST_WAIT_DRELEASE,      EV_RELEASE_CNF,         l4_timeout_d},
-       {ST_WAIT_DRELEASE,      EV_RELEASE_ERR,         l4_timeout_d},
-       {ST_WAIT_DRELEASE,      EV_DIAL,                l4_no_dchan_ready},
-       {ST_WAIT_D_REL_CNF,     EV_RELEASE_CNF,         l4_timeout_d},
-       {ST_WAIT_D_REL_CNF,     EV_RELEASE_ERR,         l4_timeout_d},
-       {ST_WAIT_D_REL_CNF,     EV_DIAL,                l4_no_dchan_ready},
-       {ST_WAIT_DSHUTDOWN,     EV_DLRL,                l4_go_null},
-       {ST_WAIT_DSHUTDOWN,     EV_DIAL,                l4_prep_dialout},
-       {ST_WAIT_DSHUTDOWN,     EV_SETUP_IND,           l4_start_dchan},
-};
-/* *INDENT-ON* */
-
-
-
-
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
-
-static void
-lc_r1(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
-       FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
-       lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
-
-}
-
-static void
-lc_r6(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmDelTimer(&lf->act_timer, 50);
-       FsmChangeState(fi, ST_LC_DELAY);
-       FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
-}
-
-static void
-lc_r2(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       if (lf->l2_establish) {
-               FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
-               if (lf->l2_start)
-                       lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
-       } else {
-               FsmChangeState(fi, ST_LC_CONNECTED);
-               lf->lccall(lf, LC_ESTABLISH, NULL);
-       }
-}
-
-static void
-lc_r3(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmChangeState(fi, ST_LC_CONNECTED);
-       lf->lccall(lf, LC_ESTABLISH, NULL);
-}
-
-static void
-lc_r7(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmChangeState(fi, ST_LC_FLUSH_WAIT);
-       lf->st->ma.manl2(lf->st, DL_FLUSH, NULL);
-}
-
-static void
-lc_r4(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       if (lf->l2_establish) {
-               FsmChangeState(fi, ST_LC_RELEASE_WAIT);
-               lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
-               /* This timer is for releasing the channel even
-                * there is a hang in layer 2 ; 5 sec are a try
-                */
-               FsmAddTimer(&lf->act_timer, 5000, EV_LC_TIMER, NULL, 53);
+               chanp->cs->iif.statcallb(&ic);
+               chanp->Flags = 0;
        } else {
-               FsmChangeState(fi, ST_LC_NULL);
-               lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
-               lf->lccall(lf, LC_RELEASE, NULL);
+               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 | REQUEST, chanp->proc);
+               chanp->Flags = 0;
+               chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL);
        }
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 }
 
-static void
-lc_r4_1(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmChangeState(fi, ST_LC_FLUSH_DELAY);
-       FsmAddTimer(&lf->act_timer, 50, EV_LC_TIMER, NULL, 52);
-}
-
-static void
-lc_r5_1(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmChangeState(fi, ST_LC_RELEASE_WAIT);
-       /* This delay is needed for send out the UA frame before
-        * PH_DEACTIVATE the interface
-        */
-       FsmAddTimer(&lf->act_timer, 10, EV_LC_TIMER, NULL, 54);
-}
-
-static void
-lc_r5(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmDelTimer(&lf->act_timer, 54);
-       FsmChangeState(fi, ST_LC_NULL);
-       lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
-       lf->lccall(lf, LC_RELEASE, NULL);
-}
 /* *INDENT-OFF* */
-static struct FsmNode LcFnList[] =
-{
-       {ST_LC_NULL,            EV_LC_ESTABLISH,        lc_r1},
-       {ST_LC_ACTIVATE_WAIT,   EV_LC_PH_ACTIVATE,      lc_r6},
-       {ST_LC_DELAY,           EV_LC_TIMER,            lc_r2},
-       {ST_LC_DELAY,           EV_LC_DL_ESTABLISH,     lc_r3},
-       {ST_LC_ESTABLISH_WAIT,  EV_LC_DL_ESTABLISH,     lc_r3},
-       {ST_LC_ESTABLISH_WAIT,  EV_LC_RELEASE,          lc_r5},
-       {ST_LC_CONNECTED,       EV_LC_FLUSH,            lc_r7},
-       {ST_LC_CONNECTED,       EV_LC_RELEASE,          lc_r4},
-       {ST_LC_CONNECTED,       EV_LC_DL_RELEASE,       lc_r5_1},
-       {ST_LC_FLUSH_WAIT,      EV_LC_DL_FLUSH,         lc_r4_1},
-       {ST_LC_FLUSH_DELAY,     EV_LC_TIMER,            lc_r4},
-       {ST_LC_RELEASE_WAIT,    EV_LC_DL_RELEASE,       lc_r5},
-       {ST_LC_RELEASE_WAIT,    EV_LC_TIMER,            lc_r5},
-       {ST_LC_ACTIVATE_WAIT,   EV_LC_TIMER,            lc_r5},
-       {ST_LC_ESTABLISH_WAIT,  EV_LC_DL_RELEASE,       lc_r5},
+static struct FsmNode fnlist[] HISAX_INITDATA =
+{
+       {ST_NULL,               EV_DIAL,                lli_prep_dialout},
+       {ST_NULL,               EV_RESUME,              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_SUSPEND,             lli_suspend},
+       {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_RESUME,              lli_prep_dialout},
+       {ST_WAIT_DSHUTDOWN,     EV_SETUP_IND,           lli_deliver_call},
 };
 /* *INDENT-ON* */
 
 
+#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
 
-
-
-
-
-
-
-
-#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;
        callcfsm.strEvent = strEvent;
        callcfsm.strState = strState;
        FsmNew(&callcfsm, fnlist, FNCOUNT);
-
-       lcfsm.state_count = LC_STATE_COUNT;
-       lcfsm.event_count = LC_EVENT_COUNT;
-       lcfsm.strEvent = strLcEvent;
-       lcfsm.strState = strLcState;
-       FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
 }
 
 void
 CallcFree(void)
 {
-       FsmFree(&lcfsm);
        FsmFree(&callcfsm);
 }
 
 static void
-release_ds(struct Channel *chanp)
+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);
                        break;
                case (ISDN_PROTO_L2_HDLC):
                case (ISDN_PROTO_L2_TRANS):
+//             case (ISDN_PROTO_L2_MODEM):
                        releasestack_transl2(st);
                        break;
        }
-       /* Reset B-Channel Statemachine */
-       FsmDelTimer(&chanp->lc_b.act_timer, 79);
-       FsmChangeState(&chanp->lc_b.lcfi, ST_LC_NULL);
 }
 
-static void
-cc_l1man(struct PStack *st, int pr, void *arg)
+struct Channel
+*selectfreechannel(struct PStack *st)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+       struct Channel *chanp = st->lli.userdata;
+       int i;
 
-       switch (pr) {
-               case (PH_ACTIVATE):
-                       FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
-                       break;
-               case (PH_DEACTIVATE):
-                       FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
-                       break;
-       }
+       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);
 }
 
-static void
-cc_l2man(struct PStack *st, int pr, void *arg)
+int
+is_activ(struct PStack *st)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+       struct Channel *chanp = st->lli.userdata;
+       int i;
 
-       switch (pr) {
-               case (DL_ESTABLISH):
-                       FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
-                       break;
-               case (DL_RELEASE):
-                       FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
-                       break;
-               case (DL_FLUSH):
-                       FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_FLUSH, NULL);
-                       break;
-       }
+       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
-dcc_l1man(struct PStack *st, int pr, void *arg)
+dchan_l3l4(struct PStack *st, int pr, void *arg)
 {
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
-       switch (pr) {
-               case (PH_ACTIVATE):
-                       FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
-                       break;
-               case (PH_DEACTIVATE):
-                       FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
-                       break;
-       }
-}
+       struct l3_process *pc = arg;
+       struct IsdnCardState *cs = st->l1.hardware;
+       struct Channel *chanp;
+       int event;
+       char tmp[64], tm[32];
 
-static void
-dcc_l2man(struct PStack *st, int pr, void *arg)
-{
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
 
        switch (pr) {
-               case (DL_ESTABLISH):
-                       FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
+               case (DL_ESTABLISH | INDICATION):
+                       event = EV_DLEST;
                        break;
-               case (DL_RELEASE):
-                       FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
+               case (DL_RELEASE | INDICATION):
+                       event = EV_DLRL;
+                       break;
+               default:
+                       event = -1;
                        break;
        }
-}
-
-static void
-l2tei_dummy(struct PStack *st, int pr, void *arg)
-{
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
-       char tmp[64], tm[32];
-
-       jiftime(tm, jiffies);
-       sprintf(tmp, "%s Channel %d Warning! Dummy l2tei called pr=%d\n", tm, chanp->chan, pr);
-       HiSax_putstatus(chanp->sp, tmp);
-}
-
-static void
-ll_handler(struct PStack *st, int pr, void *arg)
-{
-       struct Channel *chanp = (struct Channel *) st->l4.userdata;
-       char tmp[64], tm[32];
-
+       if (event >= 0) {
+               int i;
+               
+               chanp = st->lli.userdata;
+               if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
+                       i = 1;
+               else
+                       i = 0;
+               while (i < 2) {
+                       FsmEvent(&chanp->fi, event, NULL);
+                       chanp++;
+                       i++;
+               }
+                       return;
+       } else if (pr == (CC_SETUP | INDICATION)) {
+               if (!(chanp = selectfreechannel(pc->st))) {
+                       pc->st->lli.l4l3(pc->st, CC_DLRL | REQUEST, pc);
+               } else {
+                       chanp->proc = pc;
+                       pc->chan = chanp;
+                       FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+               }
+                       return;
+               }
+       chanp = pc->chan;
        switch (pr) {
-               case (CC_DISCONNECT_IND):
+               case (CC_DISCONNECT | INDICATION):
                        FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
                        break;
-               case (CC_RELEASE_CNF):
+               case (CC_RELEASE | CONFIRM):
                        FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
                        break;
-               case (CC_SETUP_IND):
-                       FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+               case (CC_SUSPEND | CONFIRM):
+                       FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
+                       break;
+               case (CC_RESUME | CONFIRM):
+                       FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
+                       break;
+               case (CC_RESUME_ERR):
+                       FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
                        break;
-               case (CC_RELEASE_IND):
+               case (CC_RELEASE | INDICATION):
                        FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
                        break;
-               case (CC_SETUP_COMPLETE_IND):
+               case (CC_SETUP_COMPL | INDICATION):
                        FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
                        break;
-               case (CC_SETUP_CNF):
+               case (CC_SETUP | CONFIRM):
                        FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
                        break;
-               case (CC_INFO_CHARGE):
+               case (CC_CHARGE | INDICATION):
                        FsmEvent(&chanp->fi, EV_CINF, NULL);
                        break;
-               case (CC_NOSETUP_RSP_ERR):
+               case (CC_NOSETUP_RSP):
                        FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL);
                        break;
                case (CC_SETUP_ERR):
@@ -1386,49 +1312,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 | INDICATION):
+               case (CC_ALERTING | INDICATION):
+                       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  */
-       }
-       sprintf(tmp, "Channel %d q.921", chanp->chan);
+       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  */
+       if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
+               sprintf(tmp, "DCh%d Q.921", chanp->chan);
+       else
+               sprintf(tmp, "DCh Q.921");
        setstack_isdnl2(st, tmp);
-       setstack_isdnl3(st, chanp);
-       st->l4.userdata = chanp;
-       st->l4.l2writewakeup = NULL;
-       st->l3.l3l4 = ll_handler;
-       st->l1.l1man = cc_l1man;
-       st->l2.l2man = cc_l2man;
-       st->pa = &chanp->para;
-       HiSax_addlist(sp, st);
+       setstack_l3dc(st, chanp);
+       st->lli.userdata = chanp;
+       st->lli.l2writewakeup = NULL;
+       st->l3.l3l4 = dchan_l3l4;
 }
 
 static void
@@ -1439,77 +1367,44 @@ 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);
-}
-
-static void
-lc_debug(struct FsmInst *fi, char *s)
-{
-       char str[256], tm[32];
-       struct LcFsm *lf = fi->userdata;
-
-       jiftime(tm, jiffies);
-       sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
-       HiSax_putstatus(lf->ch->sp, str);
-}
-
-static void
-dlc_debug(struct FsmInst *fi, char *s)
-{
-       char str[256], tm[32];
-       struct LcFsm *lf = fi->userdata;
-
-       jiftime(tm, jiffies);
-       sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
-       HiSax_putstatus(lf->ch->sp, str);
+       HiSax_putstatus(chanp->cs, str);
 }
 
 static void
-lccall_d(struct LcFsm *lf, int pr, void *arg)
-{
-       struct Channel *chanp = lf->ch;
-
-       switch (pr) {
-               case (LC_ESTABLISH):
-                       FsmEvent(&chanp->fi, EV_DLEST, NULL);
-                       break;
-               case (LC_RELEASE):
-                       FsmEvent(&chanp->fi, EV_DLRL, NULL);
-                       break;
-       }
+dummy_pstack(struct PStack *st, int pr, void *arg) {
+       printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg);
 }
 
 static void
-lccall_b(struct LcFsm *lf, int pr, void *arg)
-{
-       struct Channel *chanp = lf->ch;
-
-       switch (pr) {
-               case (LC_ESTABLISH):
-                       FsmEvent(&chanp->fi, EV_BC_EST, NULL);
-                       break;
-               case (LC_RELEASE):
-                       FsmEvent(&chanp->fi, EV_BC_REL, NULL);
-                       break;
-       }
+init_PStack(struct PStack **stp) {
+       *stp = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+       (*stp)->next = NULL;
+       (*stp)->l1.l1l2 = dummy_pstack;
+       (*stp)->l1.l1hw = dummy_pstack;
+       (*stp)->l1.l1tei = dummy_pstack;
+       (*stp)->l2.l2tei = dummy_pstack;
+       (*stp)->l2.l2l1 = dummy_pstack;
+       (*stp)->l2.l2l3 = dummy_pstack;
+       (*stp)->l3.l3l2 = dummy_pstack;
+       (*stp)->l3.l3l4 = dummy_pstack;
+       (*stp)->lli.l4l3 = dummy_pstack;
+       (*stp)->ma.layer = dummy_pstack;
 }
 
 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);
-
+       init_PStack(&chanp->b_st);
+       chanp->b_st->l1.delay = DEFAULT_B_DELAY;
        chanp->fi.fsm = &callcfsm;
        chanp->fi.state = ST_NULL;
        chanp->fi.debug = 0;
@@ -1517,58 +1412,46 @@ 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)) {
+               init_PStack(&chanp->d_st);
+               if (chan)
+                       csta->channel->d_st->next = chanp->d_st;
+               chanp->d_st->next = NULL;
+               init_d_st(chanp);
+       } else {
+               chanp->d_st = csta->channel->d_st;
+       }
        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");
+       if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
+               printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
+       test_and_set_bit(FLG_START_D, &csta->channel->Flags);
+       csta->channel->d_st->lli.l4l3(csta->channel->d_st,
+               DL_ESTABLISH | REQUEST, NULL);
+       }
        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,30 +1462,44 @@ 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);
-               }
-               release_is(csta->channel + i);
+               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 (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+                       release_d_st(csta->channel + 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):
+               case (DL_DATA  | INDICATION):
                        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, FREE_READ);
                        }
                        break;
+               case (DL_ESTABLISH | INDICATION):
+               case (DL_ESTABLISH | CONFIRM):
+                       FsmEvent(&chanp->fi, EV_BC_EST, NULL);
+                       break;
+               case (DL_RELEASE | INDICATION):
+               case (DL_RELEASE | CONFIRM):
+                       FsmEvent(&chanp->fi, EV_BC_REL, NULL);
+                       break;
                default:
                        printk(KERN_WARNING "lldata_handler unknown primitive %d\n",
                               pr);
@@ -1613,18 +1510,26 @@ 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 | INDICATION):
                        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);
+                               link_debug(chanp, "channel not open", 0);
                                dev_kfree_skb(skb, FREE_READ);
                        }
                        break;
+               case (PH_ACTIVATE | INDICATION):
+               case (PH_ACTIVATE | CONFIRM):
+                       FsmEvent(&chanp->fi, EV_BC_EST, NULL);
+                       break;
+               case (PH_DEACTIVATE | INDICATION):
+               case (PH_DEACTIVATE | CONFIRM):
+                       FsmEvent(&chanp->fi, EV_BC_REL, NULL);
+                       break;
                default:
                        printk(KERN_WARNING "lltrans_handler unknown primitive %d\n",
                               pr);
@@ -1633,78 +1538,139 @@ 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;
+       switch (chanp->l2_active_protocol) {
+               case (ISDN_PROTO_L2_X75I):
+               case (ISDN_PROTO_L2_HDLC):
+                       st->l1.mode = L1_MODE_HDLC;
+                       break;
+               case (ISDN_PROTO_L2_TRANS):
+                       st->l1.mode = L1_MODE_TRANS;
+                       break;
+#if 0
+               case (ISDN_PROTO_L2_MODEM):
+                       st->l1.mode = L1_MODE_MODEM;
+                       break;
+#endif
+       }
+       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);
+                       sprintf(tmp, "Ch%d X.75", chanp->chan);
                        setstack_isdnl2(st, tmp);
+                       setstack_l3bc(st, chanp);
                        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->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;
                        break;
                case (ISDN_PROTO_L2_HDLC):
-                       st->l1.l1l2 = lltrans_handler;
-                       st->l1.l1man = dcc_l1man;
-                       st->l4.userdata = chanp;
-                       st->l4.l1writewakeup = ll_writewakeup;
-                       st->l1.hscxmode = 2;
-                       st->l1.hscxchannel = chanp->para.bchannel - 1;
-                       break;
                case (ISDN_PROTO_L2_TRANS):
+//             case (ISDN_PROTO_L2_MODEM):
                        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->lli.userdata = chanp;
+                       st->lli.l1writewakeup = ll_writewakeup;
+                       setstack_transl2(st);
+                       setstack_l3bc(st, chanp);
                        break;
        }
+                       if (chanp->leased)
+                               st->l1.bc = chanp->chan & 1;
+                       else
+                               st->l1.bc = chanp->proc->para.bchannel - 1;
        return (0);
 }
 
+static void
+leased_l4l3(struct PStack *st, int pr, void *arg)
+{
+       struct Channel *chanp = (struct Channel *) st->lli.userdata;
+       struct sk_buff *skb = arg;
+
+       switch (pr) {
+               case (DL_DATA | REQUEST):
+                       link_debug(chanp, "leased line d-channel DATA", 0);
+                       dev_kfree_skb(skb, FREE_READ);
+                       break;
+               case (DL_ESTABLISH | REQUEST):
+                       st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
+                       break;
+               case (DL_RELEASE | REQUEST):
+                       break;
+               default:
+                       printk(KERN_WARNING "transd_l4l3 unknown primitive %d\n",
+                              pr);
+                       break;
+       }
+}
+
+static void
+leased_l1l2(struct PStack *st, int pr, void *arg)
+{
+       struct Channel *chanp = (struct Channel *) st->lli.userdata;
+       struct sk_buff *skb = arg;
+       int i,event = EV_DLRL;
+
+       switch (pr) {
+               case (PH_DATA | INDICATION):
+                       link_debug(chanp, "leased line d-channel DATA", 0);
+                       dev_kfree_skb(skb, FREE_READ);
+                       break;
+               case (PH_ACTIVATE | INDICATION):
+               case (PH_ACTIVATE | CONFIRM):
+                       event = EV_DLEST;
+               case (PH_DEACTIVATE | INDICATION):
+               case (PH_DEACTIVATE | CONFIRM):
+                       if (test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags))
+                               i = 1;
+                       else
+                               i = 0;
+                       while (i < 2) {
+                               FsmEvent(&chanp->fi, event, NULL);
+                               chanp++;
+                               i++;
+                       }
+                       break;
+               default:
+                       printk(KERN_WARNING
+                               "transd_l1l2 unknown primitive %d\n", pr);
+                       break;
+       }
+}
+
 static void
 channel_report(struct Channel *chanp)
 {
@@ -1719,17 +1685,75 @@ 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].d_st->l3.l3m.debug = debugflags & 0x80;
+               chanp[i].b_st->l3.l3m.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;
 }
 
+#if 0
+static void
+capi_debug(struct Channel *chanp, capi_msg *cm)
+{
+       char tmp[256], tm[32];
+       char *t = tmp;
+
+       jiftime(tm, jiffies);
+       t += sprintf(tmp, "%s Channel %d CAPIMSG", tm, chanp->chan);
+       t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length);
+       t--;
+       *t++ ='\n';
+       *t++ = 0;
+       HiSax_putstatus(chanp->cs, tmp);
+}
+
+void
+lli_got_fac_req(struct Channel *chanp, capi_msg *cm) {
+       if ((cm->para[0] != 3) || (cm->para[1] != 0))
+               return;
+       if (cm->para[2]<3)
+               return;
+       if (cm->para[4] != 0)
+               return;
+       switch(cm->para[3]) {
+               case 4: /* Suspend */
+                       if (cm->para[5]) {
+                               strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
+                               FsmEvent(&chanp->fi, EV_SUSPEND, cm);
+                       }
+                       break;
+               case 5: /* Resume */
+                       if (cm->para[5]) {
+                               strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] +1);
+                               if (chanp->fi.state == ST_NULL) {
+                                       FsmEvent(&chanp->fi, EV_RESUME, cm);
+                               } else {
+                                       FsmDelTimer(&chanp->dial_timer, 72);
+                                       FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73);
+                               }
+                       }
+                       break;
+       }
+}
+
+void
+lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) {
+       if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) ||
+               (cs->typ == ISDN_CTYPE_ELSA_PCI)) {
+               if (cs->hw.elsa.MFlag) {
+                       cs->cardmsg(cs, CARD_AUX_IND, cm->para);
+               }
+       }       
+}
+#endif
+
 int
 HiSax_command(isdn_ctrl * ic)
 {
@@ -1745,12 +1769,12 @@ HiSax_command(isdn_ctrl * ic)
                       ic->command, ic->driver);
                return -ENODEV;
        }
+       
        switch (ic->command) {
                case (ISDN_CMD_SETEAZ):
                        chanp = csta->channel + ic->arg;
-                       if (chanp->debug & 1)
-                               link_debug(chanp, "SETEAZ", 1);
                        break;
+               
                case (ISDN_CMD_SETL2):
                        chanp = csta->channel + (ic->arg & 0xff);
                        if (chanp->debug & 1) {
@@ -1768,9 +1792,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) {
@@ -1798,26 +1822,31 @@ HiSax_command(isdn_ctrl * ic)
                                link_debug(chanp, "HANGUP", 1);
                        FsmEvent(&chanp->fi, EV_HANGUP, NULL);
                        break;
-               case (ISDN_CMD_SUSPEND):
+#if 0
+               case (CAPI_PUT_MESSAGE):
                        chanp = csta->channel + ic->arg;
-                       if (chanp->debug & 1) {
-                               sprintf(tmp, "SUSPEND %s", ic->parm.num);
-                               link_debug(chanp, tmp, 1);
-                       }
-                       FsmEvent(&chanp->fi, EV_SUSPEND, ic);
+                       if (chanp->debug & 1)
+                               capi_debug(chanp, &ic->parm.cmsg);
+                       if (ic->parm.cmsg.Length < 8)
+                               break;
+                       switch(ic->parm.cmsg.Command) {
+                               case CAPI_FACILITY:
+                                       if (ic->parm.cmsg.Subcommand == CAPI_REQ)
+                                               lli_got_fac_req(chanp, &ic->parm.cmsg);
+                                       break;
+                               case CAPI_MANUFACTURER:
+                                       if (ic->parm.cmsg.Subcommand == CAPI_REQ)
+                                               lli_got_manufacturer(chanp, csta, &ic->parm.cmsg);
+                                       break;
+                               default:
                        break;
-               case (ISDN_CMD_RESUME):
-                       chanp = csta->channel + ic->arg;
-                       if (chanp->debug & 1) {
-                               sprintf(tmp, "RESUME %s", ic->parm.num);
-                               link_debug(chanp, tmp, 1);
                        }
-                       FsmEvent(&chanp->fi, EV_RESUME, ic);
                        break;
+#endif
                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 +1857,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 +1881,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].b_st->l1.delay = num;
+                                       csta->channel[1].b_st->l1.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 +1898,72 @@ 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);
+                                       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--;
+                                               chanp = csta->channel +num;
+                                               chanp->leased = 1;
+                                               sprintf(tmp, "card %d channel %d set leased mode\n",
+                                                       csta->cardnr + 1, num + 1);
+                                               HiSax_putstatus(csta, tmp);
+                                               chanp->d_st->l1.l1l2 = leased_l1l2;
+                                               chanp->d_st->lli.l4l3 = leased_l4l3;
+                                               chanp->d_st->lli.l4l3(chanp->d_st,
+                                                       DL_ESTABLISH | REQUEST, NULL);
+                                       }
+                                       break;
+                               case (6):       /* set B-channel test loop */
+                                       num = *(unsigned int *) ic->parm.num;
+                                       if (csta->stlist)
+                                               csta->stlist->l2.l2l1(csta->stlist,
+                                                       PH_TESTLOOP | REQUEST, (void *) (long)num);
+                                       break;
+                               case (7):       /* set card in PTP mode */
+                                       if (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+                                               printk(KERN_ERR "HiSax PTP mode only with one TEI possible\n");
+                                       } else {
+                                               test_and_set_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
+                                               test_and_set_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
+                                               csta->channel[0].d_st->l2.tei = 0;
+                                               sprintf(tmp, "set card in PTP mode\n");
+                                               HiSax_putstatus(csta, tmp);
+                                               printk(KERN_DEBUG "HiSax: %s", tmp);
+                                       }
+                                       break;
+                               case (8):       /* set card in FIXED TEI mode */
+                                       num = *(unsigned int *) ic->parm.num;
+                                       chanp = csta->channel + (num & 1);
+                                       num = num >>1;
+                                       test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag);
+                                       chanp->d_st->l2.tei = num;
+                                       sprintf(tmp, "set card in FIXED TEI (%d) mode\n", num);
                                        HiSax_putstatus(csta, tmp);
+                                       printk(KERN_DEBUG "HiSax: %s", tmp);
                                        break;
 #ifdef MODULE
                                case (55):
-#if (LINUX_VERSION_CODE < 0x020111)
-                                       MOD_USE_COUNT = MOD_VISITED;
-#else
                                        MOD_USE_COUNT = 0;
-#endif
                                        HiSax_mod_inc_use_count();
                                        break;
 #endif                         /* MODULE */
                                case (11):
                                        csta->debug = *(unsigned int *) ic->parm.num;
                                        sprintf(tmp, "l1 debugging flags card %d set to %x\n",
-                                         csta->cardnr + 1, csta->debug);
-                                       HiSax_putstatus(cards[0].sp, tmp);
+                                               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:
@@ -1933,7 +1996,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 +2008,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 +2022,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->l2_active_protocol == ISDN_PROTO_L2_X75I)
+                               st->l3.l3l2(st, DL_DATA | REQUEST, nskb);
+                       else {
+                               chanp->bcs->tx_cnt += len;
+                               st->l2.l2l1(st, PH_DATA | REQUEST, nskb);
                        }
                        dev_kfree_skb(skb, FREE_WRITE);
                } else
index 595fb713e56ad7662c0b4fba9ef0992c8c8aa99c..f23309cc404ed7092deba6c871ef03a9abb9c8a3 100644 (file)
@@ -1,58 +1,54 @@
-/* $Id: config.c,v 1.15 1997/04/06 22:57:24 keil Exp $
+/* $Id: config.c,v 1.15.2.11 1998/05/27 18:05:07 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
  *
  *
  * $Log: config.c,v $
- * Revision 1.15  1997/04/06 22:57:24  keil
- * Hisax version 2.1
+ * Revision 1.15.2.11  1998/05/27 18:05:07  keil
+ * HiSax 3.0
  *
- * Revision 1.14  1997/03/25 23:11:22  keil
- * US NI-1 protocol
+ * Revision 1.15.2.10  1998/04/11 18:43:13  keil
+ * New cards
  *
- * Revision 1.13  1997/03/23 21:45:49  keil
- * Add support for ELSA PCMCIA
+ * Revision 1.15.2.9  1998/03/07 23:15:12  tsbogend
+ * made HiSax working on Linux/Alpha
  *
- * Revision 1.12  1997/03/11 21:01:43  keil
- * nzproto is only used with modules
+ * Revision 1.15.2.8  1998/02/11 19:21:37  keil
+ * fix typo
  *
- * Revision 1.11  1997/02/14 12:23:12  fritz
- * Added support for new insmod parameter handling.
+ * Revision 1.15.2.7  1998/02/11 14:23:08  keil
+ * support for Dr Neuhaus Niccy PnP and PCI
  *
- * Revision 1.10  1997/02/14 09:22:09  keil
- * Final 2.0 version
+ * Revision 1.15.2.6  1998/02/09 11:21:19  keil
+ * Sedlbauer PCMCIA support from Marcus Niemann
  *
- * Revision 1.9  1997/02/10 11:45:09  fritz
- * More changes for Kernel 2.1.X compatibility.
+ * Revision 1.15.2.5  1998/01/27 23:28:48  keil
+ * v2.8
  *
- * Revision 1.8  1997/02/09 00:28:05  keil
- * new interface handling, one interface per card
- * default protocol now works again
+ * Revision 1.15.2.4  1998/01/27 22:33:53  keil
+ * dynalink ----> asuscom
  *
- * Revision 1.7  1997/01/27 15:56:57  keil
- * Teles PCMCIA ITK ix1 micro added
+ * Revision 1.15.2.3  1998/01/11 22:55:15  keil
+ * 16.3c support
  *
- * Revision 1.6  1997/01/21 22:17:56  keil
- * new module load syntax
+ * Revision 1.15.2.2  1997/11/15 18:55:46  keil
+ * New init, new cards
  *
- * Revision 1.5  1997/01/09 18:28:20  keil
- * cosmetic cleanups
+ * Revision 1.15.2.1  1997/10/17 22:13:40  keil
+ * update to last hisax version
  *
- * Revision 1.4  1996/11/05 19:35:17  keil
- * using config.h; some spelling fixes
+ * Revision 2.2  1997/09/11 17:24:46  keil
+ * Add new cards
  *
- * 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 TELES PCI               no parameter
+ *   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)
+ *   25 Teles S0Box             p0=irq p1=iobase (from isapnp setup)
  *
  *
  * 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}
+#define DEFAULT_CFG {0,0,0,0}
+int elsa_init_pcmcia(void*, int, int*, int);
+#ifdef MODULE
+static struct symbol_table hisax_syms_elsa = {
+#include <linux/symtab_begin.h>
+       X(elsa_init_pcmcia),
+#include <linux/symtab_end.h>
+};
+void register_elsa_symbols(void) {
+       register_symtab(&hisax_syms_elsa);
+}
 #endif
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
-#define DEFAULT_CARD ISDN_CTYPE_ELSA_QS1000
-#define DEFAULT_CFG {3,0x2f8,0}
 #endif
 #ifdef CONFIG_HISAX_AVM_A1
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_A1
-#define DEFAULT_CFG {10,0x340,0}
+#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_S0BOX
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_S0BOX
+#define DEFAULT_CFG {7,0x378,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_TELESPCI
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_TELESPCI
+#define DEFAULT_CFG {0,0,0,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);
+#ifdef MODULE
+static struct symbol_table hisax_syms_sedl= {
+#include <linux/symtab_begin.h>
+       X(sedl_init_pcmcia),
+#include <linux/symtab_end.h>
+};
+void register_sedl_symbols(void) {
+       register_symtab(&hisax_syms_sedl);
+}
+#endif
+#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[] =
 {
@@ -162,65 +274,65 @@ struct IsdnCard cards[] =
        EMPTY_CARD,
        EMPTY_CARD,
        EMPTY_CARD,
-       EMPTY_CARD,
-       EMPTY_CARD,
-       EMPTY_CARD,
-       EMPTY_CARD,
-       EMPTY_CARD,
-       EMPTY_CARD,
-       EMPTY_CARD,
-       EMPTY_CARD,
 };
 
-static char HiSaxID[96] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+static char HiSaxID[64] 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;
+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+char *HiSax_id HISAX_INITDATA = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
-int type[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-int protocol[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-int io[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-#ifdef CONFIG_HISAX_16_3       /* For Creatix/Teles PnP */
-int io0[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-int io1[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static int type[] HISAX_INITDATA =
+{0, 0, 0, 0, 0, 0, 0, 0};
+static int protocol[] HISAX_INITDATA =
+{0, 0, 0, 0, 0, 0, 0, 0};
+static int io[] HISAX_INITDATA =
+{0, 0, 0, 0, 0, 0, 0, 0};
+#undef IO0_IO1
+#ifdef CONFIG_HISAX_16_3
+#define IO0_IO1
 #endif
-int irq[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-int mem[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-char *id = HiSaxID;
+#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};
+static int io1[] HISAX_INITDATA =
+{0, 0, 0, 0, 0, 0, 0, 0};
+#endif
+static int irq[] HISAX_INITDATA =
+{0, 0, 0, 0, 0, 0, 0, 0};
+static int mem[] HISAX_INITDATA =
+{0, 0, 0, 0, 0, 0, 0, 0};
+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-8i");
+MODULE_PARM(protocol, "1-8i");
+MODULE_PARM(io, "1-8i");
+MODULE_PARM(irq, "1-8i");
+MODULE_PARM(mem, "1-8i");
 MODULE_PARM(id, "s");
 #ifdef CONFIG_HISAX_16_3       /* For Creatix/Teles PnP */
-MODULE_PARM(io0, "1-16i");
-MODULE_PARM(io1, "1-16i");
-#endif
-#endif
+MODULE_PARM(io0, "1-8i");
+MODULE_PARM(io1, "1-8i");
+#endif /* CONFIG_HISAX_16_3 */
+#endif /* (LINUX_VERSION_CODE > 0x020111) */
+#endif /* MODULE */
 
-#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 +346,24 @@ HiSax_getrev(const char *revision)
        return rev;
 }
 
-int nrcards;
+HISAX_INITFUNC(void
+HiSaxVersion(void))
+{
+       char tmp[64];
+
+       printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
+       printk(KERN_INFO "HiSax: Version 3.0\n");
+       strcpy(tmp, l1_revision);
+       printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); 
+       strcpy(tmp, l2_revision);
+       printk(KERN_INFO "HiSax: Layer2 Revision %s\n", HiSax_getrev(tmp)); 
+       strcpy(tmp, tei_revision);
+       printk(KERN_INFO "HiSax: TeiMgr Revision %s\n", HiSax_getrev(tmp)); 
+       strcpy(tmp, l3_revision);
+       printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp)); 
+       strcpy(tmp, lli_revision);
+       printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp)); 
+}
 
 void
 HiSax_mod_dec_use_count(void)
@@ -251,15 +380,15 @@ 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;
 
        argc = ints[0];
        i = 0;
        j = 1;
-       while (argc && (i < 16)) {
+       while (argc && (i < HISAX_MAX_CARDS)) {
                if (argc) {
                        cards[i].typ = ints[j];
                        j++;
@@ -297,35 +426,32 @@ 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
        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);
-
+       HiSaxVersion();
 #ifdef MODULE
        if (id)                 /* If id= string used */
                HiSax_id = id;
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < HISAX_MAX_CARDS; i++) {
                cards[i].typ = type[i];
                if (protocol[i]) {
                        cards[i].protocol = protocol[i];
@@ -343,37 +469,46 @@ 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:
+                       case ISDN_CTYPE_S0BOX:
                                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:
+                       case ISDN_CTYPE_TELESPCI:
+                               break;
                }
        }
        if (!nzproto) {
@@ -386,29 +521,31 @@ HiSax_init(void)
                HiSax_id = HiSaxID;
        if (!HiSaxID[0])
                strcpy(HiSaxID, "HiSax");
-       for (i = 0; i < 16; i++)
+       for (i = 0; i < HISAX_MAX_CARDS; i++)
                if (cards[i].typ > 0)
                        nrcards++;
        printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
               nrcards, (nrcards > 1) ? "s" : "");
 
        CallcNew();
+       Isdnl3New();
        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();
+               Isdnl3Free();
                CallcFree();
                return -EIO;
        }
@@ -418,8 +555,116 @@ HiSax_init(void)
 void
 cleanup_module(void)
 {
-       HiSax_closehardware();
-       printk(KERN_NOTICE "HiSax module removed\n");
+       int cardnr = nrcards -1;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       while(cardnr>=0)
+               HiSax_closecard(cardnr--);
+       Isdnl1Free();
+       TeiFree();
+       Isdnl2Free();
+       Isdnl3Free();
+       CallcFree();
+       restore_flags(flags);
+       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 8 structs, even though we only accept
+          two pcmcia cards
+          */
+       for (i = 0; i < HISAX_MAX_CARDS; 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 < HISAX_MAX_CARDS; i++)
+               if (cards[i].typ > 0)
+                       nrcards++;
+       printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+              nrcards, (nrcards > 1) ? "s" : "");
+
+       Isdnl1New();
+       CallcNew();
+       Isdnl3New();
+       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 8 structs, even though we only accept
+          two pcmcia cards
+          */
+       for (i = 0; i < HISAX_MAX_CARDS; 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 < HISAX_MAX_CARDS; i++)
+               if (cards[i].typ > 0)
+                       nrcards++;
+       printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+              nrcards, (nrcards > 1) ? "s" : "");
+
+       Isdnl1New();
+       CallcNew();
+       Isdnl3New();
+       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..5b909ef
--- /dev/null
@@ -0,0 +1,605 @@
+/* $Id: diva.c,v 1.1.2.9 1998/06/27 21:58:34 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.1.2.9  1998/06/27 21:58:34  keil
+ * fix release of diva 2.01
+ *
+ * Revision 1.1.2.8  1998/05/27 18:05:11  keil
+ * HiSax 3.0
+ *
+ * Revision 1.1.2.7  1998/04/24 13:37:13  keil
+ * Support for DIVA 2.01 IPAC
+ *
+ * Revision 1.1.2.6  1998/04/08 22:05:21  keil
+ * Forgot PCI fix
+ *
+ * Revision 1.1.2.5  1998/04/08 21:49:27  keil
+ * New init; fix PCI for more as one card
+ *
+ * Revision 1.1.2.4  1998/03/07 23:15:14  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
+ * Revision 1.1.2.3  1998/01/27 22:37:35  keil
+ * fast io
+ *
+ * Revision 1.1.2.2  1997/11/15 18:50:44  keil
+ * new common init function
+ *
+ * Revision 1.1.2.1  1997/10/17 22:10:36  keil
+ * new files on 2.0
+ *
+ * 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 "ipac.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/bios32.h>
+
+extern const char *CardType[];
+
+const char *Diva_revision = "$Revision: 1.1.2.9 $";
+
+#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_IPAC_ADR          0
+#define DIVA_IPAC_DATA         1
+
+#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
+#define DIVA_IPAC_ISA  3
+
+/* 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
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset+0x80));
+}
+
+static void
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset|0x80, value);
+}
+
+static void
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
+{
+       readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size);
+}
+
+static void
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
+{
+       writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, 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);
+       }
+}
+
+static void
+diva_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char ista,val;
+       char   tmp[64];
+       int icnt=20;
+
+       if (!cs) {
+               printk(KERN_WARNING "Diva: Spurious interrupt!\n");
+               return;
+       }
+       ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.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.diva.isac_adr, cs->hw.diva.isac, 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.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80);
+               if (val) {
+                       isac_interrupt(cs, val);
+               }
+       }
+       if (ista & 0x10) {
+               val = 0x01;
+               isac_interrupt(cs, val);
+       }
+       ista  = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA);
+       if ((ista & 0x3f) && icnt) {
+               icnt--;
+               goto Start_IPAC;
+       }
+       if (!icnt)
+               printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n");
+       writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF);
+       writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0);
+}
+
+
+void
+release_io_diva(struct IsdnCardState *cs)
+{
+       int bytecnt;
+       
+       if (cs->subtyp != DIVA_IPAC_ISA) {
+               del_timer(&cs->hw.diva.tl);
+               if (cs->hw.diva.cfg_reg)
+                       byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
+       }
+       if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+               bytecnt = 8;
+       else
+               bytecnt = 32;
+       if (cs->hw.diva.cfg_reg) {
+               release_region(cs->hw.diva.cfg_reg, bytecnt);
+       }
+}
+
+static void
+reset_diva(struct IsdnCardState *cs)
+{
+       long flags;
+
+       save_flags(flags);
+       sti();
+       if (cs->subtyp == DIVA_IPAC_ISA) {
+               writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+               schedule();
+               writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
+               current->state = TASK_INTERRUPTIBLE;
+               current->timeout = jiffies + (10 * HZ) / 1000;  /* Timeout 10ms */
+               schedule();
+               writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
+               schedule();
+       } else {
+               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);
+       }
+       restore_flags(flags);
+}
+
+#define DIVA_ASSIGN 1
+
+static void
+diva_led_handler(struct IsdnCardState *cs)
+{
+       int blink = 0;
+
+       if (cs->subtyp == DIVA_IPAC_ISA)
+               return;
+       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:
+                       if (cs->subtyp == DIVA_IPAC_ISA) {
+                               return(request_irq(cs->irq, &diva_interrupt_ipac,
+                                               I4L_IRQ_FLAG, "HiSax", cs));
+                       } else {
+                               return(request_irq(cs->irq, &diva_interrupt,
+                                               I4L_IRQ_FLAG, "HiSax", cs));
+                       }
+               case CARD_INIT:
+                       inithscxisac(cs, 3);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+               case (MDL_REMOVE | REQUEST):
+                       cs->hw.diva.status = 0;
+                       break;
+               case (MDL_ASSIGN | REQUEST):
+                       cs->hw.diva.status |= DIVA_ASSIGN;
+                       break;
+               case MDL_INFO_SETUP:
+                       if ((long)arg) 
+                               cs->hw.diva.status |=  0x0200;
+                       else
+                               cs->hw.diva.status |=  0x0100;
+                       break;
+               case MDL_INFO_CONN:
+                       if ((long)arg) 
+                               cs->hw.diva.status |=  0x2000;
+                       else
+                               cs->hw.diva.status |=  0x1000;
+                       break;
+               case MDL_INFO_REL:
+                       if ((long)arg) {
+                               cs->hw.diva.status &=  ~0x2000;
+                               cs->hw.diva.status &=  ~0x0200;
+                       } else {
+                               cs->hw.diva.status &=  ~0x1000;
+                               cs->hw.diva.status &=  ~0x0100;
+                       }
+                       break;
+       }
+       if (cs->subtyp != DIVA_IPAC_ISA)
+               diva_led_handler(cs);
+       return(0);
+}
+
+
+
+static         int pci_index __initdata = 0;
+
+__initfunc(int
+setup_diva(struct IsdnCard *card))
+{
+       int bytecnt;
+       u_char val;
+       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->hw.diva.ctrl_reg = 0;
+               cs->hw.diva.cfg_reg = card->para[1];
+               val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+                       cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+               printk(KERN_INFO "Diva: IPAC version %x\n", val);
+               if (val == 1) {
+                       cs->subtyp = DIVA_IPAC_ISA;
+                       cs->hw.diva.ctrl = 0;
+                       cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+                       cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+                       cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+                       cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+               } else {
+                       cs->subtyp = DIVA_ISA;
+                       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);
+               }
+               pci_index++;
+               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_PCI) ? "PCI" :
+               (cs->subtyp == DIVA_ISA) ? "ISA" : "IPAC",
+               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->BC_Read_Reg  = &ReadHSCX;
+       cs->BC_Write_Reg = &WriteHSCX;
+       cs->BC_Send_Data = &hscx_fill_fifo;
+       cs->cardmsg = &Diva_card_msg;
+       if (cs->subtyp == DIVA_IPAC_ISA) {
+               cs->readisac  = &ReadISAC_IPAC;
+               cs->writeisac = &WriteISAC_IPAC;
+               cs->readisacfifo  = &ReadISACfifo_IPAC;
+               cs->writeisacfifo = &WriteISACfifo_IPAC;
+               val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID);
+               printk(KERN_INFO "Diva: IPAC version %x\n", val);
+       } else {
+               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;
+               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 825625042ed58f1d21d5ae5d12e4fafb337b2f96..92972565c5fd9d4a985d1bf18a8874960bbab425 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: elsa.c,v 1.14 1997/04/13 19:53:25 keil Exp $
+/* $Id: elsa.c,v 1.14.2.11 1998/05/27 18:05:14 keil Exp $
 
  * elsa.c     low level stuff for Elsa isdn cards
  *
  *
  * Thanks to    Elsa GmbH for documents and informations
  *
+ *              Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE)
+ *              for ELSA PCMCIA support
+ *
  *
  * $Log: elsa.c,v $
- * Revision 1.14  1997/04/13 19:53:25  keil
- * Fixed QS1000 init, change in IRQ check delay for SMP
+ * Revision 1.14.2.11  1998/05/27 18:05:14  keil
+ * HiSax 3.0
  *
- * Revision 1.13  1997/04/07 22:58:07  keil
- * need include config.h
+ * Revision 1.14.2.10  1998/04/11 18:46:03  keil
+ * QS3000PCI support, changes for arcofi
  *
- * Revision 1.12  1997/04/06 22:54:14  keil
- * Using SKB's
+ * Revision 1.14.2.9  1998/04/08 21:44:36  keil
+ * new init; fix PCI for more as one card
  *
- * Revision 1.11  1997/03/23 21:45:46  keil
- * Add support for ELSA PCMCIA
+ * Revision 1.14.2.8  1998/03/07 23:15:15  tsbogend
+ * made HiSax working on Linux/Alpha
  *
- * Revision 1.10  1997/03/12 21:42:19  keil
- * Bugfix: IRQ hangs with QS1000
+ * Revision 1.14.2.7  1998/01/27 22:37:36  keil
+ * fast io
  *
- * Revision 1.9  1997/03/04 15:57:39  keil
- * bugfix IRQ reset Quickstep, ELSA PC changes, some stuff for new cards
+ * Revision 1.14.2.6  1998/01/11 22:57:10  keil
+ * add PCMCIA maintainer Klaus
  *
- * Revision 1.8  1997/01/27 15:51:48  keil
- * SMP proof,cosmetics
+ * Revision 1.14.2.5  1997/11/15 18:50:47  keil
+ * new common init function
  *
- * Revision 1.7  1997/01/21 22:20:48  keil
- * Elsa Quickstep support
+ * Revision 1.14.2.4  1997/10/17 22:13:44  keil
+ * update to last hisax version
  *
- * Revision 1.6  1997/01/09 18:22:46  keil
- * one more PCC-8 fix
+ * Revision 2.1  1997/07/27 21:47:08  keil
+ * new interface structures
  *
- * Revision 1.5  1996/12/08 19:46:14  keil
- * PCC-8 correct IRQs; starting ARCOFI support
+ * Revision 2.0  1997/06/26 11:02:40  keil
+ * New Layer and card interface
  *
- * 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>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
 
 extern const char *CardType[];
 
-const char *Elsa_revision = "$Revision: 1.14 $";
+const char *Elsa_revision = "$Revision: 1.14.2.11 $";
 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", "QS 3000 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
+#define ELSA_QS3000PCI 10
+
+/* PCI stuff */
+#define PCI_VENDOR_ELSA        0x1048
+#define PCI_QS1000_ID  0x1000
+#define PCI_QS3000_ID  0x3000
+#define ELSA_PCI_IRQ_MASK      0x04
+
+/* 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
+
+#define RS_ISR_PASS_LIMIT 256
+#define _INLINE_ inline
+#define FLG_MODEM_ACTIVE 1
+/* IPAC AUX */
+#define ELSA_IPAC_LINE_LED     0x40    /* Bit 6 Gelbe LED */
+#define ELSA_IPAC_STAT_LED     0x80    /* Bit 7 Gruene LED */
+
+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,0xe9,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 UP */
+const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* Normal OP */
+const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12};
+static void set_arcofi(struct IsdnCardState *cs, int bc);
+
+#if ARCOFI_USE
+#include "elsa_ser.c"
+#endif
 
 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  */
+/* Interface functions */
 
-       byteout(adr + CARD_ALE, 0);
-       insb(adr + CARD_ISAC, data, size);
-}
-
-
-static inline void
-writeisac(unsigned int adr, u_char off, u_char data)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-       long flags;
-
-       save_flags(flags);
-       cli();
-       byteout(adr + CARD_ALE, off + 0x20);
-       byteout(adr + CARD_ISAC, data);
-       restore_flags(flags);
+       return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset));
 }
 
-static inline void
-write_fifo_isac(unsigned int adr, u_char * data, int size)
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-       /* fifo write without cli because it's allready done  */
-
-       byteout(adr + CARD_ALE, 0);
-       outsb(adr + CARD_ISAC, data, size);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value);
 }
 
-#ifdef CONFIG_HISAX_ELSA_PCC
-static inline u_char
-readitac(unsigned int adr, u_char off)
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       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);
+       readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
 }
 
-static inline void
-writeitac(unsigned int adr, u_char off, u_char data)
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
-       long flags;
-
-       save_flags(flags);
-       cli();
-       byteout(adr + CARD_ALE, off);
-       byteout(adr + CARD_ITAC, data);
-       restore_flags(flags);
+       writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size);
 }
 
-static inline int
-TimerRun(struct IsdnCardState *sp)
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
 {
-       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);
+       return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset+0x80));
 }
 
-static inline void
-elsa_led_handler(struct IsdnCardState *sp)
+static void
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
-
-       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);
+       writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset|0x80, value);
 }
-#endif
 
-static inline void
-waitforCEC(int adr, int hscx)
+static void
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-       int to = 50;
-
-       while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
-               udelay(1);
-               to--;
-       }
-       if (!to)
-               printk(KERN_WARNING "Elsa: waitforCEC timeout\n");
+       readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
 }
 
-
-static inline void
-waitforXFW(int adr, int hscx)
+static void
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
 {
-       int to = 50;
-
-       while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
-               udelay(1);
-               to--;
-       }
-       if (!to)
-               printk(KERN_WARNING "Elsa: waitforXFW timeout\n");
+       writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size);
 }
 
-static inline void
-writehscxCMDR(int adr, int hscx, u_char data)
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-       long flags;
-
-       save_flags(flags);
-       cli();
-       waitforCEC(adr, hscx);
-       writehscx(adr, hscx, HSCX_CMDR, data);
-       restore_flags(flags);
+       return (readreg(cs->hw.elsa.ale,
+                       cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0)));
 }
 
-/*
- * fast interrupt here
- */
-
-
 static void
-hscxreport(struct IsdnCardState *sp, int hscx)
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
 {
-       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));
+       writereg(cs->hw.elsa.ale,
+                cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
-void
-elsa_report(struct IsdnCardState *sp)
-{
-       printk(KERN_DEBUG "ISAC\n");
-       printk(KERN_DEBUG "ISTA %x\n", readisac(sp->cfg_reg, ISAC_ISTA));
-       printk(KERN_DEBUG "STAR %x\n", readisac(sp->cfg_reg, ISAC_STAR));
-       printk(KERN_DEBUG "EXIR %x\n", readisac(sp->cfg_reg, ISAC_EXIR));
-       hscxreport(sp, 0);
-       hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
-
-static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+static inline u_char
+readitac(struct IsdnCardState *cs, u_char off)
 {
-       u_char *ptr;
-       struct IsdnCardState *sp = hsp->sp;
+       register u_char ret;
        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);
+       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_empty_fifo %c cnt %d",
-                            hsp->hscx ? 'B' : 'A', count);
-               QuickHex(t, ptr, count);
-               debugl1(sp, tmp);
-       }
+       return (ret);
 }
 
-static void
-hscx_fill_fifo(struct HscxState *hsp)
+static inline void
+writeitac(struct IsdnCardState *cs, u_char off, u_char data)
 {
-       struct IsdnCardState *sp = hsp->sp;
-       int more, count;
-       u_char *ptr;
        long flags;
 
-
-       if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
-               debugl1(sp, "hscx_fill_fifo");
-
-       if (!hsp->tx_skb)
-               return;
-       if (hsp->tx_skb->len <= 0)
-               return;
-
-       more = (hsp->mode == 1) ? 1 : 0;
-       if (hsp->tx_skb->len > 32) {
-               more = !0;
-               count = 32;
-       } else
-               count = hsp->tx_skb->len;
-
-       waitforXFW(sp->cfg_reg, hsp->hscx);
        save_flags(flags);
        cli();
-       ptr = hsp->tx_skb->data;
-       skb_pull(hsp->tx_skb, count);
-       hsp->tx_cnt -= count;
-       hsp->count += count;
-       write_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
-       writehscxCMDR(sp->cfg_reg, hsp->hscx, more ? 0x8 : 0xa);
+       byteout(cs->hw.elsa.ale, off);
+       byteout(cs->hw.elsa.itac, data);
        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)
+static inline int
+TimerRun(struct IsdnCardState *cs)
 {
-       u_char r;
-       struct HscxState *hsp = sp->hs + hscx;
-       struct sk_buff *skb;
-       int count;
-       char tmp[32];
-
-       if (!hsp->init)
-               return;
-
-       if (val & 0x80) {       /* RME */
-
-               r = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RSTA);
-               if ((r & 0xf0) != 0xa0) {
-                       if (!(r & 0x80))
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, "HSCX invalid frame");
-                       if ((r & 0x40) && hsp->mode)
-                               if (sp->debug & L1_DEB_WARN) {
-                                       sprintf(tmp, "HSCX RDO mode=%d",
-                                               hsp->mode);
-                                       debugl1(sp, tmp);
-                               }
-                       if (!(r & 0x20))
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, "HSCX CRC error");
-                       writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
-               } else {
-                       count = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RBCL) & 0x1f;
-                       if (count == 0)
-                               count = 32;
-                       hscx_empty_fifo(hsp, count);
-                       if ((count = hsp->rcvidx - 1) > 0) {
-                               if (sp->debug & L1_DEB_HSCX_FIFO) {
-                                       sprintf(tmp, "HX Frame %d", count);
-                                       debugl1(sp, tmp);
-                               }
-                               if (!(skb = dev_alloc_skb(count)))
-                                       printk(KERN_WARNING "Elsa: receive out of memory\n");
-                               else {
-                                       memcpy(skb_put(skb, count), hsp->rcvbuf, count);
-                                       skb_queue_tail(&hsp->rqueue, skb);
-                               }
-                       }
-               }
-               hsp->rcvidx = 0;
-               hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-       }
-       if (val & 0x40) {       /* RPF */
-               hscx_empty_fifo(hsp, 32);
-               if (hsp->mode == 1) {
-                       /* receive audio data */
-                       if (!(skb = dev_alloc_skb(32)))
-                               printk(KERN_WARNING "elsa: receive out of memory\n");
-                       else {
-                               memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
-                               skb_queue_tail(&hsp->rqueue, skb);
-                       }
-                       hsp->rcvidx = 0;
-                       hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-               }
-       }
-       if (val & 0x10) {       /* XPR */
-               if (hsp->tx_skb)
-                       if (hsp->tx_skb->len) {
-                               hscx_fill_fifo(hsp);
-                               return;
-                       } else {
-                               dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
-                               hsp->count = 0;
-                               if (hsp->st->l4.l1writewakeup)
-                                       hsp->st->l4.l1writewakeup(hsp->st);
-                               hsp->tx_skb = NULL;
-                       }
-               if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
-                       hsp->count = 0;
-                       hscx_fill_fifo(hsp);
-               } else
-                       hscx_sched_event(hsp, HSCX_XMTBUFREADY);
-       }
+       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);
 }
-
 /*
- * ISAC stuff goes here
+ * fast interrupt HSCX stuff goes here
  */
 
-static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
-{
-       u_char *ptr;
-       long flags;
+#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) && !(sp->debug & L1_DEB_ISAC_FIFO))
-               debugl1(sp, "isac_empty_fifo");
+#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \
+               cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
 
-       if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
-               if (sp->debug & L1_DEB_WARN) {
-                       char tmp[40];
-                       sprintf(tmp, "isac_empty_fifo overrun %d",
-                               sp->rcvidx + count);
-                       debugl1(sp, tmp);
-               }
-               writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
-               sp->rcvidx = 0;
-               return;
-       }
-       ptr = sp->rcvbuf + sp->rcvidx;
-       sp->rcvidx += count;
-       save_flags(flags);
-       cli();
-       read_fifo_isac(sp->cfg_reg, ptr, count);
-       writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
-       restore_flags(flags);
-       if (sp->debug & L1_DEB_ISAC_FIFO) {
-               char tmp[128];
-               char *t = tmp;
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \
+               cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt)
 
-               t += sprintf(t, "isac_empty_fifo cnt %d", count);
-               QuickHex(t, ptr, count);
-               debugl1(sp, tmp);
-       }
-}
+#include "hscx_irq.c"
 
 static void
-isac_fill_fifo(struct IsdnCardState *sp)
+elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
-       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;
+       struct IsdnCardState *cs = dev_id;
+       u_char val;
+       u_char tmp[32];
+       int icnt=20;
 
-       count = sp->tx_skb->len;
-       if (count <= 0)
+       if (!cs) {
+               printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
                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);
+       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;
        }
-       writeisac(sp->cfg_reg, ISAC_CIX0, (command << 2) | 3);
-}
-
-static inline void
-isac_interrupt(struct IsdnCardState *sp, u_char val)
-{
-       u_char exval, v1;
-       struct sk_buff *skb;
-       unsigned int count;
-       char tmp[32];
 #if ARCOFI_USE
-       struct BufHeader *ibh;
-       u_char *ptr;
-#endif
-
-       if (sp->debug & L1_DEB_ISAC) {
-               sprintf(tmp, "ISAC interrupt %x", val);
-               debugl1(sp, tmp);
-       }
-       if (val & 0x80) {       /* RME */
-               exval = readisac(sp->cfg_reg, ISAC_RSTA);
-               if ((exval & 0x70) != 0x20) {
-                       if (exval & 0x40)
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, "ISAC RDO");
-                       if (!(exval & 0x20))
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, "ISAC CRC error");
-                       writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
-               } else {
-                       count = readisac(sp->cfg_reg, ISAC_RBCL) & 0x1f;
-                       if (count == 0)
-                               count = 32;
-                       isac_empty_fifo(sp, count);
-                       if ((count = sp->rcvidx) > 0) {
-                               sp->rcvidx = 0;
-                               if (!(skb = alloc_skb(count, GFP_ATOMIC)))
-                                       printk(KERN_WARNING "Elsa: D receive out of memory\n");
-                               else {
-                                       SET_SKB_FREE(skb);
-                                       memcpy(skb_put(skb, count), sp->rcvbuf, count);
-                                       skb_queue_tail(&sp->rq, skb);
-                               }
-                       }
+       if (cs->hw.elsa.MFlag) {
+               val = serial_inp(cs, UART_IIR);
+               if (!(val & UART_IIR_NO_INT)) {
+                       sprintf(tmp,"IIR %02x", val);
+                       debugl1(cs, tmp);
+                       rs_interrupt_elsa(intno, cs);
                }
-               sp->rcvidx = 0;
-               isac_sched_event(sp, ISAC_RCVBUFREADY);
-       }
-       if (val & 0x40) {       /* RPF */
-               isac_empty_fifo(sp, 32);
-       }
-       if (val & 0x20) {       /* RSC */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC RSC interrupt");
-       }
-       if (val & 0x10) {       /* XPR */
-               if (sp->tx_skb)
-                       if (sp->tx_skb->len) {
-                               isac_fill_fifo(sp);
-                               goto afterXPR;
-                       } else {
-                               dev_kfree_skb(sp->tx_skb, FREE_WRITE);
-                               sp->tx_cnt = 0;
-                               sp->tx_skb = NULL;
-                       }
-               if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
-                       sp->tx_cnt = 0;
-                       isac_fill_fifo(sp);
-               } else
-                       isac_sched_event(sp, ISAC_XMTBUFREADY);
        }
-      afterXPR:
-       if (val & 0x04) {       /* CISQ */
-               sp->ph_state = (readisac(sp->cfg_reg, ISAC_CIX0) >> 2)
-                   & 0xf;
-               if (sp->debug & L1_DEB_ISAC) {
-                       sprintf(tmp, "l1state %d", sp->ph_state);
-                       debugl1(sp, tmp);
-               }
-               isac_new_ph(sp);
-       }
-       if (val & 0x02) {       /* SIN */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC SIN interrupt");
-       }
-       if (val & 0x01) {       /* EXI */
-               exval = readisac(sp->cfg_reg, ISAC_EXIR);
-               if (sp->debug & L1_DEB_WARN) {
-                       sprintf(tmp, "ISAC EXIR %02x", exval);
-                       debugl1(sp, tmp);
-               }
-               if (exval & 0x08) {
-                       v1 = readisac(sp->cfg_reg, ISAC_MOSR);
-                       if (sp->debug & L1_DEB_WARN) {
-                               sprintf(tmp, "ISAC MOSR %02x", v1);
-                               debugl1(sp, tmp);
-                       }
-#if ARCOFI_USE
-                       if (v1 & 0x08) {
-                               if (!sp->mon_rx)
-                                       if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
-                                           GFP_ATOMIC, (void *) 1, 3)) {
-                                               if (sp->debug & L1_DEB_WARN)
-                                                       debugl1(sp, "ISAC MON RX out of buffers!");
-                                               writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
-                                               goto afterMONR0;
-                                       } else
-                                               sp->mon_rxp = 0;
-                               ibh = sp->mon_rx;
-                               ptr = DATAPTR(ibh);
-                               ptr += sp->mon_rxp;
-                               sp->mon_rxp++;
-                               if (sp->mon_rxp >= 3072) {
-                                       writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
-                                       sp->mon_rxp = 0;
-                                       if (sp->debug & L1_DEB_WARN)
-                                               debugl1(sp, "ISAC MON RX overflow!");
-                                       goto afterMONR0;
-                               }
-                               *ptr = readisac(sp->cfg_reg, ISAC_MOR0);
-                               if (sp->debug & L1_DEB_WARN) {
-                                       sprintf(tmp, "ISAC MOR0 %02x", *ptr);
-                                       debugl1(sp, tmp);
-                               }
-                       }
-                     afterMONR0:
-                       if (v1 & 0x80) {
-                               if (!sp->mon_rx)
-                                       if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
-                                           GFP_ATOMIC, (void *) 1, 3)) {
-                                               if (sp->debug & L1_DEB_WARN)
-                                                       debugl1(sp, "ISAC MON RX out of buffers!");
-                                               writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
-                                               goto afterMONR1;
-                                       } else
-                                               sp->mon_rxp = 0;
-                               ibh = sp->mon_rx;
-                               ptr = DATAPTR(ibh);
-                               ptr += sp->mon_rxp;
-                               sp->mon_rxp++;
-                               if (sp->mon_rxp >= 3072) {
-                                       writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
-                                       sp->mon_rxp = 0;
-                                       if (sp->debug & L1_DEB_WARN)
-                                               debugl1(sp, "ISAC MON RX overflow!");
-                                       goto afterMONR1;
-                               }
-                               *ptr = readisac(sp->cfg_reg, ISAC_MOR1);
-                               if (sp->debug & L1_DEB_WARN) {
-                                       sprintf(tmp, "ISAC MOR1 %02x", *ptr);
-                                       debugl1(sp, tmp);
-                               }
-                       }
-                     afterMONR1:
-                       if (v1 & 0x04) {
-                               writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
-                               sp->mon_rx->datasize = sp->mon_rxp;
-                               sp->mon_flg |= MON0_RX;
-                       }
-                       if (v1 & 0x40) {
-                               writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
-                               sp->mon_rx->datasize = sp->mon_rxp;
-                               sp->mon_flg |= MON1_RX;
-                       }
-                       if (v1 == 0x02) {
-                               ibh = sp->mon_tx;
-                               if (!ibh) {
-                                       writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
-                                       goto AfterMOX0;
-                               }
-                               count = ibh->datasize - sp->mon_txp;
-                               if (count <= 0) {
-                                       writeisac(sp->cfg_reg, ISAC_MOCR, 0x0f);
-                                       BufPoolRelease(sp->mon_tx);
-                                       sp->mon_tx = NULL;
-                                       sp->mon_txp = 0;
-                                       sp->mon_flg |= MON0_TX;
-                                       goto AfterMOX0;
-                               }
-                               ptr = DATAPTR(ibh);
-                               ptr += sp->mon_txp;
-                               sp->mon_txp++;
-                               writeisac(sp->cfg_reg, ISAC_MOX0, *ptr);
-                       }
-                     AfterMOX0:
-                       if (v1 == 0x20) {
-                               ibh = sp->mon_tx;
-                               if (!ibh) {
-                                       writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
-                                       goto AfterMOX1;
-                               }
-                               count = ibh->datasize - sp->mon_txp;
-                               if (count <= 0) {
-                                       writeisac(sp->cfg_reg, ISAC_MOCR, 0xf0);
-                                       BufPoolRelease(sp->mon_tx);
-                                       sp->mon_tx = NULL;
-                                       sp->mon_txp = 0;
-                                       sp->mon_flg |= MON1_TX;
-                                       goto AfterMOX1;
-                               }
-                               ptr = DATAPTR(ibh);
-                               ptr += sp->mon_txp;
-                               sp->mon_txp++;
-                               writeisac(sp->cfg_reg, ISAC_MOX1, *ptr);
-                       }
-                     AfterMOX1:
 #endif
-               }
+       val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
+      Start_HSCX:
+       if (val) {
+               hscx_int_main(cs, val);
        }
-}
-
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
-
-       u_char exval;
-       struct HscxState *hsp;
-       char tmp[32];
-
-       if (val & 0x01) {
-               hsp = sp->hs + 1;
-               exval = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
-               if (exval == 0x40) {
-                       if (hsp->mode == 1)
-                               hscx_fill_fifo(hsp);
-                       else {
-                               /* Here we lost an TX interrupt, so
-                                  * restart transmitting the whole frame.
-                                */
-                               if (hsp->tx_skb) {
-                                       skb_push(hsp->tx_skb, hsp->count);
-                                       hsp->tx_cnt += hsp->count;
-                                       hsp->count = 0;
-                               }
-                               writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
-                               if (sp->debug & L1_DEB_WARN) {
-                                       sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
-                                       debugl1(sp, tmp);
-                               }
-                       }
-               } else if (sp->debug & L1_DEB_HSCX) {
-                       sprintf(tmp, "HSCX B EXIR %x", exval);
-                       debugl1(sp, tmp);
-               }
+       val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA);
+      Start_ISAC:
+       if (val) {
+               isac_interrupt(cs, val);
        }
-       if (val & 0xf8) {
-               if (sp->debug & L1_DEB_HSCX) {
-                       sprintf(tmp, "HSCX B interrupt %x", val);
-                       debugl1(sp, tmp);
-               }
-               hscx_interrupt(sp, val, 1);
+       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;
        }
-       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);
-               }
+       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;
        }
-       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);
+       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++;
                }
-               hscx_interrupt(sp, exval, 0);
        }
+       if (cs->hw.elsa.MFlag) {
+               val = serial_inp(cs, UART_MCR);
+               val ^= 0x8;
+               serial_outp(cs, UART_MCR, val);
+               val = serial_inp(cs, UART_MCR);
+               val ^= 0x8;
+               serial_outp(cs, UART_MCR, val);
+       }
+       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
-elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
 {
-       struct IsdnCardState *sp;
-       u_char val;
+       struct IsdnCardState *cs = dev_id;
+       u_char ista,val;
+       char   tmp[64];
+       int icnt=20;
 
-       sp = (struct IsdnCardState *) irq2dev_map[intno];
-
-       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);
-               }
+               val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
+       if (!(val & ELSA_PCI_IRQ_MASK))
+         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);
        }
-#endif
-       val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
-      Start_HSCX:
-       if (val) {
-               hscx_int_main(sp, val);
+       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);
        }
-       val = readisac(sp->cfg_reg, ISAC_ISTA);
-      Start_ISAC:
-       if (val) {
-               isac_interrupt(sp, val);
-       }
-#ifdef CONFIG_HISAX_ELSA_PCC
-       if (!TimerRun(sp))
-               goto INT_RESTART;
-#endif
-       val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
-       if (val) {
-               if (sp->debug & L1_DEB_HSCX)
-                       debugl1(sp, "HSCX IntStat after IntRoutine");
-               goto Start_HSCX;
+       if (ista & 0x20) {
+               val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80);
+               if (val) {
+                       isac_interrupt(cs, val);
+               }
        }
-       val = readisac(sp->cfg_reg, ISAC_ISTA);
-       if (val) {
-               if (sp->debug & L1_DEB_ISAC)
-                       debugl1(sp, "ISAC IntStat after IntRoutine");
-               goto Start_ISAC;
+       if (ista & 0x10) {
+               val = 0x01;
+               isac_interrupt(cs, val);
        }
-       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);
+       ista  = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
+       if ((ista & 0x3f) && icnt) {
+               icnt--;
+               goto Start_IPAC;
        }
-#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 (!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);
 }
 
-
-static void
-initisac(struct IsdnCardState *sp)
+void
+release_io_elsa(struct IsdnCardState *cs)
 {
-       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);
-}
+       int bytecnt = 8;
 
-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);
+       del_timer(&cs->hw.elsa.tl);
+       if (cs->hw.elsa.ctrl)
+               byteout(cs->hw.elsa.ctrl, 0);   /* LEDs Out */
+       if (cs->subtyp == ELSA_QS1000PCI) {
+               byteout(cs->hw.elsa.cfg + 0x4c, 0x01);  /* disable IRQ */
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+               bytecnt = 2;
+               release_region(cs->hw.elsa.cfg, 0x80);
        }
-       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->subtyp == ELSA_QS3000PCI) {
+               byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* enable ELSA PCI IRQ */
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+               release_region(cs->hw.elsa.cfg, 0x80);
+       }
+       if ((cs->subtyp == ELSA_PCFPRO) || 
+               (cs->subtyp == ELSA_QS3000) ||
+               (cs->subtyp == ELSA_PCF) ||
+               (cs->subtyp == ELSA_QS3000PCI)) {
+               bytecnt = 16;
+               release_modem(cs);
        }
-       writehscx(sp->cfg_reg, hscx, HSCX_ISTA, 0x00);
+       if (cs->hw.elsa.base)
+               release_region(cs->hw.elsa.base, bytecnt);
 }
 
-void
-release_io_elsa(struct IsdnCard *card)
+static void
+reset_elsa(struct IsdnCardState *cs)
 {
-       int bytecnt = 8;
+       long flags;
 
-       if (card->sp->subtyp == ELSA_PCFPRO)
-               bytecnt = 16;
-       if (card->sp->cfg_reg)
-               release_region(card->sp->cfg_reg, bytecnt);
+       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);
+       }
+       if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
+               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);
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff);
+               if (cs->subtyp == ELSA_QS1000PCI) 
+                       byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
+               else if (cs->subtyp == ELSA_QS3000PCI)
+                       byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */
+       }
 }
 
 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
+init_arcofi(struct IsdnCardState *cs) {
+       send_arcofi(cs, ARCOFI_XOP_0, 1, 0);
+/*     send_arcofi(cs, ARCOFI_XOP_F, 1);
+*/
 }
 
-static void
-clear_pending_ints(struct IsdnCardState *sp)
-{
-#ifdef CONFIG_HISAX_ELSA_PCMCIA
-       int val;
-       char tmp[64];
+#define ARCDEL 500
 
-       val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
-       sprintf(tmp, "HSCX B ISTA %x", val);
-       debugl1(sp, tmp);
-       if (val & 0x01) {
-               val = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
-               sprintf(tmp, "HSCX B EXIR %x", val);
-               debugl1(sp, tmp);
-       } else if (val & 0x02) {
-               val = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
-               sprintf(tmp, "HSCX A EXIR %x", val);
-               debugl1(sp, tmp);
-       }
-       val = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
-       sprintf(tmp, "HSCX A ISTA %x", val);
-       debugl1(sp, tmp);
-       val = readhscx(sp->cfg_reg, 1, HSCX_STAR);
-       sprintf(tmp, "HSCX B STAR %x", val);
-       debugl1(sp, tmp);
-       val = readhscx(sp->cfg_reg, 0, HSCX_STAR);
-       sprintf(tmp, "HSCX A STAR %x", val);
-       debugl1(sp, tmp);
-       val = readisac(sp->cfg_reg, ISAC_STAR);
-       sprintf(tmp, "ISAC STAR %x", val);
-       debugl1(sp, tmp);
-       val = readisac(sp->cfg_reg, ISAC_MODE);
-       sprintf(tmp, "ISAC MODE %x", val);
-       debugl1(sp, tmp);
-       val = readisac(sp->cfg_reg, ISAC_ADF2);
-       sprintf(tmp, "ISAC ADF2 %x", val);
-       debugl1(sp, tmp);
-       val = readisac(sp->cfg_reg, ISAC_ISTA);
-       sprintf(tmp, "ISAC ISTA %x", val);
-       debugl1(sp, tmp);
-       if (val & 0x01) {
-               val = readisac(sp->cfg_reg, ISAC_EXIR);
-               sprintf(tmp, "ISAC EXIR %x", val);
-               debugl1(sp, tmp);
-       } else if (val & 0x04) {
-               val = readisac(sp->cfg_reg, ISAC_CIR0);
-               sprintf(tmp, "ISAC CIR0 %x", val);
-               debugl1(sp, tmp);
-       }
-#endif
-       writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
-       writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
-       writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
-#ifdef CONFIG_HISAX_ELSA_PCC
-       if (sp->subtyp == ELSA_QS1000) {
-               byteout(sp->cfg_reg + CARD_START_TIMER, 0);
-               byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
-       }
-#endif
-       writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
-       writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
-       writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
-       writeisac(sp->cfg_reg, ISAC_CMDR, 0x41);
+static void
+set_arcofi(struct IsdnCardState *cs, int bc) {
+       long flags;
+       char tmp[32];
+       
+       sprintf(tmp,"set_arcofi bc=%d", bc);
+       debugl1(cs, tmp);
+       save_flags(flags);
+       sti();
+       send_arcofi(cs, ARCOFI_XOP_0, bc, 0);
+       udelay(ARCDEL);
+       send_arcofi(cs, ARCOFI_COP_5, bc, 0);
+       udelay(ARCDEL);
+       send_arcofi(cs, ARCOFI_COP_6, bc, 0);
+       udelay(ARCDEL);
+       send_arcofi(cs, ARCOFI_COP_7, bc, 0);
+       udelay(ARCDEL);
+       send_arcofi(cs, ARCOFI_COP_8, bc, 0);
+       udelay(ARCDEL);
+       send_arcofi(cs, ARCOFI_COP_9, bc, 0);
+       udelay(ARCDEL);
+       send_arcofi(cs, ARCOFI_SOP_F, bc, 0);
+       udelay(ARCDEL);
+       send_arcofi(cs, ARCOFI_XOP_1, bc, 0);
+       udelay(ARCDEL);
+       send_arcofi(cs, ARCOFI_XOP_F, bc, 0);
+       restore_flags(flags);
 }
 
-static void
-check_arcofi(struct IsdnCardState *sp)
+static int
+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(0);
+               }
+       send_arcofi(cs, ARCOFI_VERSION, 0, 1);
+       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);
+               return(1);
        }
-       sp->mon_flg = 0;
 #endif
+       return(0);
 }
 
-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.interrupts[sp->irq];
-       printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, irq_cnt);
-       ret = get_irq(sp->cardnr, &elsa_interrupt);
-#ifdef CONFIG_HISAX_ELSA_PCC
-       byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
-#endif
-       while (ret && cnt) {
-               sp->counter = 0;
-               clear_pending_ints(sp);
-               initisac(sp);
-               sp->modehscx(sp->hs, 0, 0);
-               sp->modehscx(sp->hs + 1, 0, 0);
-               save_flags(flags);
-               sp->counter = 0;
-               sti();
-#ifdef CONFIG_HISAX_ELSA_PCC
-               byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET | ENABLE_TIM_INT);
-               byteout(sp->cfg_reg + CARD_START_TIMER, 0);
-               current->state = TASK_INTERRUPTIBLE;
-               current->timeout = jiffies + (110 * HZ) / 1000;         /* Timeout 110ms */
-               schedule();
-               restore_flags(flags);
-               printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
-                      sp->counter);
-               if (abs(sp->counter - 13) < 3) {
-                       printk(KERN_INFO "Elsa: timer and irq OK\n");
-               } else {
-                       printk(KERN_WARNING
-                              "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
-                              sp->counter, sp->irq);
-               }
+       if (cs->subtyp == ELSA_PCMCIA)
+               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;
+
+       if ((cs->subtyp == ELSA_QS1000PCI) ||
+               (cs->subtyp == ELSA_QS3000PCI)) {
+               u_char led = 0xff;
+               if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED) 
+                       led ^= ELSA_IPAC_LINE_LED;
+               if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED)
+                       led ^= ELSA_IPAC_STAT_LED;
+               writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led);
+       } else  
+               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, len, ret = 0;
+       u_char *msg;
+       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) ||
+                               (cs->subtyp == ELSA_QS3000PCI))
+                               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:
+                       cs->debug |= L1_DEB_IPAC;
+                       inithscxisac(cs, 1);
+                       if ((cs->subtyp == ELSA_QS1000) ||
+                           (cs->subtyp == ELSA_QS3000)) 
+                       {
+                               byteout(cs->hw.elsa.timer, 0);
+                       }
+                       if (cs->hw.elsa.trig)
+                               byteout(cs->hw.elsa.trig, 0xff);
+                       inithscxisac(cs, 2);
+                       return(0);
+               case CARD_TEST:
+                       if ((cs->subtyp == ELSA_PCMCIA) ||
+                               (cs->subtyp == ELSA_QS1000PCI)) {
+                               return(0);
+                       } else if (cs->subtyp == ELSA_QS3000PCI) {
+                               ret = 0;
+                       } else {
+                               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);
+                               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 {
+                                       printk(KERN_WARNING
+                                              "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
+                                              cs->hw.elsa.counter, cs->irq);
+                                       ret = 1;
+                               }
+                       }
+#if ARCOFI_USE
+                       if (check_arcofi(cs)) {
+                               init_modem(cs);
+                       }
 #endif
-               printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq,
-                      kstat.interrupts[sp->irq]);
-               if (kstat.interrupts[sp->irq] == irq_cnt) {
-                       printk(KERN_WARNING
-                              "Elsa: IRQ(%d) getting no interrupts during init %d\n",
-                              sp->irq, 4 - cnt);
-                       if (cnt == 1) {
-                               irq2dev_map[sp->irq] = NULL;
-                               free_irq(sp->irq, NULL);
-                               return (0);
+                       elsa_led_handler(cs);
+                       return(ret);
+               case (MDL_REMOVE | REQUEST):
+                       cs->hw.elsa.status &= 0;
+                       break;
+               case (MDL_ASSIGN | REQUEST):
+                       cs->hw.elsa.status |= ELSA_ASSIGN;
+                       break;
+               case MDL_INFO_SETUP:
+                       if ((long) arg)
+                               cs->hw.elsa.status |= 0x0200;
+                       else
+                               cs->hw.elsa.status |= 0x0100;
+                       break;
+               case MDL_INFO_CONN:
+                       if ((long) arg)
+                               cs->hw.elsa.status |= 0x2000;
+                       else
+                               cs->hw.elsa.status |= 0x1000;
+                       break;
+               case MDL_INFO_REL:
+                       if ((long) arg) {
+                               cs->hw.elsa.status &= ~0x2000;
+                               cs->hw.elsa.status &= ~0x0200;
                        } else {
-                               reset_elsa(sp);
-                               cnt--;
+                               cs->hw.elsa.status &= ~0x1000;
+                               cs->hw.elsa.status &= ~0x0100;
                        }
-               } else {
-                       check_arcofi(sp);
-                       cnt = 0;
-               }
+                       break;
+               case CARD_AUX_IND:
+                       if (cs->hw.elsa.MFlag) {
+                               if (!arg)
+                                       return(0);
+                               msg = arg;
+                               len = *msg;
+                               msg++;
+                               modem_write_cmd(cs, msg, len);
+                       }
+                       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 +856,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 +888,301 @@ 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;
+       cs->hw.elsa.MFlag = 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 if (pcibios_find_device(PCI_VENDOR_ELSA,
+                          PCI_QS3000_ID, pci_index, &pci_bus, &pci_device_fn)
+                          == PCIBIOS_SUCCESSFUL)
+                               cs->subtyp = ELSA_QS3000PCI;
+                       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);
+               }
+               pci_index++;
+               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:
+               case ELSA_QS3000PCI:
                        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) || (cs->subtyp == ELSA_QS3000PCI)) {
+               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->subtyp == ELSA_QS3000PCI)) {
+               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_ser.c b/drivers/isdn/hisax/elsa_ser.c
new file mode 100644 (file)
index 0000000..f5d96cc
--- /dev/null
@@ -0,0 +1,684 @@
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+
+#define MAX_MODEM_BUF  256
+#define WAKEUP_CHARS   (MAX_MODEM_BUF/2)
+#define RS_ISR_PASS_LIMIT 256
+#define BASE_BAUD ( 1843200 / 16 )
+
+#ifndef MIN
+#define MIN(a,b)       ((a) < (b) ? (a) : (b))
+#endif
+
+#define SERIAL_DEBUG_OPEN 1
+#define SERIAL_DEBUG_INTR 1
+#define SERIAL_DEBUG_FLOW 1
+#undef SERIAL_DEBUG_REG
+//#define SERIAL_DEBUG_REG
+
+#ifdef SERIAL_DEBUG_REG
+static u_char deb[32];
+const char *ModemIn[] = {"RBR","IER","IIR","LCR","MCR","LSR","MSR","SCR"};
+const char *ModemOut[] = {"THR","IER","FCR","LCR","MCR","LSR","MSR","SCR"};
+#endif
+
+static char *MInit_1 = "AT &F &C1 E0 &D2 L2 M1 S64=13\n\0";
+static char *MInit_2 = "AT+FCLASS=0 V1 S2=128 X1 \\V8\n\0";
+static char *MInit_3 = "AT %G0 %B2400 L0 M0 &G0 %E1 %L1 %M0 %C3 \\N3\n\0";
+
+
+static inline unsigned int serial_in(struct IsdnCardState *cs, int offset)
+{
+#ifdef SERIAL_DEBUG_REG
+       u_int val = inb(cs->hw.elsa.base + 8 + offset);
+       sprintf(deb,"in   %s %02x",ModemIn[offset], val);
+       debugl1(cs, deb);
+       return(val);
+#else
+       return inb(cs->hw.elsa.base + 8 + offset);
+#endif
+}
+
+static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset)
+{
+#ifdef SERIAL_DEBUG_REG
+#ifdef CONFIG_SERIAL_NOPAUSE_IO
+       u_int val = inb(cs->hw.elsa.base + 8 + offset);
+       sprintf(deb,"inp  %s %02x",ModemIn[offset], val);
+#else
+       u_int val = inb_p(cs->hw.elsa.base + 8 + offset);
+       sprintf(deb,"inP  %s %02x",ModemIn[offset], val);
+#endif
+       debugl1(cs, deb);
+       return(val);
+#else
+#ifdef CONFIG_SERIAL_NOPAUSE_IO
+       return inb(cs->hw.elsa.base + 8 + offset);
+#else
+       return inb_p(cs->hw.elsa.base + 8 + offset);
+#endif
+#endif
+}
+
+static inline void serial_out(struct IsdnCardState *cs, int offset, int value)
+{
+#ifdef SERIAL_DEBUG_REG
+       sprintf(deb,"out  %s %02x",ModemOut[offset], value);
+       debugl1(cs, deb);
+#endif
+       outb(value, cs->hw.elsa.base + 8 + offset);
+}
+
+static inline void serial_outp(struct IsdnCardState *cs, int offset,
+                              int value)
+{
+#ifdef SERIAL_DEBUG_REG
+#ifdef CONFIG_SERIAL_NOPAUSE_IO
+       sprintf(deb,"outp %s %02x",ModemOut[offset], value);
+#else
+       sprintf(deb,"outP %s %02x",ModemOut[offset], value);
+#endif
+       debugl1(cs, deb);
+#endif
+#ifdef CONFIG_SERIAL_NOPAUSE_IO
+       outb(value, cs->hw.elsa.base + 8 + offset);
+#else
+       outb_p(value, cs->hw.elsa.base + 8 + offset);
+#endif
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct IsdnCardState *cs, int baud)
+{
+       int     quot = 0, baud_base;
+       unsigned cval, fcr = 0;
+       int     bits;
+       char    tmp[32];
+       unsigned long   flags;
+
+
+       /* byte size and parity */
+       cval = 0x03; bits = 10;
+       /* Determine divisor based on baud rate */
+       baud_base = BASE_BAUD;
+       quot = baud_base / baud;
+       /* If the quotient is ever zero, default to 9600 bps */
+       if (!quot)
+               quot = baud_base / 9600;
+
+       /* Set up FIFO's */
+       if ((baud_base / quot) < 2400)
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+       else
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+       serial_outp(cs, UART_FCR, fcr);
+       /* CTS flow control flag and modem status interrupts */
+       cs->hw.elsa.IER &= ~UART_IER_MSI;
+       cs->hw.elsa.IER |= UART_IER_MSI;
+       serial_outp(cs, UART_IER, cs->hw.elsa.IER);
+
+       sprintf(tmp,"modem quot=0x%x", quot);
+       debugl1(cs, tmp);
+       save_flags(flags); cli();
+       serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+       serial_outp(cs, UART_DLL, quot & 0xff);         /* LS of divisor */
+       serial_outp(cs, UART_DLM, quot >> 8);           /* MS of divisor */
+       serial_outp(cs, UART_LCR, cval);                /* reset DLAB */
+       restore_flags(flags);
+}
+
+static int mstartup(struct IsdnCardState *cs)
+{
+       unsigned long flags;
+       int     retval=0;
+
+
+       save_flags(flags); cli();
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+       serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
+
+       /*
+        * At this point there's no way the LSR could still be 0xFF;
+        * if it is, then bail out, because there's likely no UART
+        * here.
+        */
+       if (serial_inp(cs, UART_LSR) == 0xff) {
+               retval = -ENODEV;
+               goto errout;
+       }
+       
+       /*
+        * Clear the interrupt registers.
+        */
+       (void) serial_inp(cs, UART_RX);
+       (void) serial_inp(cs, UART_IIR);
+       (void) serial_inp(cs, UART_MSR);
+
+       /*
+        * Now, initialize the UART 
+        */
+       serial_outp(cs, UART_LCR, UART_LCR_WLEN8);      /* reset DLAB */
+
+       cs->hw.elsa.MCR = 0;
+       cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
+       serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
+       
+       /*
+        * Finally, enable interrupts
+        */
+       cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+       serial_outp(cs, UART_IER, cs->hw.elsa.IER);     /* enable interrupts */
+       
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       (void)serial_inp(cs, UART_LSR);
+       (void)serial_inp(cs, UART_RX);
+       (void)serial_inp(cs, UART_IIR);
+       (void)serial_inp(cs, UART_MSR);
+
+       cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0;
+       cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp =0;
+
+       /*
+        * and set the speed of the serial port
+        */
+       change_speed(cs, 57600*2);
+       cs->hw.elsa.MFlag = 1;
+errout:
+       restore_flags(flags);
+       return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void mshutdown(struct IsdnCardState *cs)
+{
+       unsigned long   flags;
+
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("Shutting down serial ....");
+#endif
+       
+       save_flags(flags); cli(); /* Disable interrupts */
+
+       /*
+        * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+        * here so the queue might never be waken up
+        */
+
+       cs->hw.elsa.IER = 0;
+       serial_outp(cs, UART_IER, 0x00);        /* disable all intrs */
+       cs->hw.elsa.MCR &= ~UART_MCR_OUT2;
+       
+       /* disable break condition */
+       serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC);
+       
+       cs->hw.elsa.MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+       serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
+
+       /* disable FIFO's */    
+       serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
+       serial_inp(cs, UART_RX);    /* read data port to reset things */
+       
+       restore_flags(flags);
+}
+
+inline int
+write_modem(struct BCState *bcs) {
+       int ret=0;
+       struct IsdnCardState *cs = bcs->cs;
+       int count, len, fp, buflen;
+       long flags;
+       
+       if (!bcs->hw.hscx.tx_skb)
+               return 0;
+       if (bcs->hw.hscx.tx_skb->len <= 0)
+               return 0;
+       save_flags(flags);
+       cli();
+       buflen = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
+       len = MIN(buflen, bcs->hw.hscx.tx_skb->len);            
+       fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
+       fp &= (MAX_MODEM_BUF -1);
+       count = MIN(len, MAX_MODEM_BUF - fp);
+       if (count < len) {
+               memcpy(cs->hw.elsa.transbuf + fp, skb_pull(bcs->hw.hscx.tx_skb, count), count);
+               cs->hw.elsa.transcnt += count;
+               ret = count;
+               count = len - count;
+               fp = 0;
+       }
+       memcpy(cs->hw.elsa.transbuf + fp, skb_pull(bcs->hw.hscx.tx_skb, count), count);
+       cs->hw.elsa.transcnt += count;
+       ret += count;
+       
+       if (cs->hw.elsa.transcnt && 
+           !(cs->hw.elsa.IER & UART_IER_THRI)) {
+               cs->hw.elsa.IER |= UART_IER_THRI;
+               serial_outp(cs, UART_IER, cs->hw.elsa.IER);
+       }
+       restore_flags(flags);
+       return(ret);
+}
+
+inline void
+modem_fill(struct BCState *bcs) {
+               
+       if (bcs->hw.hscx.tx_skb) {
+               if (bcs->hw.hscx.tx_skb->len) {
+                       write_modem(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, FREE_WRITE);
+                       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);
+               write_modem(bcs);
+       } else {
+               test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               hscx_sched_event(bcs, B_XMTBUFREADY);
+       }
+}
+
+static inline void receive_chars(struct IsdnCardState *cs,
+                                int *status)
+{
+       unsigned char ch;
+       struct sk_buff *skb;
+
+       do {
+               ch = serial_in(cs, UART_RX);
+               if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF)
+                       break;
+               cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch;
+#ifdef SERIAL_DEBUG_INTR
+               printk("DR%02x:%02x...", ch, *status);
+#endif
+               if (*status & (UART_LSR_BI | UART_LSR_PE |
+                              UART_LSR_FE | UART_LSR_OE)) {
+                                       
+#ifdef SERIAL_DEBUG_INTR
+                       printk("handling exept....");
+#endif
+               }
+               *status = serial_inp(cs, UART_LSR);
+       } while (*status & UART_LSR_DR);
+       if (cs->hw.elsa.MFlag == 2) {
+               if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt)))
+                       printk(KERN_WARNING "ElsaSER: receive out of memory\n");
+               else {
+                       memcpy(skb_put(skb, cs->hw.elsa.rcvcnt), cs->hw.elsa.rcvbuf, 
+                               cs->hw.elsa.rcvcnt);
+                       skb_queue_tail(& cs->hw.elsa.bcs->rqueue, skb);
+               }
+               hscx_sched_event(cs->hw.elsa.bcs, B_RCVBUFREADY);
+       } else {
+               char tmp[128];
+               char *t = tmp;
+
+               t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt);
+               QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt);
+               debugl1(cs, tmp);
+       }
+       cs->hw.elsa.rcvcnt = 0;
+}
+
+static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done)
+{
+       int count;
+       char tmp[64];
+       
+       sprintf(tmp, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp, 
+               cs->hw.elsa.transcnt);
+       debugl1(cs, tmp);
+       if (cs->hw.elsa.transcnt <= 0) {
+               cs->hw.elsa.IER &= ~UART_IER_THRI;
+               serial_out(cs, UART_IER, cs->hw.elsa.IER);
+               return;
+       }
+       
+       count = 16;
+       do {
+               serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]);
+               if (cs->hw.elsa.transp >= MAX_MODEM_BUF)
+                       cs->hw.elsa.transp=0;
+               if (--cs->hw.elsa.transcnt <= 0)
+                       break;
+       } while (--count > 0);
+       if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag==2))
+               modem_fill(cs->hw.elsa.bcs);
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("THRE...");
+#endif
+       if (intr_done)
+               *intr_done = 0;
+       if (cs->hw.elsa.transcnt <= 0) {
+               cs->hw.elsa.IER &= ~UART_IER_THRI;
+               serial_outp(cs, UART_IER, cs->hw.elsa.IER);
+       }
+}
+
+#if 0
+static inline void check_modem_status(struct IsdnCardState *cs)
+{
+       int     status;
+       struct async_struct *info = cs->hw.elsa.info;
+       struct  async_icount *icount;
+       
+       status = serial_inp(info, UART_MSR);
+
+       if (status & UART_MSR_ANY_DELTA) {
+               icount = &info->state->icount;
+               /* update input line counters */
+               if (status & UART_MSR_TERI)
+                       icount->rng++;
+               if (status & UART_MSR_DDSR)
+                       icount->dsr++;
+               if (status & UART_MSR_DDCD) {
+                       icount->dcd++;
+               }
+               if (status & UART_MSR_DCTS)
+                       icount->cts++;
+//             wake_up_interruptible(&info->delta_msr_wait);
+       }
+
+       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+               printk("ttys%d CD now %s...", info->line,
+                      (status & UART_MSR_DCD) ? "on" : "off");
+#endif         
+               if (status & UART_MSR_DCD)
+//                     wake_up_interruptible(&info->open_wait);
+;
+               else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                          (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+                       printk("doing serial hangup...");
+#endif
+                       if (info->tty)
+                               tty_hangup(info->tty);
+               }
+       }
+#if 0
+       if (info->flags & ASYNC_CTS_FLOW) {
+               if (info->tty->hw_stopped) {
+                       if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx start...");
+#endif
+                               info->tty->hw_stopped = 0;
+                               info->IER |= UART_IER_THRI;
+                               serial_outp(info, UART_IER, info->IER);
+//                             rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+                               return;
+                       }
+               } else {
+                       if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx stop...");
+#endif
+                               info->tty->hw_stopped = 1;
+                               info->IER &= ~UART_IER_THRI;
+                               serial_outp(info, UART_IER, info->IER);
+                       }
+               }
+       }
+#endif 0
+}
+#endif
+
+static void rs_interrupt_elsa(int irq, struct IsdnCardState *cs)
+{
+       int status, iir, msr;
+       int pass_counter = 0;
+       u_char tmp[64];
+       
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt_single(%d)...", irq);
+#endif
+
+       do {
+               status = serial_inp(cs, UART_LSR);
+               sprintf(tmp,"rs LSR %02x", status);
+               debugl1(cs, tmp);
+#ifdef SERIAL_DEBUG_INTR
+               printk("status = %x...", status);
+#endif
+               if (status & UART_LSR_DR)
+                       receive_chars(cs, &status);
+               if (status & UART_LSR_THRE)
+                       transmit_chars(cs, 0);
+               if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+                       printk("rs_single loop break.\n");
+                       break;
+               }
+               iir = serial_inp(cs, UART_IIR);
+               sprintf(tmp,"rs IIR %02x", iir);
+               debugl1(cs, tmp);
+               if ((iir & 0xf) == 0) {
+                       msr = serial_inp(cs, UART_MSR);
+                       sprintf(tmp,"rs MSR %02x", msr);
+                       debugl1(cs, tmp);
+               }
+       } while (!(iir & UART_IIR_NO_INT));
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+
+extern int open_hscxstate(struct IsdnCardState *cs, int bc);
+extern void modehscx(struct BCState *bcs, int mode, int bc);
+extern void hscx_l2l1(struct PStack *st, int pr, void *arg);
+
+void
+close_elsastate(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) {
+                       if (bcs->mode != L1_MODE_MODEM)
+                               kfree(bcs->hw.hscx.rcvbuf);
+                       bcs->hw.hscx.rcvbuf = NULL;
+               }
+               while ((skb = skb_dequeue(&bcs->rqueue))) {
+                       dev_kfree_skb(skb, FREE_READ);
+               }
+               while ((skb = skb_dequeue(&bcs->squeue))) {
+                       dev_kfree_skb(skb, FREE_WRITE);
+               }
+               if (bcs->hw.hscx.tx_skb) {
+                       dev_kfree_skb(bcs->hw.hscx.tx_skb, FREE_WRITE);
+                       bcs->hw.hscx.tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               }
+       }
+}
+
+void
+modem_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       if (pr == (PH_DATA | REQUEST)) {
+               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);
+                       write_modem(st->l1.bcs);
+               }
+       } else if (pr == (PH_ACTIVATE | REQUEST)) {
+               test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+               st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+               set_arcofi(st->l1.bcs->cs, st->l1.bc);
+               st->l1.bcs->cs->hw.elsa.MFlag=2;
+       } else if (pr == (PH_DEACTIVATE | REQUEST)) {
+               test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+               send_arcofi(st->l1.bcs->cs, ARCOFI_XOP_0, st->l1.bc, 0);
+               st->l1.bcs->cs->hw.elsa.MFlag=1;
+       } else {
+               printk(KERN_WARNING"ElsaSer: unknown pr %x\n", pr);
+       }
+}
+
+void
+modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
+       int count, fp;
+       u_char *msg = buf;
+       long flags;
+       
+       if (!len)
+               return;
+       save_flags(flags);
+       cli();          
+       if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) {
+               restore_flags(flags);
+               return;
+       }
+       fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
+       fp &= (MAX_MODEM_BUF -1);
+       count = MIN(len, MAX_MODEM_BUF - fp);
+       if (count < len) {
+               memcpy(cs->hw.elsa.transbuf + fp, msg, count);
+               cs->hw.elsa.transcnt += count;
+               msg += count;
+               count = len - count;
+               fp = 0;
+       }
+       memcpy(cs->hw.elsa.transbuf + fp, msg, count);
+       cs->hw.elsa.transcnt += count;
+       if (cs->hw.elsa.transcnt && 
+           !(cs->hw.elsa.IER & UART_IER_THRI)) {
+               cs->hw.elsa.IER |= UART_IER_THRI;
+               serial_outp(cs, UART_IER, cs->hw.elsa.IER);
+       }
+       restore_flags(flags);
+}
+
+void
+modem_set_init(struct IsdnCardState *cs) {
+       long flags;
+       int timeout;
+       
+       save_flags(flags);
+       sti();
+       modem_write_cmd(cs, MInit_1, strlen(MInit_1));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       udelay(50000);
+       modem_write_cmd(cs, MInit_2, strlen(MInit_2));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       udelay(50000);
+       modem_write_cmd(cs, MInit_3, strlen(MInit_3));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       udelay(50000);
+       restore_flags(flags);
+}
+
+int
+setstack_elsa(struct PStack *st, struct BCState *bcs)
+{
+
+       switch (st->l1.mode) {
+               case L1_MODE_HDLC:
+               case L1_MODE_TRANS:
+                       if (open_hscxstate(st->l1.hardware, bcs->channel))
+                               return (-1);
+                       st->l2.l2l1 = hscx_l2l1;
+                       break;
+               case L1_MODE_MODEM:
+                       bcs->mode = L1_MODE_MODEM;
+                       if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+                               bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf;
+                               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;
+                       bcs->cs->hw.elsa.bcs = bcs;
+                       st->l2.l2l1 = modem_l2l1;
+                       break;
+       }
+       st->l1.bcs = bcs;
+       setstack_manager(st);
+       bcs->st = st;
+       setstack_l1_B(st);
+       return (0);
+}
+
+void
+init_modem(struct IsdnCardState *cs) {
+
+       cs->bcs[0].BC_SetStack = setstack_elsa;
+       cs->bcs[1].BC_SetStack = setstack_elsa;
+       cs->bcs[0].BC_Close = close_elsastate;
+       cs->bcs[1].BC_Close = close_elsastate;
+       if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF,
+               GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                       "Elsa: No modem mem hw.elsa.rcvbuf\n");
+               return;
+       }
+       if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF,
+               GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                       "Elsa: No modem mem hw.elsa.transbuf\n");
+               kfree(cs->hw.elsa.rcvbuf);
+               cs->hw.elsa.rcvbuf = NULL;
+               return;
+       }
+       if (mstartup(cs)) {
+               printk(KERN_WARNING "Elsa: problem startup modem\n");
+       }
+//     modem_set_init(cs);
+}
+
+void
+release_modem(struct IsdnCardState *cs) {
+
+       cs->hw.elsa.MFlag = 0;
+       if (cs->hw.elsa.transbuf) {
+               if (cs->hw.elsa.rcvbuf) {
+                       mshutdown(cs);
+                       kfree(cs->hw.elsa.rcvbuf);
+                       cs->hw.elsa.rcvbuf = NULL;
+               }
+               kfree(cs->hw.elsa.transbuf);
+               cs->hw.elsa.transbuf = NULL;
+       }
+}
index d0bb2f14f0ead971671b1482f435cbf9253de4a4..f6b1894eac5e51d713a96f43db52bed04e53db17 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.4.2.4 1998/05/27 18:05:21 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,6 +7,24 @@
  *              Fritz Elfert
  *
  * $Log: fsm.c,v $
+ * Revision 1.4.2.4  1998/05/27 18:05:21  keil
+ * HiSax 3.0
+ *
+ * Revision 1.4.2.3  1998/03/07 23:15:20  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
+ * Revision 1.4.2.2  1997/11/15 18:54:29  keil
+ * cosmetics
+ *
+ * Revision 1.4.2.1  1997/10/17 22:13:49  keil
+ * update to last hisax version
+ *
+ * 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
  *
 
 #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;
 
-       fsm->jumpmatrix = (int *)
-           kmalloc(4L * fsm->state_count * fsm->event_count, GFP_KERNEL);
-       memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
-
-       for (i = 0; i < fncount; i++)
-               fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
-                             fnlist[i].state] = (int) fnlist[i].routine;
+       fsm->jumpmatrix = (FSMFNPTR *)
+               kmalloc(sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
+       memset(fsm->jumpmatrix, 0, sizeof (FSMFNPTR) * fsm->state_count * fsm->event_count);
+
+       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(%ld/%ld) ev(%ld/%ld)\n",
+                               i,(long)fnlist[i].state,(long)fsm->state_count,
+                               (long)fnlist[i].event,(long)fsm->event_count);
+               } else          
+                       fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
+                               fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
 }
 
 void
@@ -50,10 +73,15 @@ FsmFree(struct Fsm *fsm)
 int
 FsmEvent(struct FsmInst *fi, int event, void *arg)
 {
-       void (*r) (struct FsmInst *, int, void *);
+       FSMFNPTR r;
        char str[80];
 
-       r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
+       if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
+               printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
+                       (long)fi->state,(long)fi->fsm->state_count,event,(long)fi->fsm->event_count);
+               return(1);
+       }
+       r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
        if (r) {
                if (fi->debug) {
                        sprintf(str, "State %s Event %s",
@@ -155,10 +183,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..10f0e27
--- /dev/null
@@ -0,0 +1,1275 @@
+/* $Id: hfc_2bds0.c,v 1.1.2.6 1998/06/27 22:54:07 keil Exp $
+ *
+ *  specific routines for CCD's HFC 2BDS0
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bds0.c,v $
+ * Revision 1.1.2.6  1998/06/27 22:54:07  keil
+ * make 16.3c working with 3.0
+ *
+ * Revision 1.1.2.5  1998/05/27 18:05:23  keil
+ * HiSax 3.0
+ *
+ * Revision 1.1.2.4  1998/04/08 21:54:35  keil
+ * Fix "ll_trans ..." message
+ *
+ * Revision 1.1.2.3  1998/04/04 21:59:20  keil
+ * Fixed B-channel access
+ *
+ * Revision 1.1.2.2  1998/01/27 22:40:35  keil
+ * fixed IRQ latency, B-channel selection and more
+ *
+ * Revision 1.1.2.1  1998/01/11 22:54:00  keil
+ * Teles 16.3c (HFC 2BDS0) first version
+ *
+ *
+ */
+#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 {
+               SET_SKB_FREE(skb);
+               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, FREE_READ);
+                       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, FREE_READ);
+                               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(%ld/%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, FREE_WRITE);
+               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 | REQUEST):
+                       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 | INDICATION):
+                       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 | REQUEST):
+                       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 | CONFIRM, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+               case (PH_ACTIVATE | REQUEST):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+                       break;
+               case (PH_DEACTIVATE | REQUEST):
+                       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;
+       }
+}
+
+void
+close_2bs0(struct BCState *bcs)
+{
+       mode_2bs0(bcs, 0, 0);
+       if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->hw.hfc.tx_skb) {
+                       dev_kfree_skb(bcs->hw.hfc.tx_skb, FREE_WRITE);
+                       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);
+}
+
+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;
+       setstack_manager(st);
+       bcs->st = st;
+       return (0);
+}
+
+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 | CONFIRM, NULL);
+                       stptr = stptr->next;
+               }
+       }
+#endif
+       if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+               switch (cs->ph_state) {
+                       case (0):
+                               l1_msg(cs, HW_RESET | INDICATION, NULL);
+                               break;
+                       case (3):
+                               l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+                               break;
+                       case (8):
+                               l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+                               break;
+                       case (6):
+                               l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+                               break;
+                       case (7):
+                               l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       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))) {
+                       SET_SKB_FREE(skb);
+                       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, FREE_READ);
+                               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, FREE_READ);
+                                       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(%ld/%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, FREE_WRITE);
+       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, FREE_WRITE);
+                                       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_l1hw(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 | REQUEST):
+                       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 | INDICATION):
+                       if (cs->tx_skb) {
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+                               skb_queue_tail(&cs->sq, skb);
+                               break;
+                       }
+                       if ((cs->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 | REQUEST):
+#ifdef L2FRAME_DEBUG           /* psa */
+                       if (cs->debug & L1_DEB_LAPD)
+                               debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+                       if (!cs->tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+               case (HW_RESET | REQUEST):
+                       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);
+                       l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+                       break;
+               case (HW_ENABLE | REQUEST):
+                       cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
+                       break;
+               case (HW_DEACTIVATE | REQUEST):
+                       cs->hw.hfcD.mst_m &= ~HFCD_MASTER;
+                       cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+                       break;
+               case (HW_INFO3 | REQUEST):
+                       cs->hw.hfcD.mst_m |= HFCD_MASTER;
+                       cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+                       break;
+#if 0
+               case (HW_TESTLOOP | REQUEST):
+                       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(str, "hfcd_l1hw unknown pr %4x", pr);
+                               debugl1(cs, str);
+                       }
+                       break;
+       }
+}
+
+void
+setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
+{
+       st->l1.l1hw = HFCD_l1hw;
+}
+
+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 | INDICATION, 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->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..b435a6c
--- /dev/null
@@ -0,0 +1,133 @@
+/* $Id: hfc_2bds0.h,v 1.1.2.2 1998/01/27 22:41:36 keil Exp $
+
+ *  specific defines for CCD's HFC 2BDS0
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bds0.h,v $
+ * Revision 1.1.2.2  1998/01/27 22:41:36  keil
+ * add set_cs_func()
+ *
+ * Revision 1.1.2.1  1998/01/11 22:54:02  keil
+ * Teles 16.3c (HFC 2BDS0) first version
+ *
+ *
+ */
+
+#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..08209e4
--- /dev/null
@@ -0,0 +1,608 @@
+/* $Id: hfc_2bs0.c,v 1.1.2.5 1998/05/27 18:05:27 keil Exp $
+
+ *  specific routines for CCD's HFC 2BS0
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hfc_2bs0.c,v $
+ * Revision 1.1.2.5  1998/05/27 18:05:27  keil
+ * HiSax 3.0
+ *
+ * Revision 1.1.2.4  1998/04/08 21:54:38  keil
+ * Fix "ll_trans ..." message
+ *
+ * Revision 1.1.2.3  1998/04/04 21:59:23  keil
+ * Fixed B-channel access
+ *
+ * Revision 1.1.2.2  1997/11/15 18:54:27  keil
+ * cosmetics
+ *
+ * Revision 1.1.2.1  1997/10/17 22:10:41  keil
+ * new files on 2.0
+ *
+ * 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 {
+               SET_SKB_FREE(skb);
+               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, FREE_READ);
+                       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, FREE_READ);
+                       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(%ld/%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, FREE_WRITE);
+               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;
+       bcs->channel = bc;
+       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 | REQUEST):
+                       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 | INDICATION):
+                       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 | REQUEST):
+                       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 | CONFIRM, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+               case (PH_ACTIVATE | REQUEST):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+                       break;
+               case (PH_DEACTIVATE | REQUEST):
+                       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;
+       }
+}
+
+
+void
+close_hfcstate(struct BCState *bcs)
+{
+       mode_hfc(bcs, 0, 0);
+       if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->hw.hfc.tx_skb) {
+                       dev_kfree_skb(bcs->hw.hfc.tx_skb, FREE_WRITE);
+                       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);
+}
+
+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;
+       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..1f0a3dc
--- /dev/null
@@ -0,0 +1,65 @@
+/* $Id: hfc_2bs0.h,v 1.1.2.1 1997/10/17 22:10:43 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.2.1  1997/10/17 22:10:43  keil
+ * new files on 2.0
+ *
+ * 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..92ad7a62eefb6f8987667b2f1b237e48990f58f5 100644 (file)
@@ -1,52 +1,68 @@
-/* $Id: hisax.h,v 1.13 1997/04/06 22:54:12 keil Exp $
+/* $Id: hisax.h,v 1.13.2.11 1998/05/27 18:05:30 keil Exp $
 
  *   Basic declarations, defines and prototypes
  *
  * $Log: hisax.h,v $
- * Revision 1.13  1997/04/06 22:54:12  keil
- * Using SKB's
+ * Revision 1.13.2.11  1998/05/27 18:05:30  keil
+ * HiSax 3.0
  *
- * Revision 1.12  1997/03/23 21:45:45  keil
- * Add support for ELSA PCMCIA
+ * Revision 1.13.2.10  1998/04/11 18:43:16  keil
+ * New cards
  *
- * Revision 1.11  1997/02/11 01:36:02  keil
- * New Param structure
+ * Revision 1.13.2.9  1998/03/07 23:15:21  tsbogend
+ * made HiSax working on Linux/Alpha
  *
- * Revision 1.10  1997/02/09 00:23:52  keil
- * new interface handling, one interface per card
+ * Revision 1.13.2.8  1998/02/11 14:23:10  keil
+ * support for Dr Neuhaus Niccy PnP and PCI
  *
- * Revision 1.9  1997/01/27 23:18:44  keil
- * prototype for releasestack_isdnl3
+ * Revision 1.13.2.7  1998/02/09 11:21:22  keil
+ * Sedlbauer PCMCIA support from Marcus Niemann
  *
- * Revision 1.8  1997/01/27 16:02:37  keil
- * new cards, callc timers, HZDELAY macro, HiSax_getrev prototype
+ * Revision 1.13.2.6  1998/02/03 23:16:12  keil
+ * german AOC
  *
- * Revision 1.7  1997/01/21 22:22:14  keil
- * changes for 2.0; Elsa Quickstep support
+ * Revision 1.13.2.5  1998/01/27 22:42:42  keil
+ * changes for new teles 16.3c and dynalink ---> asuscom
  *
- * Revision 1.6  1997/01/04 13:48:28  keil
- * primitiv for MDL_REMOVE added
+ * Revision 1.13.2.4  1998/01/11 22:55:17  keil
+ * 16.3c support
  *
- * Revision 1.5  1996/12/08 19:49:19  keil
- * Monitor channel support
+ * Revision 1.13.2.3  1997/11/27 12:31:59  keil
+ * Working netjet driver
  *
- * Revision 1.4  1996/11/18 15:35:39  keil
- * some changes for ELSA cards
+ * Revision 1.13.2.2  1997/11/15 18:55:43  keil
+ * New init, new cards
  *
- * Revision 1.3  1996/11/05 19:37:23  keil
- * using config.h
+ * Revision 1.13.2.1  1997/10/17 22:13:51  keil
+ * update to last hisax version
  *
- * Revision 1.2  1996/10/27 22:21:52  keil
- * CallFlags for broadcast messages
+ * Revision 2.6  1997/09/11 17:25:51  keil
+ * Add new cards
  *
- * Revision 1.1  1996/10/13 20:03:46  keil
- * Initial revision
+ * Revision 2.5  1997/08/03 14:36:31  keil
+ * Implement RESTART procedure
  *
+ * Revision 2.4  1997/07/31 19:25:20  keil
+ * PTP_DATA_LINK support
  *
+ * Revision 2.3  1997/07/31 11:50:17  keil
+ * ONE TEI and FIXED TEI handling
+ *
+ * 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>
+#include <linux/serial_reg.h>
+
+#define REQUEST                0
+#define CONFIRM                1
+#define INDICATION     2
+#define RESPONSE       3
+
+#define HW_ENABLE      0x0000
+#define HW_RESET       0x0004
+#define HW_POWERUP     0x0008
+#define HW_ACTIVATE    0x0010
+#define HW_DEACTIVATE  0x0018
+#define HW_INFO2       0x0020
+#define HW_INFO3       0x0030
+#define HW_INFO4_P8    0x0040
+#define HW_INFO4_P10   0x0048
+#define HW_RSYNC       0x0060
+#define HW_TESTLOOP    0x0070
+#define CARD_RESET     0x00F0
+#define CARD_SETIRQ    0x00F1
+#define CARD_INIT      0x00F2
+#define CARD_RELEASE   0x00F3
+#define CARD_TEST      0x00F4
+#define CARD_AUX_IND   0x00F5
+
+#define PH_ACTIVATE    0x0100
+#define PH_DEACTIVATE  0x0110
+#define PH_DATA                0x0120
+#define PH_PULL                0x0130
+#define PH_TESTLOOP    0x0140
+#define PH_PAUSE       0x0150
+#define MPH_ACTIVATE   0x0180
+#define MPH_DEACTIVATE 0x0190
+#define MPH_INFORMATION        0x01A0
+
+#define DL_ESTABLISH   0x0200
+#define DL_RELEASE     0x0210
+#define DL_DATA                0x0220
+#define DL_FLUSH       0x0224
+#define DL_UNIT_DATA   0x0230
+#define MDL_ASSIGN     0x0280
+#define MDL_REMOVE     0x0284
+#define MDL_ERROR      0x0288
+#define MDL_INFO_SETUP 0x02E0
+#define MDL_INFO_CONN  0x02E4
+#define MDL_INFO_REL   0x02E8
+
+
+#define CC_SETUP       0x0300
+#define CC_RESUME      0x0304
+#define CC_MORE_INFO   0x0310
+#define CC_IGNORE      0x0320
+#define CC_REJECT      0x0324
+#define CC_SETUP_COMPL 0x0330
+#define CC_PROCEEDING  0x0340
+#define CC_ALERTING    0x0344
+#define CC_CONNECT     0x0350
+#define CC_CHARGE      0x0354
+#define CC_DISCONNECT  0x0360
+#define CC_RELEASE     0x0368
+#define CC_SUSPEND     0x0370
+#define CC_T303                0x0383
+#define CC_T304                0x0384
+#define CC_T305                0x0385
+#define CC_T308_1      0x0388
+#define CC_T308_2      0x0389
+#define CC_T310                0x0390
+#define CC_T313                0x0393
+#define CC_T318                0x0398
+#define CC_T319                0x0399
+#define CC_NOSETUP_RSP 0x03E0
+#define CC_SETUP_ERR   0x03E1
+#define CC_SUSPEND_ERR 0x03E2
+#define CC_RESUME_ERR  0x03E3
+#define CC_CONNECT_ERR 0x03E4
+#define CC_RELEASE_ERR 0x03E5
+#define CC_DLRL                0x03F0
+#define CC_RESTART     0x03F4
 
-#define PH_ACTIVATE   1
-#define PH_DATA       2
-#define PH_DEACTIVATE 3
-
-#define MDL_ASSIGN       4
-#define DL_UNIT_DATA     5
-#define SC_STARTUP       6
-#define CC_ESTABLISH     7
-#define DL_ESTABLISH     8
-#define DL_DATA          9
-#define CC_S_STATUS_ENQ  10
-
-#define CC_CONNECT       15
-#define CC_CONNECT_ACKNOWLEDGE 16
-#define CO_EOF                 17
-#define SC_DISCONNECT          18
-#define CO_DTMF                19
-#define DL_RELEASE             20
-#define DL_FLUSH               21
-
-#define CO_ALARM               22
-#define CC_REJECT              23
-
-#define CC_SETUP_REQ           24
-#define CC_SETUP_CNF           25
-#define CC_SETUP_IND           26
-#define CC_SETUP_RSP           27
-#define CC_SETUP_COMPLETE_IND  28
-
-#define CC_DISCONNECT_REQ      29
-#define CC_DISCONNECT_IND      30
-
-#define CC_RELEASE_CNF         31
-#define CC_RELEASE_IND         32
-#define CC_RELEASE_REQ         33
-
-#define CC_REJECT_REQ          34
-
-#define CC_PROCEEDING_IND      35
-
-#define CC_DLRL                36
-#define CC_DLEST               37
-
-#define CC_ALERTING_REQ        38
-#define CC_ALERTING_IND        39
-
-#define DL_STOP                40
-#define DL_START               41
-
-#define MDL_NOTEIPROC          46
-
-#define LC_ESTABLISH           47
-#define LC_RELEASE             48
-
-#define PH_REQUEST_PULL        49
-#define PH_PULL_ACK            50
-#define        PH_DATA_PULLED         51
-#define CC_INFO_CHARGE         52
-
-#define CC_MORE_INFO           53
-#define CC_IGNORE              54
-
-#define MDL_REMOVE             56
-#define MDL_VERIFY             57
-
-#define CC_T303                60
-#define CC_T304                61
-#define CC_T305                62
-#define CC_T308_1              64
-#define CC_T308_2              65
-#define CC_T310                66
-#define CC_T313                67
-#define CC_T318                68
-#define CC_T319                69
-
-#define CC_NOSETUP_RSP_ERR     70
-#define CC_SETUP_ERR           71
-#define CC_CONNECT_ERR         72
-#define CC_RELEASE_ERR         73
-
-/*
- * Message-Types
- */
-
-#define MT_ALERTING            0x01
-#define MT_CALL_PROCEEDING     0x02
-#define MT_CONNECT             0x07
-#define MT_CONNECT_ACKNOWLEDGE 0x0f
-#define MT_PROGRESS            0x03
-#define MT_SETUP               0x05
-#define MT_SETUP_ACKNOWLEDGE   0x0d
-#define MT_RESUME              0x26
-#define MT_RESUME_ACKNOWLEDGE  0x2e
-#define MT_RESUME_REJECT       0x22
-#define MT_SUSPEND             0x25
-#define MT_SUSPEND_ACKNOWLEDGE 0x2d
-#define MT_SUSPEND_REJECT      0x21
-#define MT_USER_INFORMATION    0x20
-#define MT_DISCONNECT          0x45
-#define MT_RELEASE             0x4d
-#define MT_RELEASE_COMPLETE    0x5a
-#define MT_RESTART             0x46
-#define MT_RESTART_ACKNOWLEDGE 0x4e
-#define MT_SEGMENT             0x60
-#define MT_CONGESTION_CONTROL  0x79
-#define MT_INFORMATION         0x7b
-#define MT_FACILITY            0x62
-#define MT_NOTIFY              0x6e
-#define MT_STATUS              0x7d
-#define MT_STATUS_ENQUIRY      0x75
-
-#define IE_CAUSE               0x08
-
-struct HscxIoctlArg {
-       int channel;
-       int mode;
-       int transbufsize;
-};
 
 #ifdef __KERNEL__
 
-#undef DEBUG_MAGIC
-
-#define MAX_DFRAME_LEN 3072
+#define 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 FsmInst;
+
+typedef void (* FSMFNPTR)(struct FsmInst *, int, void *);
+
 struct Fsm {
-       int *jumpmatrix;
+       FSMFNPTR *jumpmatrix;
        int state_count, event_count;
        char **strEvent, **strState;
 };
@@ -226,73 +210,111 @@ 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 (*l1hw) (struct PStack *, int, void *);
+       void (*l1tei) (struct PStack *, int, void *);
+       int mode, bc;
+       int delay;
 };
 
+#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
+#define FLG_L1_ACTIV   12
+#define FLG_ESTAB_PEND 13
+#define FLG_PTP                14
+#define FLG_FIXED_TEI  15
+
 struct Layer2 {
-       int sap, tei, ces;
-       int extended, laptype;
-       int uihsize, ihsize;
+       int tei;
+       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 (*l3l2) (struct PStack *, int, void *);
-       int state, callref;
-       struct L3Timer timer;
-       int t303, t304, t305, t308, t310, t313, t318, t319;
-       int n_t303;
+       struct FsmInst l3m;
+       struct sk_buff_head squeue;
+       struct l3_process *proc;
+       struct l3_process *global;
+       int N303;
        int debug;
-       int channr;
+       char debug_id[32];
 };
 
-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 {
-       void (*manl1) (struct PStack *, int, void *);
-       void (*manl2) (struct PStack *, int, void *);
-       void (*teil2) (struct PStack *, int, void *);
+       int     ri;
+       struct FsmInst tei_m;
+       struct FsmTimer t202;
+       int T202, N202, debug;
+       void (*layer) (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,95 +322,325 @@ 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
+#define L1_MODE_MODEM  7
+
+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
-};
-
-struct LcFsm {
-       struct FsmInst lcfi;
-       int type;
-       struct Channel *ch;
-       void (*lccall) (struct LcFsm *, int, void *);
-       struct PStack *st;
-       int l2_establish;
-       int l2_start;
-       struct FsmTimer act_timer;
-       char debug_id[32];
+       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 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 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;
+       unsigned int MFlag;
+       struct BCState *bcs;
+       u_char *transbuf;
+       u_char *rcvbuf;
+       unsigned int transp;
+       unsigned int rcvp;
+       unsigned int transcnt;
+       unsigned int rcvcnt;
+       u_char IER;
+       u_char FCR;
+       u_char LCR;
+       u_char MCR;
+       u_char ctrl_reg;
+};     
+
+struct teles3_hw {
+       unsigned int cfg_reg;
+       signed   int isac;
+       signed   int hscx[2];
+       signed   int isacfifo;
+       signed   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 *);
        struct Channel channel[2];
+       struct BCState bcs[2];
        struct PStack *stlist;
        u_char *rcvbuf;
        int rcvidx;
@@ -396,16 +648,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
@@ -413,101 +669,274 @@ struct IsdnCardState {
 #define  MON0_TX       4
 #define  MON1_TX       8
 
+#define         HISAX_MAX_CARDS        8
+
 #define  ISDN_CTYPE_16_0       1
 #define  ISDN_CTYPE_8_0                2
 #define  ISDN_CTYPE_16_3       3
 #define  ISDN_CTYPE_PNP                4
 #define  ISDN_CTYPE_A1         5
 #define  ISDN_CTYPE_ELSA       6
-#define  ISDN_CTYPE_ELSA_QS1000        7
+#define  ISDN_CTYPE_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_S0BOX      25
+
+#define  ISDN_CTYPE_COUNT      25
+
+#ifdef ISDN_CHIP_ISAC
+#undef ISDN_CHIP_ISAC
+#endif
+
+#ifndef __initfunc
+#define __initfunc(__arginit) __arginit
+#endif
 
-#define  ISDN_CTYPE_COUNT      9
+#ifndef __initdata
+#define __initdata
+#endif
+
+#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_TELESPCI
+#define  CARD_TELESPCI (1<< ISDN_CTYPE_TELESPCI)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_TELESPCI  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
+
+#ifdef CONFIG_HISAX_S0BOX
+#define        CARD_S0BOX (1 << ISDN_CTYPE_S0BOX)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define CARD_S0BOX 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 | CARD_S0BOX | CARD_TELESPCI)
+
+#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
 
 struct IsdnCard {
        int typ;
        int protocol;           /* EDSS1 or 1TR6 */
-       unsigned int para[3];
-       struct IsdnCardState *sp;
+       unsigned int para[4];
+       struct IsdnCardState *cs;
 };
 
+int HiSax_inithardware(int *);
+void HiSax_closecard(int cardnr);
 
-#define LAPD 0
-#define LAPB 1
+void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs);
+unsigned int random_ri(void);
+void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
+void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
 
-void l2down(struct PStack *st, u_char pr, struct sk_buff *skb);
-void l2up(struct PStack *st, u_char pr, struct sk_buff *skb);
-void acceptph(struct PStack *st, struct sk_buff *skb);
-void setstack_isdnl2(struct PStack *st, char *debug_id);
-int HiSax_inithardware(void);
-void HiSax_closehardware(void);
+void setstack_l1_B(struct PStack *st);
 
-void setstack_HiSax(struct PStack *st, struct IsdnCardState *sp);
-unsigned int randomces(void);
-void setstack_isdnl3(struct PStack *st, struct Channel *chanp);
-void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
+void setstack_tei(struct PStack *st);
+void setstack_manager(struct PStack *st);
+
+void setstack_isdnl2(struct PStack *st, char *debug_id);
 void releasestack_isdnl2(struct PStack *st);
+void setstack_transl2(struct PStack *st);
+void releasestack_transl2(struct PStack *st);
+
+void setstack_l3dc(struct PStack *st, struct Channel *chanp);
+void setstack_l3bc(struct PStack *st, struct Channel *chanp);
 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);
@@ -518,12 +947,11 @@ int QuickHex(char *txt, u_char * p, int cnt);
 void LogFrame(struct IsdnCardState *sp, u_char * p, int size);
 void dlogframe(struct IsdnCardState *sp, u_char * p, int size, char *comment);
 void iecpy(u_char * dest, u_char * iestart, int ieoffset);
-void setstack_transl2(struct PStack *st);
-void releasestack_transl2(struct PStack *st);
-void close_hscxstate(struct HscxState *);
-void setstack_tei(struct PStack *st);
-
-#endif                         /* __KERNEL__ */
+int discard_queue(struct sk_buff_head *q);
+#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 +961,14 @@ 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 Isdnl3New(void);
+void Isdnl3Free(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..13a7e70
--- /dev/null
@@ -0,0 +1,300 @@
+/* $Id: hscx.c,v 1.3.2.7 1998/06/26 22:02:55 keil Exp $
+
+ * hscx.c   HSCX specific routines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hscx.c,v $
+ * Revision 1.3.2.7  1998/06/26 22:02:55  keil
+ * send flags between hdlc frames
+ *
+ * Revision 1.3.2.6  1998/06/09 18:26:32  keil
+ * PH_DEACTIVATE B-channel every time signaled to higher layer
+ *
+ * Revision 1.3.2.5  1998/05/27 18:05:34  keil
+ * HiSax 3.0
+ *
+ * Revision 1.3.2.4  1998/04/08 21:57:04  keil
+ * Fix "lltrans ..." message
+ * New init code to fix problems during init if S0 is allready activ
+ *
+ * Revision 1.3.2.3  1997/11/27 12:30:55  keil
+ * cosmetic changes
+ *
+ * Revision 1.3.2.2  1997/11/15 18:54:25  keil
+ * cosmetics
+ *
+ * Revision 1.3.2.1  1997/10/17 22:10:44  keil
+ * new files on 2.0
+ *
+ * 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 "isac.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_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_CCR1, 
+                               test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d);
+                       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);
+}
+
+void
+hscx_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       switch (pr) {
+               case (PH_DATA | REQUEST):
+                       save_flags(flags);
+                       cli();
+                       if (st->l1.bcs->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 | INDICATION):
+                       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 | REQUEST):
+                       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 | CONFIRM, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+               case (PH_ACTIVATE | REQUEST):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       modehscx(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       l1_msg_b(st, pr, arg);
+                       break;
+               case (PH_DEACTIVATE | REQUEST):
+                       l1_msg_b(st, pr, arg);
+                       break;
+               case (PH_DEACTIVATE | CONFIRM):
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       modehscx(st->l1.bcs, 0, st->l1.bc);
+                       st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+                       break;
+       }
+}
+
+void
+close_hscxstate(struct BCState *bcs)
+{
+       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;
+               }
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->hw.hscx.tx_skb) {
+                       dev_kfree_skb(bcs->hw.hscx.tx_skb, FREE_WRITE);
+                       bcs->hw.hscx.tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               }
+       }
+}
+
+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);
+}
+
+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;
+       setstack_manager(st);
+       bcs->st = st;
+       setstack_l1_B(st);
+       return (0);
+}
+
+HISAX_INITFUNC(void
+clear_pending_hscx_ints(struct IsdnCardState *cs))
+{
+       int val, eval;
+       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) {
+               eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
+               sprintf(tmp, "HSCX B EXIR %x", eval);
+               debugl1(cs, tmp);
+       }
+       if (val & 0x02) {
+               eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
+               sprintf(tmp, "HSCX A EXIR %x", eval);
+               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);
+       /* disable all IRQ */
+       cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
+       cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
+}
+
+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);
+}
+
+HISAX_INITFUNC(void 
+inithscxisac(struct IsdnCardState *cs, int part))
+{
+       if (part & 1) {
+               clear_pending_isac_ints(cs);
+               clear_pending_hscx_ints(cs);
+               initisac(cs);
+               inithscx(cs);
+       }
+       if (part & 2) {
+               /* Reenable all IRQ */
+               cs->writeisac(cs, ISAC_MASK, 0);
+               cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
+               cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
+               /* RESET Receiver and Transmitter */
+               cs->writeisac(cs, ISAC_CMDR, 0x41);
+       }
+}
diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h
new file mode 100644 (file)
index 0000000..ca32839
--- /dev/null
@@ -0,0 +1,53 @@
+/* $Id: hscx.h,v 1.3.2.2 1998/04/08 21:57:30 keil Exp $
+
+ * hscx.h   HSCX specific defines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: hscx.h,v $
+ * Revision 1.3.2.2  1998/04/08 21:57:30  keil
+ * New init code to fix problems during init if S0 is allready activ
+ *
+ * Revision 1.3.2.1  1997/10/17 22:10:45  keil
+ * new files on 2.0
+ *
+ * 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);
+extern void inithscxisac(struct IsdnCardState *cs, int part);
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c
new file mode 100644 (file)
index 0000000..46da67f
--- /dev/null
@@ -0,0 +1,321 @@
+/* $Id: hscx_irq.c,v 1.5.2.3 1998/06/24 14:43:56 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.5.2.3  1998/06/24 14:43:56  keil
+ * Fix recovery of TX IRQ loss
+ *
+ * Revision 1.5.2.2  1998/05/27 18:05:36  keil
+ * HiSax 3.0
+ *
+ * Revision 1.5.2.1  1997/10/17 22:10:46  keil
+ * new files on 2.0
+ *
+ * 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 {
+                                       SET_SKB_FREE(skb);
+                                       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 {
+                               SET_SKB_FREE(skb);
+                               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, FREE_WRITE);
+                               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..aa074d6
--- /dev/null
@@ -0,0 +1,36 @@
+/* $Id: ipac.h,v 1.1.2.2 1998/04/11 18:49:48 keil Exp $
+
+ * ipac.h   IPAC specific defines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: ipac.h,v $
+ * Revision 1.1.2.2  1998/04/11 18:49:48  keil
+ * add IPAC_ATX
+ *
+ * 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_ATX       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..ee6ec7b
--- /dev/null
@@ -0,0 +1,703 @@
+/* $Id: isac.c,v 1.7.2.7 1998/05/27 18:05:38 keil Exp $
+
+ * isac.c   ISAC specific routines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: isac.c,v $
+ * Revision 1.7.2.7  1998/05/27 18:05:38  keil
+ * HiSax 3.0
+ *
+ * Revision 1.7.2.6  1998/04/08 21:57:31  keil
+ * New init code to fix problems during init if S0 is allready activ
+ *
+ * Revision 1.7.2.5  1998/03/07 23:15:24  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
+ * Revision 1.7.2.4  1998/02/09 11:24:06  keil
+ * New leased line support (Read README.HiSax!)
+ *
+ * Revision 1.7.2.3  1998/01/11 22:58:55  keil
+ * new setstack interface
+ *
+ * Revision 1.7.2.2  1997/11/15 18:54:23  keil
+ * cosmetics
+ *
+ * Revision 1.7.2.1  1997/10/17 22:10:49  keil
+ * new files on 2.0
+ *
+ * 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 (%x): %s\n", s, val, 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
+isac_new_ph(struct IsdnCardState *cs)
+{
+       switch (cs->ph_state) {
+               case (ISAC_IND_RS):
+               case (ISAC_IND_EI):
+                       ph_command(cs, ISAC_CMD_DUI);
+                       l1_msg(cs, HW_RESET | INDICATION, NULL);
+                       break;
+               case (ISAC_IND_DID):
+                       l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+                       break;
+               case (ISAC_IND_DR):
+                       l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+                       break;
+               case (ISAC_IND_PU):
+                       l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+                       break;
+               case (ISAC_IND_RSY):
+                       l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+                       break;
+               case (ISAC_IND_ARD):
+                       l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+                       break;
+               case (ISAC_IND_AI8):
+                       l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                       break;
+               case (ISAC_IND_AI10):
+                       l1_msg(cs, HW_INFO4_P10 | INDICATION, 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 | CONFIRM, 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_RX_END, &cs->HW_Flags);
+       if (test_and_clear_bit(D_RX_MON1, &cs->event))
+               test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags);
+       if (test_and_clear_bit(D_TX_MON0, &cs->event))
+               test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+       if (test_and_clear_bit(D_TX_MON1, &cs->event))
+               test_and_set_bit(HW_MON1_TX_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 {
+                                       SET_SKB_FREE(skb);
+                                       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, FREE_WRITE);
+                               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 */
+               exval = cs->readisac(cs, ISAC_CIR0);
+               if (cs->debug & L1_DEB_ISAC) {
+                       sprintf(tmp, "ISAC CIR0 %02X", exval );
+                       debugl1(cs, tmp);
+               }
+               if (exval & 2) {
+                       cs->ph_state = (exval >> 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 (exval & 1) {
+                       exval = cs->readisac(cs, ISAC_CIR1);
+                       if (cs->debug & L1_DEB_ISAC) {
+                               sprintf(tmp, "ISAC CIR1 %02X", exval );
+                               debugl1(cs, tmp);
+                       }
+               }
+       }
+       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_MONITOR) {
+                               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_MONITOR) {
+                                       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_MONITOR) {
+                                       sprintf(tmp, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]);
+                                       debugl1(cs, tmp);
+                               }
+                                       cs->mocr |= 0x40;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               }
+                     afterMONR1:
+                       if (v1 & 0x04) {
+                               cs->mocr &= 0xf0;
+                               cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               cs->mocr |= 0x0a;
+                               cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               test_and_set_bit(HW_MON0_RX_END, &cs->HW_Flags);
+                       }
+                       if (v1 & 0x40) {
+                               cs->mocr &= 0x0f;
+                               cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               cs->mocr |= 0xa0;
+                               cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                               test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags);
+                       }
+                       if (v1 & 0x02) {
+                               if ((!cs->mon_tx) || (cs->mon_txc && 
+                                       (cs->mon_txp >= cs->mon_txc) && 
+                                       !(v1 & 0x08))) {
+                                       cs->mocr &= 0xf0;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                       cs->mocr |= 0x0a;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                       if (cs->mon_txc &&
+                                               (cs->mon_txp >= cs->mon_txc))
+                                               test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+                                       goto AfterMOX0;
+                               }
+                               if (cs->mon_txc && (cs->mon_txp >= cs->mon_txc)) {
+                                       test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+                                       goto AfterMOX0;
+                               }
+                               cs->writeisac(cs, ISAC_MOX0,
+                                       cs->mon_tx[cs->mon_txp++]);
+                               if (cs->debug & L1_DEB_MONITOR) {
+                                       sprintf(tmp, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]);
+                                       debugl1(cs, tmp);
+                               }
+                       }
+                     AfterMOX0:
+                       if (v1 & 0x20) {
+                               if ((!cs->mon_tx) || (cs->mon_txc && 
+                                       (cs->mon_txp >= cs->mon_txc) && 
+                                       !(v1 & 0x80))) {
+                                       cs->mocr &= 0x0f;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                       cs->mocr |= 0xa0;
+                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
+                                       if (cs->mon_txc &&
+                                               (cs->mon_txp >= cs->mon_txc))
+                                               test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags);
+                                       goto AfterMOX1;
+                               }
+                               if (cs->mon_txc && (cs->mon_txp >= cs->mon_txc)) {
+                                       test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags);
+                                       goto AfterMOX1;
+                               }
+                               cs->writeisac(cs, ISAC_MOX1,
+                                       cs->mon_tx[cs->mon_txp++]);
+                               if (cs->debug & L1_DEB_MONITOR) {
+                                       sprintf(tmp, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]);
+                                       debugl1(cs, tmp);
+                               }
+                       }
+                     AfterMOX1:
+#endif
+               }
+       }
+}
+
+static void
+ISAC_l1hw(struct PStack *st, int pr, void *arg)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+       struct sk_buff *skb = arg;
+       int  val;
+       char str[64];
+
+       switch (pr) {
+               case (PH_DATA |REQUEST):
+                       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 |INDICATION):
+                       if (cs->tx_skb) {
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+                               skb_queue_tail(&cs->sq, skb);
+                               break;
+                       }
+                       if ((cs->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 | REQUEST):
+#ifdef L2FRAME_DEBUG           /* psa */
+                       if (cs->debug & L1_DEB_LAPD)
+                               debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+                       if (!cs->tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+               case (HW_RESET | REQUEST):
+                       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 (HW_ENABLE | REQUEST):
+                       ph_command(cs, ISAC_CMD_TIM);
+                       break;
+               case (HW_INFO3 | REQUEST):
+                       ph_command(cs, ISAC_CMD_AR8);
+                       break;
+               case (HW_TESTLOOP | REQUEST):
+                       val = 0;
+                       if (1 & (long) arg)
+                               val |= 0x0c;
+                       if (2 & (long) 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;
+               case (HW_DEACTIVATE | RESPONSE):
+                       discard_queue(&cs->rq);
+                       discard_queue(&cs->sq);
+                       if (cs->tx_skb) {
+                               dev_kfree_skb(cs->tx_skb, FREE_WRITE);
+                               cs->tx_skb = NULL;
+                       }
+                       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);
+                       break;
+               default:
+                       if (cs->debug & L1_DEB_WARN) {
+                               sprintf(str, "isac_l1hw unknown %04x", pr);
+                               debugl1(cs, str);
+                       }
+                       break;
+       }
+}
+
+void
+setstack_isac(struct PStack *st, struct IsdnCardState *cs)
+{
+       st->l1.l1hw = ISAC_l1hw;
+}
+
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+       struct PStack *stptr;
+       int     val;
+
+       if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+               if (cs->debug) {
+                       debugl1(cs, "D-Channel Busy");
+                       val = cs->readisac(cs, ISAC_RBCH);
+                       if (val & ISAC_RBCH_XAC)
+                               debugl1(cs, "ISAC XAC");
+                       else
+                               debugl1(cs, "ISAC No XAC");
+               }
+               test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+               stptr = cs->stlist;
+               
+               while (stptr != NULL) {
+                       stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+                       stptr = stptr->next;
+               }
+       }
+}
+
+HISAX_INITFUNC(void
+initisac(struct IsdnCardState *cs))
+{
+       cs->tqueue.routine = (void *) (void *) isac_bh;
+       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, eval;
+       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) {
+               eval = cs->readisac(cs, ISAC_EXIR);
+               sprintf(tmp, "ISAC EXIR %x", eval);
+               debugl1(cs, tmp);
+       }
+       val = cs->readisac(cs, ISAC_CIR0);
+       sprintf(tmp, "ISAC CIR0 %x", val);
+       debugl1(cs, tmp);
+       cs->ph_state = (val >> 2) & 0xf;
+       isac_sched_event(cs, D_L1STATECHANGE);
+       /* Disable all IRQ */
+       cs->writeisac(cs, ISAC_MASK, 0xFF);
+}
diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h
new file mode 100644 (file)
index 0000000..b904ffb
--- /dev/null
@@ -0,0 +1,84 @@
+/* $Id: isac.h,v 1.3.2.3 1998/05/27 18:05:41 keil Exp $
+
+ * isac.h   ISAC specific defines
+ *
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: isac.h,v $
+ * Revision 1.3.2.3  1998/05/27 18:05:41  keil
+ * HiSax 3.0
+ *
+ * Revision 1.3.2.2  1997/11/15 19:01:14  keil
+ * ipac changes
+ *
+ * Revision 1.3.2.1  1997/10/17 22:10:50  keil
+ * new files on 2.0
+ *
+ * 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_ADF2 0x39
+#define ISAC_SPCR 0x30
+#define ISAC_ADF1 0x38
+#define ISAC_CIR0 0x31
+#define ISAC_CIX0 0x31
+#define ISAC_CIR1 0x33
+#define ISAC_CIX1 0x33
+#define ISAC_STCR 0x37
+#define ISAC_MODE 0x22
+#define ISAC_RSTA 0x27
+#define ISAC_RBCL 0x25
+#define ISAC_RBCH 0x2A
+#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_RBCH_XAC 0x80
+
+#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 f0aaba0c90357e22af5bca5584e18c9c6d333478..5608600fe71eb52198a8b87e52b113c9697dcadb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 1.15 1997/05/27 15:17:55 fritz Exp $
+/* $Id: isdnl1.c,v 1.15.2.12 1998/05/27 18:05:43 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 1.15.2.12  1998/05/27 18:05:43  keil
+ * HiSax 3.0
+ *
+ * Revision 1.15.2.11  1998/05/26 10:36:51  keil
+ * fixes from certification
+ *
+ * Revision 1.15.2.10  1998/04/11 18:47:45  keil
+ * Fixed bug which was overwriting nrcards
+ * New card support
  *
- * Revision 1.14  1997/04/07 23:00:08  keil
- * GFP_KERNEL ---> GFP_ATOMIC
+ * Revision 1.15.2.9  1998/04/08 21:52:00  keil
+ * new debug
  *
- * Revision 1.13  1997/04/06 22:55:50  keil
- * Using SKB's
+ * Revision 1.15.2.8  1998/03/07 23:15:26  tsbogend
+ * made HiSax working on Linux/Alpha
  *
- * Revision 1.12  1997/03/26 13:43:57  keil
- * small cosmetics
+ * Revision 1.15.2.7  1998/02/11 14:23:14  keil
+ * support for Dr Neuhaus Niccy PnP and PCI
  *
- * Revision 1.11  1997/03/25 23:11:23  keil
- * US NI-1 protocol
+ * Revision 1.15.2.6  1998/02/09 11:24:11  keil
+ * New leased line support (Read README.HiSax!)
  *
- * Revision 1.10  1997/03/13 14:45:05  keil
- * using IRQ proof queue_task
+ * Revision 1.15.2.5  1998/01/27 22:33:55  keil
+ * dynalink ----> asuscom
  *
- * Revision 1.9  1997/03/12 21:44:21  keil
- * change Interrupt routine from atomic quick to normal
+ * Revision 1.15.2.4  1998/01/11 22:55:20  keil
+ * 16.3c support
  *
- * Revision 1.8  1997/02/09 00:24:31  keil
- * new interface handling, one interface per card
+ * Revision 1.15.2.3  1997/11/15 18:50:34  keil
+ * new common init function
  *
- * Revision 1.7  1997/01/27 15:56:03  keil
- * PCMCIA Teles card and ITK ix1 micro added
+ * Revision 1.15.2.2  1997/10/17 22:13:54  keil
+ * update to last hisax version
  *
- * Revision 1.6  1997/01/21 22:20:00  keil
- * changes for D-channel log; Elsa Quickstep support
+ * Revision 2.6  1997/09/12 10:05:16  keil
+ * ISDN_CTRL_DEBUG define
  *
- * Revision 1.5  1997/01/10 12:51:19  keil
- * cleanup; set newversion
+ * Revision 2.5  1997/09/11 17:24:45  keil
+ * Add new cards
  *
- * Revision 1.4  1996/12/08 19:44:53  keil
- * L2FRAME_DEBUG and other changes from Pekka Sarnila
+ * Revision 2.4  1997/08/15 17:47:09  keil
+ * avoid oops because a uninitialised timer
  *
- * Revision 1.3  1996/11/18 15:34:47  keil
- * fix HSCX version code
+ * Revision 2.3  1997/08/01 11:16:40  keil
+ * cosmetics
  *
- * Revision 1.2  1996/10/27 22:16:54  keil
- * ISAC/HSCX version lookup
+ * Revision 2.2  1997/07/30 17:11:08  keil
+ * L1deactivated exported
  *
- * Revision 1.1  1996/10/13 20:04:53  keil
- * Initial revision
+ * 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: 1.15.2.12 $";
 
 #define __NO_VERSION__
 #include <linux/config.h>
 #include "hisax.h"
 #include "isdnl1.h"
+#include <linux/kernel_stat.h>
+#define kstat_irqs( PAR ) kstat.interrupts[PAR]
 
 #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_S0BOX
+extern int setup_s0box(struct IsdnCard *card);
+#endif
+
+#if CARD_TELESPCI
+extern int setup_telespci(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", "S0Box"
+};
 
 extern struct IsdnCard cards[];
 extern int nrcards;
 extern char *HiSax_id;
+extern struct IsdnBuffers *tracebuf;
+
+#define TIMER3_VALUE 7000
+
+static
+struct Fsm l1fsm_b =
+{NULL, 0, 0, NULL, NULL};
+
+static
+struct Fsm l1fsm_d =
+{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 L1D_STATE_COUNT (ST_L1_F8+1)
+
+static char *strL1DState[] =
+{
+       "ST_L1_F2",
+       "ST_L1_F3",
+       "ST_L1_F4",
+       "ST_L1_F5",
+       "ST_L1_F6",
+       "ST_L1_F7",
+       "ST_L1_F8",
+};
+
+enum {
+       ST_L1_NULL,
+       ST_L1_WAIT_ACT,
+       ST_L1_WAIT_DEACT,
+       ST_L1_ACTIV,
+};
+
+#define L1B_STATE_COUNT (ST_L1_ACTIV+1)
+
+static char *strL1BState[] =
+{
+       "ST_L1_NULL",
+       "ST_L1_WAIT_ACT",
+       "ST_L1_WAIT_DEACT",
+       "ST_L1_ACTIV",
+};
+
+enum {
+       EV_PH_ACTIVATE,
+       EV_PH_DEACTIVATE,
+       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_PH_DEACTIVATE",
+       "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 +295,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 +328,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 +389,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.l1l2(st, PH_ACTIVATE | CONFIRM, 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.l1l2(st, PH_ACTIVATE | INDICATION, 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 | CONFIRM, NULL);
+               st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, 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 | CONFIRM, 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 | INDICATION, 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 | INDICATION, nskb);
+                                       else
+                                               printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n");
+                                       stptr = stptr->next;
+                               }
                        }
-                       SET_SKB_FREE(skb);
                        dev_kfree_skb(skb, FREE_READ);
-               } 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 | INDICATION, skb);
                                        found = !0;
                                        break;
                                } else
@@ -474,167 +516,76 @@ 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, FREE_READ);
                        }
                }
-
-       }
-
-}
-
-static void
-isac_bh(struct IsdnCardState *sp)
-{
-       if (!sp)
-               return;
-
-       if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event))
-               process_new_ph(sp);
-       if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event))
-               process_rcv(sp);
-       if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event))
-               process_xmt(sp);
-}
-
-static void
-l2l1(struct PStack *st, int pr, void *arg)
-{
-       struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
-       struct sk_buff *skb = arg;
-       char str[64];
-
-       switch (pr) {
-               case (PH_DATA):
-                       if (sp->tx_skb) {
-                               skb_queue_tail(&sp->sq, skb);
-#ifdef L2FRAME_DEBUG           /* psa */
-                               if (sp->debug & L1_DEB_LAPD)
-                                       Logl2Frame(sp, skb, "PH_DATA Queued", 0);
-#endif
-                       } else {
-                               if ((sp->dlogflag) && (!(skb->data[2] & 1))) {  /* I-FRAME */
-                                       LogFrame(sp, skb->data, skb->len);
-                                       sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
-                                       dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize,
-                                                 str);
-                               }
-                               sp->tx_skb = skb;
-                               sp->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG           /* psa */
-                               if (sp->debug & L1_DEB_LAPD)
-                                       Logl2Frame(sp, skb, "PH_DATA", 0);
-#endif
-                               sp->isac_fill_fifo(sp);
-                       }
-                       break;
-               case (PH_DATA_PULLED):
-                       if (sp->tx_skb) {
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, " l2l1 tx_skb exist this shouldn't happen");
-                               break;
-                       }
-                       if ((sp->dlogflag) && (!(skb->data[2] & 1))) {  /* I-FRAME */
-                               LogFrame(sp, skb->data, skb->len);
-                               sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
-                               dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize,
-                                         str);
-                       }
-                       sp->tx_skb = skb;
-                       sp->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG           /* psa */
-                       if (sp->debug & L1_DEB_LAPD)
-                               Logl2Frame(sp, skb, "PH_DATA_PULLED", 0);
-#endif
-                       sp->isac_fill_fifo(sp);
-                       break;
-               case (PH_REQUEST_PULL):
-#ifdef L2FRAME_DEBUG           /* psa */
-                       if (sp->debug & L1_DEB_LAPD)
-                               debugl1(sp, "-> PH_REQUEST_PULL");
-#endif
-                       if (!sp->tx_skb) {
-                               st->l1.requestpull = 0;
-                               st->l1.l1l2(st, PH_PULL_ACK, NULL);
-                       } else
-                               st->l1.requestpull = !0;
-                       break;
        }
 }
 
-
 static void
-hscx_process_xmt(struct HscxState *hsp)
+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 (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
+               st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+       if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
+               if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) {
+                       st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
+               }
        }
-       if (!hsp->active)
-               if ((!hsp->tx_skb) && (!skb_queue_len(&hsp->squeue)))
-                       hsp->sp->modehscx(hsp, 0, 0);
 }
 
 static void
-hscx_process_rcv(struct HscxState *hsp)
+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;
+       if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) {
+               FsmDelTimer(&bcs->st->l1.timer, 4);
+               FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL);
        }
-#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 | INDICATION, 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,253 +595,129 @@ HiSax_rmlist(struct IsdnCardState *sp,
        }
 }
 
-static void
-check_ph_act(struct IsdnCardState *sp)
+void
+init_bcstate(struct IsdnCardState *cs,
+            int bc)
 {
-       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;
+       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
-HiSax_manl1(struct PStack *st, int pr,
-           void *arg)
+closecard(int cardnr)
 {
-       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;
+       struct IsdnCardState *csta = cards[cardnr].cs;
+       
+       if (csta->bcs->BC_Close != NULL) { 
+               csta->bcs->BC_Close(csta->bcs + 1);
+               csta->bcs->BC_Close(csta->bcs);
        }
-}
 
-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;
+       if (csta->rcvbuf) {
+               kfree(csta->rcvbuf);
+               csta->rcvbuf = NULL;
        }
-#endif
-
-       while ((skb = skb_dequeue(&sp->sq)))
-               dev_kfree_skb(skb, FREE_WRITE);
-}
-
-void
-setstack_HiSax(struct PStack *st, struct IsdnCardState *sp)
-{
-       st->l1.hardware = sp;
-       st->protocol = sp->protocol;
-
-       setstack_tei(st);
-
-       st->l1.stlistp = &(sp->stlist);
-       st->l1.act_state = 0;
-       st->l2.l2l1 = l2l1;
-       st->l2.l2l1discardq = HiSax_l2l1discardq;
-       st->ma.manl1 = HiSax_manl1;
-       st->l1.requestpull = 0;
-}
-
-void
-init_hscxstate(struct IsdnCardState *sp,
-              int hscx)
-{
-       struct HscxState *hsp = sp->hs + hscx;
-
-       hsp->sp = sp;
-       hsp->hscx = hscx;
-
-       hsp->tqueue.next = 0;
-       hsp->tqueue.sync = 0;
-       hsp->tqueue.routine = (void *) (void *) hscx_bh;
-       hsp->tqueue.data = hsp;
-
-       hsp->inuse = 0;
-       hsp->init = 0;
-       hsp->active = 0;
-
-#ifdef DEBUG_MAGIC
-       hsp->magic = 301270;
-#endif
+       discard_queue(&csta->rq);
+       discard_queue(&csta->sq);
+       if (csta->tx_skb) {
+               dev_kfree_skb(csta->tx_skb, FREE_WRITE);
+               csta->tx_skb = NULL;
+       }
+       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);
 }
 
-int
-get_irq(int cardnr, void *routine)
+HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
 {
-       struct IsdnCard *card = cards + cardnr;
+       int irq_cnt, cnt = 3;
        long flags;
 
        save_flags(flags);
        cli();
-       if (request_irq(card->sp->irq, routine,
-                       I4L_IRQ_FLAG, "HiSax", NULL)) {
+       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",
-                      card->sp->irq);
+                       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);
-               return (0);
+               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);
+               }
        }
-       irq2dev_map[card->sp->irq] = (void *) card->sp;
        restore_flags(flags);
-       return (1);
+       return(3);
 }
 
-static void
-release_irq(int cardnr)
+HISAX_INITFUNC(static int
+checkcard(int cardnr, char *id, int *busy_flag))
 {
+       long flags;
+       int ret = 0;
        struct IsdnCard *card = cards + cardnr;
+       struct IsdnCardState *cs;
 
-       irq2dev_map[card->sp->irq] = NULL;
-       free_irq(card->sp->irq, NULL);
-}
-
-void
-close_hscxstate(struct HscxState *hs)
-{
-       struct sk_buff *skb;
-
-       hs->sp->modehscx(hs, 0, 0);
-       hs->inuse = 0;
-       if (hs->init) {
-               if (hs->rcvbuf) {
-                       kfree(hs->rcvbuf);
-                       hs->rcvbuf = NULL;
-               }
-               while ((skb = skb_dequeue(&hs->rqueue))) {
-                       SET_SKB_FREE(skb);
-                       dev_kfree_skb(skb, FREE_READ);
-               }
-               while ((skb = skb_dequeue(&hs->squeue)))
-                       dev_kfree_skb(skb, FREE_WRITE);
-               if (hs->tx_skb) {
-                       dev_kfree_skb(hs->tx_skb, FREE_WRITE);
-                       hs->tx_skb = NULL;
-               }
+       save_flags(flags);
+       cli();
+       if (!(cs = (struct IsdnCardState *)
+             kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for IsdnCardState(card %d)\n",
+                      cardnr + 1);
+               restore_flags(flags);
+               return (0);
        }
-       hs->init = 0;
-}
-
-static void
-closecard(int cardnr)
-{
-       struct IsdnCardState *csta = cards[cardnr].sp;
-       struct sk_buff *skb;
-
-       close_hscxstate(csta->hs + 1);
-       close_hscxstate(csta->hs);
-
-       if (csta->rcvbuf) {
-               kfree(csta->rcvbuf);
-               csta->rcvbuf = NULL;
-       }
-       while ((skb = skb_dequeue(&csta->rq))) {
-               SET_SKB_FREE(skb);
-               dev_kfree_skb(skb, FREE_READ);
-       }
-       while ((skb = skb_dequeue(&csta->sq)))
-               dev_kfree_skb(skb, FREE_WRITE);
-       if (csta->tx_skb) {
-               dev_kfree_skb(csta->tx_skb, FREE_WRITE);
-               csta->tx_skb = NULL;
-       }
-       switch (csta->typ) {
-#if CARD_TELES0
-               case ISDN_CTYPE_16_0:
-               case ISDN_CTYPE_8_0:
-                       release_io_teles0(cards + cardnr);
-                       break;
-#endif
-#if CARD_TELES3
-               case ISDN_CTYPE_PNP:
-               case ISDN_CTYPE_16_3:
-               case ISDN_CTYPE_TELESPCMCIA:
-                       release_io_teles3(cards + cardnr);
-                       break;
-#endif
-#if CARD_AVM_A1
-               case ISDN_CTYPE_A1:
-                       release_io_avm_a1(cards + cardnr);
-                       break;
-#endif
-#if CARD_ELSA
-               case ISDN_CTYPE_ELSA:
-               case ISDN_CTYPE_ELSA_QS1000:
-                       release_io_elsa(cards + cardnr);
-                       break;
-#endif
-#if CARD_IX1MICROR2
-               case ISDN_CTYPE_IX1MICROR2:
-                       release_io_ix1micro(cards + cardnr);
-                       break;
+       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
-               default:
-                       break;
-       }
-       ll_unload(csta);
-}
-
-static int
-checkcard(int cardnr, char *id)
-{
-       long flags;
-       int ret = 0;
-       struct IsdnCard *card = cards + cardnr;
-       struct IsdnCardState *sp;
-
-       save_flags(flags);
-       cli();
-       if (!(sp = (struct IsdnCardState *)
-             kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for IsdnCardState(card %d)\n",
-                      cardnr + 1);
-               restore_flags(flags);
-               return (0);
-       }
-       card->sp = sp;
-       sp->cardnr = cardnr;
-       sp->cfg_reg = 0;
-       sp->protocol = card->protocol;
+       cs->protocol = card->protocol;
 
        if ((card->typ > 0) && (card->typ < 31)) {
                if (!((1 << card->typ) & SUPORTED_CARDS)) {
@@ -907,33 +734,37 @@ 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_MODEM |
            ISDN_FEATURE_L2_TRANS |
            ISDN_FEATURE_L3_TRANS |
 #ifdef CONFIG_HISAX_1TR6
@@ -947,21 +778,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:
@@ -973,9 +802,20 @@ 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
+#if CARD_S0BOX
+               case ISDN_CTYPE_S0BOX:
+                       ret = setup_s0box(card);
+                       break;
+#endif
+#if CARD_TELESPCI
+               case ISDN_CTYPE_TELESPCI:
+                       ret = setup_telespci(card);
+                       break;
+#endif
 #if CARD_AVM_A1
                case ISDN_CTYPE_A1:
                        ret = setup_avm_a1(card);
@@ -983,7 +823,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
@@ -992,99 +834,111 @@ 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);
+       restore_flags(flags);
        return (1);
 }
 
-void
-HiSax_shiftcards(int idx)
+HISAX_INITFUNC(void
+HiSax_shiftcards(int idx))
 {
        int i;
 
-       for (i = idx; i < 15; i++)
+       for (i = idx; i < (HISAX_MAX_CARDS - 1); i++)
                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;
@@ -1114,15 +968,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);
                }
        }
@@ -1130,165 +984,73 @@ HiSax_inithardware(void)
 }
 
 void
-HiSax_closehardware(void)
+HiSax_closecard(int cardnr)
 {
-       int i;
-       long flags;
+       int     i,last=nrcards - 1;
 
-       save_flags(flags);
-       cli();
-       for (i = 0; i < nrcards; i++)
-               if (cards[i].sp) {
-                       ll_stop(cards[i].sp);
-                       CallcFreeChan(cards[i].sp);
-                       release_tei(cards[i].sp);
-                       release_irq(i);
-                       closecard(i);
-                       kfree((void *) cards[i].sp);
-                       cards[i].sp = NULL;
-               }
-       Isdnl2Free();
-       CallcFree();
-       restore_flags(flags);
-}
-
-static void
-hscx_l2l1(struct PStack *st, int pr, void *arg)
-{
-       struct sk_buff *skb = arg;
-       struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
-       struct HscxState *hsp = sp->hs + st->l1.hscx;
-       long flags;
-
-       switch (pr) {
-               case (PH_DATA):
-                       save_flags(flags);
-                       cli();
-                       if (hsp->tx_skb) {
-                               skb_queue_tail(&hsp->squeue, skb);
-                               restore_flags(flags);
-                       } else {
-                               restore_flags(flags);
-                               hsp->tx_skb = skb;
-                               hsp->count = 0;
-                               sp->hscx_fill_fifo(hsp);
-                       }
-                       break;
-               case (PH_DATA_PULLED):
-                       if (hsp->tx_skb) {
-                               printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
-                               break;
-                       }
-                       hsp->tx_skb = skb;
-                       hsp->count = 0;
-                       sp->hscx_fill_fifo(hsp);
-                       break;
-               case (PH_REQUEST_PULL):
-                       if (!hsp->tx_skb) {
-                               st->l1.requestpull = 0;
-                               st->l1.l1l2(st, PH_PULL_ACK, NULL);
-                       } else
-                               st->l1.requestpull = !0;
-                       break;
-       }
-
-}
-extern struct IsdnBuffers *tracebuf;
-
-static void
-hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
-                 int releasetoo)
-{
-       struct IsdnCardState *sp = (struct IsdnCardState *)
-       st->l1.hardware;
-       struct HscxState *hsp = sp->hs + st->l1.hscx;
-       struct sk_buff *skb;
-
-#ifdef DEBUG_MAGIC
-       if (hsp->magic != 301270) {
-               printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
+       if (cardnr>last)
                return;
+       if (cards[cardnr].cs) {
+               ll_stop(cards[cardnr].cs);
+               release_tei(cards[cardnr].cs);
+               closecard(cardnr);
+               free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
+               kfree((void *) cards[cardnr].cs);
+               cards[cardnr].cs = NULL;
        }
-#endif
-
-       while ((skb = skb_dequeue(&hsp->squeue)))
-               dev_kfree_skb(skb, FREE_WRITE);
-}
-
-static int
-open_hscxstate(struct IsdnCardState *sp,
-              int hscx)
-{
-       struct HscxState *hsp = sp->hs + hscx;
-
-       if (!hsp->init) {
-               if (!(hsp->rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
-                       printk(KERN_WARNING
-                              "HiSax: No memory for hscx_rcvbuf\n");
-                       return (1);
+       i = cardnr;
+       while (i!=last) {
+               cards[i] = cards[i+1];
+               i++;
                }
-               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);
+       nrcards--;
 }
 
 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 */
@@ -1325,7 +1087,7 @@ l2cmd(u_char cmd)
        }
 }
 
-static char tmp[20];
+static char tmp[24];
 
 char *
 l2frames(u_char * ptr)
@@ -1358,7 +1120,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;
@@ -1366,13 +1128,381 @@ 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;
+
+       FsmChangeState(fi, ST_L1_F3);
+       if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
+               st->l1.l1hw(st, HW_ENABLE | REQUEST, 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;
+
+       if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
+               FsmChangeState(fi, ST_L1_F4);
+               st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
+               FsmDelTimer(&st->l1.timer, 1);
+               FsmAddTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+               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;
+
+       FsmChangeState(fi, ST_L1_F6);
+       st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
+}
+
+static void
+l1_info4_ind(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L1_F7);
+       st->l1.l1hw(st, HW_INFO3 | REQUEST, 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;
+       
+       test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);        
+        if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
+               L1deactivated(st->l1.hardware);
+        if (st->l1.l1m.state != ST_L1_F6) {
+               FsmChangeState(fi, ST_L1_F3);
+               st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
+       }
+}
+
+static void
+l1_timer_act(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       
+       test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
+       test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
+       L1activated(st->l1.hardware);
+}
+
+static void
+l1_timer_deact(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       
+       test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
+       test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
+       L1deactivated(st->l1.hardware);
+       st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL);
+}
+
+static void
+l1_activate(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+                
+       st->l1.l1hw(st, HW_RESET | REQUEST, NULL);
+}
+
+static struct FsmNode L1DFnList[] 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 L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode))
+
+static void
+l1b_activate(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L1_WAIT_ACT);
+       FsmAddTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
+}
+
+static void
+l1b_deactivate(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L1_WAIT_DEACT);
+       FsmAddTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
+}
+
+static void
+l1b_timer_act(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L1_ACTIV);
+       st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+}
+
+static void
+l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L1_NULL);
+       st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
+}
+
+static struct FsmNode L1BFnList[] HISAX_INITDATA =
+{
+       {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate},
+       {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act},
+       {ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate},
+       {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact},
+};
+
+#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
+
+HISAX_INITFUNC(void Isdnl1New(void))
+{
+       l1fsm_d.state_count = L1D_STATE_COUNT;
+       l1fsm_d.event_count = L1_EVENT_COUNT;
+       l1fsm_d.strEvent = strL1Event;
+       l1fsm_d.strState = strL1DState;
+       FsmNew(&l1fsm_d, L1DFnList, L1D_FN_COUNT);
+       l1fsm_b.state_count = L1B_STATE_COUNT;
+       l1fsm_b.event_count = L1_EVENT_COUNT;
+       l1fsm_b.strEvent = strL1Event;
+       l1fsm_b.strState = strL1BState;
+       FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
+}
+
+void Isdnl1Free(void)
+{
+       FsmFree(&l1fsm_d);
+       FsmFree(&l1fsm_b);
+}
+
+static void
+dch_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+       char tmp[32];
+
+       switch (pr) {
+               case (PH_DATA | REQUEST):
+               case (PH_PULL | REQUEST):
+               case (PH_PULL |INDICATION):
+                       st->l1.l1hw(st, pr, arg);
+                       break;
+               case (PH_ACTIVATE | REQUEST):
+                       if (cs->debug) {
+                               sprintf(tmp, "PH_ACTIVATE_REQ %s",
+                                       strL1DState[st->l1.l1m.state]);
+                               debugl1(cs, tmp);
+                       }
+                       if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
+                               st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+                       else {
+                               test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
+                               FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
+                       }
+                       break;
+               case (PH_TESTLOOP | REQUEST):
+                       if (1 & (long) arg)
+                               debugl1(cs, "PH_TEST_LOOP B1");
+                       if (2 & (long) arg)
+                               debugl1(cs, "PH_TEST_LOOP B2");
+                       if (!(3 & (long) arg))
+                               debugl1(cs, "PH_TEST_LOOP DISABLED");
+                       st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
+                       break;
+               default:
+                       if (cs->debug) {
+                               sprintf(tmp, "dch_l2l1 msg %04X unhandled", pr);
+                               debugl1(cs, tmp);
+                       }
+                       break;
+       }
+}
+
+void
+l1_msg(struct IsdnCardState *cs, int pr, void *arg) {
+       struct PStack *st;
+
+       st = cs->stlist;
+       
+       while (st) {
+               switch(pr) {
+                       case (HW_RESET | INDICATION):
+                       FsmEvent(&st->l1.l1m, EV_RESET_IND, arg);
+                       break;
+                       case (HW_DEACTIVATE | CONFIRM):
+                       FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg);
+                       break;
+                       case (HW_DEACTIVATE | INDICATION):
+                       FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg);
+                       break;
+                       case (HW_POWERUP | CONFIRM):
+                       FsmEvent(&st->l1.l1m, EV_POWER_UP, arg);
+                       break;
+                       case (HW_RSYNC | INDICATION):
+                       FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg);
+                       break;
+                       case (HW_INFO2 | INDICATION):
+                       FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg);
+                       break;
+                       case (HW_INFO4_P8 | INDICATION):
+                       case (HW_INFO4_P10 | INDICATION):
+                       FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg);
+                       break;
+               default:
+                       if (cs->debug) {
+                                       sprintf(tmp, "l1msg %04X unhandled", pr);
+                               debugl1(cs, tmp);
+                       }
+                       break;
+       }
+               st = st->next;
+       }
+}
+
+void
+l1_msg_b(struct PStack *st, int pr, void *arg) {
+       switch(pr) {
+               case (PH_ACTIVATE | REQUEST):
+                       FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL);
+                       break;
+               case (PH_DEACTIVATE | REQUEST):
+                       FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL);
+                       break;
+       }
+}
+
+void
+setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
+{
+       st->l1.hardware = cs;
+       st->protocol = cs->protocol;
+       st->l1.l1m.fsm = &l1fsm_d;
+       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->l2.l2l1  = dch_l2l1;
+       st->l1.Flags = 0;
+       cs->setstack_d(st, cs);
+}
+
+void
+setstack_l1_B(struct PStack *st)
+{
+       struct IsdnCardState *cs = st->l1.hardware;
+
+       st->l1.l1m.fsm = &l1fsm_b;
+       st->l1.l1m.state = ST_L1_NULL;
+       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);
+}
index 98418c8218419b17f114ba7756083e14e0552d05..d40a3bb32a6636f24158a10f4c4359e461fb7dde 100644 (file)
@@ -1,18 +1,26 @@
-/* $Id: isdnl1.h,v 1.4 1997/04/06 22:55:52 keil Exp $
- *
+/* $Id: isdnl1.h,v 1.4.2.4 1998/05/27 18:05:49 keil Exp $
+
  * $Log: isdnl1.h,v $
- * Revision 1.4  1997/04/06 22:55:52  keil
- * Using SKB's
+ * Revision 1.4.2.4  1998/05/27 18:05:49  keil
+ * HiSax 3.0
+ *
+ * Revision 1.4.2.3  1997/12/01 09:09:08  keil
+ * more l1 debug
  *
- * Revision 1.3  1996/12/08 19:41:55  keil
- * L2FRAME_DEBUG
+ * Revision 1.4.2.2  1997/11/15 18:50:40  keil
+ * new common init function
  *
- * Revision 1.2  1996/10/27 22:26:27  keil
- * ISAC/HSCX version functions
+ * Revision 1.4.2.1  1997/10/17 22:13:58  keil
+ * update to last hisax version
  *
- * Revision 1.1  1996/10/13 20:03:47  keil
- * Initial revision
+ * Revision 2.2  1997/07/30 17:11:09  keil
+ * L1deactivated exported
  *
+ * 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 L1_DEB_MONITOR         0x200
 
+#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 get_irq(int cardnr, void *routine);
+extern void DChannel_proc_xmt(struct IsdnCardState *cs);
+extern void DChannel_proc_rcv(struct IsdnCardState *cs);
+extern void l1_msg(struct IsdnCardState *cs, int pr, void *arg);
+extern void l1_msg_b(struct PStack *st, int pr, void *arg);
+
 
 #ifdef L2FRAME_DEBUG
 extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir);
index 87f4814a5a1db54c22d8fe5178460b55db25545e..9bb4f3599b150dfa06b18de68642f2d8baa3ab79 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnl2.c,v 1.10 1997/05/06 09:38:13 keil Exp $
+/* $Id: isdnl2.c,v 1.10.2.9 1998/06/19 15:17:56 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,56 +7,58 @@
  *              Fritz Elfert
  *
  * $Log: isdnl2.c,v $
- * Revision 1.10  1997/05/06 09:38:13  keil
- * Bugfixes: - clear ack queue entries after resend
- *           - acknowlege each frame to linklevel
- *           - UA for SABM is Response, not command
- *           - only RR was send as supervisor frame (X.75 hangs after a
- *             sequence error)
+ * Revision 1.10.2.9  1998/06/19 15:17:56  keil
+ * fix LAPB tx_cnt for none I-frames
  *
- * Revision 1.9  1997/04/07 23:02:11  keil
- * missing braces
+ * Revision 1.10.2.8  1998/06/18 23:12:05  keil
+ * LAPB bugfix
  *
- * Revision 1.8  1997/04/06 22:59:59  keil
- * Using SKB's; changing function names; some minor changes
+ * Revision 1.10.2.7  1998/05/27 18:05:51  keil
+ * HiSax 3.0
  *
- * Revision 1.7  1997/02/09 00:25:44  keil
- * new interface handling, one interface per card
+ * Revision 1.10.2.6  1998/05/26 10:36:57  keil
+ * fixes from certification
  *
- * Revision 1.6  1997/01/21 22:23:42  keil
- * D-channel log changed
+ * Revision 1.10.2.5  1998/03/07 23:15:31  tsbogend
+ * made HiSax working on Linux/Alpha
  *
- * Revision 1.5  1997/01/04 13:47:06  keil
- * handling of MDL_REMOVE added (Thanks to Sim Yskes)
+ * Revision 1.10.2.4  1998/01/27 22:44:38  keil
+ * fixed window size calculation
  *
- * Revision 1.4  1996/12/08 19:51:51  keil
- * many fixes from Pekka Sarnila
+ * Revision 1.10.2.3  1997/11/15 18:54:03  keil
+ * cosmetics
  *
- * Revision 1.3  1996/11/05 19:39:12  keil
- * X.75 bugfixes Thank to Martin Maurer
+ * Revision 1.10.2.2  1997/10/17 22:13:59  keil
+ * update to last hisax version
  *
- * Revision 1.2  1996/10/30 10:20:58  keil
- * X.75 answer of SABMX fixed to response address (AVM X.75 problem)
+ * Revision 2.2  1997/07/31 11:49:05  keil
+ * Eroor handling for no TEI assign
  *
- * Revision 1.1  1996/10/13 20:04:54  keil
- * Initial revision
+ * Revision 2.1  1997/07/27 21:34:38  keil
+ * cosmetics
  *
+ * 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: 1.10.2.9 $";
 
 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 +72,7 @@ enum {
 static char *strL2State[] =
 {
        "ST_L2_1",
+       "ST_L2_2",
        "ST_L2_3",
        "ST_L2_4",
        "ST_L2_5",
@@ -81,53 +84,51 @@ 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_NOTEIPROC,
+       EV_L2_MDL_ERROR,
+       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_NOTEIPROC",
+       "EV_L2_MDL_ERROR",
+       "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,7 +144,6 @@ ReleaseWin(struct Layer2 *l2)
 {
        int i, cnt = 0;
 
-
        for (i = 0; i < MAX_WINDOW; i++) {
                if (l2->windowar[i]) {
                        cnt++;
@@ -155,55 +155,51 @@ 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
-discard_i_queue(struct PStack *st)
+inline void
+clear_exception(struct Layer2 *l2)
 {
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&st->l2.i_queue))) {
-               SET_SKB_FREE(skb);
-               dev_kfree_skb(skb, FREE_READ);
-       }
+       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);
 }
 
-int
-l2headersize(struct Layer2 *tsp, int ui)
+inline int
+l2headersize(struct Layer2 *l2, int ui)
 {
-       return ((tsp->extended && (!ui) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
+       return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
+               (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1));
 }
 
-int
-l2addrsize(struct Layer2 *tsp)
+inline int
+l2addrsize(struct Layer2 *l2)
 {
-       return (tsp->laptype == LAPD ? 2 : 1);
+       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;
@@ -213,82 +209,108 @@ sethdraddr(struct Layer2 *tsp,
        }
 }
 
-static void
-enqueue_ui(struct PStack *st,
-          struct sk_buff *skb)
+inline static void
+enqueue_super(struct PStack *st,
+             struct sk_buff *skb)
 {
-       st->l2.l2l1(st, PH_DATA, skb);
+       if (test_bit(FLG_LAPB, &st->l2.flag))
+               st->l1.bcs->tx_cnt += skb->len;
+       st->l2.l2l1(st, PH_DATA | REQUEST, skb);
 }
 
-static void
-enqueue_super(struct PStack *st,
-             struct sk_buff *skb)
+#define enqueue_ui(a, b) enqueue_super(a, b)
+
+inline int
+IsUI(u_char * data, int ext)
 {
-       st->l2.l2l1(st, PH_DATA, skb);
+       return ((data[0] & 0xef) == UI);
 }
 
-static int
-legalnr(struct PStack *st, int nr)
+inline int
+IsUA(u_char * data, int ext)
 {
-       struct Layer2 *l2 = &st->l2;
-       int lnr, lvs;
+       return ((data[0] & 0xef) == UA);
+}
 
-       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
+IsDM(u_char * data, int ext)
+{
+       return ((data[0] & 0xef) == DM);
 }
 
-static void
-setva(struct PStack *st, int nr)
+inline int
+IsDISC(u_char * data, int ext)
 {
-       struct Layer2 *l2 = &st->l2;
+       return ((data[0] & 0xef) == DISC);
+}
 
-       if (l2->va != nr) {
-               while (l2->va != nr) {
-                       l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
-                       dev_kfree_skb(l2->windowar[l2->sow], FREE_WRITE);
-                       l2->windowar[l2->sow] = NULL;
-                       l2->sow = (l2->sow + 1) % l2->window;
-                       if (st->l4.l2writewakeup)
-                               st->l4.l2writewakeup(st);
-               }
-       }
+inline int
+IsRR(u_char * data, int ext)
+{
+       if (ext)
+               return (data[0] == RR);
+       else
+               return ((data[0] & 0xf) == 1);
 }
 
-static void
-l2s1(struct FsmInst *fi, int event, void *arg)
+inline int
+IsSABMX(u_char * data, int ext)
 {
-       struct PStack *st = fi->userdata;
+       u_char d = data[0] & ~0x10;
 
-       st->l2.l2tei(st, MDL_ASSIGN, (void *) st->l2.ces);
-       FsmChangeState(fi, ST_L2_3);
+       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], FREE_WRITE);
+               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;
@@ -306,53 +328,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, FREE_READ);
+}
+
+
+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);
+}
 
-       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");
+static void
+l2_mdl_error(struct FsmInst *fi, int event, void *arg)
+{
+       struct sk_buff *skb = arg;
+       struct PStack *st = fi->userdata;
 
+       switch (event) {
+               case EV_L2_UA:
+                       if (get_PollFlagFree(st, skb))
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C');
+                       else
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D');
+                       break;
+               case EV_L2_DM:
+                       if (get_PollFlagFree(st, skb))
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
+                       else {
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
+                               establishlink(fi);
+                               test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+                       }
+                       break;
+       }
+}
 
-       cmd = (st->l2.extended ? SABME : SABM) | 0x10; 
-       send_uframe(st, cmd, CMD);
+static void
+l2_dl_establish(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       int state = fi->state;
+
+       FsmChangeState(fi, ST_L2_3); 
+       if (state == ST_L2_1)
+               st->l2.l2tei(st, MDL_ASSIGN | INDICATION, 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 | INDICATION, 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 | INDICATION, (void *) 'O');
+               FreeSkb(skb);
+       } else
+               st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
+}
+
+static void
+l2_establish(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       if (fi->state != ST_L2_4)
+               discard_queue(&st->l2.i_queue);
+       if (fi->state != ST_L2_5)
+               establishlink(fi);
+       test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+}
 
-       discard_i_queue(st);
+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.l2l3(st, DL_RELEASE  | CONFIRM, NULL);
+               return;
+       } else if (fi->state == ST_L2_5) {
+               test_and_set_bit(FLG_PEND_REL, &st->l2.flag);
+               return;
+       }
+       discard_queue(&st->l2.i_queue);
+       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
@@ -360,46 +485,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, FREE_READ);
-
-       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 | INDICATION, (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 | INDICATION, (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 | INDICATION, (void *) 'F');
                if (st->l2.vs != st->l2.va) {
-                       discard_i_queue(st);
+                       discard_queue(&st->l2.i_queue);
                        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);
+       FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
 
        if (est)
-               st->l2.l2man(st, DL_ESTABLISH, NULL);
+               st->l2.l2l3(st, DL_ESTABLISH | INDICATION, 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 | REQUEST, NULL);
 }
 
 static void
@@ -407,87 +545,166 @@ l2_got_disconn(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
-       struct Channel *chanp = st->l4.userdata;
-       u_char PollFlag;
-
-       skb_pull(skb, l2addrsize(&(st->l2)));
-       PollFlag = *skb->data & 0x10;
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb, FREE_READ);
+       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 | INDICATION, (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 | INDICATION, (void *) 'N');
+               FreeSkb(skb);
+               if ((state == ST_L2_7) || (state == ST_L2_8))
+                       establishlink(fi);
+               return;
+       }
+       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) {
+               if (test_bit(FLG_LAPB, &st->l2.flag))
+                       st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+               st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
        }
-       if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
-               send_uframe(st, UA | PollFlag, RSP);
-
-       st->l2.l2man(st, DL_RELEASE, NULL);
 }
 
+
 static void
-l2_got_st4_disc(struct FsmInst *fi, int event, void *arg)
+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;
+       int pr=-1;
        u_char PollFlag;
+       int state,rsp;
 
-       skb_pull(skb, l2addrsize(&(st->l2)));
-       PollFlag = *skb->data & 0x10;
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb, FREE_READ);
-
-       if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
-               send_uframe(st, DM | (PollFlag ? 0x10 : 0x0), RSP);
-
-}
-
-static void
-l2_got_ua_establish(struct FsmInst *fi, int event, void *arg)
-{
-       struct PStack *st = fi->userdata;
-       struct sk_buff *skb = arg;
-       u_char f;
+       state = fi->state;
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &st->l2.flag))
+               rsp = !rsp;
 
-       skb_pull(skb, l2addrsize(&(st->l2)));
-       f = *skb->data & 0x10;
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb, FREE_READ);
-       if (f) {
-               st->l2.vs = 0;
-               st->l2.va = 0;
-               st->l2.vr = 0;
-               st->l2.sow = 0;
-               FsmChangeState(fi, ST_L2_7);
-
-               FsmDelTimer(&st->l2.t200_timer, 5);
-               if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
-                       if (st->l2.l2m.debug)
-                               l2m_debug(&st->l2.l2m, "FAT 4");
-
-               st->l2.l2man(st, DL_ESTABLISH, NULL);
+       if (!rsp) {
+               st->ma.layer(st, MDL_ERROR | INDICATION, (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 | INDICATION, (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_queue(&st->l2.i_queue);
+                       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)) {
+                               pr = DL_ESTABLISH | CONFIRM;
+                       } else if (st->l2.vs != st->l2.va) {
+                               discard_queue(&st->l2.i_queue);
+                               pr = DL_ESTABLISH | INDICATION;
+                       }
+                       st->l2.vs = 0;
+                       st->l2.va = 0;
+                       st->l2.vr = 0;
+                       st->l2.sow = 0;
+                       FsmChangeState(fi, ST_L2_7);
+                       if (pr > -1)
+                               st->l2.l2l3(st, pr, NULL);
+               }
+       } else {                /* ST_L2_6 */
+               if (test_bit(FLG_LAPB, &st->l2.flag))
+                       st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+               st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+               FsmChangeState(fi, ST_L2_4);
        }
 }
 
 static void
-l2_got_ua_disconn(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, FREE_READ);
-       if (f) {
-               FsmDelTimer(&st->l2.t200_timer, 6);
+       state = fi->state;
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &st->l2.flag))
+               rsp = !rsp;
+
+       if (!rsp) {
+               st->ma.layer(st, MDL_ERROR | INDICATION, (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 | INDICATION, (void *) 'N');
+               FreeSkb(skb);
+               if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
+                       establishlink(fi);
+               return;
+       }
+       PollFlag = get_PollFlagFree(st, skb);
+       if (!PollFlag) {
+               if (fi->state == ST_L2_4) {
+                       establishlink(fi);
+                       test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+                       FsmChangeState(fi, ST_L2_5);
+               }
+       } else if (fi->state != ST_L2_4) {
+               if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+                       FsmDelTimer(&st->l2.t200, 2);
+               if (fi->state == ST_L2_5)
+                       discard_queue(&st->l2.i_queue);
+               if (test_bit(FLG_LAPB, &st->l2.flag))
+                       st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+               if (fi->state == ST_L2_6)
+                       st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL);
+               else
+                       st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
                FsmChangeState(fi, ST_L2_4);
-               st->l2.l2man(st, DL_RELEASE, NULL);
        }
 }
 
@@ -501,7 +718,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,83 +733,141 @@ 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 | INDICATION, (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 Layer2 *l2 = &st->l2;
+       int p1;
+       long flags;
+
+       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;
+                       if (test_bit(FLG_LAPB, &l2->flag))
+                               st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0);
+                       skb_queue_head(&l2->i_queue, l2->windowar[p1]);
+                       l2->windowar[p1] = NULL;
+               }
+               restore_flags(flags);
+               st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+       }
+}
+
+static void
+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;
-       int PollFlag, seq, rsp;
-       struct Layer2 *l2;
+       int PollFlag, nr, rsp, typ = RR;
+       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);
+               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 | INDICATION, (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 | INDICATION, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               }
        }
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb, FREE_READ);
+       FreeSkb(skb);
 
-       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 ((!rsp) && PollFlag)
+               enquiry_response(st);
+       if (rsp && PollFlag)
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A');
+       if (legalnr(st, nr)) {
+               if (typ == REJ) {
+                       setva(st, nr);
+                       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);
+                       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 | REQUEST, 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);
+               st->l2.l2l3(st, DL_FLUSH | INDICATION, NULL);
        }
 }
 
@@ -602,251 +877,228 @@ 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);
+       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 | REQUEST, NULL);
 }
 
-static int
-icommandreceived(struct FsmInst *fi, int event, void *arg, int *nr)
+static void
+l2_got_iframe(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;
+       int PollFlag, ns, nr, i, hs, rsp;
        char str[64];
 
+       rsp = *skb->data & 0x2;
+       if (test_bit(FLG_ORIG, &l2->flag))
+               rsp = !rsp;
+
+       if (rsp) {
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
+               FreeSkb(skb);
+               establishlink(fi);
+               return;
+       }       
        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;
+       if (test_bit(FLG_MOD128, &l2->flag)) {
+               if (skb->len <= (i + 1)) {
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               } else if ((skb->len - i - 1) > l2->maxlen) { 
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (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 {
-               p = (skb->data[i] & 0x10);
-               seq = (skb->data[i] >> 1) & 0x7;
-               *nr = (skb->data[i] >> 5) & 0x7;
+               if (skb->len <= i) {
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               } else if ((skb->len - i) > l2->maxlen) { 
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (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 (l2->vr == seq) {
-               wasok = !0;
-
-               l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
-               l2->rejexp = 0;
-
-               if (st->l2.laptype == LAPD)
+       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 + l2->ihsize,
-                                         skb->len - l2->ihsize, str);
+                               dlogframe(st->l1.hardware, skb->data + hs,
+                                         skb->len - hs, str);
                        }
-               if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
-                       if (p || (!skb_queue_len(&st->l2.i_queue)))
-                               enquiry_response(st, RR, p);
+               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 | INDICATION, skb);
        } else {
                /* n(s)!=v(r) */
-               wasok = 0;
-               SET_SKB_FREE(skb);
-               dev_kfree_skb(skb, FREE_READ);
-               if (st->l2.rejexp) {
-                       if (p)
-                               if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
-                                       enquiry_response(st, RR, p);
+               FreeSkb(skb);
+               if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
+                       if (PollFlag)
+                               enquiry_response(st);
                } else {
-                       st->l2.rejexp = !0;
-                       enquiry_command(st, REJ, 1);
+                       enquiry_cr(st, REJ, RSP, PollFlag);
+                       test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
                }
        }
-       return wasok;
-}
-
-static void
-l2_got_st7_data(struct FsmInst *fi, int event, void *arg)
-{
-       struct PStack *st = fi->userdata;
-       struct sk_buff *skb = arg;
-       int nr, wasok;
-
-       wasok = icommandreceived(fi, event, arg, &nr);
 
        if (legalnr(st, nr)) {
-               if (nr == st->l2.vs) {
-                       setva(st, nr);
-                       FsmDelTimer(&st->l2.t200_timer, 10);
-                       st->l2.t200_running = 0;
-                       FsmDelTimer(&st->l2.t203_timer, 11);
-                       if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
-                               if (st->l2.l2m.debug)
-                                       l2m_debug(&st->l2.l2m, "FAT 5");
-
-                       if (skb_queue_len(&st->l2.i_queue))
-                               st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-               } else if (nr != st->l2.va) {
-                       setva(st, nr);
-                       FsmDelTimer(&st->l2.t200_timer, 12);
-                       if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
-                               if (st->l2.l2m.debug)
-                                       l2m_debug(&st->l2.l2m, "FAT 6");
-
-                       if (skb_queue_len(&st->l2.i_queue))
-                               st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+               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
+       } else {
                nrerrorrecovery(fi);
+               return;
+       }
 
-       if (wasok)
-               st->l2.l2l3(st, DL_DATA, skb);
+       if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
+               st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
+       if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
+               enquiry_cr(st, RR, RSP, 0);
 }
 
 static void
-l2_got_st8_data(struct FsmInst *fi, int event, void *arg)
+l2_got_tei(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);
+       st->l2.tei = (long) arg;
 
-       if (legalnr(st, nr)) {
-               setva(st, nr);
-               if (skb_queue_len(&st->l2.i_queue))
-                       st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+       if (fi->state == ST_L2_3) {
+               establishlink(fi);
+               test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
        } else
-               nrerrorrecovery(fi);
-
-       if (wasok)
-               st->l2.l2l3(st, DL_DATA, skb);
+               FsmChangeState(fi, ST_L2_4);
+       if (skb_queue_len(&st->l2.ui_queue))
+               l2_send_ui(st);
 }
 
 static void
-l2_got_tei(struct FsmInst *fi, int event, void *arg)
+l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
 
-       st->l2.tei = (int) arg;
-       establishlink(fi);
-}
-
-static void
-invoke_retransmission(struct PStack *st, int nr)
-{
-       struct Layer2 *l2 = &st->l2;
-       int p1;
-
-       if (l2->vs != nr) {
-               while (l2->vs != nr) {
-
-                       l2->vs = l2->vs - 1;
-                       if (l2->vs < 0)
-                               l2->vs += l2->extended ? 128 : 8;
-
-                       p1 = l2->vs - l2->va;
-                       if (p1 < 0)
-                               p1 += l2->extended ? 128 : 8;
-                       p1 = (p1 + l2->sow) % l2->window;
-
-                       skb_queue_head(&l2->i_queue, l2->windowar[p1]);
-                       l2->windowar[p1] = NULL;
-               }
-               st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+       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);
+               test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
+               discard_queue(&st->l2.i_queue);
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G');
+               if (test_bit(FLG_LAPB, &st->l2.flag))
+                       st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+               st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+       } else {
+               st->l2.rc++;
+               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);
        }
 }
 
 static void
-l2_got_st7_rej(struct FsmInst *fi, int event, void *arg)
+l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct sk_buff *skb = arg;
-       int PollFlag, seq, rsp;
-       struct Layer2 *l2;
 
-       l2 = &st->l2;
-       if (l2->laptype == LAPD)
-               rsp = *skb->data & 0x2;
-       else
-               rsp = *skb->data == 0x3;
-       if (l2->orig)
-               rsp = !rsp;
-
-       skb_pull(skb, l2addrsize(l2));
-       if (l2->extended) {
-               PollFlag = (skb->data[1] & 0x1) == 0x1;
-               seq = skb->data[1] >> 1;
+       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 | INDICATION, (void *) 'H');
+               if (test_bit(FLG_LAPB, &st->l2.flag))
+                       st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+               st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
        } else {
-               PollFlag = (skb->data[0] & 0x10);
-               seq = (skb->data[0] >> 5) & 0x7;
+               st->l2.rc++;
+               FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
+                           NULL, 9);
+               send_uframe(st, DISC | 0x10, CMD);
        }
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb, FREE_READ);
-
-       if ((!rsp) && PollFlag)
-               enquiry_response(st, RR, PollFlag);
-
-       if (!legalnr(st, seq))
-               return;
-
-       setva(st, seq);
-       invoke_retransmission(st, seq);
-}
-
-static void
-l2_no_tei(struct FsmInst *fi, int event, void *arg)
-{
-       FsmChangeState(fi, ST_L2_4);
 }
 
 static void
-l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
+l2_st78_tout_200(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       u_char cmd;
 
-       if (st->l2.rc == st->l2.n200) {
-               FsmChangeState(fi, ST_L2_4);
-               st->l2.l2tei(st, MDL_VERIFY, (void *) st->l2.tei);
-               st->l2.l2man(st, DL_RELEASE, NULL);
+       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 (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
-                       if (st->l2.l2m.debug)
-                               l2m_debug(&st->l2.l2m, "FAT 7");
-
-               cmd = (st->l2.extended ? SABME : SABM) | 0x10; 
-               send_uframe(st, cmd, CMD);
        }
 }
 
 static void
-l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
+l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct Channel *chanp = st->l4.userdata;
-
-       if (st->l2.rc == st->l2.n200) {
-               FsmChangeState(fi, ST_L2_4);
-               st->l2.l2man(st, DL_RELEASE, NULL);
-       } else {
-               st->l2.rc++;
-
-               if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
-                       if (st->l2.l2m.debug)
-                               l2m_debug(&st->l2.l2m, "FAT 8");
-
-
-               if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
-                       send_uframe(st, DISC | 0x10, CMD);
 
+       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,7 +1112,7 @@ 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",
@@ -871,7 +1123,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
 
        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;
@@ -879,125 +1131,101 @@ 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);
+               SET_SKB_FREE(skb);
+               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 | INDICATION, 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 | REQUEST, 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 | INDICATION, (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 | INDICATION, (void *) 'N');
+                       FreeSkb(skb);
+                       establishlink(fi);
+                       return;
+               }
        }
-       SET_SKB_FREE(skb);
-       dev_kfree_skb(skb, FREE_READ);
+       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 | REQUEST, NULL);
                        else if (fi->userint & LC_FLUSH_WAIT) {
                                fi->userint &= ~LC_FLUSH_WAIT;
-                               st->l2.l2man(st, DL_FLUSH, NULL);
+                               st->l2.l2l3(st, DL_FLUSH | INDICATION, NULL);
                        }
                }
        } 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)
 {
@@ -1005,20 +1233,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 | INDICATION, (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 | INDICATION, (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, FREE_READ);
+       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 | INDICATION, (void *) 'K');
+               establishlink(fi);
+               test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+       }
+       FreeSkb(skb);
 }
 
 static void
@@ -1026,135 +1266,139 @@ 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_queue(&st->l2.i_queue);
+       discard_queue(&st->l2.ui_queue);
+       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.l2l3(st, DL_RELEASE | INDICATION, 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;
+       int rel = DL_RELEASE | INDICATION;
        
-       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_queue(&st->l2.i_queue);
+       discard_queue(&st->l2.ui_queue);
+       if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+               FsmDelTimer(&st->l2.t200, 18);
+       FsmDelTimer(&st->l2.t203, 19);
+       clear_exception(&st->l2);
+       switch (fi->state) {
+               case ST_L2_1:
+                       if (!test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
+                               break;
+               case ST_L2_3:
+                       st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+               case ST_L2_2:
+                       FsmChangeState(fi, ST_L2_1);
+                       break;
+               case ST_L2_6:
+                       rel = DL_RELEASE | CONFIRM;
+               case ST_L2_5:
+                       if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
+                               rel = DL_RELEASE | CONFIRM;
+               case ST_L2_7:
+               case ST_L2_8:
+                       st->l2.l2l3(st, rel, NULL);
+                       FsmChangeState(fi, ST_L2_4);
+                       break;
+               case ST_L2_4:
+                       if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
+                               st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+                       break;
+       }
+       test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
+       test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag);
 }
 
-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_1, EV_L1_DEACTIVATE, l2_persistant_da},
+       {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))
@@ -1164,40 +1408,69 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
 {
        struct sk_buff *skb = arg;
        u_char *datap;
-       int ret = !0;
+       char tmp[32];
+       int ret = 1, len;
 
        switch (pr) {
-               case (PH_DATA):
+               case (PH_DATA | INDICATION):
                        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 | INDICATION, (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 | INDICATION, (void *) 'L');
+                               FreeSkb(skb);
+                       }
                        if (ret) {
-                               SET_SKB_FREE(skb);
-                               dev_kfree_skb(skb, FREE_READ);
+                               FreeSkb(skb);
                        }
                        break;
-               case (PH_PULL_ACK):
+               case (PH_PULL | CONFIRM):
                        FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
                        break;
+               case (PH_PAUSE | INDICATION):
+                       test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag);
+                       break;
+               case (PH_PAUSE | CONFIRM):
+                       test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag);
+                       break;
+               case (PH_ACTIVATE | CONFIRM):
+               case (PH_ACTIVATE | INDICATION):
+                       test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag);
+                       if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag))
+                               FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+                       break;
+               case (PH_DEACTIVATE | INDICATION):
+               case (PH_DEACTIVATE | CONFIRM):
+                       test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag);
+                       FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg);
+                       break;
+               default:
+                       sprintf(tmp, "l2 unknown pr %04x", pr);
+                       l2m_debug(&st->l2.l2m, tmp);
+                       break;
        }
 }
 
@@ -1205,57 +1478,58 @@ static void
 isdnl2_l3l2(struct PStack *st, int pr, void *arg)
 {
        switch (pr) {
-               case (DL_DATA):
+               case (DL_DATA | REQUEST):
                        if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
                                dev_kfree_skb((struct sk_buff *) arg, FREE_READ);
                        }
                        break;
-               case (DL_UNIT_DATA):
+               case (DL_UNIT_DATA | REQUEST):
                        if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
                                dev_kfree_skb((struct sk_buff *) arg, FREE_READ);
                        }
                        break;
-       }
-}
-
-static void
-isdnl2_manl2(struct PStack *st, int pr, void *arg)
-{
-       switch (pr) {
-               case (DL_ESTABLISH):
-                       FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+               case (DL_ESTABLISH | REQUEST):
+                       if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) {
+                               if (test_bit(FLG_LAPD, &st->l2.flag) ||
+                                       test_bit(FLG_ORIG, &st->l2.flag)) {
+                                       FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+                               }
+                       } else {
+                               if (test_bit(FLG_LAPD, &st->l2.flag) ||
+                                       test_bit(FLG_ORIG, &st->l2.flag)) {
+                                       test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag);
+                               }
+                               st->l2.l2l1(st, PH_ACTIVATE, NULL);
+                       }
                        break;
-               case (DL_RELEASE):
+               case (DL_RELEASE | REQUEST):
+                       if (test_bit(FLG_LAPB, &st->l2.flag)) {
+                               st->l2.l2l1(st, PH_DEACTIVATE, NULL);
+                       }
                        FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
                        break;
-               case (MDL_NOTEIPROC):
-                       FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
-                       break;
-               case (DL_FLUSH):
+               case (DL_FLUSH | REQUEST):
                        (&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 (MDL_ASSIGN | REQUEST):
                        FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
                        break;
-               case (MDL_REMOVE):
+               case (MDL_REMOVE | REQUEST):
                        FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
                        break;
+               case (MDL_ERROR | RESPONSE):
+                       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);
-       discard_i_queue(st);
+       FsmDelTimer(&st->l2.t200, 15);
+       FsmDelTimer(&st->l2.t203, 16);
+       discard_queue(&st->l2.i_queue);
+       discard_queue(&st->l2.ui_queue);
        ReleaseWin(&st->l2);
 }
 
@@ -1275,17 +1549,16 @@ 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;
+       if (test_bit(FLG_LAPB, &st->l2.flag))
+               st->l2.l2m.state = ST_L2_4;
+       else
        st->l2.l2m.state = ST_L2_1;
        st->l2.l2m.debug = 0;
        st->l2.l2m.userdata = st;
@@ -1293,14 +1566,31 @@ 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);
+}
+
+static void
+transl2_l3l2(struct PStack *st, int pr, void *arg)
+{
+       switch (pr) {
+               case (DL_DATA | REQUEST):
+               case (DL_UNIT_DATA | REQUEST):
+                       st->l2.l2l1(st, PH_DATA, arg);
+                       break;
+               case (DL_ESTABLISH | REQUEST):
+                       st->l2.l2l1(st, PH_ACTIVATE, NULL);
+                       break;
+               case (DL_RELEASE | REQUEST):
+                       st->l2.l2l1(st, PH_DEACTIVATE, NULL);
+                       break;
+       }
 }
 
 void
 setstack_transl2(struct PStack *st)
 {
+       st->l3.l3l2 = transl2_l3l2;
 }
 
 void
@@ -1308,8 +1598,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 e945bd4bdf0c8a033326ac19f6d8d1f540a55b21..5b1663c689b546b67e45ff45d34251d5d06e7c5c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnl3.c,v 1.10 1997/04/06 22:54:16 keil Exp $
+/* $Id: isdnl3.c,v 1.10.2.4 1998/05/27 18:05:59 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,38 +7,34 @@
  *              Fritz Elfert
  *
  * $Log: isdnl3.c,v $
- * Revision 1.10  1997/04/06 22:54:16  keil
- * Using SKB's
- *
- * Revision 1.9  1997/03/25 23:11:25  keil
- * US NI-1 protocol
- *
- * Revision 1.8  1997/03/21 18:53:44  keil
- * Report no protocol error to syslog too
+ * Revision 1.10.2.4  1998/05/27 18:05:59  keil
+ * HiSax 3.0
  *
- * Revision 1.7  1997/03/17 18:34:38  keil
- * fixed oops if no protocol selected during config
+ * Revision 1.10.2.3  1997/11/15 18:54:09  keil
+ * cosmetics
  *
- * Revision 1.6  1997/02/16 01:04:08  fritz
- * Bugfix: Changed timer handling caused hang with 2.1.X
+ * Revision 1.10.2.2  1997/10/17 22:14:05  keil
+ * update to last hisax version
  *
- * 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: 1.10.2.4 $";
 
-void
-l3_debug(struct PStack *st, char *s)
+static
+struct Fsm l3fsm =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+       ST_L3_LC_REL,
+       ST_L3_LC_ESTAB_WAIT,
+       ST_L3_LC_REL_WAIT,
+       ST_L3_LC_ESTAB,
+};
+
+#define L3_STATE_COUNT (ST_L3_LC_ESTAB+1)
+
+static char *strL3State[] =
 {
-       char str[256], tm[32];
+       "ST_L3_LC_REL",
+       "ST_L3_LC_ESTAB_WAIT",
+       "ST_L3_LC_REL_WAIT",
+       "ST_L3_LC_ESTAB",
+};
+
+enum {
+       EV_ESTABLISH_REQ,
+       EV_ESTABLISH_IND,
+       EV_ESTABLISH_CNF,
+       EV_RELEASE_REQ,
+       EV_RELEASE_CNF,
+       EV_RELEASE_IND,
+};
+
+#define L3_EVENT_COUNT (EV_RELEASE_IND+1)
+
+static char *strL3Event[] =
+{
+       "EV_ESTABLISH_REQ",
+       "EV_ESTABLISH_IND",
+       "EV_ESTABLISH_CNF",
+       "EV_RELEASE_REQ",
+       "EV_RELEASE_CNF",
+       "EV_RELEASE_IND",
+};
+
+static void
+l3m_debug(struct FsmInst *fi, char *s)
+{
+       struct PStack *st = fi->userdata;
+       char tm[32], str[256];
 
        jiftime(tm, jiffies);
-       sprintf(str, "%s Channel %d l3 %s\n", tm, st->l3.channr, s);
+       sprintf(str, "%s %s %s\n", tm, st->l3.debug_id, s);
        HiSax_putstatus(st->l1.hardware, str);
 }
 
+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
-newl3state(struct PStack *st, int state)
+l3_debug(struct PStack *st, const char *fmt, ...)
 {
-       char tmp[80];
+       va_list args;
+       char str[256], tm[32];
+       char *t = str;
 
-       if (st->l3.debug & L3_DEB_STATE) {
-               sprintf(tmp, "newstate  %d --> %d", st->l3.state, state);
-               l3_debug(st, tmp);
-       }
-       st->l3.state = state;
+       va_start(args, fmt);
+       jiftime(tm, jiffies);
+       t += sprintf(str, "%s l3 ", tm);
+       t += vsprintf(t, fmt, args);
+       va_end(args);
+       *t++ = '\n';
+       *t++ = 0;
+       HiSax_putstatus(st->l1.hardware, str);
+}
+
+void
+newl3state(struct l3_process *pc, int state)
+{
+       if (pc->debug & L3_DEB_STATE)
+               l3_debug(pc->st, "newstate cr %d %d --> %d", pc->callref,
+                       pc->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 +225,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 *
@@ -133,9 +249,10 @@ no_l3_proto(struct PStack *st, int pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       l3_debug(st, "no protocol");
-       if (skb)
+       HiSax_putstatus(st->l1.hardware, "L3 no D protocol\n");
+       if (skb) {
                dev_kfree_skb(skb, FREE_READ);
+       }
 }
 
 #ifdef CONFIG_HISAX_EURO
@@ -150,14 +267,86 @@ 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)
+setstack_l3dc(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;
+       skb_queue_head_init(&st->l3.squeue);
+       st->l3.l3m.fsm = &l3fsm;
+       st->l3.l3m.state = ST_L3_LC_REL;
+       st->l3.l3m.debug = 1;
+       st->l3.l3m.userdata = st;
+       st->l3.l3m.userint = 0;
+       st->l3.l3m.printdebug = l3m_debug;
+       strcpy(st->l3.debug_id, "L3DC");
 
 #ifdef CONFIG_HISAX_EURO
        if (st->protocol == ISDN_PTYPE_EURO) {
@@ -175,11 +364,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" :
@@ -187,15 +376,155 @@ 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
+isdnl3_trans(struct PStack *st, int pr, void *arg) {
+       st->l3.l3l2(st, pr, arg);
 }
 
 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;
+       }
+       discard_queue(&st->l3.squeue);
+}
+
+void
+setstack_l3bc(struct PStack *st, struct Channel *chanp)
+{
+
+       st->l3.proc   = NULL;
+       st->l3.global = NULL;
+       skb_queue_head_init(&st->l3.squeue);
+       st->l3.l3m.fsm = &l3fsm;
+       st->l3.l3m.state = ST_L3_LC_REL;
+       st->l3.l3m.debug = 1;
+       st->l3.l3m.userdata = st;
+       st->l3.l3m.userint = 0;
+       st->l3.l3m.printdebug = l3m_debug;
+       strcpy(st->l3.debug_id, "L3BC");
+       st->lli.l4l3 = isdnl3_trans;
+}
+
+static void
+lc_activate(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
+       st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
+}
+
+static void
+lc_connect(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       struct sk_buff *skb = arg;
+
+       FsmChangeState(fi, ST_L3_LC_ESTAB);
+       while ((skb = skb_dequeue(&st->l3.squeue))) {
+               st->l3.l3l2(st, DL_DATA | REQUEST, skb);
+       }
+       st->l3.l3l4(st, DL_ESTABLISH | INDICATION, NULL);
+}
+
+static void
+lc_release_req(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       if (fi->state == ST_L3_LC_ESTAB_WAIT)
+               FsmChangeState(fi, ST_L3_LC_REL);
+       else
+               FsmChangeState(fi, ST_L3_LC_REL_WAIT);
+       st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
+}
+
+static void
+lc_release_ind(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L3_LC_REL);
+       discard_queue(&st->l3.squeue);
+       st->l3.l3l4(st, DL_RELEASE | INDICATION, NULL);
+}
+
+/* *INDENT-OFF* */
+static struct FsmNode L3FnList[] HISAX_INITDATA =
+{
+       {ST_L3_LC_REL,          EV_ESTABLISH_REQ,       lc_activate},
+       {ST_L3_LC_REL,          EV_ESTABLISH_IND,       lc_connect},
+       {ST_L3_LC_REL,          EV_ESTABLISH_CNF,       lc_connect},
+       {ST_L3_LC_ESTAB_WAIT,   EV_ESTABLISH_CNF,       lc_connect},
+       {ST_L3_LC_ESTAB_WAIT,   EV_RELEASE_REQ,         lc_release_req},
+       {ST_L3_LC_ESTAB_WAIT,   EV_RELEASE_IND,         lc_release_ind},
+       {ST_L3_LC_ESTAB,        EV_RELEASE_IND,         lc_release_ind},
+       {ST_L3_LC_ESTAB,        EV_RELEASE_REQ,         lc_release_req},
+       {ST_L3_LC_REL_WAIT,     EV_RELEASE_CNF,         lc_release_ind},
+       {ST_L3_LC_REL_WAIT,     EV_ESTABLISH_REQ,       lc_activate},
+};
+/* *INDENT-ON* */
+
+#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode))
+
+void
+l3_msg(struct PStack *st, int pr, void *arg)
+{
+       
+       switch (pr) {
+               case (DL_DATA | REQUEST):
+                       if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
+                               st->l3.l3l2(st, pr, arg);
+                       } else {
+                               struct sk_buff *skb = arg;
+
+                               skb_queue_head(&st->l3.squeue, skb);
+                               FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); 
+                       }
+                       break;
+               case (DL_ESTABLISH | REQUEST):
+                       FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
+                       break;
+               case (DL_ESTABLISH | CONFIRM):
+                       FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL);
+                       break;
+               case (DL_ESTABLISH | INDICATION):
+                       FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL);
+                       break;
+               case (DL_RELEASE | INDICATION):
+                       FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL);
+                       break;
+               case (DL_RELEASE | CONFIRM):
+                       FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL);
+                       break;
+               case (DL_RELEASE | REQUEST):
+                       FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
+                       break;
+       }
+}
+
+HISAX_INITFUNC(void
+Isdnl3New(void))
+{
+       l3fsm.state_count = L3_STATE_COUNT;
+       l3fsm.event_count = L3_EVENT_COUNT;
+       l3fsm.strEvent = strL3Event;
+       l3fsm.strState = strL3State;
+       FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
+}
+
+void
+Isdnl3Free(void)
+{
+       FsmFree(&l3fsm);
 }
index bed989a18613091a13fff3dad33087b31c5c6227..4ff2e570010cf1d3a865e937eec19e1f6b57d4e3 100644 (file)
@@ -1,6 +1,18 @@
-/* $Id: isdnl3.h,v 1.3 1997/04/06 22:54:17 keil Exp $
- *
+/* $Id: isdnl3.h,v 1.3.2.2 1998/05/27 18:06:02 keil Exp $
+
  * $Log: isdnl3.h,v $
+ * Revision 1.3.2.2  1998/05/27 18:06:02  keil
+ * HiSax 3.0
+ *
+ * Revision 1.3.2.1  1997/10/17 22:14:08  keil
+ * update to last hisax version
+ *
+ * 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;
+       int 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 l3_debug(struct PStack *st, const char *fmt, ...);
+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);
+extern void l3_msg(struct PStack *st, int pr, void *arg);
index dadeb8f17899e2669a8478a1d9313d68c7b71dfe..c8f6a4a8e075138eeef7b55b6b942f9f70ac030a 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 1.3.2.8 1998/04/08 21:58:41 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 1.3.2.8  1998/04/08 21:58:41  keil
+ * New init code
+ *
+ * Revision 1.3.2.7  1998/02/11 14:21:01  keil
+ * cosmetic fixes
+ *
+ * Revision 1.3.2.6  1998/01/27 22:37:33  keil
+ * fast io
+ *
+ * Revision 1.3.2.5  1997/11/15 18:50:51  keil
+ * new common init function
+ *
+ * Revision 1.3.2.4  1997/10/17 22:14:09  keil
+ * update to last hisax version
+ *
+ * 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: 1.3.2.8 $";
 
-#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,247 @@ 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 {
-                               dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
-                               hsp->count = 0;
-                               if (hsp->st->l4.l1writewakeup)
-                                       hsp->st->l4.l1writewakeup(hsp->st);
-                               hsp->tx_skb = NULL;
-                       }
-               if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
-                       hsp->count = 0;
-                       hscx_fill_fifo(hsp);
-               } else
-                       hscx_sched_event(hsp, HSCX_XMTBUFREADY);
-       }
+       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 {
-                                       SET_SKB_FREE(skb);
-                                       memcpy(skb_put(skb, count), sp->rcvbuf, count);
-                                       skb_queue_tail(&sp->rq, skb);
-                               }
-                       }
-               }
-               sp->rcvidx = 0;
-               isac_sched_event(sp, ISAC_RCVBUFREADY);
-       }
-       if (val & 0x40) {       /* RPF */
-               isac_empty_fifo(sp, 32);
-       }
-       if (val & 0x20) {       /* RSC */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC RSC interrupt");
-       }
-       if (val & 0x10) {       /* XPR */
-               if (sp->tx_skb)
-                       if (sp->tx_skb->len) {
-                               isac_fill_fifo(sp);
-                               goto afterXPR;
-                       } else {
-                               dev_kfree_skb(sp->tx_skb, FREE_WRITE);
-                               sp->tx_cnt = 0;
-                               sp->tx_skb = NULL;
-                       }
-               if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
-                       sp->tx_cnt = 0;
-                       isac_fill_fifo(sp);
-               } else
-                       isac_sched_event(sp, ISAC_XMTBUFREADY);
-       }
-      afterXPR:
-       if (val & 0x04) {       /* CISQ */
-               sp->ph_state = (IsacReadReg(sp->isac, ISAC_CIX0) >> 2)
-                   & 0xf;
-               if (sp->debug & L1_DEB_ISAC) {
-                       sprintf(tmp, "l1state %d", sp->ph_state);
-                       debugl1(sp, tmp);
-               }
-               isac_new_ph(sp);
-       }
-       if (val & 0x02) {       /* SIN */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC SIN interrupt");
-       }
-       if (val & 0x01) {       /* EXI */
-               exval = IsacReadReg(sp->isac, ISAC_EXIR);
-               if (sp->debug & L1_DEB_WARN) {
-                       sprintf(tmp, "ISAC EXIR %02x", exval);
-                       debugl1(sp, tmp);
-               }
-       }
-}
+#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 *) irq2dev_map[intno];
-
-       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.interrupts[sp->irq];
-       sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
-       debugl1(sp, tmp);
-       clear_pending_ints(sp);
-       ret = get_irq(sp->cardnr, &ix1micro_interrupt);
-       if (ret) {
-               initisac(sp);
-               sp->modehscx(sp->hs, 0, 0);
-               sp->modehscx(sp->hs + 1, 0, 0);
-               while (loop++ < 10) {
-                       /* At least 1-3 irqs must happen
-                        * (one from HSCX A, one from HSCX B, 3rd from ISAC)
-                        */
-                       if (kstat.interrupts[sp->irq] > sp->counter)
-                               break;
-                       current->state = TASK_INTERRUPTIBLE;
-                       current->timeout = jiffies + 1;
-                       schedule();
-               }
-               sprintf(tmp, "IRQ %d count %d", sp->irq,
-                       kstat.interrupts[sp->irq]);
-               debugl1(sp, tmp);
-               if (kstat.interrupts[sp->irq] == sp->counter) {
-                       printk(KERN_WARNING
-                              "ix1-Micro: IRQ(%d) getting no interrupts during init\n",
-                              sp->irq);
-                       irq2dev_map[sp->irq] = NULL;
-                       free_irq(sp->irq, NULL);
-                       return (0);
-               }
-       }
-       return (ret);
+       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:
+                       inithscxisac(cs, 3);
+                       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);
 }
index 99e318ac1660c6cb29e81547fdcabac54f351d2f..1448185dd6dadcc013de2d4c180f7a90aa4632ce 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 1.11.2.3 1998/05/27 18:06:04 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.11.2.3  1998/05/27 18:06:04  keil
+ * HiSax 3.0
  *
- * Revision 1.8  1997/01/27 23:20:21  keil
- * report revision only ones
+ * Revision 1.11.2.2  1997/11/15 18:54:12  keil
+ * cosmetics
  *
- * Revision 1.7  1997/01/21 22:30:07  keil
- * new statemachine; L3 timers
+ * Revision 1.11.2.1  1997/10/17 22:14:12  keil
+ * update to last hisax version
  *
- * Revision 1.6  1996/12/14 21:07:20  keil
- * additional states for CC_REJECT
+ * Revision 2.1  1997/08/03 15:28:09  keil
+ * release L3 empty processes
  *
- * Revision 1.5  1996/12/08 19:55:17  keil
- * change CC_REJECT_REQ routine
+ * Revision 2.0  1997/07/27 21:15:45  keil
+ * New Callref based layer3
  *
- * Revision 1.4  1996/10/30 10:18:01  keil
- * bugfixes in debugging output
+ * Revision 1.12  1997/06/26 11:11:45  keil
+ * SET_SKBFREE now on creation of a SKB
  *
- * Revision 1.3  1996/10/27 22:15:37  keil
- * bugfix reject handling
- *
- * Revision 1.2  1996/10/13 23:08:56  keil
- * added missing state for callback reject
- *
- * Revision 1.1  1996/10/13 20:04:55  keil
- * Initial revision
+ * 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: 1.11.2.3 $";
 
 #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 | REQUEST, 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 | REQUEST, 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, FREE_READ);
 
        /* Signal all services, linklevel takes care of Service-Indicator */
        if (bcfound) {
-               if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+               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->st, CC_SETUP | INDICATION, pc);
+       } 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, FREE_READ);
-       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->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 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, FREE_READ);
-       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->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 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, FREE_READ);
-       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->st, CC_ALERTING | INDICATION, pc);
 }
 
 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->st, CC_CHARGE | INDICATION, pc);
                }
-               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, FREE_READ);
 
 }
 
 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, FREE_READ);
 }
 
 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, FREE_READ);
-       st->pa->chargeinfo = 0;
-       st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+       pc->para.chargeinfo = 0;
+       pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 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, FREE_READ);
-       StopAllL3Timer(st);
-       newl3state(st, 0);
-       l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
-       st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+       StopAllL3Timer(pc);
+       newl3state(pc, 0);
+       l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
+       pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+       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, FREE_READ);
-       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->st, CC_RELEASE | CONFIRM, pc);
+       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->st, CC_CHARGE | INDICATION, pc);
                }
-               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, FREE_READ);
-       newl3state(st, 12);
-       st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+       newl3state(pc, 12);
+       pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
 }
 
 
 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, FREE_READ);
-       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->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 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 | REQUEST, 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 | REQUEST, 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->st, CC_NOSETUP_RSP, pc);
+               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->st, CC_SETUP_ERR, pc);
 }
 
 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,74 +603,74 @@ 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 | REQUEST, 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->st, CC_SETUP_ERR, pc);
 }
 
 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->st, CC_CONNECT_ERR, pc);
 }
 
 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->st, CC_RELEASE_ERR, pc);
+       release_l3_process(pc);
 }
 /* *INDENT-OFF* */
 static struct stateentry downstl[] =
 {
        {SBIT(0),
-        CC_SETUP_REQ, l3_1tr6_setup_req},
+        CC_SETUP | REQUEST, l3_1tr6_setup_req},
        {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) |
         SBIT(10),
-        CC_DISCONNECT_REQ, l3_1tr6_disconnect_req},
+        CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req},
        {SBIT(12),
-        CC_RELEASE_REQ, l3_1tr6_release_req},
+        CC_RELEASE | REQUEST, l3_1tr6_release_req},
        {ALL_STATES,
-        CC_DLRL, l3_1tr6_reset},
+        CC_DLRL | REQUEST, l3_1tr6_reset},
        {SBIT(6),
-        CC_IGNORE, l3_1tr6_reset},
+        CC_IGNORE | REQUEST, l3_1tr6_reset},
        {SBIT(6),
-        CC_REJECT_REQ, l3_1tr6_disconnect_req},
+        CC_REJECT | REQUEST, l3_1tr6_disconnect_req},
        {SBIT(6),
-        CC_ALERTING_REQ, l3_1tr6_alert_req},
+        CC_ALERTING | REQUEST, l3_1tr6_alert_req},
        {SBIT(6) | SBIT(7),
-        CC_SETUP_RSP, l3_1tr6_setup_rsp},
+        CC_SETUP | RESPONSE, l3_1tr6_setup_rsp},
        {SBIT(1),
         CC_T303, l3_1tr6_t303},
        {SBIT(2),
@@ -688,60 +720,102 @@ 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];
 
+       switch (pr) {
+               case (DL_DATA | INDICATION):
+               case (DL_UNIT_DATA | INDICATION):
+                       break;
+               case (DL_ESTABLISH | CONFIRM):
+               case (DL_ESTABLISH | INDICATION):
+               case (DL_RELEASE | INDICATION):
+               case (DL_RELEASE | CONFIRM):
+                       l3_msg(st, pr, arg);
+                       return;
+                       break;
+       }
+       if (skb->len < 4) {
+               if (st->l3.debug & L3_DEB_PROTERR) {
+                       sprintf(tmp, "up1tr6 len only %ld", skb->len);
+                       l3_debug(st, tmp);
+               }
+               dev_kfree_skb(skb, FREE_READ);
+               return;
+       }
        if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
                if (st->l3.debug & L3_DEB_PROTERR) {
-                       sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %ld state %d",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
-                               skb->data[0], skb->len, st->l3.state);
+                       sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %ld",
+                               (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+                               skb->data[0], skb->len);
+                       l3_debug(st, tmp);
+               }
+               dev_kfree_skb(skb, FREE_READ);
+               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, FREE_READ);
                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, FREE_READ);
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "up1tr6%s N0 state %d mt %x unhandled",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
-                               st->l3.state, mt);
+                       sprintf(tmp, "up1tr6%s N0 mt %x unhandled",
+                            (pr == (DL_DATA | INDICATION)) ? " " : "(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, FREE_READ);
+                                       return;
+                               }
+                       } else {
+                               dev_kfree_skb(skb, FREE_READ);
+                               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, FREE_READ);
                        if (st->l3.debug & L3_DEB_STATE) {
                                sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
-                                 (pr == DL_DATA) ? " " : "(broadcast) ",
-                                       st->l3.state, mt);
+                                 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+                                       proc->state, mt);
                                l3_debug(st, tmp);
                        }
                        return;
                } else {
                        if (st->l3.debug & L3_DEB_STATE) {
                                sprintf(tmp, "up1tr6%sstate %d mt %x",
-                                 (pr == DL_DATA) ? " " : "(broadcast) ",
-                                       st->l3.state, mt);
+                                 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+                                       proc->state, mt);
                                l3_debug(st, tmp);
                        }
-                       datastln1[i].rout(st, pr, skb);
+                       datastln1[i].rout(proc, pr, skb);
                }
        }
 }
@@ -749,26 +823,47 @@ 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 (((DL_ESTABLISH | REQUEST)== pr) || ((DL_RELEASE | REQUEST)== pr)) {
+               l3_msg(st, pr, NULL);
+               return;
+       } else if ((CC_SETUP | REQUEST) == 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 +872,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..f192de49c32bf8c179b6d5140aa954757c1a5013 100644 (file)
@@ -1,12 +1,16 @@
-/* $Id: l3_1tr6.h,v 1.1 1996/10/13 20:03:48 keil Exp $
+/* $Id: l3_1tr6.h,v 1.1.2.1 1997/10/17 22:14:15 keil Exp $
  *
  *  German 1TR6 D-channel protocol defines
  *
  * $Log: l3_1tr6.h,v $
- * Revision 1.1  1996/10/13 20:03:48  keil
- * Initial revision
+ * Revision 1.1.2.1  1997/10/17 22:14:15  keil
+ * update to last hisax version
  *
+ * 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
@@ -29,7 +33,6 @@
 #define MT_N0_CLOSE   0x75
 #define MT_N0_CLO_ACK 0x77
 
-
 /*
  * MsgType N1
  */
@@ -65,8 +68,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 73c49d9d28092c194bb0ec31291a4dc6d0baccd7..217a440ebf3581b13f0ba276f2547d5552da9b1b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 1.16 1997/06/03 20:43:46 keil Exp $
+/* $Id: l3dss1.c,v 1.16.2.4 1998/05/27 18:06:08 keil Exp $
 
  * EURO/DSS1 D-channel protocol
  *
  *              Fritz Elfert
  *
  * $Log: l3dss1.c,v $
- * Revision 1.16  1997/06/03 20:43:46  keil
- * Display numbers as default
+ * Revision 1.16.2.4  1998/05/27 18:06:08  keil
+ * HiSax 3.0
  *
- * Revision 1.15  1997/04/17 11:50:48  keil
- * pa->loc was undefined, if it was not send by the exchange
- *
- * Revision 1.14  1997/04/06 22:54:20  keil
- * Using SKB's
- *
- * Revision 1.13  1997/03/13 20:37:28  keil
- * CLIR and channel request added
- *
- * Revision 1.12  1997/02/17 00:34:26  keil
- * Bugfix: Wrong cause delivered
- *
- * Revision 1.11  1997/02/16 12:12:47  fritz
- * Bugfix: SI2 was nont initialized on incoming calls.
- *
- * Revision 1.10  1997/02/11 01:37:24  keil
- * Changed setup-interface (incoming and outgoing)
- *
- * Revision 1.9  1997/01/27 23:20:52  keil
- * report revision only ones
- *
- * Revision 1.8  1997/01/21 22:29:41  keil
- * new statemachine; L3 timers
- *
- * Revision 1.7  1996/12/14 21:06:59  keil
- * additional states for CC_REJECT
+ * Revision 1.16.2.3  1998/02/03 23:16:06  keil
+ * german AOC
  *
- * Revision 1.6  1996/12/08 22:59:16  keil
- * fixed calling party number without octet 3a
+ * Revision 1.16.2.2  1997/11/15 18:54:15  keil
+ * cosmetics
  *
- * Revision 1.5  1996/12/08 19:53:31  keil
- * fixes from Pekka Sarnila
+ * Revision 1.16.2.1  1997/10/17 22:14:16  keil
+ * update to last hisax version
  *
- * 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.16 $";
+const char *dss1_revision = "$Revision: 1.16.2.4 $";
+
+#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;
+
+       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->st, CC_CHARGE | INDICATION, pc);
+                                   }
+                                   if (pc->st->l3.debug & L3_DEB_CHARGE) {
+                                           if (*(p+2) == 0) {
+                                                   l3_debug(pc->st, "charging info during %d", pc->para.chargeinfo);
+                                           } else {
+                                                   l3_debug(pc->st, "charging info final %d", pc->para.chargeinfo);
+                                           }
+                                   }
+                           })))))
+                           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->st, CC_CHARGE | INDICATION, pc);
+                                   }
+                                   if (pc->st->l3.debug & L3_DEB_CHARGE) {
+                                           l3_debug(pc->st, "charging info final %d", pc->para.chargeinfo);
+                                   }
+                           }))))))
+                   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;
@@ -84,44 +274,204 @@ 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);
+       l3_msg(pc->st, DL_DATA | REQUEST, 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, FREE_READ);
-       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->st, CC_RELEASE | CONFIRM, pc);
+       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;
@@ -131,16 +481,19 @@ l3dss1_setup_req(struct PStack *st, u_char pr,
        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                                  */
@@ -160,7 +513,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)) {
@@ -182,19 +535,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);
@@ -207,241 +569,377 @@ 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);
+        } else {
+               *p++ = 0x7c; *p++ = 0x02; *p++ = 0x88; *p++ = 0x90;
+        }
+#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);
+       l3_msg(pc->st, DL_DATA | REQUEST, 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, FREE_READ);
-       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->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 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, FREE_READ);
-       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->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 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, FREE_READ);
-       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->st, CC_DISCONNECT | INDICATION, pc);
 }
 
 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, FREE_READ);
-       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->st, CC_SETUP | CONFIRM, pc);
 }
 
 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, FREE_READ);
-       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->st, CC_ALERTING | INDICATION, pc);
 }
 
 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
+   * 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  88: /* 0x58 incomp destination */
+         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);
+       l3_msg(pc->st, DL_DATA | REQUEST, 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, FREE_READ);
+                       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");
+               pc->para.cause = 0x60;
+               dev_kfree_skb(skb, FREE_READ);
+               l3dss1_msg_without_setup(pc, pr, NULL);
+               return;
+       }
        /*
           * 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, FREE_READ);
+                       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, FREE_READ);
 
        if (bcfound) {
-               if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
-                       sprintf(tmp, "non-digital call: %s -> %s",
-                               st->pa->setup.phone,
-                               st->pa->setup.eazmsn);
-                       l3_debug(st, tmp);
+               if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) {
+                       l3_debug(pc->st, "non-digital call: %s -> %s",
+                               pc->para.setup.phone, pc->para.setup.eazmsn);
                }
-               newl3state(st, 6);
-               st->l3.l3l4(st, CC_SETUP_IND, NULL);
-       }
+               if ((pc->para.setup.si1 != 7) &&
+                       test_bit(FLG_PTP, &pc->st->l2.flag)) {
+                       pc->para.cause = 0x58;
+                       l3dss1_msg_without_setup(pc, pr, NULL);
+                       return;
+               }
+               newl3state(pc, 6);
+               pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+       } 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, FREE_READ);
-       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->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 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];
@@ -449,12 +947,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;
@@ -465,13 +963,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);
+       l3_msg(pc->st, DL_DATA | REQUEST, 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];
@@ -479,10 +977,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;
@@ -493,13 +991,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);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
+       pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+       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;
@@ -509,38 +1008,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, FREE_READ);
-       StopAllL3Timer(st);
-       st->pa->cause = cause;
-       newl3state(st, 0);
-       l3dss1_message(st, MT_RELEASE_COMPLETE);
-       st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+       StopAllL3Timer(pc);
+       pc->para.cause = cause;
+       l3dss1_message(pc, MT_RELEASE_COMPLETE);
+       pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+       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, FREE_READ);
 
-       MsgHead(p, st->l3.callref, MT_STATUS);
+       MsgHead(p, pc->callref, MT_STATUS);
 
        *p++ = IE_CAUSE;
        *p++ = 0x2;
@@ -549,42 +1055,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);
-       st->l3.l3l2(st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, 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, FREE_READ);
+
+       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);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3dss1_release_ind(struct l3_process *pc, u_char pr, void *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->st, CC_RELEASE | INDICATION, pc);
+               newl3state(pc, 0);
+               release_l3_process(pc);
+       } else {
+               pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
+       }
 }
 
 static void
-l3dss1_t303(struct PStack *st, u_char pr, void *arg)
+l3dss1_t303(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);
+       if (pc->N303 > 0) {
+               pc->N303--;
+               L3DelTimer(&pc->timer);
+               l3dss1_setup_req(pc, pr, arg);
        } else {
-               newl3state(st, 0);
-               L3DelTimer(&st->l3.timer);
-               st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
-               st->l3.n_t303 = 1;
+               L3DelTimer(&pc->timer);
+               pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
+               release_l3_process(pc);
        }
 }
 
 static void
-l3dss1_t304(struct PStack *st, u_char pr, void *arg)
+l3dss1_t304(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->para.cause = 0xE6;
+       l3dss1_disconnect_req(pc, pr, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 
 }
 
 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;
@@ -592,11 +1152,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;
@@ -607,64 +1167,353 @@ 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);
+       l3_msg(pc->st, DL_DATA | REQUEST, 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->st, CC_SETUP_ERR, pc);
+}
+
+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->st, CC_CONNECT_ERR, pc);
+}
+
+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_t310(struct PStack *st, u_char pr, void *arg)
+l3dss1_t308_2(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->st, CC_RELEASE_ERR, pc);
+       release_l3_process(pc);
 }
 
 static void
-l3dss1_t313(struct PStack *st, u_char pr, void *arg)
+l3dss1_t318(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);
+       L3DelTimer(&pc->timer);
+       pc->para.cause = 0x66; /* Timer expiry */
+       pc->para.loc = 0; /* local */
+       pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+       newl3state(pc, 19);
+       l3dss1_message(pc, MT_RELEASE);
+       L3AddTimer(&pc->timer, T308, CC_T308_1);
 }
 
 static void
-l3dss1_t308_1(struct PStack *st, u_char pr, void *arg)
+l3dss1_t319(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);
+       L3DelTimer(&pc->timer);
+       pc->para.cause = 0x66; /* Timer expiry */
+       pc->para.loc = 0; /* local */
+       pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+       newl3state(pc, 10);
 }
 
 static void
-l3dss1_t308_2(struct PStack *st, u_char pr, void *arg)
+l3dss1_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);
+       L3DelTimer(&pc->timer);
+       pc->st->l3.l3l4(pc->st, CC_DLRL | INDICATION, pc);
+       release_l3_process(pc);
 }
+
+static void
+l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
+{
+       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, FREE_READ);
+}
+
+static void
+l3dss1_facility(struct l3_process *pc, u_char pr, void *arg)
+{
+        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_suspend_req(struct l3_process *pc, u_char pr, void *arg)
+{
+       struct sk_buff *skb;
+       u_char tmp[32];
+       u_char *p = tmp;
+       u_char i,l;
+       u_char *msg = pc->chan->setup.phone;
+
+       MsgHead(p, pc->callref, MT_SUSPEND);
+       
+       *p++ = IE_CALLID;
+       l = *msg++;
+       if (l && (l<=10)) { /* Max length 10 octets */
+               *p++ = l;
+               for (i=0;i<l;i++)
+                       *p++ = *msg++;
+       } else {
+               l3_debug(pc->st, "SUS wrong CALLID len %d", l);
+               return;
+        }
+       l = p - tmp;
+       if (!(skb = l3_alloc_skb(l)))
+               return;
+       memcpy(skb_put(skb, l), tmp, l);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
+       newl3state(pc, 15);
+       L3AddTimer(&pc->timer, T319, CC_T319);
+}
+
+static void
+l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+
+       L3DelTimer(&pc->timer);
+       newl3state(pc, 0);
+       dev_kfree_skb(skb, FREE_READ);
+       pc->para.cause = -1;
+       pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
+       release_l3_process(pc);
+}
+
+static void
+l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
+{
+       u_char *p;
+       struct sk_buff *skb = arg;
+       int cause = -1;
+
+       L3DelTimer(&pc->timer);
+       p = skb->data;
+       if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+               p++;
+               if (*p++ == 2)
+                       pc->para.loc = *p++;
+               cause = *p & 0x7f;
+       }
+       dev_kfree_skb(skb, FREE_READ);
+       pc->para.cause = cause;
+       pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+       newl3state(pc, 10);
+}
+
+static void
+l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg)
+{
+       struct sk_buff *skb;
+       u_char tmp[32];
+       u_char *p = tmp;
+       u_char i,l;
+       u_char *msg = pc->para.setup.phone;
+
+       MsgHead(p, pc->callref, MT_RESUME);
+       
+       *p++ = IE_CALLID;
+       l = *msg++;
+       if (l && (l<=10)) { /* Max length 10 octets */
+               *p++ = l;
+               for (i=0;i<l;i++)
+                       *p++ = *msg++;
+       } else {
+               l3_debug(pc->st, "RES wrong CALLID len %d", l);
+               return;
+        }
+       l = p - tmp;
+       if (!(skb = l3_alloc_skb(l)))
+               return;
+       memcpy(skb_put(skb, l), tmp, l);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
+       newl3state(pc, 17);
+       L3AddTimer(&pc->timer, T319, CC_T319);
+}
+
+static void
+l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+       u_char *p;
+       struct sk_buff *skb = arg;
+
+       L3DelTimer(&pc->timer);
+       p = skb->data;
+       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, "resume ack without bchannel");
+       } else if (pc->debug & L3_DEB_WARN)
+               l3_debug(pc->st, "resume ack without bchannel");
+       dev_kfree_skb(skb, FREE_READ);
+       pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
+       newl3state(pc, 10);
+}
+
+static void
+l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
+{
+       u_char *p;
+       struct sk_buff *skb = arg;
+       int cause = -1;
+
+       L3DelTimer(&pc->timer);
+       p = skb->data;
+       if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+               p++;
+               if (*p++ == 2)
+                       pc->para.loc = *p++;
+               cause = *p & 0x7f;
+       }
+       dev_kfree_skb(skb, FREE_READ);
+       pc->para.cause = cause;
+       newl3state(pc, 0);
+       pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+       release_l3_process(pc);
+}
+       
+static void
+l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
+{
+       u_char tmp[32];
+       u_char *p;
+       u_char ri, ch=0, 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];
+                       l3_debug(pc->st, "Restart %x", ri);
+       } else {
+               l3_debug(pc->st, "Restart without restart IE");
+               ri = 0x86;
+       }
+       p = skb->data;
+       if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+               chan = p[2] & 3;
+               ch = p[2];
+               if (pc->st->l3.debug)
+                       l3_debug(pc->st, "Restart for channel %d", chan);
+       }
+       dev_kfree_skb(skb, FREE_READ);
+       newl3state(pc, 2);
+       up = pc->st->l3.proc;
+       while (up) {
+               if ((ri & 7)==7)
+                       up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+               else if (up->para.bchannel == chan)
+                               up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+               up = up->next;
+       }
+       p = tmp;
+       MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
+       if (chan) {
+               *p++ = IE_CHANNEL_ID;
+               *p++ = 1;
+               *p++ = ch | 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);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
 /* *INDENT-OFF* */
 static struct stateentry downstatelist[] =
 {
        {SBIT(0),
-        CC_SETUP_REQ, l3dss1_setup_req},
+        CC_SETUP | REQUEST, l3dss1_setup_req},
+       {SBIT(0),
+        CC_RESUME | REQUEST, l3dss1_resume_req},
        {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10),
-        CC_DISCONNECT_REQ, l3dss1_disconnect_req},
+        CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
        {SBIT(12),
-        CC_RELEASE_REQ, l3dss1_release_req},
+        CC_RELEASE | REQUEST, l3dss1_release_req},
        {ALL_STATES,
-        CC_DLRL, l3dss1_reset},
+        CC_DLRL | REQUEST, l3dss1_reset},
+       {ALL_STATES,
+        CC_RESTART | REQUEST, l3dss1_restart},
        {SBIT(6),
-        CC_IGNORE, l3dss1_reset},
+        CC_IGNORE | REQUEST, l3dss1_reset},
        {SBIT(6),
-        CC_REJECT_REQ, l3dss1_reject_req},
+        CC_REJECT | REQUEST, l3dss1_reject_req},
        {SBIT(6),
-        CC_ALERTING_REQ, l3dss1_alert_req},
+        CC_ALERTING | REQUEST, l3dss1_alert_req},
        {SBIT(6) | SBIT(7),
-        CC_SETUP_RSP, l3dss1_setup_rsp},
+        CC_SETUP | RESPONSE, l3dss1_setup_rsp},
+       {SBIT(10),
+        CC_SUSPEND | REQUEST, l3dss1_suspend_req},
        {SBIT(1),
         CC_T303, l3dss1_t303},
        {SBIT(2),
@@ -675,6 +1524,10 @@ static struct stateentry downstatelist[] =
         CC_T313, l3dss1_t313},
        {SBIT(11),
         CC_T305, l3dss1_t305},
+       {SBIT(15),
+        CC_T319, l3dss1_t319},
+       {SBIT(17),
+        CC_T318, l3dss1_t318},
        {SBIT(19),
         CC_T308_1, l3dss1_t308_1},
        {SBIT(19),
@@ -688,100 +1541,285 @@ 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(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
+       {SBIT(19),  MT_RELEASE, l3dss1_release_ind},
+       {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | SBIT(15),
         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(15),
+        MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack},
+       {SBIT(15),
+        MT_SUSPEND_REJECT, l3dss1_suspend_rej},
+       {SBIT(17),
+        MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack},
+       {SBIT(17),
+        MT_RESUME_REJECT, l3dss1_resume_rej},
+       {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | 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 | REQUEST, l3dss1_status_req},
+       {SBIT(0),
+        CC_RESTART | REQUEST, 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;
+       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, FREE_READ);
+               if (st->l3.debug & L3_DEB_STATE) {
+                       l3_debug(st, "dss1 global state %d mt %x unhandled",
+                               proc->state, mt);
+               }
+               return;
+       } else {
+               if (st->l3.debug & L3_DEB_STATE) {
+                       l3_debug(st, "dss1 global %d mt %x",
+                               proc->state, mt);
+               }
+               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;
-       char tmp[80];
+       struct l3_process *proc;
 
+       switch (pr) {
+               case (DL_DATA | INDICATION):
+               case (DL_UNIT_DATA | INDICATION):
+                       break;
+               case (DL_ESTABLISH | CONFIRM):
+               case (DL_ESTABLISH | INDICATION):
+               case (DL_RELEASE | INDICATION):
+               case (DL_RELEASE | CONFIRM):
+                       l3_msg(st, pr, arg);
+                       return;
+                       break;
+       }
        if (skb->data[0] != PROTO_DIS_EURO) {
                if (st->l3.debug & L3_DEB_PROTERR) {
-                       sprintf(tmp, "dss1up%sunexpected discriminator %x message len %ld state %d",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
-                               skb->data[0], skb->len, st->l3.state);
-                       l3_debug(st, tmp);
+                       l3_debug(st, "dss1up%sunexpected discriminator %x message len %d",
+                               (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+                               skb->data[0], skb->len);
                }
-               SET_SKB_FREE(skb);
                dev_kfree_skb(skb, FREE_READ);
                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, FREE_READ);
+               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, FREE_READ);
+                               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, FREE_READ);
+                               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, FREE_READ);
+                               if ((proc = new_l3_process(st, cr))) {
+                                       proc->para.cause = 0x65; /* 101 */
+                                       l3dss1_msg_without_setup(proc, 0, NULL);
+                               }
+                               return;
+                       }
+               } else if (mt == MT_RELEASE_COMPLETE){
+                       dev_kfree_skb(skb, FREE_READ);
+                       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, FREE_READ);
+                       if ((proc = new_l3_process(st, cr))) {
+                               proc->para.cause = 0x51; /* 81 */
+                               l3dss1_msg_without_setup(proc, 0, 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, FREE_READ);
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1up%sstate %d mt %x unhandled",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
-                               st->l3.state, mt);
-                       l3_debug(st, tmp);
+                       l3_debug(st, "dss1up%sstate %d mt %x unhandled",
+                               (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+                               proc->state, mt);
                }
                return;
        } else {
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1up%sstate %d mt %x",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
-                               st->l3.state, mt);
-                       l3_debug(st, tmp);
+                       l3_debug(st, "dss1up%sstate %d mt %x",
+                               (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+                               proc->state, mt);
                }
-               datastatelist[i].rout(st, pr, skb);
+               datastatelist[i].rout(proc, pr, skb);
        }
 }
 
 static void
 dss1down(struct PStack *st, int pr, void *arg)
 {
-       int i;
-       char tmp[80];
+       int i, cr;
+       struct l3_process *proc;
+       struct Channel *chan;
 
+       if (((DL_ESTABLISH | REQUEST)== pr) || ((DL_RELEASE | REQUEST)== pr)) {
+               l3_msg(st, pr, NULL);
+               return;
+       } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == 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 dss1down without proc pr=%04x\n", pr);
+               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);
-                       l3_debug(st, tmp);
+                       l3_debug(st, "dss1down state %d prim %d unhandled",
+                               proc->state, pr);
                }
        } else {
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1down state %d prim %d",
-                               st->l3.state, pr);
-                       l3_debug(st, tmp);
+                       l3_debug(st, "dss1down state %d prim %d",
+                               proc->state, pr);
                }
-               downstatelist[i].rout(st, pr, arg);
+               downstatelist[i].rout(proc, pr, arg);
        }
 }
 
@@ -790,20 +1828,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..fac2149
--- /dev/null
@@ -0,0 +1,75 @@
+/* $Id: l3dss1.h,v 1.3.2.3 1998/05/27 18:06:14 keil Exp $
+ *
+ *  DSS1 (Euro) D-channel protocol defines
+ *
+ * $Log: l3dss1.h,v $
+ * Revision 1.3.2.3  1998/05/27 18:06:14  keil
+ * HiSax 3.0
+ *
+ * Revision 1.3.2.2  1998/02/03 23:16:10  keil
+ * german AOC
+ *
+ * Revision 1.3.2.1  1997/10/17 22:10:52  keil
+ * new files on 2.0
+ *
+ * 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_BEARER              0x04
+#define IE_CAUSE               0x08
+#define IE_CALLID              0x10
+#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..4943604
--- /dev/null
@@ -0,0 +1,67 @@
+/* $Id: lmgr.c,v 1.1.2.4 1998/05/27 18:06:15 keil Exp $
+
+ * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ *  Layermanagement module
+ *
+ * $Log: lmgr.c,v $
+ * Revision 1.1.2.4  1998/05/27 18:06:15  keil
+ * HiSax 3.0
+ *
+ * Revision 1.1.2.3  1998/03/07 23:15:37  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
+ * Revision 1.1.2.2  1997/11/15 18:54:19  keil
+ * cosmetics
+ *
+ * Revision 1.1.2.1  1997/10/17 22:10:53  keil
+ * new files on 2.0
+ *
+ * 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 | REQUEST, NULL);
+                       break;
+       }
+}
+
+static void
+hisax_manager(struct PStack *st, int pr, void *arg)
+{
+       char tm[32], str[256];
+       long Code;
+
+       switch (pr) {
+               case (MDL_ERROR | INDICATION):
+                       Code = (long) arg;
+                       jiftime(tm, jiffies);
+                       sprintf(str, "%s manager: MDL_ERROR %c %s\n", tm,
+                               (char)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..c420d72
--- /dev/null
@@ -0,0 +1,278 @@
+/* $Id: mic.c,v 1.1.2.5 1998/04/08 21:58:43 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.1.2.5  1998/04/08 21:58:43  keil
+ * New init code
+ *
+ * Revision 1.1.2.4  1998/02/17 15:39:20  keil
+ * fix reset problem
+ *
+ * Revision 1.1.2.3  1998/01/27 22:37:25  keil
+ * fast io
+ *
+ * Revision 1.1.2.2  1997/11/15 18:50:54  keil
+ * new common init function
+ *
+ * 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.1.2.5 $";
+
+#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 */
+                       inithscxisac(cs, 3);
+                       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..83a0991
--- /dev/null
@@ -0,0 +1,1189 @@
+/* $Id: netjet.c,v 1.1.2.7 1998/05/27 18:06:17 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.1.2.7  1998/05/27 18:06:17  keil
+ * HiSax 3.0
+ *
+ * Revision 1.1.2.6  1998/04/08 22:05:23  keil
+ * Forgot PCI fix
+ *
+ * Revision 1.1.2.5  1998/04/08 21:49:29  keil
+ * New init; fix PCI for more as one card
+ *
+ * Revision 1.1.2.4  1998/01/27 22:37:27  keil
+ * fast io
+ *
+ * Revision 1.1.2.3  1997/12/01 09:09:57  keil
+ * IRQ bit clearing
+ *
+ * Revision 1.1.2.2  1997/11/27 12:32:01  keil
+ * Working netjet driver
+ *
+ * Revision 1.1.2.1  1997/11/15 18:58:13  keil
+ * new card
+ *
+ *
+ */
+
+#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>
+#include <linux/ppp_defs.h>
+
+#ifndef bus_to_virt
+#define bus_to_virt (u_int *)
+#endif
+
+#ifndef virt_to_bus
+#define virt_to_bus (u_int)
+#endif
+
+extern const char *CardType[];
+
+const char *NETjet_revision = "$Revision: 1.1.2.7 $";
+
+#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_IRQM0_READ      0x0c
+#define NETJET_IRQM0_READ_1    0x04
+#define NETJET_IRQM0_READ_2    0x08
+#define NETJET_IRQM0_WRITE     0x03
+#define NETJET_IRQM0_WRITE_1   0x01
+#define NETJET_IRQM0_WRITE_2   0x02
+
+#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);
+}
+
+__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
+};
+
+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 int 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];
+       
+       if (!bcs->hw.tiger.tx_skb) {
+               debugl1(bcs->cs, "tiger make_raw: NULL skb");
+               return(1);
+       }
+       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 %ld 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;
+       return(0);
+}
+
+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 {
+               SET_SKB_FREE(skb);
+               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;
+       char tmp[64];
+       
+       if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) {
+               sprintf(tmp,"tiger warn read double dma %x/%x",
+                       cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
+               debugl1(cs, tmp);
+               return;
+       } else {
+               cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ;
+               cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ);
+       }       
+       if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1)
+               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 &= ~NETJET_IRQM0_READ;
+}
+
+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;
+       if (make_raw_data(bcs))
+               return;         
+       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, FREE_WRITE);
+                       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;
+       char tmp[64];
+       
+       if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
+               sprintf(tmp,"tiger warn write double dma %x/%x",
+                       cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
+               debugl1(cs, tmp);
+               return;
+       } else {
+               cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE;
+               cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE);
+       }       
+       if (cs->hw.njet.irqstat0  & NETJET_IRQM0_WRITE_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 &= ~NETJET_IRQM0_WRITE;
+}
+
+static void
+tiger_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       switch (pr) {
+               case (PH_DATA | REQUEST):
+                       save_flags(flags);
+                       cli();
+                       if (st->l1.bcs->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 | INDICATION):
+                       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 | REQUEST):
+                       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 | CONFIRM, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+               case (PH_ACTIVATE | REQUEST):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
+                       st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
+                       break;
+               case (PH_DEACTIVATE | REQUEST):
+                       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;
+       }
+}
+
+
+void
+close_tigerstate(struct BCState *bcs)
+{
+       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;
+               }
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->hw.tiger.tx_skb) {
+                       dev_kfree_skb(bcs->hw.tiger.tx_skb, FREE_WRITE);
+                       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);
+}
+
+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;
+       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;
+       char tmp[128];
+       long flags;
+
+       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);
+                       WriteISAC(cs, ISAC_MASK, 0xFF);
+                       WriteISAC(cs, ISAC_MASK, 0x0);
+               }
+       }
+       save_flags(flags);
+       cli();
+       if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) {
+               if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+                       restore_flags(flags);
+                       return;
+               }
+               cs->hw.njet.irqstat0 = sval;
+               restore_flags(flags);
+/*             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);
+*/
+/*             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 & NETJET_IRQM0_READ)
+                       read_tiger(cs);
+               if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE)
+                       write_tiger(cs);
+               test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+       } else
+               restore_flags(flags);
+
+/*     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);
+       }
+*/
+}
+
+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 | SA_SHIRQ, "HiSax", cs));
+               case CARD_INIT:
+                       inittiger(cs);
+                       clear_pending_isac_ints(cs);
+                       initisac(cs);
+                       /* Reenable all IRQ */
+                       cs->writeisac(cs, ISAC_MASK, 0);
+                       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);
+       }
+       pci_index++;
+       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..b124435
--- /dev/null
@@ -0,0 +1,406 @@
+/* $Id: niccy.c,v 1.1.2.4 1998/04/16 19:18:19 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.1.2.4  1998/04/16 19:18:19  keil
+ * need config.h
+ *
+ * Revision 1.1.2.3  1998/04/08 22:05:26  keil
+ * Forgot PCI fix
+ *
+ * Revision 1.1.2.2  1998/04/08 21:48:23  keil
+ * New init; working Niccy PCI
+ *
+ * Revision 1.1.2.1  1998/02/11 14:23:20  keil
+ * support for Dr Neuhaus Niccy PnP and PCI
+ *
+ *
+ */
+
+
+#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 *niccy_revision = "$Revision: 1.1.2.4 $";
+
+#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
+#define PCI_IRQ_CTRL_REG       0x38
+#define PCI_IRQ_ENABLE         0x1f00
+#define PCI_IRQ_DISABLE                0xff0000
+#define PCI_IRQ_ASSERT         0x800000
+
+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;
+       }
+       if (cs->subtyp == NICCY_PCI) {
+               int ival;
+               ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+               if (!(ival & PCI_IRQ_ASSERT)) /* IRQ not for us (shared) */
+                       return;
+               outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+       }
+       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) {
+               int val;
+               
+               val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+               val &= PCI_IRQ_DISABLE;
+               outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+               release_region(cs->hw.niccy.cfg_reg, 0x80);
+               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)
+{
+       int val, nval;
+       
+       val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+       nval = val | PCI_IRQ_ENABLE;
+       outl(nval, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+
+       inithscxisac(cs, 3);
+}
+
+static int
+niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       int imode;
+       
+       switch (mt) {
+               case CARD_RESET:
+                       niccy_reset(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_niccy(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       if (cs->subtyp == NICCY_PCI)
+                               imode = I4L_IRQ_FLAG | SA_SHIRQ;
+                       else
+                               imode = I4L_IRQ_FLAG;
+                       return(request_irq(cs->irq, &niccy_interrupt,
+                               imode, "HiSax", cs));
+                       break;
+               case CARD_INIT:
+                       niccy_reset(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 pci AMCC address */
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                               PCI_BASE_ADDRESS_0, &pci_ioaddr);
+                       if (!pci_ioaddr) {
+                               printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
+                               return(0);
+                       }
+                       cs->hw.niccy.cfg_reg = pci_ioaddr & ~3 ;
+                       /* get IO address */
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                               PCI_BASE_ADDRESS_1, &pci_ioaddr);
+                       if (cs->subtyp)
+                               break;
+               }
+               if (!cs->subtyp) {
+                       printk(KERN_WARNING "Niccy: No PCI card found\n");
+                       return(0);
+               }
+               pci_index++;
+               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");
+               if (check_region(cs->hw.niccy.cfg_reg, 0x80)) {
+                       printk(KERN_WARNING
+                              "HiSax: %s pci port %x-%x already in use\n",
+                               CardType[card->typ],
+                               cs->hw.niccy.cfg_reg,
+                               cs->hw.niccy.cfg_reg + 0x80);
+                       release_region(cs->hw.niccy.isac, 4);
+                       return (0);
+               } else {
+                       request_region(cs->hw.niccy.cfg_reg, 0x80, "niccy pci");
+               }
+#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);
+       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..15e05e0f646d2ceb3ee6d49219858efcb4fa6666 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.5.2.1 1997/10/17 22:14:20 keil Exp $
 
  * q931.c       code to decode ITU Q.931 call control messages
  *
  *
  *
  * $Log: q931.c,v $
+ * Revision 1.5.2.1  1997/10/17 22:14:20  keil
+ * update to last hisax version
+ *
+ * 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 +56,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/s0box.c b/drivers/isdn/hisax/s0box.c
new file mode 100644 (file)
index 0000000..539aa1c
--- /dev/null
@@ -0,0 +1,277 @@
+/* $Id: s0box.c,v 1.1.2.1 1998/04/11 18:44:41 keil Exp $
+
+ * s0box.c      low level stuff for Creatix S0BOX
+ *
+ * Author       S0BOX specific stuff: Enrik Berkhan (enrik@starfleet.inka.de)
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+const char *s0box_revision = "$Revision: 1.1.2.1 $";
+
+static inline void
+writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       outb_p(0x1c,padr+2);
+       outb_p(0x14,padr+2);
+       outb_p((addr+off)&0x7f,padr);
+       outb_p(0x16,padr+2);
+       outb_p(val,padr);
+       outb_p(0x17,padr+2);
+       outb_p(0x14,padr+2);
+       outb_p(0x1c,padr+2);
+       restore_flags(flags);
+}
+
+static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
+                        0, 0, 0, 0, 0, 0, 0, 0,
+                        0, 8, 4, 0xc, 2, 0xa, 6, 0xe } ;
+
+static inline u_char
+readreg(unsigned int padr, signed int addr, u_char off) {
+       register u_char n1, n2;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       outb_p(0x1c,padr+2);
+       outb_p(0x14,padr+2);
+       outb_p((addr+off)|0x80,padr);
+       outb_p(0x16,padr+2);
+       outb_p(0x17,padr+2);
+       n1 = (inb_p(padr+1) >> 3) & 0x17;
+       outb_p(0x16,padr+2);
+       n2 = (inb_p(padr+1) >> 3) & 0x17;
+       outb_p(0x14,padr+2);
+       outb_p(0x1c,padr+2);
+       restore_flags(flags);
+       return nibtab[n1] | (nibtab[n2] << 4);
+}
+
+static inline void
+read_fifo(unsigned int padr, signed int adr, u_char * data, int size)
+{
+       int i;
+       register u_char n1, n2;
+       
+       outb_p(0x1c, padr+2);
+       outb_p(0x14, padr+2);
+       outb_p(adr|0x80, padr);
+       outb_p(0x16, padr+2);
+       for (i=0; i<size; i++) {
+               outb_p(0x17, padr+2);
+               n1 = (inb_p(padr+1) >> 3) & 0x17;
+               outb_p(0x16,padr+2);
+               n2 = (inb_p(padr+1) >> 3) & 0x17;
+               *(data++)=nibtab[n1] | (nibtab[n2] << 4);
+       }
+       outb_p(0x14,padr+2);
+       outb_p(0x1c,padr+2);
+       return;
+}
+
+static inline void
+write_fifo(unsigned int padr, signed int adr, u_char * data, int size)
+{
+       int i;
+       outb_p(0x1c, padr+2);
+       outb_p(0x14, padr+2);
+       outb_p(adr&0x7f, padr);
+       for (i=0; i<size; i++) {
+               outb_p(0x16, padr+2);
+               outb_p(*(data++), padr);
+               outb_p(0x17, padr+2);
+       }
+       outb_p(0x14,padr+2);
+       outb_p(0x1c,padr+2);
+       return;
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg)
+#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#define MAXCOUNT 20
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat = 0;
+       int count = 0;
+
+       if (!cs) {
+               printk(KERN_WARNING "Teles: Spurious interrupt!\n");
+               return;
+       }
+       val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
+      Start_HSCX:
+       if (val) {
+               hscx_int_main(cs, val);
+               stat |= 1;
+       }
+       val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
+      Start_ISAC:
+       if (val) {
+               isac_interrupt(cs, val);
+               stat |= 2;
+       }
+       count++;
+       val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
+       if (val && count < MAXCOUNT) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX IntStat after IntRoutine");
+               goto Start_HSCX;
+       }
+       val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
+       if (val && count < MAXCOUNT) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               goto Start_ISAC;
+       }
+       if (count >= MAXCOUNT)
+               printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count);
+       if (stat & 1) {
+               writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
+               writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
+               writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
+               writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
+       }
+       if (stat & 2) {
+               writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
+               writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
+       }
+}
+
+void
+release_io_s0box(struct IsdnCardState *cs)
+{
+       release_region(cs->hw.teles3.cfg_reg, 8);
+}
+
+static int
+S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       break;
+               case CARD_RELEASE:
+                       release_io_s0box(cs);
+                       break;
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &s0box_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       inithscxisac(cs, 3);
+                       break;
+               case CARD_TEST:
+                       break;
+       }
+       return(0);
+}
+
+__initfunc(int
+setup_s0box(struct IsdnCard *card))
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, s0box_revision);
+       printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_S0BOX)
+               return (0);
+
+       cs->hw.teles3.cfg_reg = card->para[1];
+       cs->hw.teles3.hscx[0] = -0x20;
+       cs->hw.teles3.hscx[1] = 0x0;
+       cs->hw.teles3.isac = 0x20;
+       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;
+       cs->irq = card->para[0];
+       if (check_region(cs->hw.teles3.cfg_reg,8)) {
+               printk(KERN_WARNING
+                      "HiSax: %s ports %x-%x already in use\n",
+                      CardType[cs->typ],
+                       cs->hw.teles3.cfg_reg,
+                       cs->hw.teles3.cfg_reg + 7);
+               return 0;
+       } else
+               request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O");
+       printk(KERN_INFO
+              "HiSax: %s config irq:%d isac:0x%x  cfg:0x%x\n",
+              CardType[cs->typ], cs->irq,
+              cs->hw.teles3.isac, cs->hw.teles3.cfg_reg);
+       printk(KERN_INFO
+              "HiSax: hscx A:0x%x  hscx B:0x%x\n",
+              cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[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 = &S0Box_card_msg;
+       ISACVersion(cs, "S0Box:");
+       if (HscxVersion(cs, "S0Box:")) {
+               printk(KERN_WARNING
+                      "S0Box: wrong HSCX versions check IO address\n");
+               release_io_s0box(cs);
+               return (0);
+       }
+       return (1);
+}
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
new file mode 100644 (file)
index 0000000..d754c41
--- /dev/null
@@ -0,0 +1,353 @@
+/* $Id: sedlbauer.c,v 1.1.2.5 1998/04/08 21:58:44 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.1.2.5  1998/04/08 21:58:44  keil
+ * New init code
+ *
+ * Revision 1.1.2.4  1998/02/09 11:21:17  keil
+ * Sedlbauer PCMCIA support from Marcus Niemann
+ *
+ * Revision 1.1.2.3  1998/01/27 22:37:29  keil
+ * fast io
+ *
+ * Revision 1.1.2.2  1997/11/15 18:50:56  keil
+ * new common init function
+ *
+ * Revision 1.1.2.1  1997/10/17 22:10:56  keil
+ * new files on 2.0
+ *
+ * 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.1.2.5 $";
+
+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:
+                       inithscxisac(cs, 3);
+                       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/sportster.c b/drivers/isdn/hisax/sportster.c
new file mode 100644 (file)
index 0000000..6826840
--- /dev/null
@@ -0,0 +1,286 @@
+/* $Id: sportster.c,v 1.1.2.4 1998/04/08 21:58: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.1.2.4  1998/04/08 21:58:46  keil
+ * New init code
+ *
+ * Revision 1.1.2.3  1998/01/27 22:37:31  keil
+ * fast io
+ *
+ * Revision 1.1.2.2  1997/11/15 18:50:57  keil
+ * new common init function
+ *
+ * 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.1.2.4 $";
+
+#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:
+                       inithscxisac(cs, 1);
+                       cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
+                       byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
+                       inithscxisac(cs, 2);
+                       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 f13f9cd1fa47def91cc9a61ac093e338380718bd..d9f2b50936ed5d848158222ac6233dbebd316ecd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tei.c,v 1.8 1997/04/07 22:59:08 keil Exp $
+/* $Id: tei.c,v 1.8.2.6 1998/05/27 18:06:21 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 1.8.2.6  1998/05/27 18:06:21  keil
+ * HiSax 3.0
  *
- * Revision 1.7  1997/04/06 22:54:03  keil
- * Using SKB's
+ * Revision 1.8.2.5  1998/03/07 23:15:38  tsbogend
+ * made HiSax working on Linux/Alpha
  *
- * Revision 1.6  1997/02/09 00:25:12  keil
- * new interface handling, one interface per card
+ * Revision 1.8.2.4  1998/01/27 22:43:49  keil
+ * fixed MDL_ASSIGN_REQ
  *
- * Revision 1.5  1997/01/27 15:57:51  keil
+ * Revision 1.8.2.3  1997/11/15 18:54:20  keil
  * cosmetics
  *
- * Revision 1.4  1997/01/21 22:32:44  keil
- * Tei verify request
+ * Revision 1.8.2.2  1997/10/17 22:14:23  keil
+ * update to last hisax version
+ *
+ * Revision 2.2  1997/07/31 19:24:39  keil
+ * fixed a warning
  *
- * Revision 1.3  1997/01/04 13:45:02  keil
- * cleanup,adding remove tei request (thanks to Sim Yskes)
+ * Revision 2.1  1997/07/31 11:50:16  keil
+ * ONE TEI and FIXED TEI handling
  *
- * Revision 1.2  1996/12/08 19:52:39  keil
- * minor debug fix
+ * Revision 2.0  1997/07/27 21:13:30  keil
+ * New TEI managment
  *
- * Revision 1.1  1996/10/13 20:04:57  keil
- * Initial revision
+ * 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: 1.8.2.6 $";
 
-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 +130,369 @@ 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;
        }
        SET_SKB_FREE(skb);
-       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 | REQUEST, 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);
-                       dev_kfree_skb(skb, FREE_READ);
-                       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 | RESPONSE, NULL);
+               }
+       } else if (ri == st->ma.ri) {
+               FsmDelTimer(&st->ma.t202, 1);
+               FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
+               st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
+               cs = (struct IsdnCardState *) st->l1.hardware;
+               cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
        }
 }
 
-unsigned int
-randomces(void)
+static void
+tei_id_denied(struct FsmInst *fi, int event, void *arg)
 {
-       int x = jiffies & 0xffff;
+       struct PStack *st = fi->userdata;
+       struct sk_buff *skb = arg;
+       int ri, tei;
+       char tmp[64];
 
-       return (x);
+       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_man(struct PStack *sp, int i, void *v)
+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->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
+               cs = (struct IsdnCardState *) st->l1.hardware;
+               cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
+       }
+}
+
+static void
+tei_id_verify(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       char tmp[64];
+
+       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_id_req_tout(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+       char tmp[64];
+       struct IsdnCardState *cs;
+
+       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->l3.l3l2(st, MDL_ERROR | RESPONSE, 0);
+               cs = (struct IsdnCardState *) st->l1.hardware;
+               cs->cardmsg(cs, MDL_REMOVE | REQUEST, 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->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
+               cs = (struct IsdnCardState *) st->l1.hardware;
+               cs->cardmsg(cs, MDL_REMOVE | REQUEST, 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];
 
-       printk(KERN_DEBUG "tei_man\n");
+       if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
+               dev_kfree_skb(skb, FREE_READ);
+               return;
+       }
+
+       if (pr == (PH_DATA | INDICATION)) {
+               if (skb->len < 3) {
+                       sprintf(tmp, "short mgr frame %ld/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 %ld/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, FREE_READ);
 }
 
 static void
 tei_l2tei(struct PStack *st, int pr, void *arg)
 {
-       struct IsdnCardState *sp = st->l1.hardware;
+       struct IsdnCardState *cs;
 
-       tei_handler(sp->teistack, pr, arg);
+       if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
+               if (pr == (MDL_ASSIGN | INDICATION)) {
+                       if (st->ma.debug) {
+                               char tmp[64];
+                               sprintf(tmp, "fixed assign tei %d", st->l2.tei);
+                               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+                       }
+                       st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
+                       cs = (struct IsdnCardState *) st->l1.hardware;
+                       cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
+               }
+               return;
+       }
+       switch (pr) {
+               case (MDL_ASSIGN | INDICATION):
+                       FsmEvent(&st->ma.tei_m, EV_IDREQ, arg);
+                       break;
+               case (MDL_ERROR | REQUEST):
+                       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];
+
+       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;
+}
 
-       sprintf(tmp, "Card %d tei", sp->cardnr + 1);
-       setstack_isdnl2(st, tmp);
-       st->l2.debug = 0;
-       st->l3.debug = 0;
+void
+release_tei(struct IsdnCardState *cs)
+{
+       struct PStack *st = cs->stlist;
+
+       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..398786b
--- /dev/null
@@ -0,0 +1,378 @@
+/* $Id: teleint.c,v 1.1.2.6 1998/05/27 18:06:24 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.1.2.6  1998/05/27 18:06:24  keil
+ * HiSax 3.0
+ *
+ * Revision 1.1.2.5  1998/04/08 21:58:48  keil
+ * New init code
+ *
+ * Revision 1.1.2.4  1998/04/04 21:58:27  keil
+ * fix HFC BUSY on ISAC fifos
+ *
+ * Revision 1.1.2.3  1998/01/27 22:37:41  keil
+ * fast io
+ *
+ * Revision 1.1.2.2  1997/11/15 18:50:58  keil
+ * new common init function
+ *
+ * Revision 1.1.2.1  1997/10/17 22:11:00  keil
+ * new files on 2.0
+ *
+ * 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.1.2.6 $";
+
+#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;
+       register int max_delay = 20000;
+       register int i;
+       
+       byteout(ale, off);
+       for (i = 0; i<size; i++) {
+               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;
+               }
+               data[i] = bytein(adr);
+       }
+}
+
+
+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;
+       register int max_delay = 20000;
+       register int i;
+       
+       /* fifo write without cli because it's allready done  */
+       byteout(ale, off);
+       for (i = 0; i<size; i++) {
+               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;
+               }
+               byteout(adr, data[i]);
+       }
+}
+
+/* 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);
+                       /* Reenable all IRQ */
+                       cs->writeisac(cs, ISAC_MASK, 0);
+                       cs->writeisac(cs, ISAC_CMDR, 0x41);
+                       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 91f9e59b0ce3580beaad2f91aba1e704182d41e2..fd2b281e9dc20b979f526772b667417797eb59e8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 1.8 1997/04/13 19:54:04 keil Exp $
+/* $Id: teles0.c,v 1.8.2.9 1998/04/08 21:58:49 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 1.8.2.9  1998/04/08 21:58:49  keil
+ * New init code
  *
- * Revision 1.7  1997/04/06 22:54:04  keil
- * Using SKB's
+ * Revision 1.8.2.8  1998/03/07 23:15:40  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
+ * Revision 1.8.2.7  1998/02/03 23:17:16  keil
+ * IRQ 9
  *
- * Revision 1.6  1997/01/27 15:52:18  keil
- * SMP proof,cosmetics
+ * Revision 1.8.2.6  1998/01/27 22:37:43  keil
+ * fast io
  *
- * Revision 1.5  1997/01/21 22:25:59  keil
- * cleanups
+ * Revision 1.8.2.5  1997/11/15 18:51:00  keil
+ * new common init function
  *
- * Revision 1.4  1996/11/05 19:41:27  keil
- * more changes for 2.1
+ * Revision 1.8.2.4  1997/10/17 22:14:26  keil
+ * update to last hisax version
  *
- * 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: 1.8.2.9 $";
 
-#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); mb();
 }
 
 
 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) +
-              ((off & 1) ? 0x1ff : 0) + off);
+       writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
+              ((off & 1) ? 0x1ff : 0) + off); mb();
 }
 
 static inline void
 read_fifo_isac(unsigned int adr, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *) (adr + 0x100);
+       register u_char *ad = (u_char *) ((long)adr + 0x100);
        for (i = 0; i < size; i++)
                data[i] = readb(ad);
 }
 
-static void
+static inline void
 write_fifo_isac(unsigned int adr, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *) (adr + 0x100);
-       for (i = 0; i < size; i++)
-               writeb(data[i], ad);
+       register u_char *ad = (u_char *) ((long)adr + 0x100);
+       for (i = 0; i < size; i++) {
+               writeb(data[i], ad); mb();
+       }
 }
 
 static inline void
 read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
 {
        register int i;
-       register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
+       register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180));
        for (i = 0; i < size; i++)
                data[i] = readb(ad);
 }
@@ -109,749 +115,206 @@ static inline void
 write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
 {
        int i;
-       register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
-       for (i = 0; i < size; i++)
-               writeb(data[i], ad);
-}
-static inline void
-waitforCEC(int adr, int hscx)
-{
-       int to = 50;
-
-       while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
-               udelay(1);
-               to--;
+       register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180));
+       for (i = 0; i < size; i++) {
+               writeb(data[i], ad); mb();
        }
-       if (!to)
-               printk(KERN_WARNING "Teles0: waitforCEC timeout\n");
 }
 
+/* Interface functions */
 
-static inline void
-waitforXFW(int adr, int hscx)
-{
-       int to = 50;
-
-       while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
-               udelay(1);
-               to--;
-       }
-       if (!to)
-               printk(KERN_WARNING "Teles0: waitforXFW timeout\n");
-}
-
-static inline void
-writehscxCMDR(int adr, int hscx, u_char data)
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-       long flags;
-
-       save_flags(flags);
-       cli();
-       waitforCEC(adr, hscx);
-       writehscx(adr, hscx, HSCX_CMDR, data);
-       restore_flags(flags);
+       return (readisac(cs->hw.teles0.membase, 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", 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));
+       writeisac(cs->hw.teles0.membase, offset, value);
 }
 
-void
-teles0_report(struct IsdnCardState *sp)
-{
-       printk(KERN_DEBUG "ISAC\n");
-       printk(KERN_DEBUG "ISTA %x\n", readisac(sp->membase, ISAC_ISTA));
-       printk(KERN_DEBUG "STAR %x\n", readisac(sp->membase, ISAC_STAR));
-       printk(KERN_DEBUG "EXIR %x\n", readisac(sp->membase, ISAC_EXIR));
-       hscxreport(sp, 0);
-       hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
-
 static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
+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 "teles0: receive out of memory\n");
-                               else {
-                                       memcpy(skb_put(skb, count), hsp->rcvbuf, count);
-                                       skb_queue_tail(&hsp->rqueue, skb);
-                               }
-                       }
-               }
-               hsp->rcvidx = 0;
-               hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-       }
-       if (val & 0x40) {       /* RPF */
-               hscx_empty_fifo(hsp, 32);
-               if (hsp->mode == 1) {
-                       /* receive audio data */
-                       if (!(skb = dev_alloc_skb(32)))
-                               printk(KERN_WARNING "teles0: receive out of memory\n");
-                       else {
-                               memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
-                               skb_queue_tail(&hsp->rqueue, skb);
-                       }
-                       hsp->rcvidx = 0;
-                       hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-               }
-       }
-       if (val & 0x10) {       /* XPR */
-               if (hsp->tx_skb)
-                       if (hsp->tx_skb->len) {
-                               hscx_fill_fifo(hsp);
-                               return;
-                       } else {
-                               dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
-                               hsp->count = 0;
-                               if (hsp->st->l4.l1writewakeup)
-                                       hsp->st->l4.l1writewakeup(hsp->st);
-                               hsp->tx_skb = NULL;
-                       }
-               if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
-                       hsp->count = 0;
-                       hscx_fill_fifo(hsp);
-               } else
-                       hscx_sched_event(hsp, HSCX_XMTBUFREADY);
-       }
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_empty_fifo(struct IsdnCardState *sp, int count)
-{
-       u_char *ptr;
-       long flags;
-
-       if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
-               debugl1(sp, "isac_empty_fifo");
-
-       if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
-               if (sp->debug & L1_DEB_WARN) {
-                       char tmp[40];
-                       sprintf(tmp, "isac_empty_fifo overrun %d",
-                               sp->rcvidx + count);
-                       debugl1(sp, tmp);
-               }
-               writeisac(sp->membase, ISAC_CMDR, 0x80);
-               sp->rcvidx = 0;
-               return;
-       }
-       ptr = sp->rcvbuf + sp->rcvidx;
-       sp->rcvidx += count;
-       save_flags(flags);
-       cli();
-       read_fifo_isac(sp->membase, ptr, count);
-       writeisac(sp->membase, ISAC_CMDR, 0x80);
-       restore_flags(flags);
-       if (sp->debug & L1_DEB_ISAC_FIFO) {
-               char tmp[128];
-               char *t = tmp;
-
-               t += sprintf(t, "isac_empty_fifo cnt %d", count);
-               QuickHex(t, ptr, count);
-               debugl1(sp, tmp);
-       }
-}
-
-static void
-isac_fill_fifo(struct IsdnCardState *sp)
-{
-       int count, more;
-       u_char *ptr;
-       long flags;
-
-       if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
-               debugl1(sp, "isac_fill_fifo");
-
-       if (!sp->tx_skb)
-               return;
-
-       count = sp->tx_skb->len;
-       if (count <= 0)
-               return;
-
-       more = 0;
-       if (count > 32) {
-               more = !0;
-               count = 32;
-       }
-       save_flags(flags);
-       cli();
-       ptr = sp->tx_skb->data;
-       skb_pull(sp->tx_skb, count);
-       sp->tx_cnt += count;
-       write_fifo_isac(sp->membase, ptr, count);
-       writeisac(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
-       restore_flags(flags);
-       if (sp->debug & L1_DEB_ISAC_FIFO) {
-               char tmp[128];
-               char *t = tmp;
-
-               t += sprintf(t, "isac_fill_fifo cnt %d", count);
-               QuickHex(t, ptr, count);
-               debugl1(sp, tmp);
-       }
+       return (readhscx(cs->hw.teles0.membase, 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);
-       }
-       writeisac(sp->membase, ISAC_CIX0, (command << 2) | 3);
+       writehscx(cs->hw.teles0.membase, hscx, offset, value);
 }
 
-static inline void
-isac_interrupt(struct IsdnCardState *sp, u_char val)
-{
-       u_char exval;
-       struct sk_buff *skb;
-       unsigned int count;
-       char tmp[32];
-
-       if (sp->debug & L1_DEB_ISAC) {
-               sprintf(tmp, "ISAC interrupt %x", val);
-               debugl1(sp, tmp);
-       }
-       if (val & 0x80) {       /* RME */
-               exval = readisac(sp->membase, ISAC_RSTA);
-               if ((exval & 0x70) != 0x20) {
-                       if (exval & 0x40)
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, "ISAC RDO");
-                       if (!(exval & 0x20))
-                               if (sp->debug & L1_DEB_WARN)
-                                       debugl1(sp, "ISAC CRC error");
-                       writeisac(sp->membase, ISAC_CMDR, 0x80);
-               } else {
-                       count = readisac(sp->membase, ISAC_RBCL) & 0x1f;
-                       if (count == 0)
-                               count = 32;
-                       isac_empty_fifo(sp, count);
-                       if ((count = sp->rcvidx) > 0) {
-                               if (!(skb = alloc_skb(count, GFP_ATOMIC)))
-                                       printk(KERN_WARNING "teles0: D receive out of memory\n");
-                               else {
-                                       SET_SKB_FREE(skb);
-                                       memcpy(skb_put(skb, count), sp->rcvbuf, count);
-                                       skb_queue_tail(&sp->rq, skb);
-                               }
-                       }
-               }
-               sp->rcvidx = 0;
-               isac_sched_event(sp, ISAC_RCVBUFREADY);
-       }
-       if (val & 0x40) {       /* RPF */
-               isac_empty_fifo(sp, 32);
-       }
-       if (val & 0x20) {       /* RSC */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC RSC interrupt");
-       }
-       if (val & 0x10) {       /* XPR */
-               if (sp->tx_skb)
-                       if (sp->tx_skb->len) {
-                               isac_fill_fifo(sp);
-                               goto afterXPR;
-                       } else {
-                               dev_kfree_skb(sp->tx_skb, FREE_WRITE);
-                               sp->tx_cnt = 0;
-                               sp->tx_skb = NULL;
-                       }
-               if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
-                       sp->tx_cnt = 0;
-                       isac_fill_fifo(sp);
-               } else
-                       isac_sched_event(sp, ISAC_XMTBUFREADY);
-       }
-      afterXPR:
-       if (val & 0x04) {       /* CISQ */
-               sp->ph_state = (readisac(sp->membase, ISAC_CIX0) >> 2)
-                   & 0xf;
-               if (sp->debug & L1_DEB_ISAC) {
-                       sprintf(tmp, "l1state %d", sp->ph_state);
-                       debugl1(sp, tmp);
-               }
-               isac_new_ph(sp);
-       }
-       if (val & 0x02) {       /* SIN */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC SIN interrupt");
-       }
-       if (val & 0x01) {       /* EXI */
-               exval = readisac(sp->membase, ISAC_EXIR);
-               if (sp->debug & L1_DEB_WARN) {
-                       sprintf(tmp, "ISAC EXIR %02x", exval);
-                       debugl1(sp, tmp);
-               }
-       }
-}
+/*
+ * 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 *) irq2dev_map[intno];
-
-       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); mb();
+       HZDELAY(HZ / 5 + 1);
+       writeb(1, cs->hw.teles0.membase + 0x80); mb();
+       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.interrupts[sp->irq];
-       sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
-       debugl1(sp, tmp);
-       clear_pending_ints(sp);
-       ret = get_irq(sp->cardnr, &telesS0_interrupt);
-       if (ret) {
-               initisac(sp);
-               sp->modehscx(sp->hs, 0, 0);
-               sp->modehscx(sp->hs + 1, 0, 0);
-               while (loop++ < 10) {
-                       /* At least 1-3 irqs must happen
-                        * (one from HSCX A, one from HSCX B, 3rd from ISAC)
-                        */
-                       if (kstat.interrupts[sp->irq] > sp->counter)
-                               break;
-                       current->state = TASK_INTERRUPTIBLE;
-                       current->timeout = jiffies + 1;
-                       schedule();
-               }
-               sprintf(tmp, "IRQ %d count %d", sp->irq,
-                       kstat.interrupts[sp->irq]);
-               debugl1(sp, tmp);
-               if (kstat.interrupts[sp->irq] == sp->counter) {
-                       printk(KERN_WARNING
-                              "Teles0: IRQ(%d) getting no interrupts during init\n",
-                              sp->irq);
-                       irq2dev_map[sp->irq] = NULL;
-                       free_irq(sp->irq, NULL);
-                       return (0);
-               }
-       }
-       return (ret);
+       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:
+                       inithscxisac(cs, 3);
+                       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 +322,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);
 }
index 23333e7f8ab2fb6467196f5a3179a1510629361f..ba6e3a2063028a8d85e50cd75c22384a1910f5d7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: teles3.c,v 1.11 1997/04/13 19:54:05 keil Exp $
+/* $Id: teles3.c,v 1.11.2.9 1998/04/08 21:58:52 keil Exp $
 
  * teles3.c     low level stuff for Teles 16.3 & PNP isdn cards
  *
  *              Beat Doebeli
  *
  * $Log: teles3.c,v $
+ * Revision 1.11.2.9  1998/04/08 21:58:52  keil
+ * New init code
+ *
+ * Revision 1.11.2.8  1998/01/27 22:37:46  keil
+ * fast io
+ *
+ * Revision 1.11.2.7  1998/01/11 22:58:01  keil
+ * make IRQ 9 working again
+ *
+ * Revision 1.11.2.6  1997/12/01 22:35:43  keil
+ * ID Byte for 16.3 version 1.1
+ *
+ * Revision 1.11.2.5  1997/11/15 18:51:03  keil
+ * new common init function
+ *
+ * Revision 1.11.2.4  1997/10/17 22:14:30  keil
+ * update to last hisax version
+ *
+ * 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: 1.11.2.9 $";
 
-#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,407 @@ 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 "teles3: receive out of memory\n");
-                               else {
-                                       memcpy(skb_put(skb, count), hsp->rcvbuf, count);
-                                       skb_queue_tail(&hsp->rqueue, skb);
-                               }
-                       }
-               }
-               hsp->rcvidx = 0;
-               hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-       }
-       if (val & 0x40) {       /* RPF */
-               hscx_empty_fifo(hsp, 32);
-               if (hsp->mode == 1) {
-                       /* receive audio data */
-                       if (!(skb = dev_alloc_skb(32)))
-                               printk(KERN_WARNING "teles3: receive out of memory\n");
-                       else {
-                               memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
-                               skb_queue_tail(&hsp->rqueue, skb);
-                       }
-                       hsp->rcvidx = 0;
-                       hscx_sched_event(hsp, HSCX_RCVBUFREADY);
-               }
-       }
-       if (val & 0x10) {       /* XPR */
-               if (hsp->tx_skb)
-                       if (hsp->tx_skb->len) {
-                               hscx_fill_fifo(hsp);
-                               return;
-                       } else {
-                               dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
-                               hsp->count = 0;
-                               if (hsp->st->l4.l1writewakeup)
-                                       hsp->st->l4.l1writewakeup(hsp->st);
-                               hsp->tx_skb = NULL;
-                       }
-               if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
-                       hsp->count = 0;
-                       hscx_fill_fifo(hsp);
-               } else
-                       hscx_sched_event(hsp, HSCX_XMTBUFREADY);
-       }
+       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 {
-                                       SET_SKB_FREE(skb);
-                                       memcpy(skb_put(skb, count), sp->rcvbuf, count);
-                                       skb_queue_tail(&sp->rq, skb);
-                               }
-                       }
-               }
-               sp->rcvidx = 0;
-               isac_sched_event(sp, ISAC_RCVBUFREADY);
-       }
-       if (val & 0x40) {       /* RPF */
-               isac_empty_fifo(sp, 32);
-       }
-       if (val & 0x20) {       /* RSC */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC RSC interrupt");
-       }
-       if (val & 0x10) {       /* XPR */
-               if (sp->tx_skb)
-                       if (sp->tx_skb->len) {
-                               isac_fill_fifo(sp);
-                               goto afterXPR;
-                       } else {
-                               dev_kfree_skb(sp->tx_skb, FREE_WRITE);
-                               sp->tx_cnt = 0;
-                               sp->tx_skb = NULL;
-                       }
-               if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
-                       sp->tx_cnt = 0;
-                       isac_fill_fifo(sp);
-               } else
-                       isac_sched_event(sp, ISAC_XMTBUFREADY);
-       }
-      afterXPR:
-       if (val & 0x04) {       /* CISQ */
-               sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
-                   & 0xf;
-               if (sp->debug & L1_DEB_ISAC) {
-                       sprintf(tmp, "l1state %d", sp->ph_state);
-                       debugl1(sp, tmp);
-               }
-               isac_new_ph(sp);
-       }
-       if (val & 0x02) {       /* SIN */
-               /* never */
-               if (sp->debug & L1_DEB_WARN)
-                       debugl1(sp, "ISAC SIN interrupt");
-       }
-       if (val & 0x01) {       /* EXI */
-               exval = readreg(sp->isac, ISAC_EXIR);
-               if (sp->debug & L1_DEB_WARN) {
-                       sprintf(tmp, "ISAC EXIR %02x", exval);
-                       debugl1(sp, tmp);
-               }
-       }
-}
-
-static inline void
-hscx_int_main(struct IsdnCardState *sp, u_char val)
-{
-
-       u_char exval;
-       struct HscxState *hsp;
-       char tmp[32];
+#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 *) irq2dev_map[intno];
-
-       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.interrupts[sp->irq];
-       sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
-       debugl1(sp, tmp);
-       clear_pending_ints(sp);
-       ret = get_irq(sp->cardnr, &teles3_interrupt);
-       if (ret) {
-               initisac(sp);
-               sp->modehscx(sp->hs, 0, 0);
-               writereg(sp->hscx[sp->hs->hscx], HSCX_CMDR, 0x01);
-               sp->modehscx(sp->hs + 1, 0, 0);
-               writereg(sp->hscx[(sp->hs + 1)->hscx], HSCX_CMDR, 0x01);
-               while (loop++ < 10) {
-                       /* At least 1-3 irqs must happen
-                        * (one from HSCX A, one from HSCX B, 3rd from ISAC)
-                        */
-                       if (kstat.interrupts[sp->irq] > sp->counter)
-                               break;
-                       current->state = TASK_INTERRUPTIBLE;
-                       current->timeout = jiffies + 1;
-                       schedule();
-               }
-               sprintf(tmp, "IRQ %d count %d loop %d", sp->irq,
-                       kstat.interrupts[sp->irq], loop);
-               debugl1(sp, tmp);
-               if (kstat.interrupts[sp->irq] <= sp->counter) {
-                       printk(KERN_WARNING
-                              "Teles3: IRQ(%d) getting no interrupts during init\n",
-                              sp->irq);
-                       irq2dev_map[sp->irq] = NULL;
-                       free_irq(sp->irq, NULL);
-                       return (0);
-               }
-       }
-       return (ret);
+       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:
+                       inithscxisac(cs, 3);
+                       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/teles3c.c b/drivers/isdn/hisax/teles3c.c
new file mode 100644 (file)
index 0000000..e25a2c2
--- /dev/null
@@ -0,0 +1,201 @@
+/* $Id: teles3c.c,v 1.1.2.2 1998/01/27 22:40:37 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.1.2.2  1998/01/27 22:40:37  keil
+ * fixed IRQ latency, B-channel selection and more
+ *
+ * Revision 1.1.2.1  1998/01/11 22:54:04  keil
+ * Teles 16.3c (HFC 2BDS0) first version
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "hfc_2bds0.h"
+#include "isdnl1.h"
+
+extern const char *CardType[];
+
+const char *teles163c_revision = "$Revision: 1.1.2.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);
+}
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
new file mode 100644 (file)
index 0000000..5473841
--- /dev/null
@@ -0,0 +1,374 @@
+/* $Id: telespci.c,v 1.1.2.2 1998/04/20 08:52:46 keil Exp $
+
+ * telespci.c     low level stuff for Teles PCI isdn cards
+ *
+ * Author       Ton van Rosmalen 
+ *              Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: telespci.c,v $
+ * Revision 1.1.2.2  1998/04/20 08:52:46  keil
+ * Fix register offsets
+ *
+ * Revision 1.1.2.1  1998/04/11 18:44:42  keil
+ * New files
+ *
+ *
+ */
+#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 *telespci_revision = "$Revision: 1.1.2.2 $";
+
+#define ZORAN_PO_RQ_PEN        0x02000000
+#define ZORAN_PO_WR    0x00800000
+#define ZORAN_PO_GID0  0x00000000
+#define ZORAN_PO_GID1  0x00100000
+#define ZORAN_PO_GREG0 0x00000000
+#define ZORAN_PO_GREG1 0x00010000
+#define ZORAN_PO_DMASK 0xFF
+
+#define WRITE_ADDR_ISAC        (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0)
+#define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1)
+#define WRITE_DATA_ISAC        (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1)
+#define WRITE_ADDR_HSCX        (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0)
+#define READ_DATA_HSCX (ZORAN_PO_GID1 | ZORAN_PO_GREG1)
+#define WRITE_DATA_HSCX        (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1)
+
+#define ZORAN_WAIT_NOBUSY      do { \
+                                       portdata = readl(adr + 0x200); \
+                               } while (portdata & ZORAN_PO_RQ_PEN)
+
+static inline u_char
+readisac(unsigned int adr, u_char off)
+{
+       register unsigned int portdata;
+
+       ZORAN_WAIT_NOBUSY;
+       
+       /* set address for ISAC */
+       writel(WRITE_ADDR_ISAC | off, adr + 0x200);
+       ZORAN_WAIT_NOBUSY;
+       
+       /* read data from ISAC */
+       writel(READ_DATA_ISAC, adr + 0x200);
+       ZORAN_WAIT_NOBUSY;
+       return((u_char)(portdata & ZORAN_PO_DMASK));
+}
+
+static inline void
+writeisac(unsigned int adr, u_char off, u_char data)
+{
+       register unsigned int portdata;
+
+       ZORAN_WAIT_NOBUSY;
+       
+       /* set address for ISAC */
+       writel(WRITE_ADDR_ISAC | off, adr + 0x200);
+       ZORAN_WAIT_NOBUSY;
+
+       /* write data to ISAC */
+       writel(WRITE_DATA_ISAC | data, adr + 0x200);
+       ZORAN_WAIT_NOBUSY;
+}
+
+static inline u_char
+readhscx(unsigned int adr, int hscx, u_char off)
+{
+       register unsigned int portdata;
+
+       ZORAN_WAIT_NOBUSY;
+       /* set address for HSCX */
+       writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200);
+       ZORAN_WAIT_NOBUSY;
+       
+       /* read data from HSCX */
+       writel(READ_DATA_HSCX, adr + 0x200);
+       ZORAN_WAIT_NOBUSY;
+       return ((u_char)(portdata & ZORAN_PO_DMASK));
+}
+
+static inline void
+writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+{
+       register unsigned int portdata;
+
+       ZORAN_WAIT_NOBUSY;
+       /* set address for HSCX */
+       writel(WRITE_ADDR_HSCX | ((hscx ? 0x40:0) + off), adr + 0x200);
+       ZORAN_WAIT_NOBUSY;
+
+       /* write data to HSCX */
+       writel(WRITE_DATA_HSCX | data, adr + 0x200);
+       ZORAN_WAIT_NOBUSY;
+}
+
+static inline void
+read_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+       register unsigned int portdata;
+       register int i;
+
+       ZORAN_WAIT_NOBUSY;
+       /* read data from ISAC */
+       for (i = 0; i < size; i++) {
+               /* set address for ISAC fifo */
+               writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
+               ZORAN_WAIT_NOBUSY;
+               writel(READ_DATA_ISAC, adr + 0x200);
+               ZORAN_WAIT_NOBUSY;
+               data[i] = (u_char)(portdata & ZORAN_PO_DMASK);
+       }
+}
+
+static void
+write_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+       register unsigned int portdata;
+       register int i;
+
+       ZORAN_WAIT_NOBUSY;
+       /* write data to ISAC */
+       for (i = 0; i < size; i++) {
+               /* set address for ISAC fifo */
+               writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200);
+               ZORAN_WAIT_NOBUSY;
+               writel(WRITE_DATA_ISAC | data[i], adr + 0x200);
+               ZORAN_WAIT_NOBUSY;
+       }
+}
+
+static inline void
+read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+       register unsigned int portdata;
+       register int i;
+
+       ZORAN_WAIT_NOBUSY;
+       /* read data from HSCX */
+       for (i = 0; i < size; i++) {
+               /* set address for HSCX fifo */
+               writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200);
+               ZORAN_WAIT_NOBUSY;
+               writel(READ_DATA_HSCX, adr + 0x200);
+               ZORAN_WAIT_NOBUSY;
+               data[i] = (u_char) (portdata & ZORAN_PO_DMASK);
+       }
+}
+
+static inline void
+write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+       unsigned int portdata;
+       register int i;
+
+       ZORAN_WAIT_NOBUSY;
+       /* write data to HSCX */
+       for (i = 0; i < size; i++) {
+               /* set address for HSCX fifo */
+               writel(WRITE_ADDR_HSCX |(hscx ? 0x5F:0x1F), adr + 0x200);
+               ZORAN_WAIT_NOBUSY;
+               writel(WRITE_DATA_HSCX | data[i], adr + 0x200);
+               ZORAN_WAIT_NOBUSY;
+               udelay(10);
+       }
+}
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       return (readisac(cs->hw.teles0.membase, offset));
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       writeisac(cs->hw.teles0.membase, offset, value);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       read_fifo_isac(cs->hw.teles0.membase, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       write_fifo_isac(cs->hw.teles0.membase, data, size);
+}
+
+static u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       return (readhscx(cs->hw.teles0.membase, hscx, offset));
+}
+
+static void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       writehscx(cs->hw.teles0.membase, hscx, offset, value);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#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)
+
+#include "hscx_irq.c"
+
+static void
+telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#define MAXCOUNT 20
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat = 0;
+
+       if (!cs) {
+               printk(KERN_WARNING "TelesPCI: Spurious interrupt!\n");
+               return;
+       }
+       val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
+       if (val) {
+               hscx_int_main(cs, val);
+               stat |= 1;
+       }
+       val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
+       if (val) {
+               isac_interrupt(cs, val);
+               stat |= 2;
+       }
+       /* Clear interrupt register for Zoran PCI controller */
+       writel(0x70000000, cs->hw.teles0.membase + 0x3C);
+
+       if (stat & 1) {
+               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(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
+               writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
+       }
+}
+
+void
+release_io_telespci(struct IsdnCardState *cs)
+{
+       vfree((void *)cs->hw.teles0.membase);
+}
+
+static int
+TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       switch (mt) {
+               case CARD_RESET:
+                       return(0);
+               case CARD_RELEASE:
+                       release_io_telespci(cs);
+                       return(0);
+               case CARD_SETIRQ:
+                       return(request_irq(cs->irq, &telespci_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+               case CARD_INIT:
+                       inithscxisac(cs, 3);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+static         int pci_index __initdata = 0;
+
+__initfunc(int
+setup_telespci(struct IsdnCard *card))
+{
+       int found=0;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+       u_char pci_bus, pci_device_fn, pci_irq;
+       u_int pci_memaddr;
+
+       strcpy(tmp, telespci_revision);
+       printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_TELESPCI)
+               return (0);
+
+#if CONFIG_PCI
+       for (pci_index = 0; pci_index < 0xff; pci_index++) {
+               if (pcibios_find_device (0x11DE, 0x6120,
+                       pci_index, &pci_bus, &pci_device_fn)
+                       == PCIBIOS_SUCCESSFUL) {
+                       found = 1;
+               } else {
+                       break;
+               }
+               pcibios_read_config_dword(pci_bus, pci_device_fn,
+                               PCI_BASE_ADDRESS_0, &pci_memaddr);
+               pcibios_read_config_byte(pci_bus, pci_device_fn,
+                               PCI_INTERRUPT_LINE, &pci_irq);
+
+               printk(KERN_INFO "Found: Zoran, base-address: 0x%x,"
+                       " irq: 0x%x\n", pci_memaddr, pci_irq);
+               break;
+       }
+       if (!found) {
+               printk(KERN_WARNING "TelesPCI: No PCI card found\n");
+               return(0);
+       }
+       pci_index++;
+       cs->hw.teles0.membase = (u_int) vremap(pci_memaddr, PAGE_SIZE);
+       cs->irq = pci_irq;
+#else
+       printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
+       printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
+       return (0);
+#endif /* CONFIG_PCI */
+
+       /* Initialize Zoran PCI controller */
+       writel(0x00000000, cs->hw.teles0.membase + 0x28);
+       writel(0x01000000, cs->hw.teles0.membase + 0x28);
+       writel(0x01000000, cs->hw.teles0.membase + 0x28);
+       writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C);
+       writel(0x70000000, cs->hw.teles0.membase + 0x3C);
+       writel(0x61000000, cs->hw.teles0.membase + 0x40);
+       /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */
+
+       printk(KERN_INFO
+              "HiSax: %s config irq:%d mem:%x\n",
+              CardType[cs->typ], cs->irq,
+              cs->hw.teles0.membase);
+
+       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 = &TelesPCI_card_msg;
+       ISACVersion(cs, "TelesPCI:");
+       if (HscxVersion(cs, "TelesPCI:")) {
+               printk(KERN_WARNING
+                "TelesPCI: wrong HSCX versions check IO/MEM addresses\n");
+               release_io_telespci(cs);
+               return (0);
+       }
+       return (1);
+}
index a7b64702de04c3713bad484b2a69517ba6b5b7cf..81cf94a5ddd7e0f2a0aaf76cdee3978ffa6b3b10 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.45 1997/06/21 10:42:06 fritz Exp $
+ /* $Id: icn.c,v 1.45.2.3 1998/06/07 13:32:04 fritz 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.45.2.3  1998/06/07 13:32:04  fritz
+ * Minor bugfixes for broken Switches.
+ *
+ * Revision 1.45.2.2  1998/03/07 23:35:36  detabc
+ * added the abc-extension to the linux isdn-kernel
+ * for kernel-version 2.0.xx
+ * DO NOT USE FOR HIGHER KERNELS-VERSIONS
+ * all source-lines are switched with the define  CONFIG_ISDN_WITH_ABC
+ * (make config and answer ABC-Ext. Support (Compress,TCP-Keepalive ...) with yes
+ *
+ * you need also a modified isdnctrl-source the switch on the
+ * features of the abc-extension
+ *
+ * please use carefully. more detail will be follow.
+ * thanks
+ *
+ * Revision 1.45.2.1  1997/08/21 15:56:50  fritz
+ * Synchronized 2.0.X branch with 2.0.31-pre7
+ *
  * Revision 1.45  1997/06/21 10:42:06  fritz
  * Added availability to select leased mode on only one channel.
  *
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.45 $";
+*revision = "$Revision: 1.45.2.3 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -531,8 +550,13 @@ static icn_stat icn_stat_table[] =
 {
        {"BCON_",          ISDN_STAT_BCONN, 1}, /* B-Channel connected        */
        {"BDIS_",          ISDN_STAT_BHUP,  2}, /* B-Channel disconnected     */
-       {"DCON_",          ISDN_STAT_DCONN, 0}, /* D-Channel connected        */
-       {"DDIS_",          ISDN_STAT_DHUP,  0}, /* D-Channel disconnected     */
+#ifdef CONFIG_ISDN_WITH_ABC
+       {"DCON_",          ISDN_STAT_DCONN, 10}, /* D-Channel connected       */
+       {"DDIS_",          ISDN_STAT_DHUP,  11}, /* D-Channel disconnected    */
+#else
+       {"DCON_",          ISDN_STAT_DCONN, 0}, /* D-Channel connected        */
+       {"DDIS_",          ISDN_STAT_DHUP,  0}, /* D-Channel disconnected     */
+#endif
        {"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  */
@@ -582,7 +606,41 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
        cmd.driver = card->myid;
        cmd.arg = channel;
        switch (action) {
+#ifdef CONFIG_ISDN_WITH_ABC
+       case 11:
+
+               save_flags(flags);
+               cli();
+               icn_free_queue(card,channel);
+               card->rcvidx[channel] = 0;
+
+               if( card->flags & 
+                       ((channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE)) {
+
+                       isdn_ctrl ncmd;
+
+                       printk(KERN_INFO "icn: D-Channel hangup before B-Channel hangup\n");
+
+                       card->flags &= ~((channel)?
+                                       ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE);
+
+                       memset(&ncmd,0,sizeof(ncmd));
+
+                       ncmd.driver = card->myid;
+                       ncmd.arg = channel;
+                       ncmd.command = ISDN_STAT_BHUP;
+                       restore_flags(flags);
+                       card->interface.statcallb(&cmd);
+                       dflag |= (channel+1);
+
+               } else restore_flags(flags);
+               
+               break;
+#endif
                case 1:
+#ifdef CONFIG_ISDN_WITH_ABC
+                       icn_free_queue(card,channel);
+#endif
                        card->flags |= (channel) ?
                            ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
                        break;
@@ -601,17 +659,22 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
                                char *t = status + 6;
                                char *s = strpbrk(t, ",");
 
+                               memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
+                               if (!s)
+                                       break;
                                *s++ = '\0';
                                strncpy(cmd.parm.setup.phone, t,
                                        sizeof(cmd.parm.setup.phone));
-                               s = strpbrk(t = s, ",");
+                               if (!(s = strpbrk(t = s, ",")))
+                                       break;
                                *s++ = '\0';
                                if (!strlen(t))
                                        cmd.parm.setup.si1 = 0;
                                else
                                        cmd.parm.setup.si1 =
                                            simple_strtoul(t, NULL, 10);
-                               s = strpbrk(t = s, ",");
+                               if (!(s = strpbrk(t = s, ",")))
+                                       break;
                                *s++ = '\0';
                                if (!strlen(t))
                                        cmd.parm.setup.si2 = 0;
@@ -621,8 +684,6 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
                                strncpy(cmd.parm.setup.eazmsn, s,
                                        sizeof(cmd.parm.setup.eazmsn));
                        }
-                       cmd.parm.setup.plan = 0;
-                       cmd.parm.setup.screen = 0;
                        break;
                case 4:
                        sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
index dcd251a01922b85d7d054574cbc8ed8b01a75347..3e24d29f5a1fa44ae0c971a8b54500402c9cfc1d 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.44.2.4 1998/06/07 13:47:44 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.44.2.4  1998/06/07 13:47:44  fritz
+ * ABC cleanup
+ *
+ * Revision 1.44.2.2  1998/03/16 09:55:44  cal
+ * Merged in TimRu-patches. Still needs validation in conjunction with ABC-patches.
+ *
+ * Revision 1.44.2.1  1998/03/07 23:35:03  detabc
+ * added the abc-extension to the linux isdn-kernel
+ * for kernel-version 2.0.xx
+ * DO NOT USE FOR HIGHER KERNELS-VERSIONS
+ * all source-lines are switched with the define  CONFIG_ISDN_WITH_ABC
+ * (make config and answer ABC-Ext. Support (Compress,TCP-Keepalive ...) with yes
+ *
+ * you need also a modified isdnctrl-source the switch on the
+ * features of the abc-extension
+ *
+ * please use carefully. more detail will be follow.
+ * thanks
+ *
  * Revision 1.44  1997/05/27 15:17:23  fritz
  * Added changes for recent 2.1.x kernels:
  *   changed return type of isdn_close
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static char *isdn_revision = "$Revision: 1.44 $";
+static char *isdn_revision = "$Revision: 1.44.2.4 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -329,6 +348,7 @@ isdn_timer_funct(ulong dummy)
 #endif
                }
        }
+
        if (tf) {
                int flags;
 
@@ -1200,6 +1220,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 #define phone iocpar.phone
 #define cfg   iocpar.cfg
 
+
        if (minor == ISDN_MINOR_STATUS) {
                switch (cmd) {
                        case IIOCGETDVR:
index d0df7fe7965ae28d0c1a9d69a359e48abaa4a493..b90d879f7a36785fbb0805a3d763787b0c7404da 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.6.2.1 1998/03/16 09:55:48 cal Exp $
 
  * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
  *
@@ -21,6 +21,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_common.h,v $
+ * Revision 1.6.2.1  1998/03/16 09:55:48  cal
+ * Merged in TimRu-patches. Still needs validation in conjunction with ABC-patches.
+ *
  * Revision 1.6  1997/02/28 02:32:44  fritz
  * Cleanup: Moved some tty related stuff from isdn_common.c
  *          to isdn_tty.c
@@ -76,6 +79,6 @@ extern void isdn_export_syms(void);
 #else
 #define isdn_export_syms()
 #endif
-#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
+#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) || defined(CONFIG_ISDN_TIMEOUT_RULES)
 extern void isdn_dumppkt(char *, u_char *, int, int);
 #endif
index c13dadd485f7ce5a11a9ea5272f7dbd29cade780..fff79adfe57bc40b440e4330f4f02e495da9c5a6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.28 1997/06/17 13:05:57 hipp Exp $
+/* $Id: isdn_ppp.c,v 1.28.2.1 1998/03/16 09:56:02 cal Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.28.2.1  1998/03/16 09:56:02  cal
+ * Merged in TimRu-patches. Still needs validation in conjunction with ABC-patches.
+ *
  * 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)
@@ -173,7 +176,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.28 $";
+char *isdn_ppp_revision = "$Revision: 1.28.2.1 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 static struct isdn_ppp_compressor *ipc_head = NULL;
@@ -901,6 +904,7 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
                                printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
                                isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
                        }
+
                        if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) {
                                if (lp->sav_skb) {
                                        dev_kfree_skb(lp->sav_skb, FREE_WRITE);
@@ -1264,10 +1268,10 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                        return;
        }
 
-       netif_rx(skb);
-       /* net_dev->local.stats.rx_packets++; *//* done in isdn_net.c */
        /* Reset hangup-timer */
        lp->huptimer = 0;
+       netif_rx(skb);
+       /* net_dev->local.stats.rx_packets++; *//* done in isdn_net.c */
 
        return;
 }
@@ -1376,10 +1380,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
         */
 
        /* 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
-     */
+        * 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)
index a629ce27922dde273e08747a81cc294ab68a425a..1058ed172e5e41851a9ded0c77d7efba1edad13f 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.41.2.7 1998/06/07 13:48:08 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.41.2.7  1998/06/07 13:48:08  fritz
+ * ABC cleanup
+ *
+ * Revision 1.41.2.5  1998/04/08 21:42:35  keil
+ * Blocksize default 1024
+ *
+ * Revision 1.41.2.4  1998/03/19 17:58:55  detabc
+ * remove 2 debug-messages (no longer needed) bug was fixed
+ *
+ * Revision 1.41.2.3  1998/03/07 23:35:20  detabc
+ * added the abc-extension to the linux isdn-kernel
+ * for kernel-version 2.0.xx
+ * DO NOT USE FOR HIGHER KERNELS-VERSIONS
+ * all source-lines are switched with the define  CONFIG_ISDN_WITH_ABC
+ * (make config and answer ABC-Ext. Support (Compress,TCP-Keepalive ...) with yes
+ *
+ * you need also a modified isdnctrl-source the switch on the
+ * features of the abc-extension
+ *
+ * please use carefully. more detail will be follow.
+ * thanks
+ *
+ * Revision 1.41.2.2  1998/03/07 23:02:51  tsbogend
+ * fixed kernel unaligned traps on Linux/Alpha
+ *
+ * Revision 1.41.2.1  1997/08/21 15:56:11  fritz
+ * Synchronized 2.0.X branch with 2.0.31-pre7
+ *
  * 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
 
+
 /* Prototypes */
 
 static int isdn_tty_edit_at(const char *, int, modem_info *, int);
@@ -223,7 +252,7 @@ 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.41.2.7 $";
 
 #define DLE 0x10
 #define ETX 0x03
@@ -1270,7 +1299,7 @@ isdn_tty_get_lsr_info(modem_info * info, uint * value)
        status = info->lsr;
        restore_flags(flags);
        result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       put_user(result, (ulong *) value);
+       put_user(result, (uint *) value);
        return 0;
 }
 
@@ -1294,7 +1323,7 @@ isdn_tty_get_modem_info(modem_info * info, uint * value)
            | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
            | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
            | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-       put_user(result, (ulong *) value);
+       put_user(result, (uint *) value);
        return 0;
 }
 
@@ -1443,7 +1472,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);
@@ -1927,7 +1955,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;
                }
@@ -2534,7 +2562,7 @@ 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))
@@ -2643,7 +2671,7 @@ isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
                                return 1;
                        break;
                case 16:
-                       if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
+                       if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
                                return 1;
 #ifdef CONFIG_ISDN_AUDIO
                        if ((m->mdmreg[18] & 1) && (mval > VBUFX))
@@ -3095,7 +3123,7 @@ isdn_tty_parse_at(modem_info * info)
                                break;
                        case 'D':
                                /* D - Dial */
-                               isdn_tty_getdial(++p, ds, sizeof(ds));
+                               isdn_tty_getdial(++p, ds,sizeof(ds));
                                p += strlen(p);
                                if (!strlen(m->msn))
                                        isdn_tty_modem_result(10, info);
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..005706e
--- /dev/null
@@ -0,0 +1,1560 @@
+/* $Id: isdnloop.c,v 1.1 1997/03/24 23:02:04 fritz 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.1  1997/03/24 23:02:04  fritz
+ * Added isdnloop driver.
+ *
+ */
+
+#include "isdnloop.h"
+
+static char
+*revision = "$Revision: 1.1 $";
+
+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, FREE_WRITE);
+       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];
+       struct sk_buff *skb;
+       isdn_ctrl cmd;
+
+       while (card->sndcount[ch]) {
+               if ((skb = skb_dequeue(&card->bqueue[ch]))) {
+                       card->sndcount[ch] -= skb->len;
+                       if (rcard)
+                               rcard->interface.rcvcallb_skb(rcard->myid, rch, skb);
+                       cmd.command = ISDN_STAT_BSENT;
+                       cmd.driver = card->myid;
+                       cmd.arg = ch;
+                       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, FREE_WRITE);
+               } 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        */
+       {"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, "BCON_C", ch);
+                               isdnloop_fake(card->rcard[ch - 1], "BCON_I",
+                                             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;
+                                       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;
+                                       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;
+                                               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, struct sk_buff *skb)
+{
+       isdnloop_card *card = isdnloop_findcard(id);
+
+       if (card) {
+               if (!card->flags & ISDNLOOP_FLAGS_RUNNING)
+                       return -ENODEV;
+               return (isdnloop_sendbuf(channel, skb, card));
+       }
+       printk(KERN_ERR
+              "isdnloop: if_readstatus 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.maxbufsize = 4000;
+       card->interface.command = if_command;
+       card->interface.writebuf_skb = if_sendbuf;
+       card->interface.writecmd = if_writecmd;
+       card->interface.readstat = if_readstatus;
+       card->interface.features = ISDN_FEATURE_L2_X75I |
+           ISDN_FEATURE_L2_HDLC |
+           ISDN_FEATURE_L3_TRANS |
+           ISDN_FEATURE_P_UNKNOWN;
+       card->ptype = ISDN_PTYPE_UNKNOWN;
+       strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+       card->msg_buf_write = card->msg_buf;
+       card->msg_buf_read = card->msg_buf;
+       card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
+       for (i = 0; i < 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 */
+#if (LINUX_VERSION_CODE < 0x020111)
+       register_symtab(NULL);
+#else
+       EXPORT_NO_SYMBOLS;
+#endif
+
+       if ((p = strchr(revision, ':'))) {
+               strcpy(rev, p + 1);
+               p = strchr(rev, '$');
+               *p = 0;
+       } else
+               strcpy(rev, " ??? ");
+       printk(KERN_NOTICE "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, FREE_WRITE);
+               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..3dbd3fb
--- /dev/null
@@ -0,0 +1,142 @@
+/* $Id: isdnloop.h,v 1.1 1997/03/24 23:02:05 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.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
+#if (LINUX_VERSION_CODE > 0x020111)
+MODULE_AUTHOR("Fritz Elfert");
+MODULE_PARM(isdnloop_id, "s");
+MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
+#endif
+#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 889229892ab6ade92a6333536898e01558c1ca50..c17e34b639409dd2eb25c6c679529d5d30aad752 100644 (file)
@@ -192,7 +192,7 @@ XL, 3Com's PCI to 10/100baseT adapters.  It also works with the 10Mbs
 versions of the FastEtherLink cards.  The supported product IDs are
   3c590, 3c592, 3c595, 3c597, 3c900, 3c905
 
-The ISA 3c515 is supported with a seperate driver, 3c515.c, included with
+The ISA 3c515 is supported with a separate driver, 3c515.c, included with
 the kernel source or available from
     cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
 
@@ -210,7 +210,7 @@ The 3c59x series use an interface that's very similar to the previous 3c5x9
 series.  The primary interface is two programmed-I/O FIFOs, with an
 alternate single-contiguous-region bus-master transfer (see next).
 
-The 3c900 "Boomerang" series uses a full-bus-master interface with seperate
+The 3c900 "Boomerang" series uses a full-bus-master interface with separate
 lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
 DEC Tulip and Intel Speedo3.  The first chip version retains a compatible
 programmed-I/O interface that will be removed in the 'B' and subsequent
@@ -1340,7 +1340,7 @@ static void vortex_tx_timeout(struct device *dev)
 }
 
 /*
- * Handle uncommon interrupt sources.  This is a seperate routine to minimize
+ * Handle uncommon interrupt sources.  This is a separate routine to minimize
  * the cache impact.
  */
 static void
index e2ee768b40d36f414582d8200652c801a9d735a9..4f317160d50324068a858d9ee611a8f6c5924de8 100644 (file)
@@ -147,3 +147,6 @@ if [ "$CONFIG_ARCNET" != "n" ]; then
   bool '  Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
 fi
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
+fi
index a52ee71e434cf33215dbf63be2beb8f8560f8acf..986ec3120aef4459b248f4d40f3445f0402c8e6e 100644 (file)
@@ -53,6 +53,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SHAPER),y)
+L_OBJS += shaper.o
+else
+  ifeq ($(CONFIG_SHAPER),m)
+  M_OBJS += shaper.o
+  endif
+endif
+
 ifeq ($(CONFIG_SK_G16),y)
 L_OBJS += sk_g16.o
 endif
index bb30e041a24b40dc1cd5169a899a245ac723cacb..8fd6b87088e354ac1ae688abbdba36788ed42559 100644 (file)
@@ -7,6 +7,11 @@
  * Changed to support io= irq= by Alan Cox <Alan.Cox@linux.org>
  * Reworked 1995 by John Sullivan <js10039@cam.ac.uk>
  * More fixes by Philip Blundell <pjb27@cam.ac.uk>
+ * Added the Compaq LTE  Alan Cox <alan@redhat.com>
+ *
+ * Note - this driver is experimental still - it has problems on faster
+ * machines. Someone needs to sit down and go through it line by line with
+ * a databook...
  */
 
 /*
@@ -86,7 +91,8 @@
 
 static char version[] = 
 "eexpress.c: v0.10 04-May-95 John Sullivan <js10039@cam.ac.uk>\n"
-"            v0.14 19-May-96 Philip Blundell <phil@tazenda.demon.co.uk>\n";
+"            v0.14 19-May-96 Philip Blundell <phil@tazenda.demon.co.uk>\n"
+"            v0.15 04-Aug-98 Alan Cox <alan@redhat.com>\n";
 
 #include <linux/module.h>
 
@@ -701,11 +707,13 @@ static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)
        hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);
        hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);
 
-       if (hw_addr[2]!=0x00aa || ((hw_addr[1] & 0xff00)!=0x0000)) 
+       /* Standard Address or Compaq LTE Address */
+       if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
+             (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00)))) 
        {
                printk("rejected: invalid address %04x%04x%04x\n",
                        hw_addr[2],hw_addr[1],hw_addr[0]);
-               return ENODEV;
+               return -ENODEV;
        }
 
        dev->base_addr = ioaddr;
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
new file mode 100644 (file)
index 0000000..2b20856
--- /dev/null
@@ -0,0 +1,661 @@
+/*
+ *                     Simple traffic shaper for Linux NET3.
+ *
+ *     (c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
+ *                             http://www.cymru.net
+ *
+ *     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.
+ *     
+ *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
+ *     warranty for any of this software. This material is provided 
+ *     "AS-IS" and at no charge.       
+ *
+ *     
+ *     Algorithm:
+ *
+ *     Queue Frame:
+ *             Compute time length of frame at regulated speed
+ *             Add frame to queue at appropriate point
+ *             Adjust time length computation for followup frames
+ *             Any frame that falls outside of its boundaries is freed
+ *
+ *     We work to the following constants
+ *
+ *             SHAPER_QLEN     Maximum queued frames
+ *             SHAPER_LATENCY  Bounding latency on a frame. Leaving this latency
+ *                             window drops the frame. This stops us queueing 
+ *                             frames for a long time and confusing a remote
+ *                             host.
+ *             SHAPER_MAXSLIP  Maximum time a priority frame may jump forward.
+ *                             That bounds the penalty we will inflict on low
+ *                             priority traffic.
+ *             SHAPER_BURST    Time range we call "now" in order to reduce
+ *                             system load. The more we make this the burstier
+ *                             the behaviour, the better local performance you
+ *                             get through packet clustering on routers and the
+ *                             worse the remote end gets to judge rtts.
+ *
+ *     This is designed to handle lower speed links ( < 200K/second or so). We
+ *     run off a 100-150Hz base clock typically. This gives us a resolution at
+ *     200Kbit/second of about 2Kbit or 256 bytes. Above that our timer
+ *     resolution may start to cause much more burstiness in the traffic. We
+ *     could avoid a lot of that by calling kick_shaper() at the end of the 
+ *     tied device transmissions. If you run above about 100K second you 
+ *     may need to tune the supposed speed rate for the right values.
+ *
+ *     BUGS:
+ *             Downing the interface under the shaper before the shaper
+ *             will render your machine defunct. Don't for now shape over
+ *             PPP or SLIP therefore!
+ *             This will be fixed in BETA4
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_shaper.h>
+
+int sh_debug;          /* Debug flag */
+
+#define SHAPER_BANNER  "Traffic Shaper 0.05 for Linux 2.0 <alan@redhat.com>\n"
+
+/*
+ *     Locking
+ */
+static int shaper_lock(struct shaper *sh)
+{
+       unsigned long flags;
+       save_flags(flags);
+       cli();
+       /*
+        *      Lock in an interrupt may fail
+        */
+       if(sh->locked && intr_count)
+       {
+               restore_flags(flags);
+               return 0;
+       }
+       while(sh->locked)
+               sleep_on(&sh->wait_queue);
+       sh->locked=1;
+       restore_flags(flags);
+       return 1;
+}
+
+static void shaper_kick(struct shaper *sh);
+
+static void shaper_unlock(struct shaper *sh)
+{
+       sh->locked=0;
+       wake_up(&sh->wait_queue);
+       shaper_kick(sh);
+}
+
+/*
+ *     Compute clocks on a buffer
+ */
+  
+static int shaper_clocks(struct shaper *shaper, struct sk_buff *skb)
+{
+       int t=skb->len/shaper->bytespertick;
+       return t;
+}
+
+/*
+ *     Set the speed of a shaper. We compute this in bytes per tick since
+ *     thats how the machine wants to run. Quoted input is in bits per second
+ *     as is traditional (note not BAUD). We assume 8 bit bytes. 
+ */
+  
+static void shaper_setspeed(struct shaper *shaper, int bitspersec)
+{
+       shaper->bitspersdc=bitspersec;
+       shaper->bytespertick=(bitspersec/HZ)/8;
+       if(!shaper->bytespertick)
+               shaper->bytespertick++;
+}
+
+/*
+ *     Throw a frame at a shaper.
+ */
+  
+static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
+{
+       struct sk_buff *ptr;
+       
+       /*
+        *      Get ready to work on this shaper. Lock may fail if its
+        *      an interrupt and locked.
+        */
+        
+       if(!shaper_lock(shaper))
+               return -1;
+       ptr=shaper->sendq.prev;
+       
+       /*
+        *      Set up our packet details
+        */
+        
+       skb->shapelatency=0;
+       skb->shapeclock=shaper->recovery;
+       if(skb->shapeclock<jiffies)
+               skb->shapeclock=jiffies;
+       skb->shapestamp=jiffies;
+       
+       /*
+        *      Time slots for this packet.
+        */
+        
+       skb->shapelen= shaper_clocks(shaper,skb);
+       
+#ifdef SHAPER_COMPLEX /* and broken.. */
+
+       while(ptr && ptr!=(struct sk_buff *)&shaper->sendq)
+       {
+               if(ptr->pri<skb->pri 
+                       && jiffies - ptr->shapeclock < SHAPER_MAXSLIP)
+               {
+                       struct sk_buff *tmp=ptr->prev;
+
+                       /*
+                        *      It goes before us therefore we slip the length
+                        *      of the new frame.
+                        */
+
+                       ptr->shapeclock+=skb->shapelen;
+                       ptr->shapelatency+=skb->shapelen;
+
+                       /*
+                        *      The packet may have slipped so far back it
+                        *      fell off.
+                        */
+                       if(ptr->shapelatency > SHAPER_LATENCY)
+                       {
+                               skb_unlink(ptr);
+                               dev_kfree_skb(ptr, FREE_WRITE);
+                       }
+                       ptr=tmp;
+               }
+               else
+                       break;
+       }
+       if(ptr==NULL || ptr==(struct sk_buff *)&shaper->sendq)
+               skb_queue_head(&shaper->sendq,skb);
+       else
+       {
+               struct sk_buff *tmp;
+               /*
+                *      Set the packet clock out time according to the
+                *      frames ahead. Im sure a bit of thought could drop
+                *      this loop.
+                */
+               for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && tmp!=ptr; tmp=tmp->next)
+                       skb->shapeclock+=tmp->shapelen;
+               skb_append(ptr,skb);
+       }
+#else
+       {
+               struct sk_buff *tmp;
+               /*
+                *      Up our shape clock by the time pending on the queue
+                *      (Should keep this in the shaper as a variable..)
+                */
+               for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && 
+                       tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next)
+                       skb->shapeclock+=tmp->shapelen;
+               /*
+                *      Queue over time. Spill packet.
+                */
+               if(skb->shapeclock-jiffies > SHAPER_LATENCY)
+                       dev_kfree_skb(skb, FREE_WRITE);
+               else
+                       skb_queue_tail(&shaper->sendq, skb);
+       }
+#endif         
+       if(sh_debug)
+               printk("Frame queued.\n");
+       if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN)
+       {
+               ptr=skb_dequeue(&shaper->sendq);
+               dev_kfree_skb(ptr, FREE_WRITE);
+       }
+       shaper_unlock(shaper);
+       shaper_kick(shaper);
+       return 0;
+}
+
+/*
+ *     Transmit from a shaper
+ */
+static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
+{
+       struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
+       if(sh_debug)
+               printk("Kick frame on %p\n",newskb);
+       if(newskb)
+       {
+               newskb->dev=shaper->dev;
+               newskb->arp=1;
+               if(sh_debug)
+                       printk("Kick new frame to %s\n",
+                               shaper->dev->name);
+               dev_queue_xmit(newskb,shaper->dev,2);
+               if(sh_debug)
+                       printk("Kicked new frame out.\n");
+               dev_kfree_skb(skb, FREE_WRITE);
+       }
+}
+
+/*
+ *     Timer handler for shaping clock
+ */
+static void shaper_timer(unsigned long data)
+{
+       struct shaper *sh=(struct shaper *)data;
+       shaper_kick(sh);
+}
+
+/*
+ *     Kick a shaper queue and try and do something sensible with the 
+ *     queue. 
+ */
+
+static void shaper_kick(struct shaper *shaper)
+{
+       struct sk_buff *skb;
+       unsigned long flags;
+       
+       save_flags(flags);
+       cli();
+
+       del_timer(&shaper->timer);
+
+       /*
+        *      Shaper unlock will kick
+        */
+        
+       if(shaper->locked)
+       {       
+               if(sh_debug)
+                       printk("Shaper locked.\n");
+               shaper->timer.expires=jiffies+1;
+               add_timer(&shaper->timer);
+               restore_flags(flags);
+               return;
+       }
+
+               
+       /*
+        *      Walk the list (may be empty)
+        */
+        
+       while((skb=skb_peek(&shaper->sendq))!=NULL)
+       {
+               /*
+                *      Each packet due to go out by now (within an error
+                *      of SHAPER_BURST) gets kicked onto the link 
+                */
+                
+               if(sh_debug)
+                       printk("Clock = %d, jiffies = %ld\n", skb->shapeclock, jiffies);
+               if(skb->shapeclock <= jiffies + SHAPER_BURST)
+               {
+                       /*
+                        *      Pull the frame and get interrupts back on.
+                        */
+                        
+                       skb_unlink(skb);
+                       if (shaper->recovery < skb->shapeclock + skb->shapelen)
+                               shaper->recovery = skb->shapeclock + skb->shapelen;
+                       restore_flags(flags);
+
+                       /*
+                        *      Pass on to the physical target device via
+                        *      our low level packet thrower.
+                        */
+                       
+                       skb->shapepend=0;
+                       shaper_queue_xmit(shaper, skb); /* Fire */
+                       cli();
+               }
+               else
+                       break;
+       }
+
+       /*
+        *      Next kick.
+        */
+        
+       if(skb!=NULL)
+       {
+               del_timer(&shaper->timer);
+               shaper->timer.expires=skb->shapeclock;
+               add_timer(&shaper->timer);
+       }
+               
+       /*
+        *      Interrupts on, mission complete
+        */
+               
+       restore_flags(flags);
+}
+
+
+/*
+ *     Flush the shaper queues on a closedown
+ */
+static void shaper_flush(struct shaper *shaper)
+{
+       struct sk_buff *skb;
+       while((skb=skb_dequeue(&shaper->sendq))!=NULL)
+               dev_kfree_skb(skb, FREE_WRITE);
+}
+
+/*
+ *     Bring the interface up. We just disallow this until a 
+ *     bind.
+ */
+
+static int shaper_open(struct device *dev)
+{
+       struct shaper *shaper=dev->priv;
+       
+       /*
+        *      Can't open until attached.
+        */
+        
+       if(shaper->dev==NULL)
+               return -ENODEV;
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+/*
+ *     Closing a shaper flushes the queues.
+ */
+static int shaper_close(struct device *dev)
+{
+       struct shaper *shaper=dev->priv;
+       shaper_flush(shaper);
+       del_timer(&shaper->timer);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+/*
+ *     Revectored calls. We alter the parameters and call the functions
+ *     for our attached device. This enables us to bandwidth allocate after
+ *     ARP and other resolutions and not before.
+ */
+
+
+static int shaper_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+       struct shaper *sh=dev->priv;
+       return shaper_qframe(sh, skb);
+}
+
+static struct enet_statistics *shaper_get_stats(struct device *dev)
+{
+       return NULL;
+}
+
+static int shaper_header(struct sk_buff *skb, struct device *dev, 
+       unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+       struct shaper *sh=dev->priv;
+       if(sh_debug)
+               printk("Shaper header\n");
+       return sh->hard_header(skb,sh->dev,type,daddr,saddr,len);
+}
+
+static int shaper_rebuild_header(void *eth, struct device *dev, unsigned long raddr, struct sk_buff *skb)
+{
+       struct shaper *sh=dev->priv;
+       if(sh_debug)
+               printk("Shaper rebuild header\n");
+       return sh->rebuild_header(eth,sh->dev,raddr,skb);
+}
+
+static int shaper_attach(struct device *shdev, struct shaper *sh, struct device *dev)
+{
+       sh->dev = dev;
+       sh->hard_start_xmit=dev->hard_start_xmit;
+       sh->get_stats=dev->get_stats;
+       if(dev->hard_header)
+       {
+               sh->hard_header=dev->hard_header;
+               shdev->hard_header = shaper_header;
+       }
+       else
+               shdev->hard_header = NULL;
+               
+       if(dev->rebuild_header)
+       {
+               sh->rebuild_header      = dev->rebuild_header;
+               shdev->rebuild_header   = shaper_rebuild_header;
+       }
+       else
+               shdev->rebuild_header   = NULL;
+       
+       shdev->hard_header_len=dev->hard_header_len;
+       shdev->type=dev->type;
+       shdev->addr_len=dev->addr_len;
+       shdev->mtu=dev->mtu;
+       return 0;
+}
+
+static int shaper_ioctl(struct device *dev,  struct ifreq *ifr, int cmd)
+{
+       struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_data;
+       struct shaper *sh=dev->priv;
+       switch(ss->ss_cmd)
+       {
+               case SHAPER_SET_DEV:
+               {
+                       struct device *them=dev_get(ss->ss_name);
+                       if(them==NULL)
+                               return -ENODEV;
+                       if(sh->dev)
+                               return -EBUSY;
+                       return shaper_attach(dev,dev->priv, them);
+               }
+               case SHAPER_GET_DEV:
+                       if(sh->dev==NULL)
+                               return -ENODEV;
+                       memcpy(ss->ss_name, sh->dev->name, sizeof(ss->ss_name));
+                       return 0;
+               case SHAPER_SET_SPEED:
+                       shaper_setspeed(sh,ss->ss_speed);
+                       return 0;
+               case SHAPER_GET_SPEED:
+                       ss->ss_speed=sh->bitspersec;
+                       return 0;
+               default:
+                       return -EINVAL;
+       }
+}
+
+static struct shaper *shaper_alloc(struct device *dev)
+{
+       struct shaper *sh=kmalloc(sizeof(struct shaper), GFP_KERNEL);
+       if(sh==NULL)
+               return NULL;
+       memset(sh,0,sizeof(*sh));
+       skb_queue_head_init(&sh->sendq);
+       init_timer(&sh->timer);
+       sh->timer.function=shaper_timer;
+       sh->timer.data=(unsigned long)sh;
+       return sh;
+}
+
+/*
+ *     Add a shaper device to the system
+ */
+int shaper_probe(struct device *dev)
+{
+       int i;
+       
+       /*
+        *      Set up the shaper.
+        */
+       
+       dev->priv = shaper_alloc(dev);
+       if(dev->priv==NULL)
+               return -ENOMEM;
+               
+       dev->open               = shaper_open;
+       dev->stop               = shaper_close;
+       dev->hard_start_xmit    = shaper_start_xmit;
+       dev->get_stats          = shaper_get_stats;
+       dev->set_multicast_list = NULL;
+       
+       /*
+        *      Intialise the packet queues
+        */
+        
+       for(i=0;i<DEV_NUMBUFFS;i++)
+               skb_queue_head_init(&dev->buffs[i]);
+       
+       /*
+        *      Handlers for when we attach to a device.
+        */
+
+       dev->hard_header        = shaper_header;
+       dev->rebuild_header     = shaper_rebuild_header;
+       dev->do_ioctl           = shaper_ioctl;
+       dev->hard_header_len    = 0;
+       dev->type               = ARPHRD_ETHER; /* initially */
+       dev->set_mac_address    = NULL;
+       dev->mtu                = 1500;
+       dev->addr_len           = 0;
+       dev->tx_queue_len       = 10;
+       dev->flags              = 0;
+       dev->family             = AF_INET;
+       dev->pa_addr            = 0;
+       dev->pa_brdaddr         = 0;
+       dev->pa_mask            = 0;
+       dev->pa_alen            = 4;
+               
+       /*
+        *      Shaper is ok
+        */     
+        
+       return 0;
+}
+#ifdef MODULE
+
+static char devicename[9];
+
+static struct device dev_shape = 
+{
+       devicename,
+       0, 0, 0, 0,
+       0, 0,
+       0, 0, 0, NULL, shaper_probe 
+};
+
+int init_module(void)
+{
+       int i;
+       for(i=0;i<99;i++)
+       {
+               sprintf(devicename,"shaper%d",i);
+               if(dev_get(devicename)==NULL)
+                       break;
+       }
+       if(i==100)
+               return -ENFILE;
+       
+       printk(SHAPER_BANNER);  
+       if (register_netdev(&dev_shape) != 0)
+               return -EIO;
+       printk("Traffic shaper initialised.\n");
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       /*
+        *      No need to check MOD_IN_USE, as sys_delete_module() checks.
+        *      To be unloadable we must be closed and detached so we don't
+        *      need to flush things.
+        */
+        
+       unregister_netdev(&dev_shape);
+
+       /*
+        *      Free up the private structure, or leak memory :-) 
+        */
+        
+       kfree(dev_shape.priv);
+       dev_shape.priv = NULL;
+}
+
+#else
+
+static struct device dev_sh0 = 
+{
+       "shaper0",
+       0, 0, 0, 0,
+       0, 0,
+       0, 0, 0, NULL, shaper_probe 
+};
+
+
+static struct device dev_sh1 = 
+{
+       "shaper1",
+       0, 0, 0, 0,
+       0, 0,
+       0, 0, 0, NULL, shaper_probe 
+};
+
+
+static struct device dev_sh2 = 
+{
+       "shaper2",
+       0, 0, 0, 0,
+       0, 0,
+       0, 0, 0, NULL, shaper_probe 
+};
+
+static struct device dev_sh3 = 
+{
+       "shaper3",
+       0, 0, 0, 0,
+       0, 0,
+       0, 0, 0, NULL, shaper_probe 
+};
+
+void shaper_init(void)
+{
+       register_netdev(&dev_sh0);
+       register_netdev(&dev_sh1);
+       register_netdev(&dev_sh2);
+       register_netdev(&dev_sh3);
+}
+
+#endif /* MODULE */
index 09f301cef6a551c3cb53115dc14d38cca912fd37..8d7ba08311cb781b3c7645f7fb5b4a5cb432082a 100644 (file)
@@ -1,6 +1,25 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ *        + Added command line option (rs:[y|n]) to reverse the scan order
+ *          of PCI boards. The default is rs:y, which reverses the BIOS order
+ *          while registering PCI boards. The default value rs:y generates
+ *          the same order of all previous revisions of this driver.
+ *          Pls. note that "BIOS order" might have been reversed itself
+ *          after the 2.1.9x PCI modifications in the linux kernel.
+ *          The rs value is ignored when the explicit list of addresses
+ *          is used by the "eata=port0,port1,..." command line option.
+ *        + Added command line option (et:[y|n]) to force use of extended
+ *          translation (255 heads, 63 sectors) as disk geometry.
+ *          The default is et:n, which uses the disk geometry returned
+ *          by scsicam_bios_param. The default value et:n is compatible with
+ *          all previous revisions of this driver.
+ *
+ *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
+ *          Increased busy timeout from 10 msec. to 200 msec. while
+ *          processing interrupts.
+ *
  *      16 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
  *          Improved abort handling during the eh recovery process.
  *
@@ -9,7 +28,7 @@
  *          abort and reset routines.
  *          Added command line options (eh:[y|n]) to choose between
  *          new_eh_code and the old scsi code.
- *          If linux verion >= 2.1.101 the default is eh:y, while the eh
+ *          If linux version >= 2.1.101 the default is eh:y, while the eh
  *          option is ignored for previous releases and the old scsi code
  *          is used.
  *
  *  PM3222     -  SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI)
  *  PM3224     -  SmartRAID Adapter for PCI  (PM3224W is 16-bit wide SCSI)
  *
+ *  The above list is just an indication: as a matter of fact all DPT
+ *  boards using the EATA/DMA protocol are supported by this driver,
+ *  since they use exactely the same programming interface.
+ *
  *  The DPT PM2001 provides only the EATA/PIO interface and hence is not
  *  supported by this driver.
  *
  *
  *  eh:y  use new scsi code (linux 2.2 only);
  *  eh:n  use old scsi code;
+ *  et:y  force use of extended translation (255 heads, 63 sectors);
+ *  et:n  use disk geometry detected by scsicam_bios_param;
+ *  rs:y  reverse scan order while detecting PCI boards;
+ *  rs:n  use BIOS order while detecting PCI boards;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  tc:y  enables tagged commands;
  *  tm:3  use only ordered queue tags;
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 32).
  *
- *  The default value is: "eata=lc:n,tc:n,mq:16,tm:0". An example using
- *  the list of detection probes could be:
- *  "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n".
+ *  The default value is: "eata=lc:n,tc:n,mq:16,tm:0,et:n,rs:n".
+ *  An example using the list of detection probes could be:
+ *  "eata=0x7410,0x230,lc:y,tc:n,mq:4,eh:n,et:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \
- *                max_queue_depth=4 tag_mode=0 use_new_eh_code=0
+ *                max_queue_depth=4 tag_mode=0 use_new_eh_code=0 \
+ *                ext_tran=0 rev_scan=1
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
  *        When the driver detects a batch including overlapping requests
  *        (a really rare event) strict serial (pid) order is enforced.
  *  ----------------------------------------------------------------------------
+ *  The extended translation option (et:y) is useful when using large physical
+ *  disks/arrays. It could also be useful when switching between Adaptec boards
+ *  and DPT boards without reformatting the disk.
+ *  When a boot disk is partitioned with extended translation, in order to
+ *  be able to boot it with a DPT board is could be necessary to add to
+ *  lilo.conf additional commands as in the following example:
+ *
+ *  fix-table
+ *  disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546
+ *
+ *  where the above geometry should be replaced with the one reported at
+ *  power up by the DPT controller.
+ *  ----------------------------------------------------------------------------
  *
  *  The boards are named EATA0, EATA1,... according to the detection order.
  *
@@ -326,6 +367,8 @@ MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(tag_mode, "i");
 MODULE_PARM(use_new_eh_code, "i");
+MODULE_PARM(ext_tran, "i");
+MODULE_PARM(rev_scan, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
 
@@ -409,6 +452,7 @@ struct proc_dir_entry proc_scsi_eata2x = {
 #undef  DEBUG_RESET
 #undef  DEBUG_GENERATE_ERRORS
 #undef  DEBUG_GENERATE_ABORTS
+#undef  DEBUG_GEOMETRY
 
 #define MAX_ISA 4
 #define MAX_VESA 0
@@ -659,6 +703,8 @@ static int do_trace = FALSE;
 static int setup_done = FALSE;
 static int link_statistics = 0;
 static int tag_mode = TAG_MIXED;
+static int ext_tran = FALSE;
+static int rev_scan = TRUE;
 
 #if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
 static int tagged_comm = TRUE;
@@ -1063,9 +1109,9 @@ __initfunc (static inline int port_detect \
 
    if (j == 0) {
       printk("EATA/DMA 2.0x: Copyright (C) 1994-1998 Dario Ballabio.\n");
-      printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c.\n",
-             driver_name, tag_type, YESNO(linked_comm),
-             max_queue_depth, YESNO(use_new_eh_code));
+      printk("%s config options -> tc:%c, lc:%c, mq:%d, eh:%c, rs:%c, et:%c.\n",
+             driver_name, tag_type, YESNO(linked_comm), max_queue_depth,
+             YESNO(use_new_eh_code), YESNO(rev_scan), YESNO(ext_tran));
       }
 
    printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
@@ -1128,6 +1174,8 @@ __initfunc (void eata2x_setup(char *str, int *ints)) {
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
       else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
+      else if (!strncmp(cur, "et:", 3))  ext_tran = val;
+      else if (!strncmp(cur, "rs:", 3))  rev_scan = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1161,8 +1209,8 @@ __initfunc (static void add_pci_ports(void)) {
       if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
              continue;
 
-      /* Reverse the returned address order */
-      io_port[MAX_INT_PARAM + MAX_PCI - k] =
+      /* Order addresses according to rev_scan value */
+      io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
              (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
       }
 
@@ -1189,8 +1237,8 @@ __initfunc (static void add_pci_ports(void)) {
       if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
              continue;
 
-      /* Reverse the returned address order */
-      io_port[MAX_INT_PARAM + MAX_PCI - k] =
+      /* Order addresses according to rev_scan value */
+      io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
              (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
       }
 
@@ -1842,6 +1890,23 @@ int eata2x_reset(Scsi_Cmnd *SCarg) {
 
 #endif /* new_eh_code */
 
+int eata2x_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
+   int size = disk->capacity;
+
+   if (ext_tran || (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+      dkinfo[0] = 255;
+      dkinfo[1] = 63;
+      dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+      }
+
+#if defined (DEBUG_GEOMETRY)
+   printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name,
+           dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
+   return FALSE;
+}
+
 static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
                  unsigned int rev) {
    unsigned int i, j, k, y;
@@ -2020,7 +2085,7 @@ static inline void ihdlr(int irq, unsigned int j) {
                         HD(j)->iocount);
 
    /* Check if this board is still busy */
-   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+   if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP)) {
       reg = inb(sh[j]->io_port + REG_STATUS);
       printk("%s: ihdlr, busy timeout error,  irq %d, reg 0x%x, count %d.\n",
              BN(j), irq, reg, HD(j)->iocount);
index e495b2d14343895f9a48a2c671bfd574e9b73ed5..f1641f42d469269b0143b74f07ac26f13f1de1b8 100644 (file)
@@ -14,8 +14,9 @@ int eata2x_abort(Scsi_Cmnd *);
 int eata2x_old_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *);
 int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
+int eata2x_biosparam(Disk *, kdev_t, int *);
 
-#define EATA_VERSION "4.31.00"
+#define EATA_VERSION "4.33.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
@@ -32,7 +33,7 @@ int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
                 eh_device_reset_handler: NULL,                               \
                 eh_bus_reset_handler:    NULL,                               \
                 eh_host_reset_handler:   eata2x_reset,                       \
-                bios_param:              scsicam_bios_param,                 \
+                bios_param:              eata2x_biosparam,                   \
                 this_id:                 7,                                  \
                 unchecked_isa_dma:       1,                                  \
                 use_clustering:          ENABLE_CLUSTERING,                  \
@@ -48,7 +49,7 @@ int eata2x_old_reset(Scsi_Cmnd *, unsigned int);
                 queuecommand:            eata2x_queuecommand,                \
                 abort:                   eata2x_old_abort,                   \
                 reset:                   eata2x_old_reset,                   \
-                bios_param:              scsicam_bios_param,                 \
+                bios_param:              eata2x_biosparam,                   \
                 this_id:                 7,                                  \
                 unchecked_isa_dma:       1,                                  \
                 use_clustering:          ENABLE_CLUSTERING                   \
index e503dd8498ecc59e8e803b97d84908a1a5ebca2a..b8722ebaa5a71b93b980f336713b0e9742ebcdb1 100644 (file)
@@ -284,6 +284,7 @@ static struct dev_info device_list[] =
 {"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"REGAL","CDC-4X","*", BLIST_MAX5LUN | BLIST_SINGLELUN},
 {"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
+{"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -687,6 +688,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
   case TYPE_MOD:
   case TYPE_PROCESSOR:
   case TYPE_SCANNER:
+  case TYPE_MEDIUM_CHANGER:
     SDpnt->writeable = 1;
     break;
   case TYPE_WORM:
index 5dd63f0d3ecae86975ac668188514ab46c6a91fa..cad88bc29a731623e6f325ca1f77c4b4fc3323e6 100644 (file)
@@ -1,6 +1,18 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ *          Added command line option (et:[y|n]) to use the existing
+ *          translation (returned by scsicam_bios_param) as disk geometry.
+ *          The default is et:n, which uses the disk geometry jumpered
+ *          on the board.
+ *          The default value et:n is compatible with all previous revisions
+ *          of this driver.
+ *
+ *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
+ *          Increased busy timeout from 10 msec. to 200 msec. while
+ *          processing interrupts.
+ *
  *      18 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
  *          Improved abort handling during the eh recovery process.
  *
@@ -9,7 +21,7 @@
  *          abort and reset routines.
  *          Added command line options (eh:[y|n]) to choose between
  *          new_eh_code and the old scsi code.
- *          If linux verion >= 2.1.101 the default is eh:y, while the eh
+ *          If linux version >= 2.1.101 the default is eh:y, while the eh
  *          option is ignored for previous releases and the old scsi code
  *          is used.
  *
  *
  *  eh:y  use new scsi code (linux 2.2 only);
  *  eh:n  use old scsi code;
+ *  et:y  use disk geometry returned by scsicam_bios_param;
+ *  et:n  use disk geometry jumpered on the board;
  *  lc:y  enables linked commands;
  *  lc:n  disables linked commands;
  *  of:y  enables old firmware support;
  *  of:n  disables old firmware support;
  *  mq:xx set the max queue depth to the value xx (2 <= xx <= 8).
  *
- *  The default value is: "u14-34f=lc:n,of:n,mq:8". An example using the list
- *  of detection probes could be: "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n".
+ *  The default value is: "u14-34f=lc:n,of:n,mq:8,et:n".
+ *  An example using the list of detection probes could be:
+ *  "u14-34f=0x230,0x340,lc:y,of:n,mq:4,eh:n,et:n".
  *
  *  When loading as a module, parameters can be specified as well.
  *  The above example would be (use 1 in place of y and 0 in place of n):
  *
  *  modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
- *                max_queue_depth=4 use_new_eh_code=0
+ *                max_queue_depth=4 use_new_eh_code=0 ext_tran=0
  *
  *  ----------------------------------------------------------------------------
  *  In this implementation, linked commands are designed to work with any DISK
@@ -310,6 +325,7 @@ MODULE_PARM(have_old_firmware, "i");
 MODULE_PARM(link_statistics, "i");
 MODULE_PARM(max_queue_depth, "i");
 MODULE_PARM(use_new_eh_code, "i");
+MODULE_PARM(ext_tran, "i");
 MODULE_AUTHOR("Dario Ballabio");
 #endif
 
@@ -401,6 +417,7 @@ struct proc_dir_entry proc_scsi_u14_34f = {
 #undef  DEBUG_RESET
 #undef  DEBUG_GENERATE_ERRORS
 #undef  DEBUG_GENERATE_ABORTS
+#undef  DEBUG_GEOMETRY
 
 #define MAX_ISA 3
 #define MAX_VESA 1
@@ -552,6 +569,7 @@ static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);
 static int do_trace = FALSE;
 static int setup_done = FALSE;
 static int link_statistics = 0;
+static int ext_tran = FALSE;
 
 #if defined(HAVE_OLD_UX4F_FIRMWARE)
 static int have_old_firmware = TRUE;
@@ -872,9 +890,9 @@ __initfunc (static inline int port_detect \
 
    if (j == 0) {
       printk("UltraStor 14F/34F: Copyright (C) 1994-1998 Dario Ballabio.\n");
-      printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c.\n",
+      printk("%s config options -> of:%c, lc:%c, mq:%d, eh:%c, et:%c.\n",
              driver_name, YESNO(have_old_firmware), YESNO(linked_comm),
-             max_queue_depth, YESNO(use_new_eh_code));
+             max_queue_depth, YESNO(use_new_eh_code), YESNO(ext_tran));
       }
 
    printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
@@ -918,6 +936,7 @@ __initfunc (void u14_34f_setup(char *str, int *ints)) {
       else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
       else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
       else if (!strncmp(cur, "eh:", 3))  use_new_eh_code = val;
+      else if (!strncmp(cur, "et:", 3))  ext_tran = val;
 
       if ((cur = strchr(cur, ','))) ++cur;
       }
@@ -1551,6 +1570,18 @@ int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
    dkinfo[0] = HD(j)->heads;
    dkinfo[1] = HD(j)->sectors;
    dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
+
+   if (ext_tran && (scsicam_bios_param(disk, dev, dkinfo) < 0)) {
+      dkinfo[0] = 255;
+      dkinfo[1] = 63;
+      dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+      }
+
+#if defined (DEBUG_GEOMETRY)
+   printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name,
+           dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
    return FALSE;
 }
 
@@ -1733,7 +1764,7 @@ static inline void ihdlr(int irq, unsigned int j) {
                         HD(j)->iocount);
 
    /* Check if this board is still busy */
-   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+   if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP)) {
       outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
       printk("%s: ihdlr, busy timeout error,  irq %d, reg 0x%x, count %d.\n",
              BN(j), irq, reg, HD(j)->iocount);
index 47029641948823612e9137f6dad1dc9dc6c25f3c..943b8cbb3cc89aa6b9892e4b68eca28480136b65 100644 (file)
@@ -4,6 +4,7 @@
 #ifndef _U14_34F_H
 #define _U14_34F_H
 
+#include <scsi/scsicam.h>
 #include <linux/version.h>
 
 int u14_34f_detect(Scsi_Host_Template *);
@@ -15,7 +16,7 @@ int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_old_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "4.31.00"
+#define U14_34F_VERSION "4.33.00"
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
index 828a6f96ff39ac7c9167a64087a6d1eed3e6ad14..24d3d32336d5711e58d62090124b9c781fed069e 100644 (file)
@@ -1201,6 +1201,8 @@ probe_sbmpu (struct address_info *hw_config)
        }
       hw_config->name = "Sound Blaster 16";
       hw_config->irq = -devc->irq;
+      hw_config->dma = -1;
+      hw_config->dma2 = -1;
       sb16_set_mpu_port(devc, hw_config);
       break;
 
index 6e42e5431a3190a17eec9c30e423574ed996b7e7..9f6a3ae6cd71f94c8da98e8e8bf73a61441b4566 100644 (file)
@@ -1149,8 +1149,10 @@ sequencer_open (int dev, struct fileinfo *file)
       }
 
   if (!max_synthdev && !max_mididev)
+  {
+    sequencer_busy = 0;
     return -(ENXIO);
-
+  }
   synth_open_mask = 0;
 
   for (i = 0; i < max_mididev; i++)
index d7e2fc621c8b561d4d611c1d47cca2f628d678d3..c097011bb00f39e995c3a5fa500c16a0aff96d3a 100644 (file)
@@ -587,7 +587,7 @@ int isofs_bmap(struct inode * inode,int block)
        int i;
 
        if (block<0) {
-               printk("_isofs_bmap: block<0");
+               printk("_isofs_bmap: block<0\n");
                return 0;
        }
 
@@ -597,7 +597,8 @@ int isofs_bmap(struct inode * inode,int block)
         * If we are beyond the end of this file, don't give out any
         * blocks.
         */
-       if( b_off > inode->i_size )
+       if( (b_off > inode->i_size) || 
+               ((b_off ==  inode->i_size) && (b_off & (PAGE_SIZE - 1))) )
          {
            off_t       max_legal_read_offset;
 
@@ -614,7 +615,7 @@ int isofs_bmap(struct inode * inode,int block)
            if( b_off >= max_legal_read_offset )
              {
 
-               printk("_isofs_bmap: block>= EOF(%d, %ld)", block, 
+               printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block, 
                       inode->i_size);
              }
            return 0;
index d5a414eccb9987e7290928c23a9668d1c4d03046..2d24607bf7c364ebe0c4a4bd5d420d495b7e5304 100644 (file)
@@ -344,6 +344,9 @@ static int run_nfsiod(void *dummy)
        current->session = 1;
        current->pgrp = 1;
        sprintf(current->comm, "nfsiod");
+#ifndef MODULE
+       current->blocked = ~0UL;
+#endif
        ret = nfsiod();
        MOD_DEC_USE_COUNT;
        return ret;
index 167c5b5017b3d304dedf0a1c4231cb71ad5b80d1..95b1350ed18d2a328a87156edab3333a34a6d833 100644 (file)
@@ -99,10 +99,14 @@ nfsiod(void)
                /* Wait until user enqueues request */
                dprintk("BIO: before: now %d nfsiod's active\n", active);
                dprintk("BIO: nfsiod %d waiting\n", current->pid);
+#ifndef MODULE
+               current->signal = 0;
+#endif
                interruptible_sleep_on(&req->rq_wait);
-
+#ifdef  MODULE
                if (current->signal & ~current->blocked)
                        break;
+#endif
                if (!req->rq_rpcreq.rq_slot)
                        continue;
                dprintk("BIO: nfsiod %d woken up; calling nfs_rpc_doio.\n",
index 000cc5e6a46fe64150a27effd7ed55e996b577e0..262fbf54365c9e5a75b715fbd80218c5a0a77d70 100644 (file)
@@ -29,7 +29,7 @@
  * Yves Arrouye      :  remove removal of trailing spaces in get_array.
  *                     <Yves.Arrouye@marin.fdn.fr>
  *
- * Alan Cox         :  security fixes. <Alan.Cox@linux.org>a
+ * Alan Cox         :  security fixes. <Alan.Cox@linux.org>
  */
 
 #include <linux/types.h>
index 5e936d7ffc0428c83f44b4ade0eb21c7624fc272..fb374b80ef4b46945f7491ac5d57e4bbbe916b34 100644 (file)
@@ -205,13 +205,13 @@ extern struct timezone sys_tz;
 static int
 utc2local(int time)
 {
-       return time - sys_tz.tz_minuteswest * 60;
+       return time - sys_tz.tz_minuteswest * 60 + sys_tz.tz_dsttime * 3600;
 }
 
 static int
 local2utc(int time)
 {
-       return time + sys_tz.tz_minuteswest * 60;
+       return time + sys_tz.tz_minuteswest * 60 - sys_tz.tz_dsttime * 3600;
 }
 
 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
index 7b851a1bd3c75ec24d78559c642136f04b94dc2a..2bcacea0e09165c177ec9686c71eab1c11d78bfa 100644 (file)
@@ -27,6 +27,53 @@ extern char wp_works_ok;     /* doesn't work on a 386 */
 extern char hlt_works_ok;      /* problems on some 486Dx4's and old 386's */
 extern int  have_cpuid;                /* We have a CPUID */
 
+extern unsigned long cpu_hz;   /* CPU clock frequency from time.c */
+
+/*
+ *     Detection of CPU model (CPUID).
+ */
+extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+       __asm__("cpuid"
+               : "=a" (*eax),
+                 "=b" (*ebx),
+                 "=c" (*ecx),
+                 "=d" (*edx)
+               : "a" (op)
+               : "cc");
+}
+
+/*
+ * Cyrix CPU register indexes (use special macros to access these)
+ */
+#define CX86_CCR2 0xc2
+#define CX86_CCR3 0xc3
+#define CX86_CCR4 0xe8
+#define CX86_CCR5 0xe9
+#define CX86_DIR0 0xfe
+#define CX86_DIR1 0xff
+
+/*
+ * Cyrix CPU register access macros
+ */
+
+extern inline unsigned char getCx86(unsigned char reg)
+{
+       unsigned char data;
+
+       __asm__ __volatile__("movb %1,%%al\n\t"
+                     "outb %%al,$0x22\n\t"
+                     "inb $0x23,%%al" : "=a" (data) : "q" (reg));
+       return data;
+}
+
+extern inline void setCx86(unsigned char reg, unsigned char data)
+{
+       __asm__ __volatile__("outb %%al,$0x22\n\t"
+            "movb %1,%%al\n\t"
+            "outb %%al,$0x23" : : "a" (reg), "q" (data));
+}
+
 /*
  * Bus types (default is ISA, but people can check others with these..)
  * MCA_bus hardcoded to 0 for now.
index ff0caafe07dae523a806b34ca0db619671629577..ed8b06dccd85a3f752513fe715c3b718e118f4fc 100644 (file)
@@ -160,6 +160,7 @@ struct cpuinfo_x86
        char x86_mask;
        char x86_vendor_id[16];
        int  x86_capability;
+       int  x86_ext_capability;
        int  fdiv_bug;
        int  have_cpuid;
        char wp_works_ok;
index 401933c3f031a3dc4d0851b56424b3663b142998..cc980ee1f001f34b0ed7a57bcfd28bc7211a6a84 100644 (file)
@@ -1,11 +1,41 @@
 /*
- * $Id: b1lli.h,v 1.1 1997/03/04 21:27:32 calle Exp $
+ * $Id: b1lli.h,v 1.1.2.9 1998/03/20 14:30:02 calle Exp $
  *
  * ISDN lowlevel-module for AVM B1-card.
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: b1lli.h,v $
+ * Revision 1.1.2.9  1998/03/20 14:30:02  calle
+ * added cardnr to detect if you try to add same T1 to different io address.
+ * change number of nccis depending on number of channels.
+ *
+ * Revision 1.1.2.8  1998/03/04 17:32:33  calle
+ * Changes for T1.
+ *
+ * Revision 1.1.2.7  1998/02/27 15:38:29  calle
+ * T1 running with slow link.
+ *
+ * Revision 1.1.2.6  1998/02/24 17:57:36  calle
+ * changes for T1.
+ *
+ * Revision 1.1.2.5  1998/01/27 16:11:50  calle
+ * support for PCMCIA B1/M1/M2 ready.
+ *
+ * Revision 1.1.2.4  1998/01/26 14:51:56  calle
+ * interface change for pcmcia cards.
+ *
+ * Revision 1.1.2.3  1998/01/23 16:46:45  calle
+ * new functions for pcmcia cards.
+ *
+ * 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 +62,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,33 +86,47 @@ 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;
+        int cardnr;  /* for HEMA/T1 */
+} 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 */
+#define AVMB1_REMOVECARD       6       /* remove a card (usefull for T1) */
 
 
-#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
 
-#define        AVMB1_PORTLEN   0x1f
+#ifdef __KERNEL__
+
+#define        AVMB1_PORTLEN           0x1f
 
-#define AVM_MAXVERSION 8
-#define AVM_NBCHAN     2
+#define AVM_MAXVERSION         8
 
-#define AVM_NAPPS      30
-#define AVM_NPLCI      5
-#define AVM_NNCCI      6
+#define AVM_NAPPS              30
+#define AVM_NNCCI_PER_CHANNEL  4
 
 /*
  * Main driver data
@@ -81,6 +137,8 @@ typedef struct avmb1_card {
        int cnr;
        unsigned short port;
        unsigned irq;
+       int cardtype;
+       int cardnr; /* for T1-HEMA */
        volatile unsigned short cardstate;
        int interrupt;
        int blocked;
@@ -108,14 +166,18 @@ typedef struct avmb1_card {
 
 
 /* b1lli.c */
-int B1_detect(unsigned short base);
+int B1_detect(unsigned short base, int cardtype);
+int T1_detectandinit(unsigned short base, unsigned irq, int cardnr);
 void B1_reset(unsigned short base);
+void T1_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_enable_irq(unsigned short base);
+void B1_setinterrupt(unsigned short base, unsigned irq, int cardtype);
 unsigned char B1_disable_irq(unsigned short base);
-int B1_valid_irq(unsigned irq);
+void T1_disable_irq(unsigned short base);
+int B1_valid_irq(unsigned irq, int cardtype);
+int B1_valid_port(unsigned port, 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 +195,16 @@ 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 efed32b4db7e32ff919b53cecd6617db085f11e2..4ede3d0b0ac72cdd436f90474fd99ba8cb9cbd0c 100644 (file)
@@ -1,14 +1,51 @@
-/*
+/* $Revision: 2.4 $$Date: 1998/06/01 12:09:53 $
  * linux/include/linux/cyclades.h
  *
- * This file is maintained by Marcio Saito <marcio@cyclades.com> and
+ * This file is maintained by Ivan Passos <ivan@cyclades.com>, 
+ * Marcio Saito <marcio@cyclades.com> and
  * Randolph Bentson <bentson@grieg.seaslug.org>.
  *
  * This file contains the general definitions for the cyclades.c driver
  *$Log: cyclades.h,v $
- * Revision 1.5  1995/11/13  21:13:31  bentson
- * changes suggested by Michael Chastain <mec@duracef.shout.net>
- * to support use of this file in non-kernel applications
+ *Revision 2.4  1998/06/01 12:09:53  ivan
+ *removed closing_wait2 from cyclades_port structure;
+ *
+ *Revision 2.3  1998/03/16 18:01:12  ivan
+ *changes in the cyclades_port structure to get it closer to the 
+ *standard serial port structure;
+ *added constants for new ioctls;
+ *
+ *Revision 2.2  1998/02/17 16:50:00  ivan
+ *changes in the cyclades_port structure (addition of shutdown_wait and 
+ *chip_rev variables);
+ *added constants for new ioctls and for CD1400 rev. numbers.
+ *
+ *Revision 2.1 1997/10/24 16:03:00  ivan
+ *added rflow (which allows enabling the CD1400 special flow control 
+ *feature) and rtsdtr_inv (which allows DTR/RTS pin inversion) to 
+ *cyclades_port structure;
+ *added Alpha support
+ *
+ *Revision 2.0  1997/06/30 10:30:00  ivan
+ *added some new doorbell command constants related to IOCTLW and
+ *UART error signaling
+ *
+ *Revision 1.8  1997/06/03 15:30:00  ivan
+ *added constant ZFIRM_HLT
+ *added constant CyPCI_Ze_win ( = 2 * Cy_PCI_Zwin)
+ *
+ *Revision 1.7  1997/03/26 10:30:00  daniel
+ *new entries at the end of cyclades_port struct to reallocate
+ *variables illegally allocated within card memory.
+ *
+ *Revision 1.6  1996/09/09 18:35:30  bentson
+ *fold in changes for Cyclom-Z -- including structures for
+ *communicating with board as well modest changes to original
+ *structures to support new features.
+ *
+ *Revision 1.5  1995/11/13 21:13:31  bentson
+ *changes suggested by Michael Chastain <mec@duracef.shout.net>
+ *to support use of this file in non-kernel applications
  *
  *
  */
@@ -34,17 +71,411 @@ struct cyclades_monitor {
 #define CYSETTIMEOUT            0x435907
 #define CYGETDEFTIMEOUT         0x435908
 #define CYSETDEFTIMEOUT         0x435909
+#define CYSETRFLOW             0x43590a
+#define CYGETRFLOW             0x43590b
+#define CYSETRTSDTR_INV                0x43590c
+#define CYGETRTSDTR_INV                0x43590d
+#define CYZPOLLCYCLE           0x43590e
+#define CYGETCD1400VER         0x43590f
+#define CYGETCARDINFO          0x435910
+#define        CYSETWAIT               0x435911
+#define        CYGETWAIT               0x435912
+
+/*************** CYCLOM-Z ADDITIONS ***************/
+
+#define CZIOC           ('M' << 8)
+#define CZ_NBOARDS      (CZIOC|0xfa)
+#define CZ_BOOT_START   (CZIOC|0xfb)
+#define CZ_BOOT_DATA    (CZIOC|0xfc)
+#define CZ_BOOT_END     (CZIOC|0xfd)
+#define CZ_TEST         (CZIOC|0xfe)
+
+#define CZ_DEF_POLL    (HZ/25)
+
+#define MAX_BOARD       4       /* Max number of boards */
+#define MAX_DEV         256     /* Max number of ports total */
+#define        CYZ_MAX_SPEED   921600
+
+#define        CYZ_FIFO_SIZE   16
+
+#define CYZ_BOOT_NWORDS 0x100
+struct CYZ_BOOT_CTRL {
+        unsigned short  nboard;
+        int             status[MAX_BOARD];
+        int             nchannel[MAX_BOARD];
+        int             fw_rev[MAX_BOARD];
+        unsigned long   offset;
+        unsigned long   data[CYZ_BOOT_NWORDS];
+};
+
+
+#ifndef DP_WINDOW_SIZE
+/* #include "cyclomz.h" */
+/****************** ****************** *******************/
+/*
+ *     The data types defined below are used in all ZFIRM interface
+ *     data structures. They accomodate differences between HW
+ *     architectures and compilers.
+ */
+
+#if defined(__alpha__)
+typedef unsigned long  ucdouble;       /* 64 bits, unsigned */
+typedef unsigned int   uclong;         /* 32 bits, unsigned */
+#else
+typedef unsigned long  uclong;         /* 32 bits, unsigned */
+#endif
+typedef unsigned short ucshort;        /* 16 bits, unsigned */
+typedef unsigned char  ucchar;         /* 8 bits, unsigned */
+
+/*
+ *     Memory Window Sizes
+ */
+
+#define        DP_WINDOW_SIZE          (0x00080000)    /* window size 512 Kb */
+#define        ZE_DP_WINDOW_SIZE       (0x00100000)    /* window size 1 Mb (Ze and
+                                                 8Zo V.2 */
+#define        CTRL_WINDOW_SIZE        (0x00000080)    /* runtime regs 128 bytes */
+
+/*
+ *     CUSTOM_REG - Cyclom-Z/PCI Custom Registers Set. The driver
+ *     normally will access only interested on the fpga_id, fpga_version,
+ *     start_cpu and stop_cpu.
+ */
+
+struct CUSTOM_REG {
+       uclong  fpga_id;                /* FPGA Identification Register */
+       uclong  fpga_version;           /* FPGA Version Number Register */
+       uclong  cpu_start;              /* CPU start Register (write) */
+       uclong  cpu_stop;               /* CPU stop Register (write) */
+       uclong  misc_reg;               /* Miscelaneous Register */
+       uclong  idt_mode;               /* IDT mode Register */
+       uclong  uart_irq_status;        /* UART IRQ status Register */
+       uclong  clear_timer0_irq;       /* Clear timer interrupt Register */
+       uclong  clear_timer1_irq;       /* Clear timer interrupt Register */
+       uclong  clear_timer2_irq;       /* Clear timer interrupt Register */
+       uclong  test_register;          /* Test Register */
+       uclong  test_count;             /* Test Count Register */
+       uclong  timer_select;           /* Timer select register */
+       uclong  pr_uart_irq_status;     /* Prioritized UART IRQ stat Reg */
+       uclong  ram_wait_state;         /* RAM wait-state Register */
+       uclong  uart_wait_state;        /* UART wait-state Register */
+       uclong  timer_wait_state;       /* timer wait-state Register */
+       uclong  ack_wait_state;         /* ACK wait State Register */
+};
+
+/*
+ *     RUNTIME_9060 - PLX PCI9060ES local configuration and shared runtime
+ *     registers. This structure can be used to access the 9060 registers
+ *     (memory mapped).
+ */
+
+struct RUNTIME_9060 {
+       uclong  loc_addr_range; /* 00h - Local Address Range */
+       uclong  loc_addr_base;  /* 04h - Local Address Base */
+       uclong  loc_arbitr;     /* 08h - Local Arbitration */
+       uclong  endian_descr;   /* 0Ch - Big/Little Endian Descriptor */
+       uclong  loc_rom_range;  /* 10h - Local ROM Range */
+       uclong  loc_rom_base;   /* 14h - Local ROM Base */
+       uclong  loc_bus_descr;  /* 18h - Local Bus descriptor */
+       uclong  loc_range_mst;  /* 1Ch - Local Range for Master to PCI */
+       uclong  loc_base_mst;   /* 20h - Local Base for Master PCI */
+       uclong  loc_range_io;   /* 24h - Local Range for Master IO */
+       uclong  pci_base_mst;   /* 28h - PCI Base for Master PCI */
+       uclong  pci_conf_io;    /* 2Ch - PCI configuration for Master IO */
+       uclong  filler1;        /* 30h */
+       uclong  filler2;        /* 34h */
+       uclong  filler3;        /* 38h */
+       uclong  filler4;        /* 3Ch */
+       uclong  mail_box_0;     /* 40h - Mail Box 0 */
+       uclong  mail_box_1;     /* 44h - Mail Box 1 */
+       uclong  mail_box_2;     /* 48h - Mail Box 2 */
+       uclong  mail_box_3;     /* 4Ch - Mail Box 3 */
+       uclong  filler5;        /* 50h */
+       uclong  filler6;        /* 54h */
+       uclong  filler7;        /* 58h */
+       uclong  filler8;        /* 5Ch */
+       uclong  pci_doorbell;   /* 60h - PCI to Local Doorbell */
+       uclong  loc_doorbell;   /* 64h - Local to PCI Doorbell */
+       uclong  intr_ctrl_stat; /* 68h - Interrupt Control/Status */
+       uclong  init_ctrl;      /* 6Ch - EEPROM control, Init Control, etc */
+};
+
+/* Values for the Local Base Address re-map register */
+
+#define        WIN_RAM         0x00000001L     /* set the sliding window to RAM */
+#define        WIN_CREG        0x14000001L     /* set the window to custom Registers */
+
+/* Values timer select registers */
+
+#define        TIMER_BY_1M     0x00            /* clock divided by 1M */
+#define        TIMER_BY_256K   0x01            /* clock divided by 256k */
+#define        TIMER_BY_128K   0x02            /* clock divided by 128k */
+#define        TIMER_BY_32K    0x03            /* clock divided by 32k */
+
+/****************** ****************** *******************/
+#endif
+
+#ifndef ZFIRM_ID
+/* #include "zfwint.h" */
+/****************** ****************** *******************/
+/*
+ *     This file contains the definitions for interfacing with the
+ *     Cyclom-Z ZFIRM Firmware.
+ */
+
+/* General Constant definitions */
+
+#define        MAX_CHAN        64              /* max number of channels per board */
+
+/* firmware id structure (set after boot) */
+
+#define ID_ADDRESS     0x00000180L     /* signature/pointer address */
+#define        ZFIRM_ID        0x5557465AL     /* ZFIRM/U signature */
+#define        ZFIRM_HLT       0x59505B5CL     /* ZFIRM needs external power supply */
+#define        ZFIRM_RST       0x56040674L     /* RST signal (due to FW reset) */
+
+#define        ZF_TINACT_DEF   1000            /* default inactivity timeout 
+                                          (1000 ms) */
+#define        ZF_TINACT       ZF_TINACT_DEF
+
+struct FIRM_ID {
+       uclong  signature;              /* ZFIRM/U signature */
+       uclong  zfwctrl_addr;           /* pointer to ZFW_CTRL structure */
+};
+
+/* Op. System id */
+
+#define        C_OS_LINUX      0x00000030      /* generic Linux system */
+
+/* channel op_mode */
+
+#define        C_CH_DISABLE    0x00000000      /* channel is disabled */
+#define        C_CH_TXENABLE   0x00000001      /* channel Tx enabled */
+#define        C_CH_RXENABLE   0x00000002      /* channel Rx enabled */
+#define        C_CH_ENABLE     0x00000003      /* channel Tx/Rx enabled */
+#define        C_CH_LOOPBACK   0x00000004      /* Loopback mode */
+
+/* comm_parity - parity */
+
+#define        C_PR_NONE       0x00000000      /* None */
+#define        C_PR_ODD        0x00000001      /* Odd */
+#define C_PR_EVEN      0x00000002      /* Even */
+#define C_PR_MARK      0x00000004      /* Mark */
+#define C_PR_SPACE     0x00000008      /* Space */
+#define C_PR_PARITY    0x000000ff
+
+#define        C_PR_DISCARD    0x00000100      /* discard char with frame/par error */
+#define C_PR_IGNORE    0x00000200      /* ignore frame/par error */
+
+/* comm_data_l - data length and stop bits */
+
+#define C_DL_CS5       0x00000001
+#define C_DL_CS6       0x00000002
+#define C_DL_CS7       0x00000004
+#define C_DL_CS8       0x00000008
+#define        C_DL_CS         0x0000000f
+#define C_DL_1STOP     0x00000010
+#define C_DL_15STOP    0x00000020
+#define C_DL_2STOP     0x00000040
+#define        C_DL_STOP       0x000000f0
+
+/* interrupt enabling/status */
+
+#define        C_IN_DISABLE    0x00000000      /* zero, disable interrupts */
+#define        C_IN_TXBEMPTY   0x00000001      /* tx buffer empty */
+#define        C_IN_TXLOWWM    0x00000002      /* tx buffer below LWM */
+#define        C_IN_RXHIWM     0x00000010      /* rx buffer above HWM */
+#define        C_IN_RXNNDT     0x00000020      /* rx no new data timeout */
+#define        C_IN_MDCD       0x00000100      /* modem DCD change */
+#define        C_IN_MDSR       0x00000200      /* modem DSR change */
+#define        C_IN_MRI        0x00000400      /* modem RI change */
+#define        C_IN_MCTS       0x00000800      /* modem CTS change */
+#define        C_IN_RXBRK      0x00001000      /* Break received */
+#define        C_IN_PR_ERROR   0x00002000      /* parity error */
+#define        C_IN_FR_ERROR   0x00004000      /* frame error */
+#define C_IN_OVR_ERROR  0x00008000      /* overrun error */
+#define C_IN_RXOFL     0x00010000      /* RX buffer overflow */
+#define C_IN_IOCTLW    0x00020000      /* I/O control w/ wait */
+/* flow control */
+
+#define        C_FL_OXX        0x00000001      /* output Xon/Xoff flow control */
+#define        C_FL_IXX        0x00000002      /* output Xon/Xoff flow control */
+#define C_FL_OIXANY    0x00000004      /* output Xon/Xoff (any xon) */
+#define        C_FL_SWFLOW     0x0000000f
+
+/* flow status */
+
+#define        C_FS_TXIDLE     0x00000000      /* no Tx data in the buffer or UART */
+#define        C_FS_SENDING    0x00000001      /* UART is sending data */
+#define        C_FS_SWFLOW     0x00000002      /* Tx is stopped by received Xoff */
+
+/* rs_control/rs_status RS-232 signals */
+
+#define        C_RS_DCD        0x00000100      /* CD */
+#define        C_RS_DSR        0x00000200      /* DSR */
+#define        C_RS_RI         0x00000400      /* RI */
+#define        C_RS_CTS        0x00000800      /* CTS */
+#define        C_RS_RTS        0x00000001      /* RTS */
+#define        C_RS_DTR        0x00000004      /* DTR */
+
+/* commands Host <-> Board */
+
+#define        C_CM_RESET      0x01            /* reset/flush buffers */
+#define        C_CM_IOCTL      0x02            /* re-read CH_CTRL */
+#define        C_CM_IOCTLW     0x03            /* re-read CH_CTRL, intr when done */
+#define        C_CM_IOCTLM     0x04            /* RS-232 outputs change */
+#define        C_CM_SENDXOFF   0x10            /* send Xoff */
+#define        C_CM_SENDXON    0x11            /* send Xon */
+#define C_CM_CLFLOW    0x12            /* Clear flow control (resume) */
+#define        C_CM_SENDBRK    0x41            /* send break */
+#define        C_CM_INTBACK    0x42            /* Interrupt back */
+#define        C_CM_SET_BREAK  0x43            /* Tx break on */
+#define        C_CM_CLR_BREAK  0x44            /* Tx break off */
+#define        C_CM_CMD_DONE   0x45            /* Previous command done */
+#define        C_CM_TINACT     0x51            /* set inactivity detection */
+#define        C_CM_IRQ_ENBL   0x52            /* enable generation of interrupts */
+#define        C_CM_IRQ_DSBL   0x53            /* disable generation of interrupts */
+#define        C_CM_ACK_ENBL   0x54            /* enable acknolowdged interrupt mode */
+#define        C_CM_ACK_DSBL   0x55            /* disable acknolowdged intr mode */
+#define        C_CM_FLUSH_RX   0x56            /* flushes Rx buffer */
+#define        C_CM_FLUSH_TX   0x57            /* flushes Tx buffer */
+
+#define        C_CM_TXBEMPTY   0x60            /* Tx buffer is empty */
+#define        C_CM_TXLOWWM    0x61            /* Tx buffer low water mark */
+#define        C_CM_RXHIWM     0x62            /* Rx buffer high water mark */
+#define        C_CM_RXNNDT     0x63            /* rx no new data timeout */
+#define        C_CM_MDCD       0x70            /* modem DCD change */
+#define        C_CM_MDSR       0x71            /* modem DSR change */
+#define        C_CM_MRI        0x72            /* modem RI change */
+#define        C_CM_MCTS       0x73            /* modem CTS change */
+#define        C_CM_RXBRK      0x84            /* Break received */
+#define        C_CM_PR_ERROR   0x85            /* Parity error */
+#define        C_CM_FR_ERROR   0x86            /* Frame error */
+#define C_CM_OVR_ERROR  0x87            /* Overrun error */
+#define C_CM_RXOFL     0x88            /* RX buffer overflow */
+#define        C_CM_CMDERROR   0x90            /* command error */
+#define        C_CM_FATAL      0x91            /* fatal error */
+#define        C_CM_HW_RESET   0x92            /* reset board */
+
+/*
+ *     CH_CTRL - This per port structure contains all parameters
+ *     that control an specific port. It can be seen as the
+ *     configuration registers of a "super-serial-controller".
+ */
+
+struct CH_CTRL {
+       uclong  op_mode;        /* operation mode */
+       uclong  intr_enable;    /* interrupt masking */
+       uclong  sw_flow;        /* SW flow control */
+       uclong  flow_status;    /* output flow status */
+       uclong  comm_baud;      /* baud rate  - numerically specified */
+       uclong  comm_parity;    /* parity */
+       uclong  comm_data_l;    /* data length/stop */
+       uclong  comm_flags;     /* other flags */
+       uclong  hw_flow;        /* HW flow control */
+       uclong  rs_control;     /* RS-232 outputs */
+       uclong  rs_status;      /* RS-232 inputs */
+       uclong  flow_xon;       /* xon char */
+       uclong  flow_xoff;      /* xoff char */
+       uclong  hw_overflow;    /* hw overflow counter */
+       uclong  sw_overflow;    /* sw overflow counter */
+       uclong  comm_error;     /* frame/parity error counter */
+};
+
+
+/*
+ *     BUF_CTRL - This per channel structure contains
+ *     all Tx and Rx buffer control for a given channel.
+ */
+
+struct BUF_CTRL        {
+       uclong  flag_dma;       /* buffers are in Host memory */
+       uclong  tx_bufaddr;     /* address of the tx buffer */
+       uclong  tx_bufsize;     /* tx buffer size */
+       uclong  tx_threshold;   /* tx low water mark */
+       uclong  tx_get;         /* tail index tx buf */
+       uclong  tx_put;         /* head index tx buf */
+       uclong  rx_bufaddr;     /* address of the rx buffer */
+       uclong  rx_bufsize;     /* rx buffer size */
+       uclong  rx_threshold;   /* rx high water mark */
+       uclong  rx_get;         /* tail index rx buf */
+       uclong  rx_put;         /* head index rx buf */
+       uclong  filler[5];      /* filler to align structures */
+};
+
+/*
+ *     BOARD_CTRL - This per board structure contains all global 
+ *     control fields related to the board.
+ */
+
+struct BOARD_CTRL {
+
+       /* static info provided by the on-board CPU */
+       uclong  n_channel;      /* number of channels */
+       uclong  fw_version;     /* firmware version */
+
+       /* static info provided by the driver */
+       uclong  op_system;      /* op_system id */
+       uclong  dr_version;     /* driver version */
+
+       /* board control area */
+       uclong  inactivity;     /* inactivity control */
+
+       /* host to FW commands */
+       uclong  hcmd_channel;   /* channel number */
+       uclong  hcmd_param;     /* pointer to parameters */
+
+       /* FW to Host commands */
+       uclong  fwcmd_channel;  /* channel number */
+       uclong  fwcmd_param;    /* pointer to parameters */
+
+       /* filler so the structures are aligned */
+       uclong  filler[7];
+};
+
+/*
+ *     ZFW_CTRL - This is the data structure that includes all other
+ *     data structures used by the Firmware.
+ */
+struct ZFW_CTRL {
+       struct BOARD_CTRL       board_ctrl;
+       struct CH_CTRL          ch_ctrl[MAX_CHAN];
+       struct BUF_CTRL         buf_ctrl[MAX_CHAN];
+};
+
+/****************** ****************** *******************/
+#endif
+
+
+
 
 #ifdef __KERNEL__
 
+/***************************************
+ * Memory access functions/macros      *
+ * (required to support Alpha systems) *
+ ***************************************/
+
+#define cy_writeb(port,val)     {writeb((ucchar)(val),(ulong)(port)); mb();}
+#define cy_writew(port,val)     {writew((ushort)(val),(ulong)(port)); mb();}
+#define cy_writel(port,val)     {writel((uclong)(val),(ulong)(port)); mb();}
+
+#define cy_readb(port)  readb(port)
+#define cy_readw(port)  readw(port)
+#define cy_readl(port)  readl(port)
+
 /* Per card data structure */
 
 struct cyclades_card {
-    int base_addr;
+    long base_addr;
+    long ctl_addr;
     int irq;
-    int num_chips;     /* 0 if card is absent */
+    int num_chips;     /* 0 if card absent, 1 if Z/PCI, else Y */
     int first_line;    /* minor number of first channel on card */
     int bus_index;     /* address shift - 0 for ISA, 1 for PCI */
+    int        inact_ctrl;     /* FW Inactivity control - 0 disabled, 1 enabled */
 };
 
 struct cyclades_chip {
@@ -62,23 +493,28 @@ struct cyclades_chip {
 
 struct cyclades_port {
        int                     magic;
-       int                     type;
        int                     card;
        int                     line;
        int                     flags;          /* defined in tty.h */
+       int                     type;           /* UART type */
        struct tty_struct       *tty;
        int                     read_status_mask;
+       int                     ignore_status_mask;
        int                     timeout;
        int                     xmit_fifo_size;
        int                     cor1,cor2,cor3,cor4,cor5;
        int                     tbpr,tco,rbpr,rco;
-       int                     ignore_status_mask;
+       int                     baud;
+       int                     rflow;
+       int                     rtsdtr_inv;
+       int                     chip_rev;
+       int                     custom_divisor;
+       int                     x_char; /* to be pushed out ASAP */
        int                     close_delay;
-       int                     IER;    /* Interrupt Enable Register */
-       int                     event;
+       unsigned short          closing_wait;
+       unsigned long           event;
        unsigned long           last_active;
        int                     count;  /* # of fd on device */
-       int                     x_char; /* to be pushed out ASAP */
        int                     x_break;
        int                     blocked_open; /* # of blocked opens */
        long                    session; /* Session of opening process */
@@ -94,29 +530,49 @@ struct cyclades_port {
        struct termios          callout_termios;
        struct wait_queue       *open_wait;
        struct wait_queue       *close_wait;
+       struct wait_queue       *shutdown_wait;
         struct cyclades_monitor mon;
+       unsigned long           jiffies[3];
+       unsigned long           rflush_count;
 };
 
 /*
  * Events are used to schedule things to happen at timer-interrupt
  * time, instead of at cy interrupt time.
  */
-#define Cy_EVENT_READ_PROCESS  0
-#define Cy_EVENT_WRITE_WAKEUP  1
-#define Cy_EVENT_HANGUP                2
-#define Cy_EVENT_BREAK         3
-#define Cy_EVENT_OPEN_WAKEUP   4
+#define Cy_EVENT_READ_PROCESS          0
+#define Cy_EVENT_WRITE_WAKEUP          1
+#define Cy_EVENT_HANGUP                        2
+#define Cy_EVENT_BREAK                 3
+#define Cy_EVENT_OPEN_WAKEUP           4
+#define Cy_EVENT_SHUTDOWN_WAKEUP       5
+
+#define        CLOSING_WAIT_DELAY      60*HZ
+#define CY_CLOSING_WAIT_NONE   65535
+#define CY_CLOSING_WAIT_INF    0
+
 
+#define CyMAX_CHIPS_PER_CARD   8
+#define CyMAX_CHAR_FIFO                12
+#define CyPORTS_PER_CHIP       4
+#define        CD1400_MAX_SPEED        115200
 
+#define        CyISA_Ywin      0x2000
 
-#define CyMaxChipsPerCard 8
+#define CyPCI_Ywin     0x4000
+#define CyPCI_Zctl     CTRL_WINDOW_SIZE
+#define CyPCI_Zwin     0x80000
+#define CyPCI_Ze_win   (2 * CyPCI_Zwin)
 
 /**** CD1400 registers ****/
 
-#define CyRegSize  0x0400
-#define Cy_HwReset 0x1400
-#define Cy_ClrIntr 0x1800
-#define Cy_EpldRev 0x1e00
+#define CD1400_REV_G   0x46
+#define CD1400_REV_J   0x48
+
+#define CyRegSize      0x0400
+#define Cy_HwReset     0x1400
+#define Cy_ClrIntr     0x1800
+#define Cy_EpldRev     0x1e00
 
 /* Global Registers */
 
@@ -152,6 +608,9 @@ struct cyclades_port {
 #define CyPPR          (0x7E*2)
 #define      CyCLOCK_20_1MS    (0x27)
 #define      CyCLOCK_25_1MS    (0x31)
+#define      CyCLOCK_25_5MS    (0xf4)
+#define      CyCLOCK_60_1MS    (0x75)
+#define      CyCLOCK_60_2MS    (0xea)
 
 /* Virtual Registers */
 
@@ -274,10 +733,6 @@ struct cyclades_port {
 #define CyTBPR         (0x72*2)
 #define CyTCOR         (0x76*2)
 
-/* max number of chars in the FIFO */
-
-#define CyMAX_CHAR_FIFO        12
-
 /***************************************************************************/
 
 #endif /* __KERNEL__ */
diff --git a/include/linux/if_shaper.h b/include/linux/if_shaper.h
new file mode 100644 (file)
index 0000000..5c64f47
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __LINUX_SHAPER_H
+#define __LINUX_SHAPER_H
+
+#ifdef __KERNEL__
+
+#define SHAPER_QLEN    10
+/*
+ *     This is a bit speed dependant (read it shouldnt be a constant!)
+ *
+ *     5 is about right for 28.8 upwards. Below that double for every
+ *     halving of speed or so. - ie about 20 for 9600 baud.
+ */
+#define SHAPER_LATENCY (5*HZ)
+#define SHAPER_MAXSLIP 2
+#define SHAPER_BURST   (HZ/50)         /* Good for >128K then */
+
+struct shaper
+{
+       struct sk_buff_head sendq;
+       __u32 bitspersec;
+       __u32 bytespertick;
+       __u32 shapelatency;
+       __u32 shapeclock;
+       __u32 recovery;         /* Time we can next clock a packet out on
+                                  an empty queue */
+       char locked;
+       struct device *dev;
+       int  (*hard_start_xmit) (struct sk_buff *skb,
+               struct device *dev);
+       int  (*hard_header) (struct sk_buff *skb,
+               struct device *dev,
+               unsigned short type,
+               void *daddr,
+               void *saddr,
+               unsigned len);
+       int  (*rebuild_header)(void *eth, struct device *dev,
+                unsigned long raddr, struct sk_buff *skb);
+       struct enet_statistics* (*get_stats)(struct device *dev);
+       struct wait_queue *wait_queue;
+       struct timer_list timer;
+};
+
+#endif
+
+#define SHAPER_SET_DEV         0x0001
+#define SHAPER_SET_SPEED       0x0002
+#define SHAPER_GET_DEV         0x0003
+#define SHAPER_GET_SPEED       0x0004
+
+struct shaperconf
+{
+       __u16   ss_cmd;
+       union
+       {
+               char    ssu_name[14];
+               __u32   ssu_speed;
+       } ss_u;
+#define ss_speed ss_u.ssu_speed
+#define ss_name ss_u.ssu_name
+};
+
+#endif
index dba8330295a39ac15872d48419763061475d65db..b00b0b4d1393b8a9d322e30a29ea114b097b49e3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.32 1997/08/21 09:49:46 fritz Exp $
+/* $Id: isdn.h,v 1.31.2.10 1998/06/07 13:48:30 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.32  1997/08/21 09:49:46  fritz
- * Increased NET_DV
+ * Revision 1.31.2.10  1998/06/07 13:48:30  fritz
+ * ABC cleanup
+ *
+ * Revision 1.31.2.9  1998/06/02 12:12:49  detabc
+ * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
+ * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
+ *
+ * Revision 1.31.2.8  1998/05/06 08:30:44  detabc
+ * add Item to stop icmp-unreach (max. 6 times of dialwait delay)
+ *
+ * Revision 1.31.2.7  1998/04/26 19:51:40  detabc
+ * removed unused code
+ *
+ * Revision 1.31.2.6  1998/04/26 11:10:46  detabc
+ * add items for the abc_tx_queus and the abc_delayed_hangup
+ * only used if the abc-extension is enabled
+ *
+ * Revision 1.31.2.5  1998/04/18 17:39:45  detabc
+ * remove some unused abc-lines
+ * added defines und items for abc-secure callback (only used with abc-extenrsion)
+ *
+ * Revision 1.31.2.4  1998/04/08 21:42:25  keil
+ * Blocksize default 1024
+ *
+ * Revision 1.31.2.3  1998/03/16 09:56:28  cal
+ * Merged in TimRu-patches. Still needs validation in conjunction with ABC-patches.
+ *
+ * Revision 1.31.2.2  1998/03/07 23:35:45  detabc
+ * added the abc-extension to the linux isdn-kernel
+ * for kernel-version 2.0.xx
+ * DO NOT USE FOR HIGHER KERNELS-VERSIONS
+ * all source-lines are switched with the define  CONFIG_ISDN_WITH_ABC
+ * (make config and answer ABC-Ext. Support (Compress,TCP-Keepalive ...) with yes
+ *
+ * you need also a modified isdnctrl-source the switch on the
+ * features of the abc-extension
+ *
+ * please use carefully. more detail will be follow.
+ * thanks
+ *
+ * Revision 1.31.2.1  1997/08/21 15:57:04  fritz
+ * Synchronized 2.0.X branch with 2.0.31-pre7
  *
  * Revision 1.31  1997/06/22 11:57:07  fritz
  * Added ability to adjust slave triggerlevel.
 #define IIOCGETCPS  _IO('I',21)
 #define IIOCGETDVR  _IO('I',22)
 
+#define IIOCNETARU  _IO('I',23)
+#define IIOCNETDRU  _IO('I',24)
+#define IIOCNETGRU  _IO('I',25)
+
+#define IIOCNETBUD  _IO('I',26)
+
 #define IIOCNETALN  _IO('I',32)
 #define IIOCNETDLN  _IO('I',33)
 
@@ -254,6 +300,9 @@ typedef struct {
   int  pppbind;      /* ippp device for bindings              */
   int  chargeint;    /* Use fixed charge interval length      */
   int  triggercps;   /* BogoCPS needed for triggering slave   */
+  int  dialtimeout;  /* Dial-Timeout                          */
+  int  dialwait;     /* Time to wait after failed dial        */
+  int  stopped;      /* Flag: Stopped                         */
 } isdn_net_ioctl_cfg;
 
 #ifdef __KERNEL__
@@ -364,6 +413,9 @@ typedef struct {
 #define ISDN_NET_TMP        0x10       /* tmp interface until getting an IP */
 #define ISDN_NET_DYNAMIC    0x20       /* this link is dynamically allocated */
 #endif
+
+#define ISDN_NET_STOPPED    0x40       /* this interface is stopped         */
+
 #define ISDN_NET_MAGIC      0x49344C02 /* for paranoia-checking             */
 
 /* Phone-list-element */
@@ -423,7 +475,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 */
+  int                                          triggercps;     /* BogoCPS needed for triggering slave   */
   struct device          *srobin;      /* Ptr to Master device for slaves  */
   isdn_net_phone         *phone[2];    /* List of remote-phonenumbers      */
                                       /* phone[0] = Incoming Numbers      */
@@ -460,6 +512,11 @@ typedef struct isdn_net_local_s {
                                    struct device *,
                                     unsigned char *);
   int  pppbind;                        /* ippp device for bindings         */
+  int                                  dialtimeout;    /* How long shall we try on dialing? (jiffies) */
+  int                  dialwait;               /* How long shall we wait after failed attempt? (jiffies) */
+  ulong                        dialstarted;    /* jiffies of first dialing-attempt */
+  ulong                        dialwait_timer; /* jiffies of earliest next dialing-attempt */
+  int                  huptimeout;     /* How long will the connection be up? (seconds) */
 } isdn_net_local;
 
 #ifdef CONFIG_ISDN_PPP
@@ -502,7 +559,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
 
@@ -624,7 +682,7 @@ struct sqqueue {
 struct mpqueue {
   struct mpqueue *next;
   struct mpqueue *last;
-  long sqno;
+  long    sqno;
   struct sk_buff *skb;
   int BEbyte;
   unsigned long time;
@@ -663,8 +721,12 @@ struct ippp_struct {
   struct slcompress *slcomp;
 #endif
   unsigned long debug;
-  struct isdn_ppp_compressor *compressor,*link_compressor;
+  struct isdn_ppp_compressor *compressor, *link_compressor;
   void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
+#ifdef ISDN_SYNCPPP_READDRESS
+  unsigned long        old_pa_addr;
+  unsigned long        old_pa_dstaddr;
+#endif
 };
 
 #endif
index 5b1f18a882136410b9f2a1dc8ff52b47e0083bcc..24935ee42bd00a232f678bed387b923e1da594f1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.20 1997/05/27 15:18:06 fritz Exp $
+/* $Id: isdnif.h,v 1.20.2.1 1998/03/07 23:00:50 tsbogend Exp $
  *
  * Linux ISDN subsystem
  *
@@ -22,6 +22,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.20.2.1  1998/03/07 23:00:50  tsbogend
+ * added defines for Linux/Alpha 2.0.x with alpha-patches
+ *
  * Revision 1.20  1997/05/27 15:18:06  fritz
  * Added changes for recent 2.1.x kernels:
  *   changed return type of isdn_close
@@ -382,9 +385,15 @@ static inline unsigned long copy_to_user(void *to, const void *from, unsigned lo
 }
 
 #define GET_USER(x, addr) ( x = get_user(addr) )
+#ifdef __alpha__ /* needed for 2.0.x with alpha-patches */
+#define RWTYPE long
+#define LSTYPE long
+#define RWARG unsigned long
+#else
 #define RWTYPE int
 #define LSTYPE int
 #define RWARG int
+#endif
 #define LSARG off_t
 #else
 #include <asm/uaccess.h>
index 335c74eecb0dbc3da9abfa205f6931bd5b31201d..63549d441c661e73c477714b00c8241110febf90 100644 (file)
@@ -44,7 +44,8 @@ struct serial_struct {
 #define PORT_16550A    4
 #define PORT_CIRRUS     5
 #define PORT_16650     6
-#define PORT_MAX       6
+#define PORT_STARTECH  7
+#define PORT_MAX       7
 
 /*
  * Definitions for async_struct (and serial_struct) flags field
index aa38f2bf55b38bba5eefd6582cdecc4f10a3e86c..cf05129b98c6b140e554688570c11ad187d5ca4b 100644 (file)
@@ -112,6 +112,17 @@ struct sk_buff
        unsigned char   *end;                   /* End pointer                                  */
        void            (*destructor)(struct sk_buff *);        /* Destruct function            */
        __u16           redirport;              /* Redirect port                                */
+
+       /*
+        *      Keep this at the end then we wont break stuff.
+        */
+#if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE)
+        __u32           shapelatency;           /* Latency on frame */
+        __u32           shapeclock;             /* Time it should go out */
+        __u32           shapelen;               /* Frame length in clocks */
+        __u32           shapestamp;             /* Stamp for shaper    */
+        __u16           shapepend;              /* Pending */
+#endif
 };
 
 #ifdef CONFIG_SKB_LARGE
index 4bf6f9fd99586e304c6d15e8053967e01e7cdbb8..5aa5bcda0b9b1d4f458365a494cc0fbf1c7b1b4a 100644 (file)
@@ -169,6 +169,9 @@ extern void atari_scsi_setup (char *str, int *ints);
 extern void wd33c93_setup (char *str, int *ints);
 extern void gvp11_setup (char *str, int *ints);
 
+#ifdef CONFIG_CYCLADES
+extern void cy_setup(char *str, int *ints);
+#endif
 #ifdef CONFIG_DIGI
 extern void pcxx_setup(char *str, int *ints);
 #endif
@@ -446,6 +449,9 @@ struct kernel_param bootsetups[] = {
 #if defined(CONFIG_GVP11_SCSI)
        { "gvp11=", gvp11_setup },
 #endif
+#ifdef CONFIG_CYCLADES
+       { "cyclades=", cy_setup },
+#endif
 #ifdef CONFIG_DIGI
        { "digi=", pcxx_setup },
 #endif
index 0a3658e1f20fbb8ccf5e17419082011d59c89ebe..0789abba8862fa6df2eed496b71f8de0f0753f77 100644 (file)
@@ -310,6 +310,7 @@ struct symbol_table symbol_table = {
        X(sys_call_table),
        X(hard_reset_now),
        X(_ctype),
+       X(_ctmp),
        X(get_random_bytes),
 
        /* Signal interfaces */
@@ -368,6 +369,10 @@ struct symbol_table symbol_table = {
        X(get_write_access),
        X(put_write_access),
 
+#ifdef CONFIG_PROC_FS
+       X(proc_dir_inode_operations),
+#endif
+
        /********************************************************
         * Do not add anything below this line,
         * as the stacked modules depend on this!
index 962e13d731f8d41de0818988cf31ff286e1a1564..83a9f52e99b0fb8caf963c4756c7c942df11f17c 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -179,7 +179,7 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
                        if (locks_verify_locked(file->f_inode))
                                return -EAGAIN;
                        /* cevans -- whoops another append-only file flaw */
-                       if (IS_APPEND(file->f_inode) && (prot & PROT_WRITE))
+                       if (IS_APPEND(file->f_inode) && (file->f_mode & 2))
                                return -EACCES;
                        /* fall through */
                case MAP_PRIVATE: