]> git.neil.brown.name Git - history.git/commitdiff
pre-2.3.4.. 2.3.4pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:11 +0000 (15:25 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:11 +0000 (15:25 -0500)
There's a pre-2.3.4-1 out there in "testing" on ftp.kernel.org, which has
the new scalable network code (well, the first cut of it, anyway). It also
updates ISDN and PPC to newer versions. Please test it out and give
feedback..

                Linus

284 files changed:
CREDITS
Documentation/isdn/HiSax.cert [new file with mode: 0644]
Documentation/isdn/INTERFACE
Documentation/isdn/README
Documentation/isdn/README.HiSax
Documentation/isdn/README.TimRu.De [new file with mode: 0644]
Documentation/isdn/README.act2000
Documentation/isdn/README.audio
Documentation/isdn/README.concap
Documentation/isdn/README.eicon [new file with mode: 0644]
Documentation/isdn/README.icn
Documentation/isdn/README.x25
Makefile
README
arch/alpha/kernel/process.c
arch/alpha/kernel/ptrace.c
arch/arm/kernel/ptrace.c
arch/i386/defconfig
arch/mips/kernel/ptrace.c
arch/ppc/Makefile
arch/ppc/boot/Makefile
arch/ppc/boot/misc.c
arch/ppc/chrpboot/Makefile
arch/ppc/coffboot/Makefile
arch/ppc/common_defconfig
arch/ppc/config.in
arch/ppc/defconfig
arch/ppc/kernel/Makefile
arch/ppc/kernel/checks.c
arch/ppc/kernel/chrp_pci.c
arch/ppc/kernel/chrp_setup.c
arch/ppc/kernel/head.S
arch/ppc/kernel/mbx_setup.c
arch/ppc/kernel/misc.S
arch/ppc/kernel/pmac_setup.c
arch/ppc/kernel/prep_pci.c
arch/ppc/kernel/prep_setup.c
arch/ppc/kernel/process.c
arch/ppc/kernel/ptrace.c
arch/ppc/kernel/residual.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/softemu8xx.c
arch/ppc/kernel/syscalls.c
arch/ppc/kernel/traps.c
arch/ppc/mm/fault.c
arch/ppc/mm/init.c
arch/ppc/xmon/Makefile [new file with mode: 0644]
arch/ppc/xmon/adb.c [new file with mode: 0644]
arch/ppc/xmon/ansidecl.h [new file with mode: 0644]
arch/ppc/xmon/nonstdio.h [new file with mode: 0644]
arch/ppc/xmon/ppc-dis.c [new file with mode: 0644]
arch/ppc/xmon/ppc-opc.c [new file with mode: 0644]
arch/ppc/xmon/ppc.h [new file with mode: 0644]
arch/ppc/xmon/privinst.h [new file with mode: 0644]
arch/ppc/xmon/setjmp.c [new file with mode: 0644]
arch/ppc/xmon/start.c [new file with mode: 0644]
arch/ppc/xmon/subr_prf.c [new file with mode: 0644]
arch/ppc/xmon/xmon.c [new file with mode: 0644]
arch/sparc/kernel/ptrace.c
arch/sparc/kernel/sys_sunos.c
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/sys_sunos32.c
arch/sparc64/solaris/ioctl.c
drivers/block/cmd646.c
drivers/block/ide.c
drivers/char/Config.in
drivers/char/Makefile
drivers/char/cyclades.c
drivers/char/i2c-parport.c [new file with mode: 0644]
drivers/char/keyboard.c
drivers/isdn/Config.in
drivers/isdn/Makefile
drivers/isdn/act2000/act2000.h
drivers/isdn/act2000/act2000_isa.c
drivers/isdn/act2000/act2000_isa.h
drivers/isdn/act2000/capi.c
drivers/isdn/act2000/capi.h
drivers/isdn/act2000/module.c
drivers/isdn/avmb1/b1capi.c
drivers/isdn/avmb1/b1lli.c
drivers/isdn/avmb1/b1pci.c
drivers/isdn/avmb1/capi.c
drivers/isdn/avmb1/capidev.h
drivers/isdn/avmb1/capidrv.c
drivers/isdn/avmb1/capidrv.h
drivers/isdn/avmb1/compat.h
drivers/isdn/eicon/Makefile [new file with mode: 0644]
drivers/isdn/eicon/eicon.h [new file with mode: 0644]
drivers/isdn/eicon/eicon_dsp.h [new file with mode: 0644]
drivers/isdn/eicon/eicon_idi.c [new file with mode: 0644]
drivers/isdn/eicon/eicon_idi.h [new file with mode: 0644]
drivers/isdn/eicon/eicon_io.c [new file with mode: 0644]
drivers/isdn/eicon/eicon_isa.c [new file with mode: 0644]
drivers/isdn/eicon/eicon_isa.h [new file with mode: 0644]
drivers/isdn/eicon/eicon_mod.c [new file with mode: 0644]
drivers/isdn/eicon/eicon_pci.c [new file with mode: 0644]
drivers/isdn/eicon/eicon_pci.h [new file with mode: 0644]
drivers/isdn/hisax/Makefile
drivers/isdn/hisax/arcofi.c
drivers/isdn/hisax/arcofi.h
drivers/isdn/hisax/asuscom.c
drivers/isdn/hisax/avm_a1.c
drivers/isdn/hisax/avm_a1p.c [new file with mode: 0644]
drivers/isdn/hisax/avm_pci.c [new file with mode: 0644]
drivers/isdn/hisax/callc.c
drivers/isdn/hisax/cert.c [new file with mode: 0644]
drivers/isdn/hisax/config.c
drivers/isdn/hisax/diva.c
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
drivers/isdn/hisax/hfc_2bs0.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hscx.c
drivers/isdn/hisax/hscx.h
drivers/isdn/hisax/hscx_irq.c
drivers/isdn/hisax/ipac.h
drivers/isdn/hisax/isac.c
drivers/isdn/hisax/isac.h
drivers/isdn/hisax/isar.c [new file with mode: 0644]
drivers/isdn/hisax/isar.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
drivers/isdn/hisax/lmgr.c
drivers/isdn/hisax/md5sums.asc [new file with mode: 0644]
drivers/isdn/hisax/mic.c
drivers/isdn/hisax/netjet.c
drivers/isdn/hisax/niccy.c
drivers/isdn/hisax/q931.c
drivers/isdn/hisax/rawhdlc.c
drivers/isdn/hisax/s0box.c [new file with mode: 0644]
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/sportster.c
drivers/isdn/hisax/tei.c
drivers/isdn/hisax/teleint.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/teles3.c
drivers/isdn/hisax/teles3c.c
drivers/isdn/hisax/telespci.c [new file with mode: 0644]
drivers/isdn/icn/icn.c
drivers/isdn/icn/icn.h
drivers/isdn/isdn_audio.c
drivers/isdn/isdn_audio.h
drivers/isdn/isdn_bsdcomp.c [new file with mode: 0644]
drivers/isdn/isdn_budget.c [new file with mode: 0644]
drivers/isdn/isdn_cards.c
drivers/isdn/isdn_cards.h
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_concap.c
drivers/isdn/isdn_net.c
drivers/isdn/isdn_net.h
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_ppp.h
drivers/isdn/isdn_timru.c [new file with mode: 0644]
drivers/isdn/isdn_tty.c
drivers/isdn/isdn_tty.h
drivers/isdn/isdn_x25iface.c
drivers/isdn/isdnloop/isdnloop.c
drivers/isdn/isdnloop/isdnloop.h
drivers/isdn/pcbit/callbacks.c
drivers/isdn/pcbit/drv.c
drivers/isdn/pcbit/pcbit.h
drivers/isdn/sc/message.c
drivers/misc/parport_init.c
drivers/misc/parport_pc.c
drivers/misc/parport_share.c
drivers/net/Space.c
drivers/net/arcnet.c
drivers/net/hamradio/bpqether.c
drivers/net/lapbether.c
drivers/net/net_init.c
drivers/net/strip.c
drivers/scsi/README.st
drivers/scsi/st.c
drivers/scsi/st.h
drivers/sound/es1370.c
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/inits.h
drivers/usb/keymap.c
drivers/usb/maps/fixup.map
drivers/usb/mouse.c
drivers/usb/ohci-hcd.c
drivers/usb/printer.c [new file with mode: 0644]
drivers/usb/uhci-debug.c
drivers/usb/uhci.c
drivers/usb/usb-debug.c
drivers/usb/usb.c
drivers/usb/usb.h
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/efs/.cvsignore [deleted file]
fs/open.c
fs/select.c
fs/stat.c
include/asm-alpha/processor.h
include/asm-alpha/semaphore.h
include/asm-arm/processor.h
include/asm-i386/processor.h
include/asm-i386/softirq.h
include/asm-i386/spinlock.h
include/asm-i386/system.h
include/asm-m68k/processor.h
include/asm-mips/processor.h
include/asm-ppc/ide.h
include/asm-ppc/mmu.h
include/asm-ppc/pgtable.h
include/asm-ppc/processor.h
include/asm-ppc/ptrace.h
include/asm-ppc/semaphore.h
include/asm-ppc/system.h
include/asm-sparc/processor.h
include/asm-sparc64/processor.h
include/asm-sparc64/softirq.h
include/asm-sparc64/spinlock.h
include/linux/b1lli.h
include/linux/blkpg.h
include/linux/cyclades.h
include/linux/i2c.h
include/linux/isdn.h
include/linux/isdn_budget.h [new file with mode: 0644]
include/linux/isdn_lzscomp.h [new file with mode: 0644]
include/linux/isdn_ppp.h
include/linux/isdn_timru.h [new file with mode: 0644]
include/linux/isdnif.h
include/linux/lp.h
include/linux/netdevice.h
include/linux/pagemap.h
include/linux/parport.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/wait.h
include/net/route.h
include/net/sock.h
include/net/tcp.h
kernel/ksyms.c
kernel/signal.c
kernel/time.c
mm/filemap.c
mm/mmap.c
net/core/dev.c
net/core/dev_mcast.c
net/core/rtnetlink.c
net/core/sock.c
net/ethernet/eth.c
net/ipv4/af_inet.c
net/ipv4/devinet.c
net/ipv4/fib_rules.c
net/ipv4/igmp.c
net/ipv4/ipconfig.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/timer.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/mcast.c
net/ipv6/proc.c
net/ipv6/raw.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/netrom/nr_route.c
net/netsyms.c
net/rose/rose_route.c
net/sched/sch_api.c
net/sched/sch_generic.c
net/socket.c
net/unix/af_unix.c
net/x25/af_x25.c

diff --git a/CREDITS b/CREDITS
index bd305c7fee8dcc4fba1eabad25bb5f35f501ca73..ce6898a791ab6aeb008819ecd919704d859f4e69 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -767,11 +767,8 @@ S: 5623 HZ Eindhoven
 S: The Netherlands
 
 N: Kai Harrekilde-Petersen
-E: khp@dolphinics.no
+E: khp@olicom.dk
 D: Original author of the ftape-HOWTO, i82078 fdc detection code.
-S: Peder Holters vei 13
-S: 1168 Oslo
-S: Norway
 
 N: Andrew Haylett
 E: ajh@primag.co.uk
@@ -1439,8 +1436,8 @@ S: D-37083 Goettingen
 S: Germany
 
 N: David Mosberger-Tang
-E: David.Mosberger@acm.org
-D: Linux/Alpha
+E: davidm@hpl.hp.com if IA-64 related, else David.Mosberger@acm.org
+D: Linux/Alpha and Linux/ia64
 S: 35706 Runckel Lane
 S: Fremont, California 94536
 S: USA
diff --git a/Documentation/isdn/HiSax.cert b/Documentation/isdn/HiSax.cert
new file mode 100644 (file)
index 0000000..b1f8aaa
--- /dev/null
@@ -0,0 +1,76 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+
+First:
+
+    HiSax is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+However, if you wish to modify the HiSax sources, please note the following:
+
+HiSax has passed the ITU approval test suite with ELSA Quickstep ISDN cards.
+The certification is only valid for the combination of the tested software
+version and the tested hardware. Any changes to the HiSax source code may
+therefore affect the certification.
+
+If you change the main files of the HiSax ISDN stack, the certification will
+become invalid. Because in most countries it is illegal to connect
+unapproved ISDN equipment to the public network, I have to guarantee that
+changes in HiSax do not affect the certification.
+
+In order to make a valid certification apparent to the user, I have built in
+some validation checks that are made during the make process. The HiSax main
+files are protected by md5 checksums and the md5sum file is pgp signed by
+myself:
+
+KeyID 1024/FF992F6D 1997/01/16 Karsten Keil <keil@temic-ech.spacenet.de>
+Key fingerprint = 92 6B F7 58 EE 86 28 C8  C4 1A E6 DC 39 89 F2 AA
+
+Only if the checksums are OK, and the signature of the file
+"drivers/isdn/hisax/md5sums.asc" match, is the certification valid; a
+message confirming this is then displayed during the hisax init process.
+
+The affected files are:
+
+drivers/isdn/hisax/isac.c
+drivers/isdn/hisax/isdnl1.c
+drivers/isdn/hisax/isdnl2.c
+drivers/isdn/hisax/isdnl3.c
+drivers/isdn/hisax/tei.c
+drivers/isdn/hisax/callc.c
+drivers/isdn/hisax/l3dss1.c
+drivers/isdn/hisax/l3_1tr6.c
+drivers/isdn/hisax/cert.c
+drivers/isdn/hisax/elsa.c
+
+Please send any changes, bugfixes and patches to me rather than implementing
+them directly into the HiSax sources.
+
+This does not reduce your rights granted by the GNU General Public License.
+If you wish to change the sources, go ahead; but note that then the
+certification is invalid even if you use ELSA Quickstep cards.
+
+Here are the certification registration numbers for ELSA Quickstep cards:
+German   D133361J CETECOM ICT Services GmbH 0682
+European D133362J CETECOM ICT Services GmbH 0682
+
+
+Karsten Keil
+keil@isdn4linux.de
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.3i
+Charset: noconv
+
+iQCVAwUBNj5OKDpxHvX/mS9tAQFHuQP/WeImlqCcDZ2d132yAvRBWFULlJoSf1P/
+c1lVTeaWvsSaY5Cu9hrKhXXhPzeEaitUbcUBPXdpzFWCA5CE902lnz7AhgRC+HF1
+0qiKgkZZyc/5HKasFymR1+IWSLw30GesP3Di/ZMR3NJi8SlY9PIjx7hnEMunGSRO
+1ufPvfWWuu8=
+=nGJk
+-----END PGP SIGNATURE-----
index cf938f67f0b45ed1ff90afd7157a4a6828b5f52d..213136b5549f807c2586ac2454ef9f3036fc9cef 100644 (file)
@@ -1,4 +1,4 @@
-$Id: INTERFACE,v 1.8 1998/02/20 17:38:20 fritz Exp $
+$Id: INTERFACE,v 1.11 1999/03/02 12:14:51 armin Exp $
 
 Description of the Interface between Linklevel and Hardwarelevel
   of isdn4linux:
@@ -478,6 +478,14 @@ Description of the Interface between Linklevel and Hardwarelevel
       1           = At least one device matching this call (RING on ttyI).
                     HL-driver may send ALERTING on the D-channel in this case.
       2           = Call will be rejected.
+      3           = Incomplete number.
+                    The CalledNumber would match, if more digits are appended.
+                    This feature is needed for Number-Blocks assigned to
+                    a line. In this case, the LL driver should assemble the
+                                       CalledNumber by handling keypad protocol and try again
+                                       later with a longer CalledNumber.
+                                       HL drivers serving ordinary lines should interpret this
+                                       return code like 0 (nothing matches).
       -1          = An error happened. (Invalid parameters for example.)
 
   ISDN_STAT_RUN:
@@ -526,7 +534,9 @@ Description of the Interface between Linklevel and Hardwarelevel
       driver      = driver-Id
       command     = ISDN_STAT_BCONN
       arg         = channel-number, locally to the driver. (starting with 0)
-      para        = unused.
+      para.num    = ASCII-String, containing type of connection (for analog
+                   modem only). This will be appended to the CONNECT message
+                   e.g. 14400/V.32bis
 
   ISDN_STAT_DHUP:
 
index 1b226ada6580fdd7fc544ffd100fab0f0ebb9b38..7b17183e069cf701c31df3dc6996f3cf528aa35a 100644 (file)
@@ -31,7 +31,7 @@ README for the ISDN-subsystem
    This mailinglist is bidirectionally gated to the newsgroup
 
      de.alt.comm.isdn4linux
-   
+
   There is also a well maintained FAQ (both english and german) available
   at ftp.franken.de in /pub/isdn4linux/FAQ/
   This FAQ is also available at http://www.lrz-muenchen.de/~ui161ab/www/isdn/
@@ -41,11 +41,11 @@ README for the ISDN-subsystem
   In the following Text, the terms MSN and EAZ are used.
 
   MSN is the abbreviation for (M)ultiple(S)ubscriber(N)umber, and applies
-  to Euro(EDSS1)-type lines. Usually it is simply the phone-number.
+  to Euro(EDSS1)-type lines. Usually it is simply the phone number.
 
   EAZ is the abbreviation of (E)ndgeraete(A)uswahl(Z)iffer and
   applies to German 1TR6-type lines. This is a one-digit string,
-  simply appended to the base phone-number
+  simply appended to the base phone number
 
   The internal handling is nearly identical, so replace the appropriate
   term to that one, which applies to your local ISDN-environment.
@@ -56,13 +56,13 @@ README for the ISDN-subsystem
   A low-level-driver can register itself through an interface (which is
   defined in isdnif.h) and gets assigned a slot.
   The following char-devices are made available for each channel:
-  
+
   A raw-control-device with the following functions:
      write: raw D-channel-messages (format: depends on driver).
      read:  raw D-channel-messages (format: depends on driver).
      ioctl: depends on driver, i.e. for the ICN-driver, the base-address of
             the ports and the shared memory on the card can be set and read
-            also the boot-code and the protocol software can be loaded into 
+            also the boot-code and the protocol software can be loaded into
             the card.
 
    O N L Y !!!  for debugging (no locking against other devices):
@@ -74,38 +74,38 @@ README for the ISDN-subsystem
 
    128 tty-devices (64 cuix and 64 ttyIx) with integrated modem-emulator:
    The functionality is almost the same as that of a serial device
-   (the line-discs are handled by the kernel), which lets you run 
-   SLIP, CSLIP and asynchronous PPP through the devices. We have tested 
+   (the line-discs are handled by the kernel), which lets you run
+   SLIP, CSLIP and asynchronous PPP through the devices. We have tested
    Seyon, minicom, CSLIP (uri-dip) PPP and mgetty (compiled with NO_FAX),
    XCept.
 
    The modem-emulation supports the following:
            1.3.1 Commands:
 
-               ATA     Answer incoming call.
-              ATD<No.> Dial, the number may contain:
+               ATA      Answer incoming call.
+               ATD<No.> Dial, the number may contain:
                         [0-9] and [,#.*WPT-S]
                         the latter are ignored until 'S'.
-                        The 'S' must precede the number, if 
+                        The 'S' must precede the number, if
                         the line is a SPV (German 1TR6).
-               ATE0    Echo off.
-              ATE1     Echo on (default).
+               ATE0     Echo off.
+               ATE1     Echo on (default).
                ATH      Hang-up.
-              ATH1     Off hook (ignored).
+               ATH1     Off hook (ignored).
                ATH0     Hang-up.
-              ATI      Return "ISDN for Linux...".
+               ATI      Return "ISDN for Linux...".
                ATI0        "
                ATI1        "
-              ATI2     Report of last connection.
+               ATI2     Report of last connection.
                ATO      On line (data mode).
                ATQ0     Enable result codes (default).
                ATQ1     Disable result codes (default).
-               ATSx=y  Set register x to y.
-              ATSx?    Show contents of register x.
+               ATSx=y   Set register x to y.
+               ATSx?    Show contents of register x.
                ATV0     Numeric responses.
                ATV1     English responses (default).
-              ATZ      Load registers and EAZ/MSN from Profile.
-              AT&Bx    Set Send-Packet-size to x (max. 4000)
+               ATZ      Load registers and EAZ/MSN from Profile.
+               AT&Bx    Set Send-Packet-size to x (max. 4000)
                         The real packet-size may be limited by the
                         low-level-driver used. e.g. the HiSax-Module-
                         limit is 2000. You will get NO Error-Message,
@@ -114,13 +114,13 @@ README for the ISDN-subsystem
                         driver may not be selected (see "Automatic
                         Assignment") however the size of outgoing packets
                         will be limited correctly.
-              AT&D0    Ignore DTR
-              AT&D2    DTR-low-edge: Hang up and return to 
+               AT&D0    Ignore DTR
+               AT&D2    DTR-low-edge: Hang up and return to
                         command mode (default).
                AT&D3    Same as AT&D2 but also resets all registers.
-              AT&Ex    Set the EAZ/MSN for this channel to x.
-              AT&F     Reset all registers and profile to "factory-defaults"
-              AT&Rx    Select V.110 bitrate adaption.
+               AT&Ex    Set the EAZ/MSN for this channel to x.
+               AT&F     Reset all registers and profile to "factory-defaults"
+               AT&Rx    Select V.110 bitrate adaption.
                         This command enables V.110 protocol with 9600 baud
                         (x=9600), 19200 baud (x=19200) or 38400 baud
                         (x=38400). A value of x=0 disables V.110 switching
@@ -142,24 +142,24 @@ README for the ISDN-subsystem
                             The value 198 is choosen arbitrarily. Users
                             _MUST_ negotiate this value before establishing
                             a connection.
-              AT&Sx    Set window-size (x = 1..8) (not yet implemented)
-              AT&V     Show all settings.
+               AT&Sx    Set window-size (x = 1..8) (not yet implemented)
+               AT&V     Show all settings.
                AT&W0    Write registers and EAZ/MSN to profile. See also
                         iprofd (5.c in this README).
-               AT&X0   BTX-mode and T.70-mode off (default)
-              AT&X1    BTX-mode on. (S13.1=1, S13.5=0 S14=0, S16=7, S18=7, S19=0)
-              AT&X2    T.70-mode on. (S13.1=1, S13.5=1, S14=0, S16=7, S18=7, S19=0)
+               AT&X0    BTX-mode and T.70-mode off (default)
+               AT&X1    BTX-mode on. (S13.1=1, S13.5=0 S14=0, S16=7, S18=7, S19=0)
+               AT&X2    T.70-mode on. (S13.1=1, S13.5=1, S14=0, S16=7, S18=7, S19=0)
 
            For voice-mode commands refer to README.audio
 
-          1.3.2 Escape sequence:
+           1.3.2 Escape sequence:
                During a connection, the emulation reacts just like
                a normal modem to the escape sequence <DELAY>+++<DELAY>.
-              (The escape character - default '+' - can be set in the
+               (The escape character - default '+' - can be set in the
                register 2).
-               The DELAY must at least be 1.5 seconds long and delay 
+               The DELAY must at least be 1.5 seconds long and delay
                between the escape characters must not exceed 0.5 seconds.
-     
+
            1.3.3 Registers:
 
               Nr.  Default  Description
@@ -172,7 +172,7 @@ README for the ISDN-subsystem
               4    10       Line feed character (ASCII).
               5    8        Backspace character (ASCII).
               6    3        Delay in seconds before dialing.
-              7    60       Wait for carrier (ignored).
+              7    60       Wait for carrier.
               8    2        Pause time for comma (ignored)
               9    6        Carrier detect time (ignored)
              10    7        Carrier loss to disconnect time (ignored).
@@ -203,8 +203,8 @@ README for the ISDN-subsystem
                                       1 = T.70 protocol (Only for BTX!) on
                             Bit 2:    0 = Don't hangup on DTR low.
                                       1 = Hangup on DTR low.
-                           Bit 3:    0 = Standard response messages
-                                     1 = Extended response messages
+                            Bit 3:    0 = Standard response messages
+                                      1 = Extended response messages
                             Bit 4:    0 = CALLER NUMBER before every RING.
                                       1 = CALLER NUMBER after first RING.
                             Bit 5:    0 = T.70 extended protocol off
@@ -215,18 +215,19 @@ README for the ISDN-subsystem
                                           an incoming call happened (RING) and
                                           the remote party hung up before any
                                           local ATA was given.
-            14   0         Layer-2 protocol:
-                                     0 = X75/LAPB with I-frames
-                                     1 = X75/LAPB with UI-frames
+             14   0         Layer-2 protocol:
+                                      0 = X75/LAPB with I-frames
+                                      1 = X75/LAPB with UI-frames
                                       2 = X75/LAPB with BUI-frames
                                       3 = HDLC
                                       4 = Transparent (audio)
                                       7 = V.110, 9600 baud
                                       8 = V.110, 19200 baud
                                       9 = V.110, 38400 baud
+                                     10 = Analog Modem (only if hardware supports this)
              15   0         Layer-3 protocol: (at the moment always 0)
                                       0 = transparent
-            16   250       Send-Packet-size/16
+             16   250       Send-Packet-size/16
              17   8         Window-size (not yet implemented)
              18   4         Bit coded register, Service-Octet-1 to accept,
                             or to be used on dialout:
@@ -262,7 +263,7 @@ README for the ISDN-subsystem
 
   All inactive physical lines are listening to all EAZs for incoming
   calls and are NOT assigned to a specific tty or network interface.
-  When an incoming call is detected, the driver looks first for a network 
+  When an incoming call is detected, the driver looks first for a network
   interface and then for an opened tty which:
 
   1. is configured for the same EAZ.
@@ -270,7 +271,7 @@ README for the ISDN-subsystem
   3. (only for network interfaces if the security flag is set)
      contains the caller number in its access list.
   4. Either the channel is not bound exclusively to another Net-interface, or
-     it is bound AND the other checks apply to exactly this Interface.
+     it is bound AND the other checks apply to exactly this interface.
      (For usage of the bind-features, refer to the isdnctrl-man-page)
 
   Only when a matching interface or tty is found is the call accepted
@@ -301,7 +302,7 @@ README for the ISDN-subsystem
   Always use the latest module utilities. The current version is
   named in Documentation/Changes. Some old versions of insmod
   are not capable of setting the driver-Ids correctly.
+
 3. Lowlevel-driver configuration.
 
    Configuration depends on how the drivers are built. See the
@@ -310,7 +311,7 @@ README for the ISDN-subsystem
 4. Device-inodes
 
    The major and minor numbers and their names are described in
-   Documentation/devices.txt. The major-numbers are:
+   Documentation/devices.txt. The major numbers are:
 
      43 for the ISDN-tty's.
      44 for the ISDN-callout-tty's.
@@ -350,45 +351,64 @@ README for the ISDN-subsystem
    g) Set the timeout for hang-up:
        isdnctrl huptimeout isdn0 <timeout_in_seconds>
 
-   h) additionally you may activate charge-hang-up (= Hang up before 
+   h) additionally you may activate charge-hang-up (= Hang up before
       next charge-info, this only works, if your isdn-provider transmits
       the charge-info during and after the connection):
        isdnctrl chargehup isdn0 on
 
-   i) Setup the interface with ifconfig as usual, and set a route to it.
-
-   j) (optional) If you run X11 and have Tcl/Tk-wish Version 4.0, you can use
+   i) Set the dial mode of the interface:
+       isdnctrl dialmode isdn0 auto
+      "off" means that you (or the system) cannot make any connection
+        (neither incoming or outgoing connections are possible). Use
+        this if you want to be sure that no connections will be made.
+      "auto" means that the interface is in auto-dial mode, and will
+        attempt to make a connection whenever a network data packet needs
+        the interface's link. Note that this can cause unexpected dialouts,
+        and lead to a high phone bill! Some daemons or other pc's that use
+        this interface can cause this.
+        Incoming connections are also possible.
+      "manual" is a dial mode created to prevent the unexpected dialouts.
+        In this mode, the interface will never make any connections on its
+        own. You must explicitly initiate a connection with "isdnctrl dial
+        isdn0". However, after an idle time of no traffic as configured for
+       the huptimeout value with isdnctrl, the connection _will_ be ended.
+       If you don't want any automatic hangup, set the huptimeout value to 0.
+        "manual" is the default.
+
+   j) Setup the interface with ifconfig as usual, and set a route to it.
+
+   k) (optional) If you run X11 and have Tcl/Tk-wish version 4.0, you can use
      the script tools/tcltk/isdnmon. You can add actions for line-status
      changes. See the comments at the beginning of the script for how to
      do that. There are other tty-based tools in the tools-subdirectory
      contributed by Michael Knigge (imon), Volker Götz (imontty) and
      Andreas Kool (isdnmon).
 
-   k) For initial testing, you can set the verbose-level to 2 (default: 0).
+   l) For initial testing, you can set the verbose-level to 2 (default: 0).
       Then all incoming calls are logged, even if they are not addressed
       to one of the configured net-interfaces:
       isdnctrl verbose 2
 
-  Now you are ready! A ping to the set address should now result in a
-  dial-out (look at syslog kernel-messages).
-  The phone-numbers and EAZs can be assigned at any time with isdnctrl.
+  Now you are ready! A ping to the set address should now result in an
+  automatic dial-out (look at syslog kernel-messages).
+  The phone numbers and EAZs can be assigned at any time with isdnctrl.
   You can add as many interfaces as you like with addif following the
-  directions above. Of course, there may be some limitations. But we have 
-  tested as many as 20 interfaces without any problem. However, if you 
-  don't give an interface name to addif, the  kernel will assign a name 
+  directions above. Of course, there may be some limitations. But we have
+  tested as many as 20 interfaces without any problem. However, if you
+  don't give an interface name to addif, the  kernel will assign a name
   which starts with "eth". The number of "eth"-interfaces is limited by
   the kernel.
 
 5. Additional options for isdnctrl:
 
-   "isdnctrl secure <InterfaceName> on" 
+   "isdnctrl secure <InterfaceName> on"
    Only incoming calls, for which the caller-id is listed in the access
    list of the interface are accepted. You can add caller-id's With the
    command "isdnctrl addphone <InterfaceName> in <caller-id>"
    Euro-ISDN does not transmit the leading '0' of the caller-id for an
    incoming call, therefore you should configure it accordingly.
    If the real number for the dialout e.g. is "09311234567" the number
-   to configure here is "9311234567". The pattern-match function 
+   to configure here is "9311234567". The pattern-match function
    works similar to the shell mechanism.
 
      ?     one arbitrary digit
@@ -398,23 +418,23 @@ README for the ISDN-subsystem
            a '^' as the first character in a list inverts the list
 
 
-   "isdnctrl secure <InterfaceName> off" 
+   "isdnctrl secure <InterfaceName> off"
    Switch off secure operation (default).
 
-   "isdnctrl ihup <InterfaceName> [on|off]" 
+   "isdnctrl ihup <InterfaceName> [on|off]"
    Switch the hang-up-timer for incoming calls on or off.
 
-   "isdnctrl eaz <InterfaceName>" 
+   "isdnctrl eaz <InterfaceName>"
    Returns the EAZ of an interface.
 
-   "isdnctrl delphone <InterfaceName> in|out <number>" 
+   "isdnctrl delphone <InterfaceName> in|out <number>"
    Deletes a number from one of the access-lists of the interface.
 
-   "isdnctrl delif <InterfaceName>" 
+   "isdnctrl delif <InterfaceName>"
    Removes the interface (and possible slaves) from the kernel.
    (You have to unregister it with "ifconfig <InterfaceName> down" before).
 
-   "isdnctrl callback <InterfaceName> [on|off]" 
+   "isdnctrl callback <InterfaceName> [on|off]"
    Switches an interface to callback-mode. In this mode, an incoming call
    will be rejected and after this the remote-station will be called. If
    you test this feature by using ping, some routers will re-dial very
@@ -435,14 +455,14 @@ README for the ISDN-subsystem
    only while an interface is down.
 
    At the moment the following values are supported:
+
    rawip    (Default) Selects raw-IP-encapsulation. This means, MAC-headers
-            are stripped off.  
+            are stripped off.
    ip       IP with type-field. Same as IP but the type-field of the MAC-header
             is preserved.
    x25iface X.25 interface encapsulation (first byte semantics as defined in
-           ../networking/x25-iface.txt). Use this for running the linux
-           X.25 network protocol stack (AF_X25 sockets) on top of isdn.
+            ../networking/x25-iface.txt). Use this for running the linux
+            X.25 network protocol stack (AF_X25 sockets) on top of isdn.
    cisco-h  A special-mode for communicating with a Cisco, which is configured
             to do "hdlc"
    ethernet No stripping. Packets are sent with full MAC-header.
@@ -454,7 +474,7 @@ README for the ISDN-subsystem
 
 
    NOTE:    x25iface encapsulation is currently experimental. Please
-           read README.x25 for further details    
+            read README.x25 for further details
 
 
    Watching packets, using standard-tcpdump will fail for all encapsulations
@@ -462,16 +482,16 @@ README for the ISDN-subsystem
    without MAC-header. A patch for tcpdump is included in the utility-package
    mentioned above.
 
-   "isdnctrl l2_prot <InterfaceName> <L2-ProtocolName>" 
-   Selects a layer-2-protocol. 
+   "isdnctrl l2_prot <InterfaceName> <L2-ProtocolName>"
+   Selects a layer-2-protocol.
    (With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available.
    With other drivers, "x75ui", "x75bui", "x25dte", "x25dce" may be
    possible too. See README.x25 for x25 related l2 protocols.)
 
-   isdnctrl l3_prot <InterfaceName> <L3-ProtocolName> 
+   isdnctrl l3_prot <InterfaceName> <L3-ProtocolName>
    The same for layer-3. (At the moment only "trans" is allowed)
 
-   "isdnctrl list <InterfaceName>" 
+   "isdnctrl list <InterfaceName>"
    Shows all parameters of an interface and the charge-info.
    Try "all" as the interface name.
 
@@ -479,13 +499,13 @@ README for the ISDN-subsystem
    Forces hangup of an interface.
 
    "isdnctrl bind <InterfaceName> <DriverId>,<ChannelNumber> [exclusive]"
-   If you are using more than one ISDN-Card, it is sometimes necessary to
-   dial out using a specific Card or even preserve a specific Channel for
-   Dialout of a specific net-interface. This can be done with the above
+   If you are using more than one ISDN card, it is sometimes necessary to
+   dial out using a specific card or even preserve a specific channel for
+   dialout of a specific net-interface. This can be done with the above
    command. Replace <DriverId> by whatever you assigned while loading the
-   module. The <ChannelNumber> is counting from zero. The upper Limit
-   depends on the card used. At the Moment no card supports more than
-   2 Channels, so the upper limit is one.
+   module. The <ChannelNumber> is counted from zero. The upper limit
+   depends on the card used. At the moment no card supports more than
+   2 channels, so the upper limit is one.
 
    "isdnctrl unbind <InterfaceName>"
    unbinds a previously bound interface.
@@ -494,10 +514,10 @@ README for the ISDN-subsystem
    If switched on, isdn4linux replies a REJECT to incoming calls, it
    cannot match to any configured interface.
    If switched off, nothing happens in this case.
-   You normally should NOT enable this feature, if the ISDN-adaptor is not
-   the only device, connected to the S0-bus. Otherwise it could happen, that
+   You normally should NOT enable this feature, if the ISDN adapter is not
+   the only device connected to the S0-bus. Otherwise it could happen that
    isdn4linux rejects an incoming call, which belongs to another device on
-   the bus. 
+   the bus.
 
    "isdnctrl addslave <InterfaceName> <SlaveName>
    Creates a slave interface for channel-bundling. Slave interfaces are
@@ -539,9 +559,9 @@ README for the ISDN-subsystem
    isdnctrl eaz isdn1 4      # listen on 12345674(1tr6) only.
    ...
    isdnctrl eaz isdn2 987654 # listen on 987654(euro) only.
-   
+
    Same scheme is used with AT&E...  at the tty's.
-  
+
 6. If you want to write a new low-level-driver, you are welcome.
    The interface to the link-level-module is described in the file INTERFACE.
    If the interface should be expanded for any reason, don't do it
index 4b49e0939b23f71a12edc7c078aecd47a50bc1b8..9f48e71e6edebb576691afb319a175d620a43f82 100644 (file)
@@ -1,7 +1,7 @@
 HiSax is a Linux hardware-level driver for passive ISDN cards with Siemens
 chipset (ISAC_S 2085/2086/2186, HSCX SAB 82525). It is based on the Teles
 driver from Jan den Ouden.
-It is meant to be used with isdn4linux, an ISDN link-level module for Linux 
+It is meant to be used with isdn4linux, an ISDN link-level module for Linux
 written by Fritz Elfert.
 
     This program is free software; you can redistribute it and/or modify
@@ -25,24 +25,33 @@ Supported cards
 Teles 8.0/16.0/16.3 and compatible ones
 Teles 16.3c
 Teles S0/PCMCIA
-Creatix PnP S0 
+Teles PCI
+Teles S0Box
+Creatix S0Box
+Creatix PnP S0
 Compaq ISDN S0 ISA card
 AVM A1 (Fritz, Teledat 150)
+AVM Fritz PCMCIA
+AVM Fritz PnP
+AVM Fritz PCI
 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)
+PCBIT-DP (OEM version of ASUSCOM NETWORK INC. ISDNLink)
 HFC-2BS0 based cards (TeleInt SA1)
-Sedlbauer Speed Card (Speed Win, Teledat 100)
-Sedlbauer Speed Star (PCMCIA)
+Sedlbauer Speed Card (Speed Win, Teledat 100, PCI, Fax+)
+Sedlbauer Speed Star/Speed Star2 (PCMCIA)
+Sedlbauer ISDN-Controller PC/104
 USR Sportster internal TA (compatible Stollmann tina-pp V3)
-ith Kommunikationstechnik GmbH MIC 16 ISA card 
+ith Kommunikationstechnik GmbH MIC 16 ISA card
 Traverse Technologie NETjet PCI S0 card
 Dr. Neuhaus Niccy PnP/PCI
 
@@ -50,6 +59,8 @@ 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.
@@ -113,7 +124,7 @@ The parameter for the D-Channel protocol may be omitted if you selected the
 correct one during kernel config. Valid values are "1" for German 1TR6,
 "2" for EDSS1 (Euro ISDN) and "3" for leased lines (no D-Channel).
 
-The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying 
+The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying
 the I/O addresses of the ISAC and HSCX chips, respectively.
 
 Card types:
@@ -135,24 +146,29 @@ Card types:
    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  
+   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  
+   15   Sedlbauer Speed Card     irq, io
+   15   Sedlbauer PC/104         irq, io
+   15   Sedlbauer Speed PCI     no parameter
+   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)
+   26   AVM A1 PCMCIA (Fritz!)   irq, io (set with card manager)
+   27   AVM PnP (Fritz!PnP)      irq, io  (from isapnp setup)
+   27   AVM PCI (Fritz!PCI)      no parameter
+   28   Sedlbauer Speed Fax+     irq, io (from isapnp setup)
 
 
-        
-At the moment IRQ sharing is not possible. Please make sure that your IRQ
-is free and enabled for ISA use.
-Note: For using the ELSA PCMCIA you need the cardmanager under MSDOS for
-enabling at the moment, then boot linux with loadlin.
+At the moment IRQ sharing is only possible with PCI cards. Please make sure
+that your IRQ is free and enabled for ISA use.
 
 
 Examples for module loading
@@ -169,7 +185,7 @@ Examples for module loading
 4. Any ELSA PCC/PCF card, Euro ISDN
    modprobe hisax type=6 protocol=2
 
-5. Teles 16.3 PnP, Euro ISDN, with isapnp configured 
+5. Teles 16.3 PnP, Euro ISDN, with isapnp configured
    isapnp config:  (INT 0 (IRQ 10 (MODE +E)))
                   (IO 0 (BASE 0x0580))
                    (IO 1 (BASE 0x0180))
@@ -210,8 +226,8 @@ where
                 Note: the ID string must start with an alphabetical character!
 
 Card types:
-       
-  type  
+
+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
@@ -227,22 +243,33 @@ Card types:
    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 !)  
+   15  Sedlbauer Speed Card    pa=irq  pb=io (Speed Win only as module !)
+   15   Sedlbauer PC/104        pa=irq  pb=io
+   15   Sedlbauer Speed PCI    no parameter
    16   USR Sportster internal  pa=irq  pb=io
    17   MIC card                pa=irq  pb=io
    18   ELSA Quickstep 1000PCI  no parameter
    19   Compaq ISDN S0 ISA card ONLY WORKS AS A MODULE !
    20   NETjet PCI card         no parameter
-   21   Sedlbauer Speed Star (PCMCIA)  pa=irq, pb=io  (set with card manager)
+   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)
+   26   AVM A1 PCMCIA (Fritz!)  irq, io (set with card manager)
+   27   AVM PnP (Fritz!PnP)     ONLY WORKS AS A MODULE !
+   27   AVM PCI (Fritz!PCI)     no parameter
+   28   Sedlbauer Speed Fax+    ONLY WORKS AS A MODULE !
+
 
 Running the driver
 ------------------
 
-When you insmod isdn.o and hisax.o (or with the in-kernel version, during 
+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)
@@ -257,7 +284,7 @@ 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 some ELSA cards can 
+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
@@ -265,8 +292,7 @@ from within isdn4linux, you should also define a driver ID while doing
 insmod: Simply append hisax_id=<SomeString> to the insmod command line. This
 string MUST NOT start with a digit or a small 'x'!
 
-At this point you can run a 'cat /dev/isdnctrl0' and view debugging 
-messages. 
+At this point you can run a 'cat /dev/isdnctrl0' and view debugging messages.
 
 At the moment, debugging messages are enabled with the hisaxctrl tool:
 
@@ -283,28 +309,35 @@ options you wish enabled:
 
 With DebugCmd set to 1:
 
-         1  Link-level <--> hardware-level communication
-         2  Top state machine
-         4  D-Channel Q.931 (call control messages)
-         8  D-Channel Q.921
-        16  B-Channel X.75
-        32  D-Channel l2
-        64  B-Channel l2
-       128  D-Channel link state debugging
-       256  B-Channel link state debugging
-       512  TEI debug
-      1024  LOCK debug in callc.c
-      2048  More paranoid debug in callc.c (not for normal use)
+   0x0001  Link-level <--> hardware-level communication
+   0x0002  Top state machine
+   0x0004  D-Channel Frames for isdnlog
+   0x0008  D-Channel Q.921
+   0x0010  B-Channel X.75
+   0x0020  D-Channel l2
+   0x0040  B-Channel l2
+   0x0080  D-Channel link state debugging
+   0x0100  B-Channel link state debugging
+   0x0200  TEI debug
+   0x0400  LOCK debug in callc.c
+   0x0800  More paranoid debug in callc.c (not for normal use)
+   0x1000  D-Channel l1 state debugging
+   0x2000  B-Channel l1 state debugging
 
 With DebugCmd set to 11:
 
-         1  Warnings (default: on)
-         2  IRQ status
-         4  ISAC
-         8  ISAC FIFO
-        16  HSCX
-        32  HSCX FIFO (attention: full B-Channel output!)
-        64  D-Channel LAPD frame types
+   0x0001  Warnings (default: on)
+   0x0002  IRQ status
+   0x0004  ISAC
+   0x0008  ISAC FIFO
+   0x0010  HSCX
+   0x0020  HSCX FIFO (attention: full B-Channel output!)
+   0x0040  D-Channel LAPD frame types
+   0x0080  IPAC debug
+   0x0100  HFC receive debug
+   0x0200  ISAC monitor debug
+   0x0400  D-Channel frames for isdnlog (set with 1 0x4 too)
+   0x0800  D-Channel message verbose
 
 With DebugCmd set to 13:
 
@@ -317,27 +350,39 @@ For example, 'hisaxctrl HiSax 1 0x3ff' enables full generic debugging.
 
 Because of some obscure problems with some switch equipment, the delay
 between the CONNECT message and sending the first data on the B-channel is now
-configurable with 
+configurable with
 
 hisaxctrl <DriverId> 2 <delay>
 <delay> in ms Value between 50 and 800 ms is recommended.
 
+Downloading Firmware
+--------------------
+At the moment, the Sedlbauer speed fax+ is the only card, which
+needs to download firmware.
+The firmware is downloaded with the hisaxctrl tool:
+
+    hisaxctrl <DriverId> 9 <firmware_filename>
+
+<DriverId> default is HiSax, if you didn't specify one,
+
+where <firmware_filename> is the filename of the firmware file.
+
+For example, 'hisaxctrl HiSax 9 ISAR.BIN' downloads the firmware for
+ISAR based cards (like the Sedlbauer speed fax+).
 
 Warning
 -------
-HiSax is a work in progress and may crash your machine. It has not been
-certified and therefore operation on your PTT's ISDN network is probably
-illegal.
-
+HiSax is a work in progress and may crash your machine.
+For certification look at HiSax.cert file.
 
 Limitations
 -----------
 At this time, HiSax only works on Euro ISDN lines and German 1TR6 lines.
-For leased lines see appendix. 
+For leased lines see appendix.
 
-Bugs 
+Bugs
 ----
-If you find any, please let me know. 
+If you find any, please let me know.
 
 
 Thanks
@@ -354,8 +399,10 @@ Special thanks to:
        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). 
+       send me a mail).
 
         Firma ELSA GmbH
         Firma Eicon.Diehl GmbH
@@ -364,20 +411,23 @@ Special thanks to:
        Firma S.u.S.E
        Firma ith Kommunikationstechnik GmbH
        Firma Traverse Technologie Australia
-        
+       Firma Medusa GmbH  (www.medusa.de).
+       Firma Quant-X Austria for sponsoring a DEC Alpha board+CPU
+       Firma Cologne Chip Designs GmbH
+
         My girl friend and partner in life Ute for her patience with me.
 
 
 Enjoy,
 
-Karsten Keil   
-keil@temic-ech.spacenet.de
+Karsten Keil
+keil@isdn4linux.de
 
 
 Appendix: Teles PCMCIA driver
 -----------------------------
 
-See 
+See
    http://www.stud.uni-wuppertal.de/~ea0141/pcmcia.html
 for instructions.
 
@@ -451,7 +501,7 @@ to e.g. the Internet:
       /sbin/isdnctrl l2_prot isdn0 hdlc
       # Attention you must not set an outgoing number !!! This won't work !!!
       # The incomming number is LEASED0 for the first card, LEASED1 for the
-      # second and so on. 
+      # 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:
@@ -461,11 +511,12 @@ to e.g. the Internet:
    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 
+   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!
+b) Use state of the art isdn4k-utils
 
 Here an example script:
 #!/bin/sh
@@ -517,6 +568,7 @@ case "$1" in
                        /sbin/isdnctrl encap isdn0s cisco-h
                fi
        fi
+       /sbin/isdnctrl dialmode isdn0 auto
        # configure tcp/ip
        /sbin/ifconfig isdn0 ${LOCAL_IP} pointopoint ${REMOTE_IP}
        /sbin/route add -host ${REMOTE_IP} isdn0
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 eb5d6749b2b3d9ebd597be928b1622448e8ce9aa..7248ead804ab276cd7b079beebf3a78c32ddee14 100644 (file)
@@ -1,4 +1,4 @@
-$Id: README.act2000,v 1.1 1997/09/24 23:50:16 fritz Exp $
+$Id: README.act2000,v 1.2 1998/04/29 19:49:06 he Exp $
 
 This document describes the ACT2000 driver for the
 IBM Active 2000 ISDN card.
@@ -7,7 +7,7 @@ There are 3 Types of this card available. A ISA-, MCA-, and PCMCIA-Bus
 Version. Currently, only the ISA-Bus version of the card is supported.
 However MCA and PCMCIA will follow soon.
 
-The ISA-Bus Version uses 8 IO-ports. The base port address has to be set
+The ISA-Bus Version uses 8 IO-ports. The base port adress has to be set
 manually using the DIP switches.
 
 Setting up the DIP switches for the IBM Active 2000 ISDN card:
index d7b845162fa70a11e6e75cc9ded2ef7f972b439e..3708064017ab097fc10d95708a78ed293cd489a4 100644 (file)
@@ -1,4 +1,4 @@
-$Id: README.audio,v 1.5 1997/02/23 23:53:46 fritz Exp $
+$Id: README.audio,v 1.7 1998/07/26 18:45:34 armin Exp $
 
 ISDN subsystem for Linux.
   Description of audio mode.
@@ -50,10 +50,11 @@ The following commands are supported:
                          the application. See below for data format
 
         AT+VSD=x,y       Set silence-detection parameters.
-                         NO EFFECT, supported for compatibility
-                         only. Possible parameters:
-                           x = 0 ... 31
-                           y = 0 ... 255
+                         Possible parameters:
+                           x = 0 ... 31  sensitivity threshold level.
+                                         (default 0 , deactivated)
+                           y = 0 ... 255 range of interval in units
+                                         of 0.1 second. (default 70)
         AT+VSD=?         Report possible parameters.
         AT+VSD?          Show current parameters.
 
@@ -102,13 +103,14 @@ General behavior and description of data formats/protocol.
     <DLE>C                  Touchtone "C" received.
     <DLE>D                  Touchtone "D" received.
 
+    <DLE>q                  quiet. Silence detected after non-silence.
+    <DLE>s                  silence. Silence detected from the
+                            start of recording.
+
     Currently unsupported DLE sequences:
 
     <DLE>c                  FAX calling tone received.
     <DLE>b                  busy tone received.
-    <DLE>q                  quiet. Silence detected after non-silence.
-    <DLE>s                  silence. Silence detected from the
-                            start of recording.
 
   Audio playback.
 
index 7728692fcbc2cd16228f6e3fff97d7ef20b1e787..02a99c7dd5d8df171a6d7e64e3fe470e0e27c384 100644 (file)
@@ -256,3 +256,4 @@ protocol is configured. Thus, eliminating the performance penalty
 of the concap interface when a trivial concap protocol is used.
 Nevertheless, the device remains able to support encapsulation
 protocol configuration.
+
diff --git a/Documentation/isdn/README.eicon b/Documentation/isdn/README.eicon
new file mode 100644 (file)
index 0000000..2266928
--- /dev/null
@@ -0,0 +1,92 @@
+$Id: README.eicon,v 1.3 1999/03/29 11:10:04 armin Exp $
+
+(c) 1999 Cytronics & Melware
+
+This document describes the eicon driver for the
+Eicon.Diehl active ISDN cards.
+
+It is meant to be used with isdn4linux, an ISDN link-level module for Linux.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+NOTE : Since the eicon driver is still experimental, this README file
+       may be incomplete and not up to date.
+
+
+However, the driver should work under following conditions :
+
+Supported Cards
+---------------
+
+- S-Card ISA
+- SX-Card ISA
+- SXn-Card ISA
+- SCOM-Card ISA
+- Quadro-Card ISA
+- S2M-Card ISA
+- DIVA Server BRI/PCI 2M
+- DIVA Server PRI/PCI 2M (9M 23M 30M)
+  (Only analog modem functions of the DSPs are currently implemented)
+
+ISDN D-Channel Protocols
+------------------------
+
+- ETSI (Euro-DSS1) 
+- 1TR6 (German ISDN) *not testet*
+
+
+
+You can load the module simply by using the insmod or modprobe function :
+
+  insmod eicon [id=driverid] [membase=<membase>] [irq=<irq>]
+
+
+The module will automatically probe the PCI-cards. If the id-options
+is omitted, the driver will assume 'eicon0' for the first pci card and
+increases the digit with each further card. With a given driver-id
+the module appends a number starting with '0'.
+
+For ISA-cards you have to specify membase, irq and id. If id or
+membase is missing/invalid, the driver will not be loaded except
+PCI-cards were found. Additional ISA-cards and irq/membase changes
+can be done with the eiconctrl utility.
+
+After loading the module, you have to download the protocol and
+dsp-code by using the eiconctrl utility of isdn4k-utils.
+
+
+Example for loading and starting a BRI card with E-DSS1 Protocol.
+
+       eiconctrl [-d DriverId] load etsi
+
+
+Example for loading and starting a PRI card with E-DSS1 Protocol.
+
+       eiconctrl [-d DriverId] load etsi -s2 -n
+
+
+Details about using the eiconctrl utility are in 'man eiconctrl'
+or will be printed by starting eiconctrl without any parameters.
+
+
+
+Any reports about bugs, errors and even wishes are welcome.
+
+
+Have fun !
+
+Armin Schindler
+mac@melware.de
+http://www.melware.de
index 155e87457ae884f67abf495005bf508e8a40d77c..9c72e602509adf3da1daff2d122e9547425c8a43 100644 (file)
@@ -1,4 +1,4 @@
-$Id: README.icn,v 1.5 1997/04/23 18:55:55 fritz Exp $
+$Id: README.icn,v 1.6 1998/04/29 19:49:08 he Exp $
 
 You can get the ICN-ISDN-card from:
 
index 0964f734c34b1a97d5658f918ca88b7b5d83845f..9794f41183f50e618b95978036504c0a11c613a6 100644 (file)
@@ -1,29 +1,24 @@
-X25 support within isdn4linux
-
-
-This is experimental code and should be used with linux version 2.1.72.
-or later. Use it completely at your own risk.
-
+  
+X.25 support within isdn4linux
+==============================
 
+This is alpha/beta test code. Use it completely at your own risk.
 As new versions appear, the stuff described here might suddenly change
 or become invalid without notice.
 
 Keep in mind:
 
-You are using an experimental kernel (2.1.x series) with an experimental
-x25 protocol implementation and experimental x25-on-top-of-isdn extensions.
-Thus, be prepared to face problems related therefrom.
+You are using several new parts of the 2.2.x kernel series which
+have not been tested in a large scale. Therefore, you might encounter
+more bugs as usual.
 
-- If you connect to an x25 neighbour not operated by yourself, ASK the
+- If you connect to an X.25 neighbour not operated by yourself, ASK the
   other side first. Be prepared that bugs in the protocol implementation
-  might result in problems (even crashing the peer, however such ugly events
-  should only happen if your peer's protocol implementation has serious bugs).
+  might result in problems.
 
 - This implementation has never wiped out my whole hard disk yet. But as
-  this is experimental code, don't blame me if that happened to you. Take
-  appropriate actions (such as backing up important data) before
-  trying this code.
+  this is experimental code, don't blame me if that happened to you.
+  Backing up important data will never harm.
 
 - Monitor your isdn connections while using this software. This should
   prevent you from undesired phone bills in case of driver problems.
@@ -32,7 +27,7 @@ Thus, be prepared to face problems related therefrom.
 
 
 How to configure the kernel
-
+===========================
  
 The ITU-T (former CCITT) X.25 network protocol layer has been implemented
 in the Linux source tree since version 2.1.16. The isdn subsystem might be 
@@ -48,32 +43,33 @@ from the ISDN subsystem options when you configure your kernel for
 compilation. You currently also need to enable
 "Prompt for development and/or incomplete code/drivers" from the
 "Code maturity level options" menu. For the x25trace utility to work
-you also need to enable "Packet socket" (I recommend to choose "y",
-not "m" for testing) from the networking options.
+you also need to enable "Packet socket".
 
+For local testing it is also recommended to enable the isdnloop driver
+from the isdn subsystem's configuration menu.
 
-For testing you should also select the isdnloop driver from the
-isdn subsystem's configuration menu.
+For testing, it is recommended that all isdn drivers and the X.25 PLP
+protocol are compiled as loadable modules. Like this, you can recover
+from certain errors by simply unloading and reloading the modules.
 
 
 
 What's it for? How to use it?
+=============================
 
-
-X25 on top of isdn might be useful with two different scenarios:
+X.25 on top of isdn might be useful with two different scenarios:
 
 - You might want to access a public X.25 data network from your Linux box.
   You can use i4l if you were physically connected to the X.25 switch
-  by an ISDN line (leased line as well as dial up connection should work,
-  but connecting to x.25 network switches is currently untested. Testing
-  needs to be done by somebody with access to such a switch.) 
+  by an ISDN line (leased line as well as dial up connection should work)
 
-- Or you might want to operate certain ISDN teleservices on 
-  your linux box. A lot of those teleservices run on top of the ISO-8208 
-  network layer protocol. ISO-8208 is essentially the same as ITU-T X.25.
+- Or you might want to operate certain ISDN teleservices on your linux
+  box. A lot of those teleservices run on top of the ISO-8208
+  (DTE-DTE mode) network layer protocol. ISO-8208 is essentially the
+  same as ITU-T X.25.
 
-  Popular candidates of such teleservices are EUROFILE transfer or any
-  teleservice applying ITU-T recommendation T.90 (i.e., AFAIK, G4 Fax).
+  Popular candidates of such teleservices are EUROfile transfer or any
+  teleservice applying ITU-T recommendation T.90.
 
 To use the X.25 protocol on top of isdn, just create an isdn network
 interface as usual, configure your own and/or peer's ISDN numbers,
@@ -81,21 +77,18 @@ and choose x25iface encapsulation by
 
    isdnctrl encap <iface-name> x25iface.
 
-Once encap is set like this, the device can be used by the x25 packet layer.
+Once encap is set like this, the device can be used by the X.25 packet layer.
 
-All the stuff needed for x25 is implemented inside the isdn link
+All the stuff needed for X.25 is implemented inside the isdn link
 level (mainly isdn_net.c and some new source files). Thus, it should
-work with every existing HL driver. I was able to successfully open x25
+work with every existing HL driver. I was able to successfully open X.25
 connections on top of the isdnloop driver and the hisax driver.
 "x25iface"-encapsulation bypasses demand dialing. Dialing will be
-initiated when the upper (x25 packet) layer requests the lapb datalink to
-be established. But hangup timeout is still active. The connection
-will not automatically be re-established by the isdn_net module
-itself when new data arrives after the hangup timeout. But
-the x25 network code will re-establish the datalink connection
-(resulting in re-dialing and an x25 protocol reset) when new data is
-to be transmitted. (This currently does not work properly with the
-isdnloop driver, see "known problems" below)
+initiated when the upper (X.25 packet) layer requests the lapb datalink to
+be established. But hangup timeout is still active. Whenever a hangup
+occurs, all existing X.25 connections on that link will be cleared
+It is recommended to use sufficiently large hangup-timeouts for the
+isdn interfaces.
 
 
 In order to set up a conforming protocol stack you also need to
@@ -114,104 +107,64 @@ To mimic an X.25 network switch (DCE side of the connection), use
    isdnctrl l2_prot <iface-name> x25dce
 
 However, x25dte or x25dce is currently not supported by any real HL
-level driver. The main difference between x75 and x25dte/dce is that
+level driver. The main difference between x75i and x25dte/dce is that
 x25d[tc]e uses fixed lap_b addresses. With x75i, the side which
 initiates the isdn connection uses the DTE's lap_b address while the
-called side used the DCE's lap_b address. Thus, l2_prot x75i will
-probably work if you access a public x25 network as long as the
-corresponding isdn connection is set up by you. However, I've never
-tested this.
-
-
+called side used the DCE's lap_b address. Thus, l2_prot x75i might
+probably work if you access a public X.25 network as long as the
+corresponding isdn connection is set up by you. At least one test
+was successful to connect via isdn4linux to an X.25 switch using this
+trick. At the switch side, a terminal adapter X.21 was used to connect
+it to the isdn.
 
-How to use the test installation?
 
+How to set up a test installation?
+==================================
 
-To test x25 on top of isdn, you need to get
+To test X.25 on top of isdn, you need to get
 
-- a patched version of the "isdnctrl" program that supports setting the new
-  x25 specific parameters.
+- a recent version of the "isdnctrl" program that supports setting the new
+  X.25 specific parameters.
 
-- the x25-utils-2.1.x package from ftp.pspt.fi/pub/ham/linux/ax25
-  or any mirror site (i.e. ftp://ftp.gwdg.de/pub/linux/misc/ax25/).
+- the x25-utils-2.X package from 
+  ftp://ftp.hes.iki.fi/pub/ham/linux/ax25/x25utils-*
+  (don't confuse the x25-utils with the ax25-utils)
 
-- a kernel patch that enhances isdn4linux to provide x25 network
-  interface support. (This file is part of that kernel patch).
-
-- an application that uses linux AF_X25 sockets program. 
+- an application program that uses linux PF_X25 sockets (some are
+  contained in the x25-util package).
 
 Before compiling the user level utilities make sure that the compiler/
-preprocessor will fetch the proper (patched) kernel header files. Either make
-/usr/include/linux a symbolic link pointing to your developer kernel's
-include/linux directory or set the appropriate compiler flags.
-
-It is recommended that all isdn drivers and the x25 PLP protocol 
-are compiled as loadable modules. Like this, you can recover
-from certain errors by simply unloading and reloading the modules.
+preprocessor will fetch the proper kernel header files of this kernel
+source tree. Either make /usr/include/linux a symbolic link pointing to 
+this kernel's include/linux directory or set the appropriate compiler flags.
 
 When all drivers and interfaces are loaded and configured you need to
-ifconfig the network interfaces up and add x25-routes to them. Use
+ifconfig the network interfaces up and add X.25-routes to them. Use
 the usual ifconfig tool.
 
 ifconfig <iface-name> up
 
 But a special x25route tool (distributed with the x25-util package)
-is needed to set up x25 routes. I.e. 
+is needed to set up X.25 routes. I.e. 
 
 x25route add 01 <iface-name>
 
-will cause all x.25 connections to the destination x.25-address
+will cause all x.25 connections to the destination X.25-address
 "01" to be routed to your created isdn network interface.
 
-
-There are currently no real x25 applications available. However, for
+There are currently no real X.25 applications available. However, for
 tests, the x25-utils package contains a modified version of telnet
-and telnetd that uses x25 sockets instead of tcp/ip sockets. Use
-this for your first tests. Furthermore, there is an x25.echod and a client
-named "eftp" (which contains some experimental code to download files
-from a remote eft server using the EUROfile transfer protocol).
-It available at ftp://ftp.hamburg.pop.de/pub/LOCAL/linux/i4l-eft/eftp4linux-*
+and telnetd that uses X.25 sockets instead of tcp/ip sockets. You can
+use those for your first tests. Furthermore, you might check
+ftp://ftp.hamburg.pop.de/pub/LOCAL/linux/i4l-eft/ which contains some
+alpha-test implementation ("eftp4linux") of the EUROfile transfer
+protocol.
+
+The scripts distributed with the eftp4linux test releases might also
+provide useful examples for setting up X.25 on top of isdn.
 
 The x25-utility package also contains an x25trace tool that can be
-used to monitor x25 packets received by the network interfaces.
+used to monitor X.25 packets received by the network interfaces.
 The /proc/net/x25* files also contain useful information. 
 
-The eftp4linux test release also contains an "ix25test" script that can
-be used for testing x25 on top of isdn4linux. Edit
-this script according to your local needs and then call it as
-
-ix25test start
-
-This will set up a sample configuration using the isdnloop and hisax
-driver and create some isdn network interfaces.
-It is recommended that all other isdn drivers and the
-x25 module are unloaded before calling this script.
-
-
-
-Known problems and deficiencies:
-
-The isdnloop HL driver apparently has problems to re-establish a
-connection that has been hung up from the outgoing device. You have to
-unload the isdnloop driver after the faked isdn-connection is closed
-and insmod it again. With the Hisax driver, this problem is not present.
-
-Sometimes the x25 module cannot be unloaded (decrementation of its use
-count seems to get lost occasionally).
-
-Using the x25 based telnet and telnetd programm to establish connection
-from your own to your own computer repeatedly sometimes totally locked
-up my system. However, this kernel patch also modifies
-net/x25/af_x25.c to include a workaround. With this workaround
-enabled, my system is stable. (If you want to disable the
-workaround, just undefine ISDN_X25_FIXES in af_x25.c).
-
-The latter problem could be reproduced by using hisax as well as the
-isdnloop driver. It seems that it is not caused by the isdn code.
-Somehow, the inode of a socket is freed while a process still refers
-the socket's wait queue. This causes problems when the process tries to
-remove itself from the wait queue (referred by the dangling
-sock->sleep pointer) before returning from a select() system call.
-
 - Henner
-
index 07ec9fb168b13b65c0ff401c316014d880d0ac58..3b89528ee2b12a266535502d9e57eafda74a35eb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 2
+SUBLEVEL = 4
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff --git a/README b/README
index 6c8b96d00cbc1536b1196ffae27e28021d5c306d..ff9effabe5b201de5ef658c1c43ac49303b66afa 100644 (file)
--- a/README
+++ b/README
@@ -62,7 +62,7 @@ INSTALLING the kernel:
  - If you install the full sources, do a
 
                cd /usr/src
-               gzip -cd linux-2.3.XX.tar.gz | tar xfv -
+               gzip -cd linux-2.3.XX.tar.gz | tar xvf -
 
    to get it all put in place. Replace "XX" with the version number of the
    latest kernel.
index 93fb02b9774f554c4eb6060bf52c5fbadf2c9882..1993ed3b41eb601d65b770e1f4c9a44fd2bf9fa8 100644 (file)
@@ -58,10 +58,10 @@ static struct fs_struct init_fs = INIT_FS;
 static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
-struct mm_struct init_mm = INIT_MM;
+struct mm_struct init_mm = INIT_MM(init_mm);
 
 union task_union init_task_union __attribute__((section("init_task")))
-        = { task: INIT_TASK };
+        = { task: INIT_TASK(init_task_union.task) };
 
 /*
  * No need to acquire the kernel lock, we're entirely local..
index 18c9a8b13dc04b68476007e1aee64a65669e6136..243f89587c756e7d48e24f4f7ecee2f222b8af65 100644 (file)
@@ -506,7 +506,8 @@ sys_ptrace(long request, long pid, long addr, long data,
                     (current->uid != child->uid) ||
                     (current->gid != child->egid) ||
                     (current->gid != child->sgid) ||
-                    (current->gid != child->gid))
+                    (current->gid != child->gid) ||
+                    (!cap_issubset(child->cap_permitted, current->cap_permitted)))
                    && !capable(CAP_SYS_PTRACE))
                        goto out;
                /* the same process cannot be attached many times */
index 3df4ce886fe67a8276b8004a448352e743906897..2caa1fa95a4784ee99ef1fc09d7f17ef1baec02f 100644 (file)
@@ -580,6 +580,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                    (current->uid != child->uid) ||
                    (current->gid != child->egid) ||
                    (current->gid != child->sgid) ||
+                   (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
                    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
                        goto out;
                /* the same process cannot be attached many times */
index 6cc7a54414e08e7b0224c752e13aceac84384e2d..11d77ecc318303b6c872d3d5693fe5a059a56e6b 100644 (file)
@@ -306,6 +306,7 @@ CONFIG_USB_MOUSE=y
 CONFIG_USB_KBD=y
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
 
 #
 # Filesystems
index 6bf33f095e81611532873a4bf4bd99cc307870c3..58a6332d4cc6f5d925a376e5c5ee2e7b8251592c 100644 (file)
@@ -297,6 +297,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                    (current->uid != child->uid) ||
                    (current->gid != child->egid) ||
                    (current->gid != child->sgid) ||
+                   (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
                    (current->gid != child->gid)) && 
                    !capable(CAP_SYS_PTRACE)) {
                        res = -EPERM;
index d865053c48c870e778293cc4bc5e9a19fc6643cb..e150d9325ff1b93f35889d62fc8b507df1393d5e 100644 (file)
@@ -29,6 +29,10 @@ ifdef CONFIG_8xx
 CFLAGS := $(CFLAGS) -mcpu=860
 endif
 
+ifdef CONFIG_PPC64
+CFLAGS := $(CFLAGS) -Wa,-mppc64bridge #-Wa,-mppc64
+#CFLAGS := $(CFLAGS) -Wa,-mppc64 -mpowerpc64
+endif
 
 HEAD := arch/ppc/kernel/head.o
 
index 5a83e79eeb79dba914b7b049f7b95c20ab036514..58c9c3c82b12e87c0907d1813278227c6d57cfc4 100644 (file)
@@ -26,9 +26,15 @@ IOFF = 0
 ISZ = 0
 
 ifeq ($(CONFIG_SMP),y)
-TFTPIMAGE=/tftpboot/zImage.prep.smp
+TFTPIMAGE=/tftpboot/zImage.prep.smp$(MSIZE)
 else
-TFTPIMAGE=/tftpboot/zImage.prep
+TFTPIMAGE=/tftpboot/zImage.prep$(MSIZE)
+endif
+
+ifeq ($(CONFIG_PPC64),y)
+MSIZE=.64
+else
+MSIZE=
 endif
 
 ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
index 15d347df5720f5e0c4a8c4b8d50c47c8b3c2048a..65b0e74a67dc0ea2e825f864969571cde6b6374d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.64 1999/04/30 05:52:46 cort Exp $
+ * $Id: misc.c,v 1.65 1999/05/17 19:11:13 cort Exp $
  * 
  * Adapted for PowerPC by Gary Thomas
  *
@@ -363,7 +363,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
                        if (board_type == 0xe0) {       
                                base_mod = inb(0x803);
                                /* if a MVME2300/2400 or a Sitka then no keyboard */
-                               if((base_mod == 0x9) || (base_mod == 0xF9) ||
+                               if((base_mod == 0xFA) || (base_mod == 0xF9) ||
                                   (base_mod == 0xE1)) {
                                        keyb_present = 0;       /* no keyboard */
                                }
index cd0336bc9762827eabcf74f9ec787388923d5124..e22acbbbc0cda9a4f8d4dc9825673bce0e33b72f 100644 (file)
@@ -23,15 +23,21 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
 OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o # initrd.o
 LIBS = $(TOPDIR)/lib/lib.a
 
+ifeq ($(CONFIG_PPC64),y)
+MSIZE=.64
+else
+MSIZE=
+endif
+
 ifeq ($(CONFIG_ALL_PPC),y)
 # yes, we want to build chrp stuff
 CONFIG_CHRP = y
 endif
 
 ifeq ($(CONFIG_SMP),y)
-TFTPIMAGE=/tftpboot/zImage.chrp.smp
+TFTPIMAGE=/tftpboot/zImage.chrp.smp$(MSIZE)
 else
-TFTPIMAGE=/tftpboot/zImage.chrp
+TFTPIMAGE=/tftpboot/zImage.chrp$(MSIZE)
 endif
 
 all:   $(TOPDIR)/zImage
index 9ca967785bcdcf474aa0799055c9e604b840e2d2..9151717467801d0f5514f02d0c5e84568009ee62 100644 (file)
@@ -23,10 +23,16 @@ ifeq ($(CONFIG_ALL_PPC),y)
 CONFIG_PMAC = y
 endif
 
+ifeq ($(CONFIG_PPC64),y)
+MSIZE=.64
+else
+MSIZE=
+endif
+
 ifeq ($(CONFIG_SMP),y)
-TFTPIMAGE=/tftpboot/zImage.pmac.smp
+TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE)
 else
-TFTPIMAGE=/tftpboot/zImage.pmac
+TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE)
 endif
 
 ifeq ($(CONFIG_PMAC),y)
index 131244790395120820a96d308da46d440554e9a4..06e1f45868d1f49cd11431872d44aac8667405c9 100644 (file)
@@ -7,21 +7,24 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
+# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_6xx=y
 
 #
 # General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -32,7 +35,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
+# CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
 CONFIG_VGA_CONSOLE=y
@@ -48,7 +51,6 @@ CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -66,7 +68,9 @@ CONFIG_BLK_DEV_IDE=y
 #
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
+# CONFIG_IDECD_SLOTS is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDESCSI is not set
@@ -75,13 +79,15 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
-# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -89,6 +95,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
+CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -151,12 +158,12 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -191,14 +198,8 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX is not set
 # CONFIG_SCSI_SYM53C8XX is not set
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -236,7 +237,7 @@ CONFIG_BMAC=y
 # CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -296,32 +297,18 @@ CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-# CONFIG_FB_ATY is not set
+CONFIG_FB_ATY=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
+# CONFIG_FB_MATROX is not set
+CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-# CONFIG_FBCON_MFB is not set
-# CONFIG_FBCON_CFB2 is not set
-# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
-# CONFIG_FBCON_AFB is not set
-# CONFIG_FBCON_ILBM is not set
-# CONFIG_FBCON_IPLAN2P2 is not set
-# CONFIG_FBCON_IPLAN2P4 is not set
-# CONFIG_FBCON_IPLAN2P8 is not set
-# CONFIG_FBCON_MAC is not set
-# CONFIG_FBCON_VGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -337,25 +324,15 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
-
-#
-# Mice
-#
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
+CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 
 #
@@ -390,10 +367,11 @@ CONFIG_AUTOFS_FS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -477,4 +455,4 @@ CONFIG_DMASOUND=y
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+CONFIG_XMON=y
index 43493a540ad6b22711a21acaf337bfdb2f3a3331..183f81f1c856f57fe2810cba689dd00cb3bc23f0 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.92 1999/04/30 05:41:43 cort Exp $
+# $Id: config.in,v 1.93 1999/05/14 22:36:58 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -8,8 +8,9 @@ mainmenu_option next_comment
 comment 'Platform support'
 define_bool CONFIG_PPC y
 choice 'Processor type' \
-       "6xx/7xx        CONFIG_6xx \
-        860/821        CONFIG_8xx" 6xx/7xx
+       "6xx/7xx                CONFIG_6xx \
+        630/Power3(64-Bit)     CONFIG_PPC64 \
+        860/821                CONFIG_8xx" 6xx/7xx
 
 choice 'Machine Type' \
        "PowerMac       CONFIG_PMAC \
@@ -23,6 +24,10 @@ bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_ALL_PPC" != "y" ];then
   define_bool CONFIG_MACH_SPECIFIC y
 fi
+
+if [ "$CONFIG_PPC64" != "y" ];then
+  define_bool CONFIG_6xx y
+fi
 endmenu
 
 if [ "$CONFIG_MBX" = "y" ];then
index 131244790395120820a96d308da46d440554e9a4..06e1f45868d1f49cd11431872d44aac8667405c9 100644 (file)
@@ -7,21 +7,24 @@
 #
 CONFIG_PPC=y
 CONFIG_6xx=y
+# CONFIG_PPC64 is not set
 # CONFIG_8xx is not set
-# CONFIG_PMAC is not set
+CONFIG_PMAC=y
 # CONFIG_PREP is not set
 # CONFIG_CHRP is not set
-CONFIG_ALL_PPC=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
 # CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_6xx=y
 
 #
 # General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 CONFIG_PCI=y
 # CONFIG_PCI_QUIRKS is not set
@@ -32,7 +35,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
+# CONFIG_BINFMT_MISC is not set
 # CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
 CONFIG_VGA_CONSOLE=y
@@ -48,7 +51,6 @@ CONFIG_PROC_DEVICETREE=y
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
 # CONFIG_MOTOROLA_HOTSWAP is not set
-# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -66,7 +68,9 @@ CONFIG_BLK_DEV_IDE=y
 #
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
 CONFIG_BLK_DEV_IDECD=y
+# CONFIG_IDECD_SLOTS is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDESCSI is not set
@@ -75,13 +79,15 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
 CONFIG_BLK_DEV_IDE_PMAC=y
-# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_PMAC_IDEDMA_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -89,6 +95,7 @@ CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
+CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -151,12 +158,12 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -191,14 +198,8 @@ CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_NCR53C8XX is not set
 # CONFIG_SCSI_SYM53C8XX is not set
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -236,7 +237,7 @@ CONFIG_BMAC=y
 # CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -296,32 +297,18 @@ CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-# CONFIG_FB_ATY is not set
+CONFIG_FB_ATY=y
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
+# CONFIG_FB_MATROX is not set
+CONFIG_FB_ATY=y
 # CONFIG_FB_VIRTUAL is not set
-CONFIG_FBCON_ADVANCED=y
-# CONFIG_FBCON_MFB is not set
-# CONFIG_FBCON_CFB2 is not set
-# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
-# CONFIG_FBCON_AFB is not set
-# CONFIG_FBCON_ILBM is not set
-# CONFIG_FBCON_IPLAN2P2 is not set
-# CONFIG_FBCON_IPLAN2P4 is not set
-# CONFIG_FBCON_IPLAN2P8 is not set
-# CONFIG_FBCON_MAC is not set
-# CONFIG_FBCON_VGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -337,25 +324,15 @@ CONFIG_FONT_SUN12x22=y
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_SERIAL is not set
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_MOUSE=y
-
-#
-# Mice
-#
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
+CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 
 #
@@ -390,10 +367,11 @@ CONFIG_AUTOFS_FS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 CONFIG_HFS_FS=y
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
@@ -477,4 +455,4 @@ CONFIG_DMASOUND=y
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+CONFIG_XMON=y
index 5c8b44a90a33c30ae9b0a417fe5f10388aaaaaad..1be8c322ad7a630a94ad088ccd293c80d751f257 100644 (file)
@@ -65,7 +65,7 @@ find_name : find_name.c
        $(HOSTCC) -o find_name find_name.c
 
 checks: checks.c
-       $(HOSTCC) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
+       $(HOSTCC) ${CFLAGS} -D__KERNEL__ -o checks checks.c
        ./checks
 
 include $(TOPDIR)/Rules.make
index 9bb8e690ee4ad2b98e12e0c71c653fa139339e54..841295d8227f597108ad07fd805ba588ebc64150 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
index fa4dda10b5a51153c80d278c505148678d2ee9cf..f36f59f86116214ca954ca942ca1bc15350f6b47 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/openpic.h>
+#include <linux/ide.h>
 
 #include <asm/io.h>
 #include <asm/pgtable.h>
index 99e97e69eae44d6db96368cd25d8957de90acb16..d3dbcca414261f0e295e8940f8e7a3f64702936a 100644 (file)
@@ -286,29 +286,6 @@ __initfunc(void
        if ( !strncmp("MOT", get_property(find_path_device("/"),
                                          "model", NULL),3) )
                *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
-       /*
-        * The f50 has a lot of IO space - we need to map some in that
-        * isn't covered by the BAT mappings in MMU_init() -- Cort
-        */
-       if ( !strncmp("F5", get_property(find_path_device("/"),
-                                        "ibm,model-class", NULL),2) )
-       {
-#if 0          
-               /*
-                * This ugly hack allows us to force ioremap() to
-                * create a 1-to-1 mapping for us, even though
-                * the address is < ioremap_base.  This is necessary
-                * since we want our PCI IO space to have contiguous
-                * virtual addresses and I think it's worse to have
-                * calls to map_page() here.
-                * -- Cort
-                */
-               unsigned long hold = ioremap_base;
-               ioremap_base = 0;
-               __ioremap(0x90000000, 0x10000000, _PAGE_NO_CACHE);
-               ioremap_base = hold;
-#endif         
-       }
 }
 
 void
index b9ecc2dccd9d820ae4ca90b537c11a75b6844525..9cbde2c5b38a13a390e9e4616d6f33e57427e5db 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.130 1999/05/09 19:16:43 cort Exp $
+ *  $Id: head.S,v 1.131 1999/05/14 22:37:21 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -97,18 +97,32 @@ LG_CACHE_LINE_SIZE = 4
        bdnz    0b
 #endif
 
+#ifdef CONFIG_PPC64
+#define LOAD_BAT(n, offset, reg, RA, RB) \
+       ld      RA,offset+0(reg);       \
+       ld      RB,offset+8(reg);       \
+       mtspr   IBAT##n##U,RA;          \
+       mtspr   IBAT##n##L,RB;          \
+       ld      RA,offset+16(reg);      \
+       ld      RB,offset+24(reg);      \
+       mtspr   DBAT##n##U,RA;          \
+       mtspr   DBAT##n##L,RB;          \
+       
+#else /* CONFIG_PPC64 */
+       
 /* 601 only have IBAT cr0.eq is set on 601 when using this macro */ 
 #define LOAD_BAT(n, offset, reg, RA, RB) \
-       lwz     RA,offset+0(reg); \
+       lwz     RA,offset+0(reg);       \
        lwz     RB,offset+4(reg);       \
-       mtspr   IBAT##n##U,RA;  \
-       mtspr   IBAT##n##L,RB;  \
-       beq     1f;             \
+       mtspr   IBAT##n##U,RA;          \
+       mtspr   IBAT##n##L,RB;          \
+       beq     1f;                     \
        lwz     RA,offset+8(reg);       \
        lwz     RB,offset+12(reg);      \
-       mtspr   DBAT##n##U,RA;  \
-       mtspr   DBAT##n##L,RB;  \
-1:      
+       mtspr   DBAT##n##U,RA;          \
+       mtspr   DBAT##n##L,RB;          \
+1:     
+#endif /* CONFIG_PPC64 */       
 
 #ifndef CONFIG_APUS
 #define tophys(rd,rs,rt)       addis   rd,rs,-KERNELBASE@h
@@ -206,6 +220,16 @@ _start:
        
        .globl  __start
 __start:
+#ifdef CONFIG_PPC64
+/* 
+ * Go into 32-bit mode to boot.  OF should do this for
+ * us already but just in case...
+ * -- Cort 
+ */
+       mfmsr   r10
+       clrldi  r10,r10,3
+       mtmsr   r10
+#endif 
 /*
  * We have to do any OF calls before we map ourselves to KERNELBASE,
  * because OF may have I/O devices mapped in in that area
@@ -226,10 +250,11 @@ __secondary_start:
  * of RAM to KERNELBASE.  From this point on we can't safely
  * call OF any more.
  */
+       lis     r11,KERNELBASE@h
+#ifndef CONFIG_PPC64
        mfspr   r9,PVR
        rlwinm  r9,r9,16,16,31          /* r9 = 1 for 601, 4 for 604 */
        cmpi    0,r9,1
-       lis     r11,KERNELBASE@h
        bne     4f
        ori     r11,r11,4               /* set up BAT registers for 601 */
        li      r8,0x7f                 /* valid, block length = 8MB */
@@ -240,6 +265,7 @@ __secondary_start:
        mtspr   IBAT1U,r9
        mtspr   IBAT1L,r10
        b       5f
+#endif /* CONFIG_PPC64 */
 4:
 #ifdef CONFIG_APUS
        ori     r11,r11,BL_8M<<2|0x2    /* set up an 8MB mapping */
@@ -248,9 +274,17 @@ __secondary_start:
        lwz     r8,0(r8)
        addis   r8,r8,KERNELBASE@h
        addi    r8,r8,2
-#else
+#else  
        ori     r11,r11,BL_256M<<2|0x2  /* set up BAT registers for 604 */
        li      r8,2                    /* R/W access */
+#ifdef CONFIG_PPC64
+       /* clear out the high 32 bits in the BAT */
+       clrldi  r11,r11,32
+       clrldi  r8,r8,32
+       /* turn off the pagetable mappings just in case */
+       clrldi  r16,r16,63
+       mtsdr1  r16
+#else /* CONFIG_PPC64 */
        /* 
         * allow secondary cpus to get at all of ram in early bootup
         * since their init_task may be up there -- Cort
@@ -268,6 +302,7 @@ __secondary_start:
        mtspr   DBAT2U,r21              /* bit in upper BAT register */
        mtspr   IBAT2L,r28
        mtspr   IBAT2U,r21
+#endif /* CONFIG_PPC64 */
 #endif
        mtspr   DBAT0L,r8               /* N.B. 6xx (not 601) have valid */
        mtspr   DBAT0U,r11              /* bit in upper BAT register */
@@ -1246,7 +1281,7 @@ hash_page:
        eieio
        lis     r2,hash_table_lock@h
        ori     r2,r2,hash_table_lock@l
-       tophys(r2,r2,r6)
+       tophys(r2,r2,r6)
        lis     r6,100000000@h
        mtctr   r6
        lwz     r0,PROCESSOR-TSS(r5)
@@ -1294,6 +1329,11 @@ hash_page:
        stw     r6,0(r2)                /* update PTE (accessed/dirty bits) */
 
        /* Convert linux-style PTE to low word of PPC-style PTE */
+#ifdef CONFIG_PPC64
+       /* clear the high 32 bits just in case */
+       clrldi  r6,r6,32
+       clrldi  r4,r4,32
+#endif /* CONFIG_PPC64 */
        rlwinm  r4,r6,32-9,31,31        /* _PAGE_HWWRITE -> PP lsb */
        rlwimi  r6,r6,32-1,31,31        /* _PAGE_USER -> PP (both bits now) */
        ori     r4,r4,0xe04             /* clear out reserved bits */
@@ -1301,16 +1341,34 @@ hash_page:
 
        /* Construct the high word of the PPC-style PTE */
        mfsrin  r5,r3                   /* get segment reg for segment */
+#ifdef CONFIG_PPC64
+       sldi    r5,r5,12
+#else /* CONFIG_PPC64 */
        rlwinm  r5,r5,7,1,24            /* put VSID in 0x7fffff80 bits */
+#endif /* CONFIG_PPC64 */
+       
 #ifndef __SMP__                                /* do this later for SMP */
+#ifdef CONFIG_PPC64
+       ori     r5,r5,1                 /* set V (valid) bit */
+#else /* CONFIG_PPC64 */
        oris    r5,r5,0x8000            /* set V (valid) bit */
+#endif /* CONFIG_PPC64 */
 #endif
+       
+#ifdef CONFIG_PPC64
+/* XXX:         does this insert the api correctly? -- Cort */
+       rlwimi  r5,r3,17,21,25          /* put in API (abbrev page index) */
+#else /* CONFIG_PPC64 */
        rlwimi  r5,r3,10,26,31          /* put in API (abbrev page index) */
-
+#endif /* CONFIG_PPC64 */
        /* Get the address of the primary PTE group in the hash table */
        .globl  hash_page_patch_A
 hash_page_patch_A:
        lis     r4,Hash_base@h          /* base address of hash table */
+#ifdef CONFIG_PPC64
+       /* just in case */
+       clrldi  r4,r4,32
+#endif 
        rlwimi  r4,r5,32-1,26-Hash_bits,25      /* (VSID & hash_mask) << 6 */
        rlwinm  r0,r3,32-6,26-Hash_bits,25      /* (PI & hash_mask) << 6 */
        xor     r4,r4,r0                /* make primary hash */
@@ -1799,7 +1857,11 @@ start_here:
  */
 #ifndef CONFIG_8xx
        lis     r6,_SDR1@ha
+#ifdef CONFIG_PPC64    
+       ld      r6,_SDR1@l(r6)
+#else
        lwz     r6,_SDR1@l(r6)
+#endif         
 #else
        /* The right way to do this would be to track it down through
         * init's TSS like the context switch code does, but this is
@@ -1828,6 +1890,14 @@ start_here:
 #endif
 #ifndef CONFIG_8xx
        mtspr   SDR1,r6
+#ifdef CONFIG_PPC64
+       /* clear the v bit in the ASR so we can
+        * behave as if we have segment registers 
+        * -- Cort
+        */
+       clrldi  r6,r6,63
+       mtasr   r6
+#endif /* CONFIG_PPC64 */
        li      r0,16           /* load up segment register values */
        mtctr   r0              /* for context 0 */
        lis     r3,0x2000       /* Ku = 1, VSID = 0 */
@@ -1844,10 +1914,17 @@ start_here:
        lis     r3,BATS@ha
        addi    r3,r3,BATS@l
        tophys(r3,r3,r4)
+#ifdef CONFIG_PPC64
+       LOAD_BAT(0,0,r3,r4,r5)
+       LOAD_BAT(1,32,r3,r4,r5)
+       LOAD_BAT(2,64,r3,r4,r5)
+       LOAD_BAT(3,96,r3,r4,r5)
+#else /* CONFIG_PPC64 */
        LOAD_BAT(0,0,r3,r4,r5)
        LOAD_BAT(1,16,r3,r4,r5)
        LOAD_BAT(2,32,r3,r4,r5)
        LOAD_BAT(3,48,r3,r4,r5)
+#endif /* CONFIG_PPC64 */
 #endif /* CONFIG_8xx */
 /* Set up for using our exception vectors */
        /* ptr to phys current tss */
index f086ef743e845e91931a20fa156d696036c78b43..40f016fb5afb3defefeed5b7dbf63441c58ece86 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mbx_setup.c,v 1.9 1999/04/28 11:54:09 davem Exp $
+ * $Id: mbx_setup.c,v 1.10 1999/05/14 07:24:19 davem Exp $
  *
  *  linux/arch/ppc/kernel/setup.c
  *
index cbeb4ffce9cd2f4c33bf4e99dd2387a6ac7a8bd8..acb480a047c0eb874d2f1dbd5e3c08a6c38892aa 100644 (file)
@@ -648,15 +648,6 @@ __clear_msr_me:
         mtmsr   r0                      /* Update machine state */
         blr
 
-/*
- * Fetch the current SR register
- *   get_SR(int index)
- */
-_GLOBAL(get_SR)
-       mfsrin  r4,r3
-       mr      r3,r4
-       blr
-
 /*
  * Create a kernel thread
  *   __kernel_thread(flags, fn, arg)
index bfd34fea62d70112fe518411e597b8f33d3a4421..afa1227a7c7913f690e6a49b802d192c9a5ad2a3 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/blk.h>
 #include <linux/vt_kern.h>
 #include <linux/console.h>
+#include <linux/ide.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -543,18 +544,19 @@ pmac_ide_fix_driveid(struct hd_driveid *id)
         ppc_generic_ide_fix_driveid(id);
 }
 
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
 /* This is declared in drivers/block/ide-pmac.c */
 void pmac_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
-
+#else
 /*
  * This registers the standard ports for this architecture with the IDE
  * driver.
  */
-void
-ide_init_default_hwifs(void)
+void pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
 }
 #endif
+#endif
 
 __initfunc(void
 pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
index dd7f1eee1cf3e75549356bac7521cc62e6e07503..63a1e9ddf78c9c02c5d8e5a15ec628c10092a702 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: prep_pci.c,v 1.33 1999/05/09 20:15:54 cort Exp $
+ * $Id: prep_pci.c,v 1.35 1999/05/10 23:31:03 cort Exp $
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -38,6 +38,8 @@ unsigned char *Motherboard_routes;
 /* Used for Motorola to store system config register */
 static unsigned long   *ProcInfo;
 
+extern void chrp_do_IRQ(struct pt_regs *,int , int);
+
 /* Tables for known hardware */   
 
 /* Motorola PowerStackII - Utah */
@@ -731,6 +733,8 @@ __initfunc(int raven_init(void))
        OpenPIC_InitSenses = mvme2600_openpic_initsenses;
        OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
 
+       ppc_md.do_IRQ = chrp_do_IRQ;
+       
        /* If raven is present on Motorola store the system config register
         * for later use.
         */
index 30207bf3d82ceae191654fa2645501106bf0c970..45c64837c7485ba877458d100c803f621a063467 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/timex.h>
 #include <linux/pci.h>
 #include <linux/openpic.h>
+#include <linux/ide.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -247,7 +248,7 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
        case _PREP_Motorola:
                /* Enable L2.  Assume we don't need to flush -- Cort*/
                *(unsigned char *)(0x8000081c) |= 3;
-               ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+               ROOT_DEV = to_kdev_t(0x0802); /* sda2 */
                break;
        case _PREP_Radstone:
                ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
@@ -774,10 +775,8 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.get_cpuinfo    = prep_get_cpuinfo;
        ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
        ppc_md.init_IRQ       = prep_init_IRQ;
-       if ( !OpenPIC )
-               ppc_md.do_IRQ         = prep_do_IRQ;
-       else
-               ppc_md.do_IRQ         = chrp_do_IRQ;
+       /* this gets changed later on if we have an OpenPIC -- Cort */
+       ppc_md.do_IRQ         = prep_do_IRQ;
        ppc_md.init           = NULL;
 
        ppc_md.restart        = prep_restart;
index db87c2384a8afbb3c89210bd7d339071854a7997..0147d427de7f771e384bff91eb719dd616387910 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.83 1999/05/10 04:43:43 cort Exp $
+ * $Id: process.c,v 1.85 1999/05/16 21:27:08 cort Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
@@ -51,8 +51,8 @@ static struct fs_struct init_fs = INIT_FS;
 static struct file * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
-struct mm_struct init_mm = INIT_MM;
-union task_union init_task_union = { INIT_TASK };
+struct mm_struct init_mm = INIT_MM(init_mm);
+union task_union init_task_union = { INIT_TASK(init_task_union.task) };
 /* only used to get secondary processor up */
 struct task_struct *current_set[NR_CPUS] = {&init_task, };
 
@@ -235,24 +235,6 @@ void show_regs(struct pt_regs * regs)
 out:
 }
 
-void instruction_dump (unsigned long *pc)
-{
-       int i;
-
-       if((((unsigned long) pc) & 3))
-                return;
-
-       printk("Instruction DUMP:");
-       for(i = -3; i < 6; i++)
-       {
-               unsigned long p;
-               if (__get_user( p, &pc[i] ))
-                       break;
-               printk("%c%08lx%c",i?' ':'<',p,i?' ':'>');
-       }
-       printk("\n");
-}
-
 void exit_thread(void)
 {
        if (last_task_used_math == current)
index b3a25fd2b534de6bb7770ac5cade7d2ce29ed291..b101a3e9696822ca02a0a3334c1aecd2169bc943 100644 (file)
@@ -330,8 +330,12 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                if ((!child->dumpable ||
                    (current->uid != child->euid) ||
                    (current->uid != child->uid) ||
+                   (current->uid != child->suid) ||
                    (current->gid != child->egid) ||
-                   (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+                   (current->gid != child->gid) ||
+                   (current->gid != child->sgid) ||
+                   (!cap_issubset(child->cap_permitted, current->cap_permitted)))
+                   && !capable(CAP_SYS_PTRACE))
                        goto out;
                /* the same process cannot be attached many times */
                if (child->flags & PF_PTRACED)
index dc740aaf6583240dbf1c858e444ef6b0d5641f2b..d9fb239702548c92681caca413393d2f8b5aa387 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: residual.c,v 1.14 1998/10/11 17:38:10 cort Exp $
+ * $Id: residual.c,v 1.15 1999/05/14 07:24:27 davem Exp $
  *
  * Code to deal with the PReP residual data.
  *
index 8e656d77ce0cff0c00c91fa9188e7ec5b3bd4838..3fdb35718bc428a74cbbcc3a3c03f7ae50023b2a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.132 1999/03/24 00:32:19 cort Exp $
+ * $Id: setup.c,v 1.133 1999/05/14 07:24:30 davem Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
index b90760d7e280c1f8d98020c5bc6b2a8a9164e384..64f954b2e31cea612aab363e11b3e6e9b630b344 100644 (file)
@@ -34,6 +34,7 @@
 
 /* Eventually we may need a look-up table, but this works for now.
 */
+#define LFS    48
 #define LFD    50
 #define LFDU   51
 #define STFD   54
@@ -83,6 +84,12 @@ Soft_emulate_8xx(struct pt_regs *regs)
                else
                        regs->gpr[idxreg] = (uint)ea;
                break;
+       case LFS:
+               sdisp = (instword & 0xffff);
+               ea = (uint *)(regs->gpr[idxreg] + sdisp);
+               if (copy_from_user(ip, ea, sizeof(float)))
+                       retval = EFAULT;
+               break;
        case STFD:
                /* this is a 16 bit quantity that is sign extended
                 * so use a signed short here -- Cort
index 4d96a6f0af8748e0db7698dc74f06181a979f158..b974562260a4b4dce19b7d2c811f0a901a89d915 100644 (file)
@@ -205,15 +205,12 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
 
        lock_kernel();
        if (!(flags & MAP_ANONYMOUS)) {
-               file = fget(fd);
-               if (!file)
+               if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
                        goto out;
        }
        
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        ret = do_mmap(file, addr, len, prot, flags, offset);
-       if (file)
-               fput(file);
 out:
        unlock_kernel();
        return ret;
index 87cc2bd683f828dfd7e74972471c11411eb8aa2d..c33bff3e0b498f823242d97c4cef9a966487ba98 100644 (file)
@@ -79,7 +79,6 @@ _exception(int signr, struct pt_regs *regs)
                debugger(regs);
 #endif
                print_backtrace((unsigned long *)regs->gpr[1]);
-               instruction_dump((unsigned long *)regs->nip);
                panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
        }
        force_sig(signr, current);
@@ -127,7 +126,6 @@ MachineCheckException(struct pt_regs *regs)
                debugger(regs);
 #endif
                print_backtrace((unsigned long *)regs->gpr[1]);
-               instruction_dump((unsigned long *)regs->nip);
                panic("machine check");
        }
        _exception(SIGSEGV, regs);      
@@ -216,7 +214,6 @@ StackOverflow(struct pt_regs *regs)
 #endif
        show_regs(regs);
        print_backtrace((unsigned long *)regs->gpr[1]);
-       instruction_dump((unsigned long *)regs->nip);
        panic("kernel stack overflow");
 }
 
index 92299e825b44d36f9fbc9b43efe949055ad15e66..fde053df9b4039c130e03a2571255c96c2e372ed 100644 (file)
@@ -89,7 +89,6 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
                        printk("page fault in interrupt handler, addr=%lx\n",
                               address);
                        show_regs(regs);
-                       instruction_dump((unsigned long *)regs->nip);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
                        if (debugger_kernel_faults)
                                debugger(regs);
@@ -176,7 +175,6 @@ bad_page_fault(struct pt_regs *regs, unsigned long address)
        /* kernel has accessed a bad area */
        show_regs(regs);
        print_backtrace( (unsigned long *)regs->gpr[1] );
-       instruction_dump((unsigned long *)regs->nip);
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
        if (debugger_kernel_faults)
                debugger(regs);
index eac750568a27422aef9a38687d36c171d23487a8..74b12ef0019a9af35d958ac5e64abb6b358eafe1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.164 1999/05/05 17:33:55 cort Exp $
+ *  $Id: init.c,v 1.165 1999/05/14 22:37:29 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -1510,7 +1510,7 @@ __initfunc(static void hash_init(void))
        for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++)
                ;
        Hash_size = h;
-       Hash_mask << 10;  /* so setting _SDR1 works the same -- Cort */
+       Hash_mask <<= 10;  /* so setting _SDR1 works the same -- Cort */
 #else
        for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2)
                ;
diff --git a/arch/ppc/xmon/Makefile b/arch/ppc/xmon/Makefile
new file mode 100644 (file)
index 0000000..ba501cf
--- /dev/null
@@ -0,0 +1,6 @@
+# Makefile for xmon
+
+O_TARGET = x.o
+O_OBJS = start.o xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/xmon/adb.c b/arch/ppc/xmon/adb.c
new file mode 100644 (file)
index 0000000..e91384d
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include "nonstdio.h"
+#include "privinst.h"
+
+#define scanhex        xmon_scanhex
+#define skipbl xmon_skipbl
+
+#define ADB_B          (*(volatile unsigned char *)0xf3016000)
+#define ADB_SR         (*(volatile unsigned char *)0xf3017400)
+#define ADB_ACR                (*(volatile unsigned char *)0xf3017600)
+#define ADB_IFR                (*(volatile unsigned char *)0xf3017a00)
+
+static inline void eieio(void) { asm volatile ("eieio" : :); }
+
+#define N_ADB_LOG      1000
+struct adb_log {
+    unsigned char b;
+    unsigned char ifr;
+    unsigned char acr;
+    unsigned int time;
+} adb_log[N_ADB_LOG];
+int n_adb_log;
+
+void
+init_adb_log(void)
+{
+    adb_log[0].b = ADB_B;
+    adb_log[0].ifr = ADB_IFR;
+    adb_log[0].acr = ADB_ACR;
+    adb_log[0].time = get_dec();
+    n_adb_log = 0;
+}
+
+void
+dump_adb_log(void)
+{
+    unsigned t, t0;
+    struct adb_log *ap;
+    int i;
+
+    ap = adb_log;
+    t0 = ap->time;
+    for (i = 0; i <= n_adb_log; ++i, ++ap) {
+       t = t0 - ap->time;
+       printf("b=%x ifr=%x acr=%x at %d.%.7d\n", ap->b, ap->ifr, ap->acr,
+              t / 1000000000, (t % 1000000000) / 100);
+    }
+}
+
+void
+adb_chklog(void)
+{
+    struct adb_log *ap = &adb_log[n_adb_log + 1];
+
+    ap->b = ADB_B;
+    ap->ifr = ADB_IFR;
+    ap->acr = ADB_ACR;
+    if (ap->b != ap[-1].b || (ap->ifr & 4) != (ap[-1].ifr & 4)
+       || ap->acr != ap[-1].acr) {
+       ap->time = get_dec();
+       ++n_adb_log;
+    }
+}
+
+int
+adb_bitwait(int bmask, int bval, int fmask, int fval)
+{
+    int i;
+    struct adb_log *ap;
+
+    for (i = 10000; i > 0; --i) {
+       adb_chklog();
+       ap = &adb_log[n_adb_log];
+       if ((ap->b & bmask) == bval && (ap->ifr & fmask) == fval)
+           return 0;
+    }
+    return -1;
+}
+
+int
+adb_wait(void)
+{
+    if (adb_bitwait(0, 0, 4, 4) < 0) {
+       printf("adb: ready wait timeout\n");
+       return -1;
+    }
+    return 0;
+}
+
+void
+adb_readin(void)
+{
+    int i, j;
+    unsigned char d[64];
+
+    if (ADB_B & 8) {
+       printf("ADB_B: %x\n", ADB_B);
+       return;
+    }
+    i = 0;
+    adb_wait();
+    j = ADB_SR;
+    eieio();
+    ADB_B &= ~0x20;
+    eieio();
+    for (;;) {
+       if (adb_wait() < 0)
+           break;
+       d[i++] = ADB_SR;
+       eieio();
+       if (ADB_B & 8)
+           break;
+       ADB_B ^= 0x10;
+       eieio();
+    }
+    ADB_B |= 0x30;
+    if (adb_wait() == 0)
+       j = ADB_SR;
+    for (j = 0; j < i; ++j)
+       printf("%.2x ", d[j]);
+    printf("\n");
+}
+
+int
+adb_write(unsigned char *d, int i)
+{
+    int j;
+    unsigned x;
+
+    if ((ADB_B & 8) == 0) {
+       printf("r: ");
+       adb_readin();
+    }
+    for (;;) {
+       ADB_ACR = 0x1c;
+       eieio();
+       ADB_SR = d[0];
+       eieio();
+       ADB_B &= ~0x20;
+       eieio();
+       if (ADB_B & 8)
+           break;
+       ADB_ACR = 0xc;
+       eieio();
+       ADB_B |= 0x20;
+       eieio();
+       adb_readin();
+    }
+    adb_wait();
+    for (j = 1; j < i; ++j) {
+       ADB_SR = d[j];
+       eieio();
+       ADB_B ^= 0x10;
+       eieio();
+       if (adb_wait() < 0)
+           break;
+    }
+    ADB_ACR = 0xc;
+    eieio();
+    x = ADB_SR;
+    eieio();
+    ADB_B |= 0x30;
+    return j;
+}
+
+void
+adbcmds(void)
+{
+    char cmd;
+    unsigned rtcu, rtcl, dec, pdec, x;
+    int i, j;
+    unsigned char d[64];
+
+    cmd = skipbl();
+    switch (cmd) {
+    case 't':
+       for (;;) {
+           rtcl = get_rtcl();
+           rtcu = get_rtcu();
+           dec = get_dec();
+           printf("rtc u=%u l=%u dec=%x (%d = %d.%.7d)\n",
+                  rtcu, rtcl, dec, pdec - dec, (pdec - dec) / 1000000000,
+                  ((pdec - dec) % 1000000000) / 100);
+           pdec = dec;
+           if (cmd == 'x')
+               break;
+           while (xmon_read(stdin, &cmd, 1) != 1)
+               ;
+       }
+       break;
+    case 'r':
+       init_adb_log();
+       while (adb_bitwait(8, 0, 0, 0) == 0)
+           adb_readin();
+       break;
+    case 'w':
+       i = 0;
+       while (scanhex(&x))
+           d[i++] = x;
+       init_adb_log();
+       j = adb_write(d, i);
+       printf("sent %d bytes\n", j);
+       while (adb_bitwait(8, 0, 0, 0) == 0)
+           adb_readin();
+       break;
+    case 'l':
+       dump_adb_log();
+       break;
+    }
+}
diff --git a/arch/ppc/xmon/ansidecl.h b/arch/ppc/xmon/ansidecl.h
new file mode 100644 (file)
index 0000000..be04e42
--- /dev/null
@@ -0,0 +1,141 @@
+/* ANSI and traditional C compatability macros
+   Copyright 1991, 1992 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* ANSI and traditional C compatibility macros
+
+   ANSI C is assumed if __STDC__ is #defined.
+
+   Macro       ANSI C definition       Traditional C definition
+   -----       ---- - ----------       ----------- - ----------
+   PTR         `void *'                `char *'
+   LONG_DOUBLE `long double'           `double'
+   VOLATILE    `volatile'              `'
+   SIGNED      `signed'                `'
+   PTRCONST    `void *const'           `char *'
+   ANSI_PROTOTYPES  1                  not defined
+
+   CONST is also defined, but is obsolete.  Just use const.
+
+   DEFUN (name, arglist, args)
+
+       Defines function NAME.
+
+       ARGLIST lists the arguments, separated by commas and enclosed in
+       parentheses.  ARGLIST becomes the argument list in traditional C.
+
+       ARGS list the arguments with their types.  It becomes a prototype in
+       ANSI C, and the type declarations in traditional C.  Arguments should
+       be separated with `AND'.  For functions with a variable number of
+       arguments, the last thing listed should be `DOTS'.
+
+   DEFUN_VOID (name)
+
+       Defines a function NAME, which takes no arguments.
+
+   obsolete --     EXFUN (name, (prototype))   -- obsolete.
+
+       Replaced by PARAMS.  Do not use; will disappear someday soon.
+       Was used in external function declarations.
+       In ANSI C it is `NAME PROTOTYPE' (so PROTOTYPE should be enclosed in
+       parentheses).  In traditional C it is `NAME()'.
+       For a function that takes no arguments, PROTOTYPE should be `(void)'.
+
+    PARAMS ((args))
+
+       We could use the EXFUN macro to handle prototype declarations, but
+       the name is misleading and the result is ugly.  So we just define a
+       simple macro to handle the parameter lists, as in:
+
+             static int foo PARAMS ((int, char));
+
+       This produces:  `static int foo();' or `static int foo (int, char);'
+
+       EXFUN would have done it like this:
+
+             static int EXFUN (foo, (int, char));
+
+       but the function is not external...and it's hard to visually parse
+       the function name out of the mess.   EXFUN should be considered
+       obsolete; new code should be written to use PARAMS.
+
+    For example:
+       extern int printf PARAMS ((CONST char *format DOTS));
+       int DEFUN(fprintf, (stream, format),
+                 FILE *stream AND CONST char *format DOTS) { ... }
+       void DEFUN_VOID(abort) { ... }
+*/
+
+#ifndef        _ANSIDECL_H
+
+#define        _ANSIDECL_H     1
+
+
+/* Every source file includes this file,
+   so they will all get the switch for lint.  */
+/* LINTLIBRARY */
+
+
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32)
+/* All known AIX compilers implement these things (but don't always
+   define __STDC__).  The RISC/OS MIPS compiler defines these things
+   in SVR4 mode, but does not define __STDC__.  */
+
+#define        PTR             void *
+#define        PTRCONST        void *CONST
+#define        LONG_DOUBLE     long double
+
+#define        AND             ,
+#define        NOARGS          void
+#define        CONST           const
+#define        VOLATILE        volatile
+#define        SIGNED          signed
+#define        DOTS            , ...
+
+#define        EXFUN(name, proto)              name proto
+#define        DEFUN(name, arglist, args)      name(args)
+#define        DEFUN_VOID(name)                name(void)
+
+#define PROTO(type, name, arglist)     type name arglist
+#define PARAMS(paramlist)              paramlist
+#define ANSI_PROTOTYPES                        1
+
+#else  /* Not ANSI C.  */
+
+#define        PTR             char *
+#define        PTRCONST        PTR
+#define        LONG_DOUBLE     double
+
+#define        AND             ;
+#define        NOARGS
+#define        CONST
+#ifndef const /* some systems define it in header files for non-ansi mode */
+#define        const
+#endif
+#define        VOLATILE
+#define        SIGNED
+#define        DOTS
+
+#define        EXFUN(name, proto)              name()
+#define        DEFUN(name, arglist, args)      name arglist args;
+#define        DEFUN_VOID(name)                name()
+#define PROTO(type, name, arglist) type name ()
+#define PARAMS(paramlist)              ()
+
+#endif /* ANSI C.  */
+
+#endif /* ansidecl.h   */
diff --git a/arch/ppc/xmon/nonstdio.h b/arch/ppc/xmon/nonstdio.h
new file mode 100644 (file)
index 0000000..84211a2
--- /dev/null
@@ -0,0 +1,22 @@
+typedef int    FILE;
+extern FILE *xmon_stdin, *xmon_stdout;
+#define EOF    (-1)
+#define stdin  xmon_stdin
+#define stdout xmon_stdout
+#define printf xmon_printf
+#define fprintf        xmon_fprintf
+#define fputs  xmon_fputs
+#define fgets  xmon_fgets
+#define putchar        xmon_putchar
+#define getchar        xmon_getchar
+#define putc   xmon_putc
+#define getc   xmon_getc
+#define fopen(n, m)    NULL
+#define fflush(f)      do {} while (0)
+#define fclose(f)      do {} while (0)
+extern char *fgets(char *, int, void *);
+extern void xmon_printf(const char *, ...);
+extern void xmon_fprintf(void *, const char *, ...);
+extern void xmon_sprintf(char *, const char *, ...);
+
+#define perror(s)      printf("%s: no files!\n", (s))
diff --git a/arch/ppc/xmon/ppc-dis.c b/arch/ppc/xmon/ppc-dis.c
new file mode 100644 (file)
index 0000000..798ac1a
--- /dev/null
@@ -0,0 +1,190 @@
+/* ppc-dis.c -- Disassemble PowerPC instructions
+   Copyright 1994 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them 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.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "nonstdio.h"
+#include "ansidecl.h"
+#include "ppc.h"
+
+static int print_insn_powerpc PARAMS ((FILE *, unsigned long insn,
+                                      unsigned memaddr, int dialect));
+
+extern void print_address PARAMS((unsigned memaddr));
+
+/* Print a big endian PowerPC instruction.  For convenience, also
+   disassemble instructions supported by the Motorola PowerPC 601.  */
+
+int
+print_insn_big_powerpc (FILE *out, unsigned long insn, unsigned memaddr)
+{
+  return print_insn_powerpc (out, insn, memaddr,
+                            PPC_OPCODE_PPC | PPC_OPCODE_601);
+}
+
+/* Print a PowerPC or POWER instruction.  */
+
+static int
+print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
+                   int dialect)
+{
+  const struct powerpc_opcode *opcode;
+  const struct powerpc_opcode *opcode_end;
+  unsigned long op;
+
+  /* Get the major opcode of the instruction.  */
+  op = PPC_OP (insn);
+
+  /* Find the first match in the opcode table.  We could speed this up
+     a bit by doing a binary search on the major opcode.  */
+  opcode_end = powerpc_opcodes + powerpc_num_opcodes;
+  for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
+    {
+      unsigned long table_op;
+      const unsigned char *opindex;
+      const struct powerpc_operand *operand;
+      int invalid;
+      int need_comma;
+      int need_paren;
+
+      table_op = PPC_OP (opcode->opcode);
+      if (op < table_op)
+               break;
+      if (op > table_op)
+               continue;
+
+      if ((insn & opcode->mask) != opcode->opcode
+         || (opcode->flags & dialect) == 0)
+               continue;
+
+      /* Make two passes over the operands.  First see if any of them
+                have extraction functions, and, if they do, make sure the
+                instruction is valid.  */
+      invalid = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+               {
+                 operand = powerpc_operands + *opindex;
+                 if (operand->extract)
+                   (*operand->extract) (insn, &invalid);
+               }
+      if (invalid)
+               continue;
+
+      /* The instruction is valid.  */
+      fprintf(out, "%s", opcode->name);
+      if (opcode->operands[0] != 0)
+               fprintf(out, "\t");
+
+      /* Now extract and print the operands.  */
+      need_comma = 0;
+      need_paren = 0;
+      for (opindex = opcode->operands; *opindex != 0; opindex++)
+               {
+                 long value;
+
+                 operand = powerpc_operands + *opindex;
+
+                 /* Operands that are marked FAKE are simply ignored.  We
+                    already made sure that the extract function considered
+                    the instruction to be valid.  */
+                 if ((operand->flags & PPC_OPERAND_FAKE) != 0)
+                   continue;
+
+                 /* Extract the value from the instruction.  */
+                 if (operand->extract)
+                   value = (*operand->extract) (insn, (int *) 0);
+                 else
+                   {
+                     value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
+                     if ((operand->flags & PPC_OPERAND_SIGNED) != 0
+                         && (value & (1 << (operand->bits - 1))) != 0)
+                       value -= 1 << operand->bits;
+                   }
+
+                 /* If the operand is optional, and the value is zero, don't
+                    print anything.  */
+                 if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
+                     && (operand->flags & PPC_OPERAND_NEXT) == 0
+                     && value == 0)
+                   continue;
+
+                 if (need_comma)
+                   {
+                     fprintf(out, ",");
+                     need_comma = 0;
+                   }
+
+                 /* Print the operand as directed by the flags.  */
+                 if ((operand->flags & PPC_OPERAND_GPR) != 0)
+                   fprintf(out, "r%ld", value);
+                 else if ((operand->flags & PPC_OPERAND_FPR) != 0)
+                   fprintf(out, "f%ld", value);
+                 else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
+                   print_address (memaddr + value);
+                 else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
+                   print_address (value & 0xffffffff);
+                 else if ((operand->flags & PPC_OPERAND_CR) == 0
+                          || (dialect & PPC_OPCODE_PPC) == 0)
+                   fprintf(out, "%ld", value);
+                 else
+                   {
+                     if (operand->bits == 3)
+                               fprintf(out, "cr%d", value);
+                     else
+                       {
+                         static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
+                         int cr;
+                         int cc;
+
+                         cr = value >> 2;
+                         if (cr != 0)
+                           fprintf(out, "4*cr%d", cr);
+                         cc = value & 3;
+                         if (cc != 0)
+                           {
+                             if (cr != 0)
+                                       fprintf(out, "+");
+                             fprintf(out, "%s", cbnames[cc]);
+                           }
+                       }
+           }
+
+         if (need_paren)
+           {
+             fprintf(out, ")");
+             need_paren = 0;
+           }
+
+         if ((operand->flags & PPC_OPERAND_PARENS) == 0)
+           need_comma = 1;
+         else
+           {
+             fprintf(out, "(");
+             need_paren = 1;
+           }
+       }
+
+      /* We have found and printed an instruction; return.  */
+      return 4;
+    }
+
+  /* We could not find a match.  */
+  fprintf(out, ".long 0x%lx", insn);
+
+  return 4;
+}
diff --git a/arch/ppc/xmon/ppc-opc.c b/arch/ppc/xmon/ppc-opc.c
new file mode 100644 (file)
index 0000000..b356686
--- /dev/null
@@ -0,0 +1,2816 @@
+/* ppc-opc.c -- PowerPC opcode list
+   Copyright 1994 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them 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.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include <linux/posix_types.h>
+#include "ansidecl.h"
+#include "ppc.h"
+
+/* This file holds the PowerPC opcode table.  The opcode table
+   includes almost all of the extended instruction mnemonics.  This
+   permits the disassembler to use them, and simplifies the assembler
+   logic, at the cost of increasing the table size.  The table is
+   strictly constant data, so the compiler should be able to put it in
+   the .text section.
+
+   This file also holds the operand table.  All knowledge about
+   inserting operands into instructions and vice-versa is kept in this
+   file.  */
+\f
+/* Local insertion and extraction functions.  */
+
+static unsigned long insert_bat PARAMS ((unsigned long, long, const char **));
+static long extract_bat PARAMS ((unsigned long, int *));
+static unsigned long insert_bba PARAMS ((unsigned long, long, const char **));
+static long extract_bba PARAMS ((unsigned long, int *));
+static unsigned long insert_bd PARAMS ((unsigned long, long, const char **));
+static long extract_bd PARAMS ((unsigned long, int *));
+static unsigned long insert_bdm PARAMS ((unsigned long, long, const char **));
+static long extract_bdm PARAMS ((unsigned long, int *));
+static unsigned long insert_bdp PARAMS ((unsigned long, long, const char **));
+static long extract_bdp PARAMS ((unsigned long, int *));
+static unsigned long insert_bo PARAMS ((unsigned long, long, const char **));
+static long extract_bo PARAMS ((unsigned long, int *));
+static unsigned long insert_boe PARAMS ((unsigned long, long, const char **));
+static long extract_boe PARAMS ((unsigned long, int *));
+static unsigned long insert_ds PARAMS ((unsigned long, long, const char **));
+static long extract_ds PARAMS ((unsigned long, int *));
+static unsigned long insert_li PARAMS ((unsigned long, long, const char **));
+static long extract_li PARAMS ((unsigned long, int *));
+static unsigned long insert_mbe PARAMS ((unsigned long, long, const char **));
+static long extract_mbe PARAMS ((unsigned long, int *));
+static unsigned long insert_mb6 PARAMS ((unsigned long, long, const char **));
+static long extract_mb6 PARAMS ((unsigned long, int *));
+static unsigned long insert_nb PARAMS ((unsigned long, long, const char **));
+static long extract_nb PARAMS ((unsigned long, int *));
+static unsigned long insert_nsi PARAMS ((unsigned long, long, const char **));
+static long extract_nsi PARAMS ((unsigned long, int *));
+static unsigned long insert_ral PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_ram PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_ras PARAMS ((unsigned long, long, const char **));
+static unsigned long insert_rbs PARAMS ((unsigned long, long, const char **));
+static long extract_rbs PARAMS ((unsigned long, int *));
+static unsigned long insert_sh6 PARAMS ((unsigned long, long, const char **));
+static long extract_sh6 PARAMS ((unsigned long, int *));
+static unsigned long insert_spr PARAMS ((unsigned long, long, const char **));
+static long extract_spr PARAMS ((unsigned long, int *));
+static unsigned long insert_tbr PARAMS ((unsigned long, long, const char **));
+static long extract_tbr PARAMS ((unsigned long, int *));
+\f
+/* The operands table.
+
+   The fields are bits, shift, signed, insert, extract, flags.  */
+
+const struct powerpc_operand powerpc_operands[] =
+{
+  /* The zero index is used to indicate the end of the list of
+     operands.  */
+#define UNUSED (0)
+  { 0, 0, 0, 0, 0 },
+
+  /* The BA field in an XL form instruction.  */
+#define BA (1)
+#define BA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_CR },
+
+  /* The BA field in an XL form instruction when it must be the same
+     as the BT field in the same instruction.  */
+#define BAT (2)
+  { 5, 16, insert_bat, extract_bat, PPC_OPERAND_FAKE },
+
+  /* The BB field in an XL form instruction.  */
+#define BB (3)
+#define BB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_CR },
+
+  /* The BB field in an XL form instruction when it must be the same
+     as the BA field in the same instruction.  */
+#define BBA (4)
+  { 5, 11, insert_bba, extract_bba, PPC_OPERAND_FAKE },
+
+  /* The BD field in a B form instruction.  The lower two bits are
+     forced to zero.  */
+#define BD (5)
+  { 16, 0, insert_bd, extract_bd, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when absolute addressing is
+     used.  */
+#define BDA (6)
+  { 16, 0, insert_bd, extract_bd, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the - modifier is used.
+     This sets the y bit of the BO field appropriately.  */
+#define BDM (7)
+  { 16, 0, insert_bdm, extract_bdm,
+      PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the - modifier is used
+     and absolute address is used.  */
+#define BDMA (8)
+  { 16, 0, insert_bdm, extract_bdm,
+      PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the + modifier is used.
+     This sets the y bit of the BO field appropriately.  */
+#define BDP (9)
+  { 16, 0, insert_bdp, extract_bdp,
+      PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The BD field in a B form instruction when the + modifier is used
+     and absolute addressing is used.  */
+#define BDPA (10)
+  { 16, 0, insert_bdp, extract_bdp,
+      PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The BF field in an X or XL form instruction.  */
+#define BF (11)
+  { 3, 23, 0, 0, PPC_OPERAND_CR },
+
+  /* An optional BF field.  This is used for comparison instructions,
+     in which an omitted BF field is taken as zero.  */
+#define OBF (12)
+  { 3, 23, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The BFA field in an X or XL form instruction.  */
+#define BFA (13)
+  { 3, 18, 0, 0, PPC_OPERAND_CR },
+
+  /* The BI field in a B form or XL form instruction.  */
+#define BI (14)
+#define BI_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_CR },
+
+  /* The BO field in a B form instruction.  Certain values are
+     illegal.  */
+#define BO (15)
+#define BO_MASK (0x1f << 21)
+  { 5, 21, insert_bo, extract_bo, 0 },
+
+  /* The BO field in a B form instruction when the + or - modifier is
+     used.  This is like the BO field, but it must be even.  */
+#define BOE (16)
+  { 5, 21, insert_boe, extract_boe, 0 },
+
+  /* The BT field in an X or XL form instruction.  */
+#define BT (17)
+  { 5, 21, 0, 0, PPC_OPERAND_CR },
+
+  /* The condition register number portion of the BI field in a B form
+     or XL form instruction.  This is used for the extended
+     conditional branch mnemonics, which set the lower two bits of the
+     BI field.  This field is optional.  */
+#define CR (18)
+  { 3, 18, 0, 0, PPC_OPERAND_CR | PPC_OPERAND_OPTIONAL },
+
+  /* The D field in a D form instruction.  This is a displacement off
+     a register, and implies that the next operand is a register in
+     parentheses.  */
+#define D (19)
+  { 16, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The DS field in a DS form instruction.  This is like D, but the
+     lower two bits are forced to zero.  */
+#define DS (20)
+  { 16, 0, insert_ds, extract_ds, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
+
+  /* The FL1 field in a POWER SC form instruction.  */
+#define FL1 (21)
+  { 4, 12, 0, 0, 0 },
+
+  /* The FL2 field in a POWER SC form instruction.  */
+#define FL2 (22)
+  { 3, 2, 0, 0, 0 },
+
+  /* The FLM field in an XFL form instruction.  */
+#define FLM (23)
+  { 8, 17, 0, 0, 0 },
+
+  /* The FRA field in an X or A form instruction.  */
+#define FRA (24)
+#define FRA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRB field in an X or A form instruction.  */
+#define FRB (25)
+#define FRB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRC field in an A form instruction.  */
+#define FRC (26)
+#define FRC_MASK (0x1f << 6)
+  { 5, 6, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FRS field in an X form instruction or the FRT field in a D, X
+     or A form instruction.  */
+#define FRS (27)
+#define FRT (FRS)
+  { 5, 21, 0, 0, PPC_OPERAND_FPR },
+
+  /* The FXM field in an XFX instruction.  */
+#define FXM (28)
+#define FXM_MASK (0xff << 12)
+  { 8, 12, 0, 0, 0 },
+
+  /* The L field in a D or X form instruction.  */
+#define L (29)
+  { 1, 21, 0, 0, PPC_OPERAND_OPTIONAL },
+
+  /* The LEV field in a POWER SC form instruction.  */
+#define LEV (30)
+  { 7, 5, 0, 0, 0 },
+
+  /* The LI field in an I form instruction.  The lower two bits are
+     forced to zero.  */
+#define LI (31)
+  { 26, 0, insert_li, extract_li, PPC_OPERAND_RELATIVE | PPC_OPERAND_SIGNED },
+
+  /* The LI field in an I form instruction when used as an absolute
+     address.  */
+#define LIA (32)
+  { 26, 0, insert_li, extract_li, PPC_OPERAND_ABSOLUTE | PPC_OPERAND_SIGNED },
+
+  /* The MB field in an M form instruction.  */
+#define MB (33)
+#define MB_MASK (0x1f << 6)
+  { 5, 6, 0, 0, 0 },
+
+  /* The ME field in an M form instruction.  */
+#define ME (34)
+#define ME_MASK (0x1f << 1)
+  { 5, 1, 0, 0, 0 },
+
+  /* The MB and ME fields in an M form instruction expressed a single
+     operand which is a bitmask indicating which bits to select.  This
+     is a two operand form using PPC_OPERAND_NEXT.  See the
+     description in opcode/ppc.h for what this means.  */
+#define MBE (35)
+  { 5, 6, 0, 0, PPC_OPERAND_OPTIONAL | PPC_OPERAND_NEXT },
+  { 32, 0, insert_mbe, extract_mbe, 0 },
+
+  /* The MB or ME field in an MD or MDS form instruction.  The high
+     bit is wrapped to the low end.  */
+#define MB6 (37)
+#define ME6 (MB6)
+#define MB6_MASK (0x3f << 5)
+  { 6, 5, insert_mb6, extract_mb6, 0 },
+
+  /* The NB field in an X form instruction.  The value 32 is stored as
+     0.  */
+#define NB (38)
+  { 6, 11, insert_nb, extract_nb, 0 },
+
+  /* The NSI field in a D form instruction.  This is the same as the
+     SI field, only negated.  */
+#define NSI (39)
+  { 16, 0, insert_nsi, extract_nsi,
+      PPC_OPERAND_NEGATIVE | PPC_OPERAND_SIGNED },
+
+  /* The RA field in an D, DS, X, XO, M, or MDS form instruction.  */
+#define RA (40)
+#define RA_MASK (0x1f << 16)
+  { 5, 16, 0, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in a D or X form instruction which is an updating
+     load, which means that the RA field may not be zero and may not
+     equal the RT field.  */
+#define RAL (41)
+  { 5, 16, insert_ral, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in an lmw instruction, which has special value
+     restrictions.  */
+#define RAM (42)
+  { 5, 16, insert_ram, 0, PPC_OPERAND_GPR },
+
+  /* The RA field in a D or X form instruction which is an updating
+     store or an updating floating point load, which means that the RA
+     field may not be zero.  */
+#define RAS (43)
+  { 5, 16, insert_ras, 0, PPC_OPERAND_GPR },
+
+  /* The RB field in an X, XO, M, or MDS form instruction.  */
+#define RB (44)
+#define RB_MASK (0x1f << 11)
+  { 5, 11, 0, 0, PPC_OPERAND_GPR },
+
+  /* The RB field in an X form instruction when it must be the same as
+     the RS field in the instruction.  This is used for extended
+     mnemonics like mr.  */
+#define RBS (45)
+  { 5, 1, insert_rbs, extract_rbs, PPC_OPERAND_FAKE },
+
+  /* The RS field in a D, DS, X, XFX, XS, M, MD or MDS form
+     instruction or the RT field in a D, DS, X, XFX or XO form
+     instruction.  */
+#define RS (46)
+#define RT (RS)
+#define RT_MASK (0x1f << 21)
+  { 5, 21, 0, 0, PPC_OPERAND_GPR },
+
+  /* The SH field in an X or M form instruction.  */
+#define SH (47)
+#define SH_MASK (0x1f << 11)
+  { 5, 11, 0, 0, 0 },
+
+  /* The SH field in an MD form instruction.  This is split.  */
+#define SH6 (48)
+#define SH6_MASK ((0x1f << 11) | (1 << 1))
+  { 6, 1, insert_sh6, extract_sh6, 0 },
+
+  /* The SI field in a D form instruction.  */
+#define SI (49)
+  { 16, 0, 0, 0, PPC_OPERAND_SIGNED },
+
+  /* The SI field in a D form instruction when we accept a wide range
+     of positive values.  */
+#define SISIGNOPT (50)
+  { 16, 0, 0, 0, PPC_OPERAND_SIGNED | PPC_OPERAND_SIGNOPT },
+
+  /* The SPR field in an XFX form instruction.  This is flipped--the
+     lower 5 bits are stored in the upper 5 and vice- versa.  */
+#define SPR (51)
+#define SPR_MASK (0x3ff << 11)
+  { 10, 11, insert_spr, extract_spr, 0 },
+
+  /* The BAT index number in an XFX form m[ft]ibat[lu] instruction.  */
+#define SPRBAT (52)
+#define SPRBAT_MASK (0x3 << 17)
+  { 2, 17, 0, 0, 0 },
+
+  /* The SPRG register number in an XFX form m[ft]sprg instruction.  */
+#define SPRG (53)
+#define SPRG_MASK (0x3 << 16)
+  { 2, 16, 0, 0, 0 },
+
+  /* The SR field in an X form instruction.  */
+#define SR (54)
+  { 4, 16, 0, 0, 0 },
+
+  /* The SV field in a POWER SC form instruction.  */
+#define SV (55)
+  { 14, 2, 0, 0, 0 },
+
+  /* The TBR field in an XFX form instruction.  This is like the SPR
+     field, but it is optional.  */
+#define TBR (56)
+  { 10, 11, insert_tbr, extract_tbr, PPC_OPERAND_OPTIONAL },
+
+  /* The TO field in a D or X form instruction.  */
+#define TO (57)
+#define TO_MASK (0x1f << 21)
+  { 5, 21, 0, 0, 0 },
+
+  /* The U field in an X form instruction.  */
+#define U (58)
+  { 4, 12, 0, 0, 0 },
+
+  /* The UI field in a D form instruction.  */
+#define UI (59)
+  { 16, 0, 0, 0, 0 },
+};
+
+/* The functions used to insert and extract complicated operands.  */
+
+/* The BA field in an XL form instruction when it must be the same as
+   the BT field in the same instruction.  This operand is marked FAKE.
+   The insertion function just copies the BT field into the BA field,
+   and the extraction function just checks that the fields are the
+   same.  */
+
+/*ARGSUSED*/
+static unsigned long 
+insert_bat (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (((insn >> 21) & 0x1f) << 16);
+}
+
+static long
+extract_bat (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The BB field in an XL form instruction when it must be the same as
+   the BA field in the same instruction.  This operand is marked FAKE.
+   The insertion function just copies the BA field into the BB field,
+   and the extraction function just checks that the fields are the
+   same.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bba (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (((insn >> 16) & 0x1f) << 11);
+}
+
+static long
+extract_bba (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The BD field in a B form instruction.  The lower two bits are
+   forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bd (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (value & 0xfffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_bd (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The BD field in a B form instruction when the - modifier is used.
+   This modifier means that the branch is not expected to be taken.
+   We must set the y bit of the BO field to 1 if the offset is
+   negative.  When extracting, we require that the y bit be 1 and that
+   the offset be positive, since if the y bit is 0 we just want to
+   print the normal form of the instruction.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bdm (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if ((value & 0x8000) != 0)
+    insn |= 1 << 21;
+  return insn | (value & 0xfffc);
+}
+
+static long
+extract_bdm (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn & (1 << 21)) == 0
+         || (insn & (1 << 15)) == 0))
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The BD field in a B form instruction when the + modifier is used.
+   This is like BDM, above, except that the branch is expected to be
+   taken.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_bdp (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if ((value & 0x8000) == 0)
+    insn |= 1 << 21;
+  return insn | (value & 0xfffc);
+}
+
+static long
+extract_bdp (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn & (1 << 21)) == 0
+         || (insn & (1 << 15)) != 0))
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* Check for legal values of a BO field.  */
+
+static int
+valid_bo (value)
+     long value;
+{
+  /* Certain encodings have bits that are required to be zero.  These
+     are (z must be zero, y may be anything):
+         001zy
+        011zy
+        1z00y
+        1z01y
+        1z1zz
+     */
+  switch (value & 0x14)
+    {
+    default:
+    case 0:
+      return 1;
+    case 0x4:
+      return (value & 0x2) == 0;
+    case 0x10:
+      return (value & 0x8) == 0;
+    case 0x14:
+      return value == 0x14;
+    }
+}
+
+/* The BO field in a B form instruction.  Warn about attempts to set
+   the field to an illegal value.  */
+
+static unsigned long
+insert_bo (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (errmsg != (const char **) NULL
+      && ! valid_bo (value))
+    *errmsg = "invalid conditional option";
+  return insn | ((value & 0x1f) << 21);
+}
+
+static long
+extract_bo (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long value;
+
+  value = (insn >> 21) & 0x1f;
+  if (invalid != (int *) NULL
+      && ! valid_bo (value))
+    *invalid = 1;
+  return value;
+}
+
+/* The BO field in a B form instruction when the + or - modifier is
+   used.  This is like the BO field, but it must be even.  When
+   extracting it, we force it to be even.  */
+
+static unsigned long
+insert_boe (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (errmsg != (const char **) NULL)
+    {
+      if (! valid_bo (value))
+       *errmsg = "invalid conditional option";
+      else if ((value & 1) != 0)
+       *errmsg = "attempt to set y bit when using + or - modifier";
+    }
+  return insn | ((value & 0x1f) << 21);
+}
+
+static long
+extract_boe (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long value;
+
+  value = (insn >> 21) & 0x1f;
+  if (invalid != (int *) NULL
+      && ! valid_bo (value))
+    *invalid = 1;
+  return value & 0x1e;
+}
+
+/* The DS field in a DS form instruction.  This is like D, but the
+   lower two bits are forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_ds (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (value & 0xfffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_ds (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if ((insn & 0x8000) != 0)
+    return (insn & 0xfffc) - 0x10000;
+  else
+    return insn & 0xfffc;
+}
+
+/* The LI field in an I form instruction.  The lower two bits are
+   forced to zero.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_li (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (value & 0x3fffffc);
+}
+
+/*ARGSUSED*/
+static long
+extract_li (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if ((insn & 0x2000000) != 0)
+    return (insn & 0x3fffffc) - 0x4000000;
+  else
+    return insn & 0x3fffffc;
+}
+
+/* The MB and ME fields in an M form instruction expressed as a single
+   operand which is itself a bitmask.  The extraction function always
+   marks it as invalid, since we never want to recognize an
+   instruction which uses a field of this type.  */
+
+static unsigned long
+insert_mbe (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  unsigned long uval;
+  int mb, me;
+
+  uval = value;
+
+  if (uval == 0)
+    {
+      if (errmsg != (const char **) NULL)
+       *errmsg = "illegal bitmask";
+      return insn;
+    }
+
+  me = 31;
+  while ((uval & 1) == 0)
+    {
+      uval >>= 1;
+      --me;
+    }
+
+  mb = me;
+  uval >>= 1;
+  while ((uval & 1) != 0)
+    {
+      uval >>= 1;
+      --mb;
+    }
+
+  if (uval != 0)
+    {
+      if (errmsg != (const char **) NULL)
+       *errmsg = "illegal bitmask";
+    }
+
+  return insn | (mb << 6) | (me << 1);
+}
+
+static long
+extract_mbe (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long ret;
+  int mb, me;
+  int i;
+
+  if (invalid != (int *) NULL)
+    *invalid = 1;
+
+  ret = 0;
+  mb = (insn >> 6) & 0x1f;
+  me = (insn >> 1) & 0x1f;
+  for (i = mb; i < me; i++)
+    ret |= 1 << (31 - i);
+  return ret;
+}
+
+/* The MB or ME field in an MD or MDS form instruction.  The high bit
+   is wrapped to the low end.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_mb6 (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | ((value & 0x1f) << 6) | (value & 0x20);
+}
+
+/*ARGSUSED*/
+static long
+extract_mb6 (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  return ((insn >> 6) & 0x1f) | (insn & 0x20);
+}
+
+/* The NB field in an X form instruction.  The value 32 is stored as
+   0.  */
+
+static unsigned long
+insert_nb (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value < 0 || value > 32)
+    *errmsg = "value out of range";
+  if (value == 32)
+    value = 0;
+  return insn | ((value & 0x1f) << 11);
+}
+
+/*ARGSUSED*/
+static long
+extract_nb (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long ret;
+
+  ret = (insn >> 11) & 0x1f;
+  if (ret == 0)
+    ret = 32;
+  return ret;
+}
+
+/* The NSI field in a D form instruction.  This is the same as the SI
+   field, only negated.  The extraction function always marks it as
+   invalid, since we never want to recognize an instruction which uses
+   a field of this type.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_nsi (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | ((- value) & 0xffff);
+}
+
+static long
+extract_nsi (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL)
+    *invalid = 1;
+  if ((insn & 0x8000) != 0)
+    return - ((insn & 0xffff) - 0x10000);
+  else
+    return - (insn & 0xffff);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+   load, which means that the RA field may not be zero and may not
+   equal the RT field.  */
+
+static unsigned long
+insert_ral (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value == 0
+      || value == ((insn >> 21) & 0x1f))
+    *errmsg = "invalid register operand when updating";
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in an lmw instruction, which has special value
+   restrictions.  */
+
+static unsigned long
+insert_ram (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value >= ((insn >> 21) & 0x1f))
+    *errmsg = "index register in load range";
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RA field in a D or X form instruction which is an updating
+   store or an updating floating point load, which means that the RA
+   field may not be zero.  */
+
+static unsigned long
+insert_ras (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value == 0)
+    *errmsg = "invalid register operand when updating";
+  return insn | ((value & 0x1f) << 16);
+}
+
+/* The RB field in an X form instruction when it must be the same as
+   the RS field in the instruction.  This is used for extended
+   mnemonics like mr.  This operand is marked FAKE.  The insertion
+   function just copies the BT field into the BA field, and the
+   extraction function just checks that the fields are the same.  */
+
+/*ARGSUSED*/
+static unsigned long 
+insert_rbs (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | (((insn >> 21) & 0x1f) << 11);
+}
+
+static long
+extract_rbs (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  if (invalid != (int *) NULL
+      && ((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f))
+    *invalid = 1;
+  return 0;
+}
+
+/* The SH field in an MD form instruction.  This is split.  */
+
+/*ARGSUSED*/
+static unsigned long
+insert_sh6 (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4);
+}
+
+/*ARGSUSED*/
+static long
+extract_sh6 (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20);
+}
+
+/* The SPR field in an XFX form instruction.  This is flipped--the
+   lower 5 bits are stored in the upper 5 and vice- versa.  */
+
+static unsigned long
+insert_spr (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
+}
+
+static long
+extract_spr (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
+}
+
+/* The TBR field in an XFX instruction.  This is just like SPR, but it
+   is optional.  When TBR is omitted, it must be inserted as 268 (the
+   magic number of the TB register).  These functions treat 0
+   (indicating an omitted optional operand) as 268.  This means that
+   ``mftb 4,0'' is not handled correctly.  This does not matter very
+   much, since the architecture manual does not define mftb as
+   accepting any values other than 268 or 269.  */
+
+#define TB (268)
+
+static unsigned long
+insert_tbr (insn, value, errmsg)
+     unsigned long insn;
+     long value;
+     const char **errmsg;
+{
+  if (value == 0)
+    value = TB;
+  return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6);
+}
+
+static long
+extract_tbr (insn, invalid)
+     unsigned long insn;
+     int *invalid;
+{
+  long ret;
+
+  ret = ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0);
+  if (ret == TB)
+    ret = 0;
+  return ret;
+}
+\f
+/* Macros used to form opcodes.  */
+
+/* The main opcode.  */
+#define OP(x) (((x) & 0x3f) << 26)
+#define OP_MASK OP (0x3f)
+
+/* The main opcode combined with a trap code in the TO field of a D
+   form instruction.  Used for extended mnemonics for the trap
+   instructions.  */
+#define OPTO(x,to) (OP (x) | (((to) & 0x1f) << 21))
+#define OPTO_MASK (OP_MASK | TO_MASK)
+
+/* The main opcode combined with a comparison size bit in the L field
+   of a D form or X form instruction.  Used for extended mnemonics for
+   the comparison instructions.  */
+#define OPL(x,l) (OP (x) | (((l) & 1) << 21))
+#define OPL_MASK OPL (0x3f,1)
+
+/* An A form instruction.  */
+#define A(op, xop, rc) (OP (op) | (((xop) & 0x1f) << 1) | ((rc) & 1))
+#define A_MASK A (0x3f, 0x1f, 1)
+
+/* An A_MASK with the FRB field fixed.  */
+#define AFRB_MASK (A_MASK | FRB_MASK)
+
+/* An A_MASK with the FRC field fixed.  */
+#define AFRC_MASK (A_MASK | FRC_MASK)
+
+/* An A_MASK with the FRA and FRC fields fixed.  */
+#define AFRAFRC_MASK (A_MASK | FRA_MASK | FRC_MASK)
+
+/* A B form instruction.  */
+#define B(op, aa, lk) (OP (op) | (((aa) & 1) << 1) | ((lk) & 1))
+#define B_MASK B (0x3f, 1, 1)
+
+/* A B form instruction setting the BO field.  */
+#define BBO(op, bo, aa, lk) (B ((op), (aa), (lk)) | (((bo) & 0x1f) << 21))
+#define BBO_MASK BBO (0x3f, 0x1f, 1, 1)
+
+/* A BBO_MASK with the y bit of the BO field removed.  This permits
+   matching a conditional branch regardless of the setting of the y
+   bit.  */
+#define Y_MASK (1 << 21)
+#define BBOY_MASK (BBO_MASK &~ Y_MASK)
+
+/* A B form instruction setting the BO field and the condition bits of
+   the BI field.  */
+#define BBOCB(op, bo, cb, aa, lk) \
+  (BBO ((op), (bo), (aa), (lk)) | (((cb) & 0x3) << 16))
+#define BBOCB_MASK BBOCB (0x3f, 0x1f, 0x3, 1, 1)
+
+/* A BBOCB_MASK with the y bit of the BO field removed.  */
+#define BBOYCB_MASK (BBOCB_MASK &~ Y_MASK)
+
+/* A BBOYCB_MASK in which the BI field is fixed.  */
+#define BBOYBI_MASK (BBOYCB_MASK | BI_MASK)
+
+/* The main opcode mask with the RA field clear.  */
+#define DRA_MASK (OP_MASK | RA_MASK)
+
+/* A DS form instruction.  */
+#define DSO(op, xop) (OP (op) | ((xop) & 0x3))
+#define DS_MASK DSO (0x3f, 3)
+
+/* An M form instruction.  */
+#define M(op, rc) (OP (op) | ((rc) & 1))
+#define M_MASK M (0x3f, 1)
+
+/* An M form instruction with the ME field specified.  */
+#define MME(op, me, rc) (M ((op), (rc)) | (((me) & 0x1f) << 1))
+
+/* An M_MASK with the MB and ME fields fixed.  */
+#define MMBME_MASK (M_MASK | MB_MASK | ME_MASK)
+
+/* An M_MASK with the SH and ME fields fixed.  */
+#define MSHME_MASK (M_MASK | SH_MASK | ME_MASK)
+
+/* An MD form instruction.  */
+#define MD(op, xop, rc) (OP (op) | (((xop) & 0x7) << 2) | ((rc) & 1))
+#define MD_MASK MD (0x3f, 0x7, 1)
+
+/* An MD_MASK with the MB field fixed.  */
+#define MDMB_MASK (MD_MASK | MB6_MASK)
+
+/* An MD_MASK with the SH field fixed.  */
+#define MDSH_MASK (MD_MASK | SH6_MASK)
+
+/* An MDS form instruction.  */
+#define MDS(op, xop, rc) (OP (op) | (((xop) & 0xf) << 1) | ((rc) & 1))
+#define MDS_MASK MDS (0x3f, 0xf, 1)
+
+/* An MDS_MASK with the MB field fixed.  */
+#define MDSMB_MASK (MDS_MASK | MB6_MASK)
+
+/* An SC form instruction.  */
+#define SC(op, sa, lk) (OP (op) | (((sa) & 1) << 1) | ((lk) & 1))
+#define SC_MASK (OP_MASK | (0x3ff << 16) | (1 << 1) | 1)
+
+/* An X form instruction.  */
+#define X(op, xop) (OP (op) | (((xop) & 0x3ff) << 1))
+
+/* An X form instruction with the RC bit specified.  */
+#define XRC(op, xop, rc) (X ((op), (xop)) | ((rc) & 1))
+
+/* The mask for an X form instruction.  */
+#define X_MASK XRC (0x3f, 0x3ff, 1)
+
+/* An X_MASK with the RA field fixed.  */
+#define XRA_MASK (X_MASK | RA_MASK)
+
+/* An X_MASK with the RB field fixed.  */
+#define XRB_MASK (X_MASK | RB_MASK)
+
+/* An X_MASK with the RT field fixed.  */
+#define XRT_MASK (X_MASK | RT_MASK)
+
+/* An X_MASK with the RA and RB fields fixed.  */
+#define XRARB_MASK (X_MASK | RA_MASK | RB_MASK)
+
+/* An X_MASK with the RT and RA fields fixed.  */
+#define XRTRA_MASK (X_MASK | RT_MASK | RA_MASK)
+
+/* An X form comparison instruction.  */
+#define XCMPL(op, xop, l) (X ((op), (xop)) | (((l) & 1) << 21))
+
+/* The mask for an X form comparison instruction.  */
+#define XCMP_MASK (X_MASK | (1 << 22))
+
+/* The mask for an X form comparison instruction with the L field
+   fixed.  */
+#define XCMPL_MASK (XCMP_MASK | (1 << 21))
+
+/* An X form trap instruction with the TO field specified.  */
+#define XTO(op, xop, to) (X ((op), (xop)) | (((to) & 0x1f) << 21))
+#define XTO_MASK (X_MASK | TO_MASK)
+
+/* An XFL form instruction.  */
+#define XFL(op, xop, rc) (OP (op) | (((xop) & 0x3ff) << 1) | ((rc) & 1))
+#define XFL_MASK (XFL (0x3f, 0x3ff, 1) | (1 << 25) | (1 << 16))
+
+/* An XL form instruction with the LK field set to 0.  */
+#define XL(op, xop) (OP (op) | (((xop) & 0x3ff) << 1))
+
+/* An XL form instruction which uses the LK field.  */
+#define XLLK(op, xop, lk) (XL ((op), (xop)) | ((lk) & 1))
+
+/* The mask for an XL form instruction.  */
+#define XL_MASK XLLK (0x3f, 0x3ff, 1)
+
+/* An XL form instruction which explicitly sets the BO field.  */
+#define XLO(op, bo, xop, lk) \
+  (XLLK ((op), (xop), (lk)) | (((bo) & 0x1f) << 21))
+#define XLO_MASK (XL_MASK | BO_MASK)
+
+/* An XL form instruction which explicitly sets the y bit of the BO
+   field.  */
+#define XLYLK(op, xop, y, lk) (XLLK ((op), (xop), (lk)) | (((y) & 1) << 21))
+#define XLYLK_MASK (XL_MASK | Y_MASK)
+
+/* An XL form instruction which sets the BO field and the condition
+   bits of the BI field.  */
+#define XLOCB(op, bo, cb, xop, lk) \
+  (XLO ((op), (bo), (xop), (lk)) | (((cb) & 3) << 16))
+#define XLOCB_MASK XLOCB (0x3f, 0x1f, 0x3, 0x3ff, 1)
+
+/* An XL_MASK or XLYLK_MASK or XLOCB_MASK with the BB field fixed.  */
+#define XLBB_MASK (XL_MASK | BB_MASK)
+#define XLYBB_MASK (XLYLK_MASK | BB_MASK)
+#define XLBOCBBB_MASK (XLOCB_MASK | BB_MASK)
+
+/* An XL_MASK with the BO and BB fields fixed.  */
+#define XLBOBB_MASK (XL_MASK | BO_MASK | BB_MASK)
+
+/* An XL_MASK with the BO, BI and BB fields fixed.  */
+#define XLBOBIBB_MASK (XL_MASK | BO_MASK | BI_MASK | BB_MASK)
+
+/* An XO form instruction.  */
+#define XO(op, xop, oe, rc) \
+  (OP (op) | (((xop) & 0x1ff) << 1) | (((oe) & 1) << 10) | ((rc) & 1))
+#define XO_MASK XO (0x3f, 0x1ff, 1, 1)
+
+/* An XO_MASK with the RB field fixed.  */
+#define XORB_MASK (XO_MASK | RB_MASK)
+
+/* An XS form instruction.  */
+#define XS(op, xop, rc) (OP (op) | (((xop) & 0x1ff) << 2) | ((rc) & 1))
+#define XS_MASK XS (0x3f, 0x1ff, 1)
+
+/* A mask for the FXM version of an XFX form instruction.  */
+#define XFXFXM_MASK (X_MASK | (1 << 20) | (1 << 11))
+
+/* An XFX form instruction with the FXM field filled in.  */
+#define XFXM(op, xop, fxm) \
+  (X ((op), (xop)) | (((fxm) & 0xff) << 12))
+
+/* An XFX form instruction with the SPR field filled in.  */
+#define XSPR(op, xop, spr) \
+  (X ((op), (xop)) | (((spr) & 0x1f) << 16) | (((spr) & 0x3e0) << 6))
+#define XSPR_MASK (X_MASK | SPR_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+   SPRBAT field.  */
+#define XSPRBAT_MASK (XSPR_MASK &~ SPRBAT_MASK)
+
+/* An XFX form instruction with the SPR field filled in except for the
+   SPRG field.  */
+#define XSPRG_MASK (XSPR_MASK &~ SPRG_MASK)
+
+/* The BO encodings used in extended conditional branch mnemonics.  */
+#define BODNZF (0x0)
+#define BODNZFP        (0x1)
+#define BODZF  (0x2)
+#define BODZFP (0x3)
+#define BOF    (0x4)
+#define BOFP   (0x5)
+#define BODNZT (0x8)
+#define BODNZTP        (0x9)
+#define BODZT  (0xa)
+#define BODZTP (0xb)
+#define BOT    (0xc)
+#define BOTP   (0xd)
+#define BODNZ  (0x10)
+#define BODNZP (0x11)
+#define BODZ   (0x12)
+#define BODZP  (0x13)
+#define BOU    (0x14)
+
+/* The BI condition bit encodings used in extended conditional branch
+   mnemonics.  */
+#define CBLT   (0)
+#define CBGT   (1)
+#define CBEQ   (2)
+#define CBSO   (3)
+
+/* The TO encodings used in extended trap mnemonics.  */
+#define TOLGT  (0x1)
+#define TOLLT  (0x2)
+#define TOEQ   (0x4)
+#define TOLGE  (0x5)
+#define TOLNL  (0x5)
+#define TOLLE  (0x6)
+#define TOLNG  (0x6)
+#define TOGT   (0x8)
+#define TOGE   (0xc)
+#define TONL   (0xc)
+#define TOLT   (0x10)
+#define TOLE   (0x14)
+#define TONG   (0x14)
+#define TONE   (0x18)
+#define TOU    (0x1f)
+\f
+/* Smaller names for the flags so each entry in the opcodes table will
+   fit on a single line.  */
+#undef PPC
+#define PPC PPC_OPCODE_PPC
+#define POWER PPC_OPCODE_POWER
+#define POWER2 PPC_OPCODE_POWER2
+#define B32 PPC_OPCODE_32
+#define B64 PPC_OPCODE_64
+#define M601 PPC_OPCODE_601
+\f
+/* The opcode table.
+
+   The format of the opcode table is:
+
+   NAME             OPCODE     MASK            FLAGS           { OPERANDS }
+
+   NAME is the name of the instruction.
+   OPCODE is the instruction opcode.
+   MASK is the opcode mask; this is used to tell the disassembler
+     which bits in the actual opcode must match OPCODE.
+   FLAGS are flags indicated what processors support the instruction.
+   OPERANDS is the list of operands.
+
+   The disassembler reads the table in order and prints the first
+   instruction which matches, so this table is sorted to put more
+   specific instructions before more general instructions.  It is also
+   sorted by major opcode.  */
+
+const struct powerpc_opcode powerpc_opcodes[] = {
+{ "tdlgti",  OPTO(2,TOLGT), OPTO_MASK, PPC|B64,        { RA, SI } },
+{ "tdllti",  OPTO(2,TOLLT), OPTO_MASK, PPC|B64,        { RA, SI } },
+{ "tdeqi",   OPTO(2,TOEQ), OPTO_MASK,  PPC|B64,        { RA, SI } },
+{ "tdlgei",  OPTO(2,TOLGE), OPTO_MASK, PPC|B64,        { RA, SI } },
+{ "tdlnli",  OPTO(2,TOLNL), OPTO_MASK, PPC|B64,        { RA, SI } },
+{ "tdllei",  OPTO(2,TOLLE), OPTO_MASK, PPC|B64,        { RA, SI } },
+{ "tdlngi",  OPTO(2,TOLNG), OPTO_MASK, PPC|B64,        { RA, SI } },
+{ "tdgti",   OPTO(2,TOGT), OPTO_MASK,  PPC|B64,        { RA, SI } },
+{ "tdgei",   OPTO(2,TOGE), OPTO_MASK,  PPC|B64,        { RA, SI } },
+{ "tdnli",   OPTO(2,TONL), OPTO_MASK,  PPC|B64,        { RA, SI } },
+{ "tdlti",   OPTO(2,TOLT), OPTO_MASK,  PPC|B64,        { RA, SI } },
+{ "tdlei",   OPTO(2,TOLE), OPTO_MASK,  PPC|B64,        { RA, SI } },
+{ "tdngi",   OPTO(2,TONG), OPTO_MASK,  PPC|B64,        { RA, SI } },
+{ "tdnei",   OPTO(2,TONE), OPTO_MASK,  PPC|B64,        { RA, SI } },
+{ "tdi",     OP(2),    OP_MASK,        PPC|B64,        { TO, RA, SI } },
+
+{ "twlgti",  OPTO(3,TOLGT), OPTO_MASK, PPC,            { RA, SI } },
+{ "tlgti",   OPTO(3,TOLGT), OPTO_MASK, POWER,          { RA, SI } },
+{ "twllti",  OPTO(3,TOLLT), OPTO_MASK, PPC,            { RA, SI } },
+{ "tllti",   OPTO(3,TOLLT), OPTO_MASK, POWER,          { RA, SI } },
+{ "tweqi",   OPTO(3,TOEQ), OPTO_MASK,  PPC,            { RA, SI } },
+{ "teqi",    OPTO(3,TOEQ), OPTO_MASK,  POWER,          { RA, SI } },
+{ "twlgei",  OPTO(3,TOLGE), OPTO_MASK, PPC,            { RA, SI } },
+{ "tlgei",   OPTO(3,TOLGE), OPTO_MASK, POWER,          { RA, SI } },
+{ "twlnli",  OPTO(3,TOLNL), OPTO_MASK, PPC,            { RA, SI } },
+{ "tlnli",   OPTO(3,TOLNL), OPTO_MASK, POWER,          { RA, SI } },
+{ "twllei",  OPTO(3,TOLLE), OPTO_MASK, PPC,            { RA, SI } },
+{ "tllei",   OPTO(3,TOLLE), OPTO_MASK, POWER,          { RA, SI } },
+{ "twlngi",  OPTO(3,TOLNG), OPTO_MASK, PPC,            { RA, SI } },
+{ "tlngi",   OPTO(3,TOLNG), OPTO_MASK, POWER,          { RA, SI } },
+{ "twgti",   OPTO(3,TOGT), OPTO_MASK,  PPC,            { RA, SI } },
+{ "tgti",    OPTO(3,TOGT), OPTO_MASK,  POWER,          { RA, SI } },
+{ "twgei",   OPTO(3,TOGE), OPTO_MASK,  PPC,            { RA, SI } },
+{ "tgei",    OPTO(3,TOGE), OPTO_MASK,  POWER,          { RA, SI } },
+{ "twnli",   OPTO(3,TONL), OPTO_MASK,  PPC,            { RA, SI } },
+{ "tnli",    OPTO(3,TONL), OPTO_MASK,  POWER,          { RA, SI } },
+{ "twlti",   OPTO(3,TOLT), OPTO_MASK,  PPC,            { RA, SI } },
+{ "tlti",    OPTO(3,TOLT), OPTO_MASK,  POWER,          { RA, SI } },
+{ "twlei",   OPTO(3,TOLE), OPTO_MASK,  PPC,            { RA, SI } },
+{ "tlei",    OPTO(3,TOLE), OPTO_MASK,  POWER,          { RA, SI } },
+{ "twngi",   OPTO(3,TONG), OPTO_MASK,  PPC,            { RA, SI } },
+{ "tngi",    OPTO(3,TONG), OPTO_MASK,  POWER,          { RA, SI } },
+{ "twnei",   OPTO(3,TONE), OPTO_MASK,  PPC,            { RA, SI } },
+{ "tnei",    OPTO(3,TONE), OPTO_MASK,  POWER,          { RA, SI } },
+{ "twi",     OP(3),    OP_MASK,        PPC,            { TO, RA, SI } },
+{ "ti",      OP(3),    OP_MASK,        POWER,          { TO, RA, SI } },
+
+{ "mulli",   OP(7),    OP_MASK,        PPC,            { RT, RA, SI } },
+{ "muli",    OP(7),    OP_MASK,        POWER,          { RT, RA, SI } },
+
+{ "subfic",  OP(8),    OP_MASK,        PPC,            { RT, RA, SI } },
+{ "sfi",     OP(8),    OP_MASK,        POWER,          { RT, RA, SI } },
+
+{ "dozi",    OP(9),    OP_MASK,        POWER|M601,     { RT, RA, SI } },
+
+{ "cmplwi",  OPL(10,0),        OPL_MASK,       PPC,            { OBF, RA, UI } },
+{ "cmpldi",  OPL(10,1), OPL_MASK,      PPC|B64,        { OBF, RA, UI } },
+{ "cmpli",   OP(10),   OP_MASK,        PPC,            { BF, L, RA, UI } },
+{ "cmpli",   OP(10),   OP_MASK,        POWER,          { BF, RA, UI } },
+
+{ "cmpwi",   OPL(11,0),        OPL_MASK,       PPC,            { OBF, RA, SI } },
+{ "cmpdi",   OPL(11,1),        OPL_MASK,       PPC|B64,        { OBF, RA, SI } },
+{ "cmpi",    OP(11),   OP_MASK,        PPC,            { BF, L, RA, SI } },
+{ "cmpi",    OP(11),   OP_MASK,        POWER,          { BF, RA, SI } },
+
+{ "addic",   OP(12),   OP_MASK,        PPC,            { RT, RA, SI } },
+{ "ai",             OP(12),    OP_MASK,        POWER,          { RT, RA, SI } },
+{ "subic",   OP(12),   OP_MASK,        PPC,            { RT, RA, NSI } },
+
+{ "addic.",  OP(13),   OP_MASK,        PPC,            { RT, RA, SI } },
+{ "ai.",     OP(13),   OP_MASK,        POWER,          { RT, RA, SI } },
+{ "subic.",  OP(13),   OP_MASK,        PPC,            { RT, RA, NSI } },
+
+{ "li",             OP(14),    DRA_MASK,       PPC,            { RT, SI } },
+{ "lil",     OP(14),   DRA_MASK,       POWER,          { RT, SI } },
+{ "addi",    OP(14),   OP_MASK,        PPC,            { RT, RA, SI } },
+{ "cal",     OP(14),   OP_MASK,        POWER,          { RT, D, RA } },
+{ "subi",    OP(14),   OP_MASK,        PPC,            { RT, RA, NSI } },
+{ "la",             OP(14),    OP_MASK,        PPC,            { RT, D, RA } },
+
+{ "lis",     OP(15),   DRA_MASK,       PPC,            { RT, SISIGNOPT } },
+{ "liu",     OP(15),   DRA_MASK,       POWER,          { RT, SISIGNOPT } },
+{ "addis",   OP(15),   OP_MASK,        PPC,            { RT,RA,SISIGNOPT } },
+{ "cau",     OP(15),   OP_MASK,        POWER,          { RT,RA,SISIGNOPT } },
+{ "subis",   OP(15),   OP_MASK,        PPC,            { RT, RA, NSI } },
+
+{ "bdnz-",   BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,      { BDM } },
+{ "bdnz+",   BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,      { BDP } },
+{ "bdnz",    BBO(16,BODNZ,0,0), BBOYBI_MASK, PPC,      { BD } },
+{ "bdn",     BBO(16,BODNZ,0,0), BBOYBI_MASK, POWER,    { BD } },
+{ "bdnzl-",  BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,      { BDM } },
+{ "bdnzl+",  BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,      { BDP } },
+{ "bdnzl",   BBO(16,BODNZ,0,1), BBOYBI_MASK, PPC,      { BD } },
+{ "bdnl",    BBO(16,BODNZ,0,1), BBOYBI_MASK, POWER,    { BD } },
+{ "bdnza-",  BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,      { BDMA } },
+{ "bdnza+",  BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,      { BDPA } },
+{ "bdnza",   BBO(16,BODNZ,1,0), BBOYBI_MASK, PPC,      { BDA } },
+{ "bdna",    BBO(16,BODNZ,1,0), BBOYBI_MASK, POWER,    { BDA } },
+{ "bdnzla-", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,      { BDMA } },
+{ "bdnzla+", BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,      { BDPA } },
+{ "bdnzla",  BBO(16,BODNZ,1,1), BBOYBI_MASK, PPC,      { BDA } },
+{ "bdnla",   BBO(16,BODNZ,1,1), BBOYBI_MASK, POWER,    { BDA } },
+{ "bdz-",    BBO(16,BODZ,0,0), BBOYBI_MASK, PPC,       { BDM } },
+{ "bdz+",    BBO(16,BODZ,0,0), BBOYBI_MASK, PPC,       { BDP } },
+{ "bdz",     BBO(16,BODZ,0,0), BBOYBI_MASK, PPC|POWER, { BD } },
+{ "bdzl-",   BBO(16,BODZ,0,1), BBOYBI_MASK, PPC,       { BDM } },
+{ "bdzl+",   BBO(16,BODZ,0,1), BBOYBI_MASK, PPC,       { BDP } },
+{ "bdzl",    BBO(16,BODZ,0,1), BBOYBI_MASK, PPC|POWER, { BD } },
+{ "bdza-",   BBO(16,BODZ,1,0), BBOYBI_MASK, PPC,       { BDMA } },
+{ "bdza+",   BBO(16,BODZ,1,0), BBOYBI_MASK, PPC,       { BDPA } },
+{ "bdza",    BBO(16,BODZ,1,0), BBOYBI_MASK, PPC|POWER, { BDA } },
+{ "bdzla-",  BBO(16,BODZ,1,1), BBOYBI_MASK, PPC,       { BDMA } },
+{ "bdzla+",  BBO(16,BODZ,1,1), BBOYBI_MASK, PPC,       { BDPA } },
+{ "bdzla",   BBO(16,BODZ,1,1), BBOYBI_MASK, PPC|POWER, { BDA } },
+{ "blt-",    BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "blt+",    BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "blt",     BBOCB(16,BOT,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bltl-",   BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bltl+",   BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bltl",    BBOCB(16,BOT,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "blta-",   BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "blta+",   BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "blta",    BBOCB(16,BOT,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bltla-",  BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bltla+",  BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bltla",   BBOCB(16,BOT,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bgt-",    BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bgt+",    BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bgt",     BBOCB(16,BOT,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bgtl-",   BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bgtl+",   BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bgtl",    BBOCB(16,BOT,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bgta-",   BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bgta+",   BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bgta",    BBOCB(16,BOT,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bgtla-",  BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bgtla+",  BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bgtla",   BBOCB(16,BOT,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "beq-",    BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "beq+",    BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "beq",     BBOCB(16,BOT,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "beql-",   BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "beql+",   BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "beql",    BBOCB(16,BOT,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "beqa-",   BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "beqa+",   BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "beqa",    BBOCB(16,BOT,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "beqla-",  BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "beqla+",  BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "beqla",   BBOCB(16,BOT,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bso-",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bso+",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bso",     BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bsol-",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bsol+",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bsol",    BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bsoa-",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bsoa+",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bsoa",    BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bsola-",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bsola+",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bsola",   BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bun-",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bun+",    BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bun",     BBOCB(16,BOT,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BD } },
+{ "bunl-",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bunl+",   BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bunl",    BBOCB(16,BOT,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BD } },
+{ "buna-",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "buna+",   BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "buna",    BBOCB(16,BOT,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDA } },
+{ "bunla-",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bunla+",  BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bunla",   BBOCB(16,BOT,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDA } },
+{ "bge-",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bge+",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bge",     BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bgel-",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bgel+",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bgel",    BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bgea-",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bgea+",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bgea",    BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bgela-",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bgela+",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bgela",   BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnl-",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bnl+",    BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bnl",     BBOCB(16,BOF,CBLT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnll-",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bnll+",   BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bnll",    BBOCB(16,BOF,CBLT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnla-",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnla+",   BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnla",    BBOCB(16,BOF,CBLT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnlla-",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnlla+",  BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnlla",   BBOCB(16,BOF,CBLT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "ble-",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "ble+",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "ble",     BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "blel-",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "blel+",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "blel",    BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "blea-",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "blea+",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "blea",    BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "blela-",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "blela+",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "blela",   BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bng-",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bng+",    BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bng",     BBOCB(16,BOF,CBGT,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bngl-",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bngl+",   BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bngl",    BBOCB(16,BOF,CBGT,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnga-",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnga+",   BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnga",    BBOCB(16,BOF,CBGT,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bngla-",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bngla+",  BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bngla",   BBOCB(16,BOF,CBGT,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bne-",    BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bne+",    BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bne",     BBOCB(16,BOF,CBEQ,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnel-",   BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bnel+",   BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bnel",    BBOCB(16,BOF,CBEQ,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnea-",   BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnea+",   BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnea",    BBOCB(16,BOF,CBEQ,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnela-",  BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnela+",  BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnela",   BBOCB(16,BOF,CBEQ,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bns-",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bns+",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bns",     BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnsl-",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bnsl+",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bnsl",    BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC|POWER, { CR, BD } },
+{ "bnsa-",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnsa+",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnsa",    BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnsla-",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnsla+",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnsla",   BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC|POWER, { CR, BDA } },
+{ "bnu-",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bnu+",    BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bnu",     BBOCB(16,BOF,CBSO,0,0), BBOYCB_MASK, PPC, { CR, BD } },
+{ "bnul-",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDM } },
+{ "bnul+",   BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BDP } },
+{ "bnul",    BBOCB(16,BOF,CBSO,0,1), BBOYCB_MASK, PPC, { CR, BD } },
+{ "bnua-",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnua+",   BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnua",    BBOCB(16,BOF,CBSO,1,0), BBOYCB_MASK, PPC, { CR, BDA } },
+{ "bnula-",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDMA } },
+{ "bnula+",  BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDPA } },
+{ "bnula",   BBOCB(16,BOF,CBSO,1,1), BBOYCB_MASK, PPC, { CR, BDA } },
+{ "bdnzt-",  BBO(16,BODNZT,0,0), BBOY_MASK, PPC,       { BI, BDM } },
+{ "bdnzt+",  BBO(16,BODNZT,0,0), BBOY_MASK, PPC,       { BI, BDP } },
+{ "bdnzt",   BBO(16,BODNZT,0,0), BBOY_MASK, PPC,       { BI, BD } },
+{ "bdnztl-", BBO(16,BODNZT,0,1), BBOY_MASK, PPC,       { BI, BDM } },
+{ "bdnztl+", BBO(16,BODNZT,0,1), BBOY_MASK, PPC,       { BI, BDP } },
+{ "bdnztl",  BBO(16,BODNZT,0,1), BBOY_MASK, PPC,       { BI, BD } },
+{ "bdnzta-", BBO(16,BODNZT,1,0), BBOY_MASK, PPC,       { BI, BDMA } },
+{ "bdnzta+", BBO(16,BODNZT,1,0), BBOY_MASK, PPC,       { BI, BDPA } },
+{ "bdnzta",  BBO(16,BODNZT,1,0), BBOY_MASK, PPC,       { BI, BDA } },
+{ "bdnztla-",BBO(16,BODNZT,1,1), BBOY_MASK, PPC,       { BI, BDMA } },
+{ "bdnztla+",BBO(16,BODNZT,1,1), BBOY_MASK, PPC,       { BI, BDPA } },
+{ "bdnztla", BBO(16,BODNZT,1,1), BBOY_MASK, PPC,       { BI, BDA } },
+{ "bdnzf-",  BBO(16,BODNZF,0,0), BBOY_MASK, PPC,       { BI, BDM } },
+{ "bdnzf+",  BBO(16,BODNZF,0,0), BBOY_MASK, PPC,       { BI, BDP } },
+{ "bdnzf",   BBO(16,BODNZF,0,0), BBOY_MASK, PPC,       { BI, BD } },
+{ "bdnzfl-", BBO(16,BODNZF,0,1), BBOY_MASK, PPC,       { BI, BDM } },
+{ "bdnzfl+", BBO(16,BODNZF,0,1), BBOY_MASK, PPC,       { BI, BDP } },
+{ "bdnzfl",  BBO(16,BODNZF,0,1), BBOY_MASK, PPC,       { BI, BD } },
+{ "bdnzfa-", BBO(16,BODNZF,1,0), BBOY_MASK, PPC,       { BI, BDMA } },
+{ "bdnzfa+", BBO(16,BODNZF,1,0), BBOY_MASK, PPC,       { BI, BDPA } },
+{ "bdnzfa",  BBO(16,BODNZF,1,0), BBOY_MASK, PPC,       { BI, BDA } },
+{ "bdnzfla-",BBO(16,BODNZF,1,1), BBOY_MASK, PPC,       { BI, BDMA } },
+{ "bdnzfla+",BBO(16,BODNZF,1,1), BBOY_MASK, PPC,       { BI, BDPA } },
+{ "bdnzfla", BBO(16,BODNZF,1,1), BBOY_MASK, PPC,       { BI, BDA } },
+{ "bt-",     BBO(16,BOT,0,0), BBOY_MASK, PPC,          { BI, BDM } },
+{ "bt+",     BBO(16,BOT,0,0), BBOY_MASK, PPC,          { BI, BDP } },
+{ "bt",             BBO(16,BOT,0,0), BBOY_MASK, PPC,           { BI, BD } },
+{ "bbt",     BBO(16,BOT,0,0), BBOY_MASK, POWER,                { BI, BD } },
+{ "btl-",    BBO(16,BOT,0,1), BBOY_MASK, PPC,          { BI, BDM } },
+{ "btl+",    BBO(16,BOT,0,1), BBOY_MASK, PPC,          { BI, BDP } },
+{ "btl",     BBO(16,BOT,0,1), BBOY_MASK, PPC,          { BI, BD } },
+{ "bbtl",    BBO(16,BOT,0,1), BBOY_MASK, POWER,                { BI, BD } },
+{ "bta-",    BBO(16,BOT,1,0), BBOY_MASK, PPC,          { BI, BDMA } },
+{ "bta+",    BBO(16,BOT,1,0), BBOY_MASK, PPC,          { BI, BDPA } },
+{ "bta",     BBO(16,BOT,1,0), BBOY_MASK, PPC,          { BI, BDA } },
+{ "bbta",    BBO(16,BOT,1,0), BBOY_MASK, POWER,                { BI, BDA } },
+{ "btla-",   BBO(16,BOT,1,1), BBOY_MASK, PPC,          { BI, BDMA } },
+{ "btla+",   BBO(16,BOT,1,1), BBOY_MASK, PPC,          { BI, BDPA } },
+{ "btla",    BBO(16,BOT,1,1), BBOY_MASK, PPC,          { BI, BDA } },
+{ "bbtla",   BBO(16,BOT,1,1), BBOY_MASK, POWER,                { BI, BDA } },
+{ "bf-",     BBO(16,BOF,0,0), BBOY_MASK, PPC,          { BI, BDM } },
+{ "bf+",     BBO(16,BOF,0,0), BBOY_MASK, PPC,          { BI, BDP } },
+{ "bf",             BBO(16,BOF,0,0), BBOY_MASK, PPC,           { BI, BD } },
+{ "bbf",     BBO(16,BOF,0,0), BBOY_MASK, POWER,                { BI, BD } },
+{ "bfl-",    BBO(16,BOF,0,1), BBOY_MASK, PPC,          { BI, BDM } },
+{ "bfl+",    BBO(16,BOF,0,1), BBOY_MASK, PPC,          { BI, BDP } },
+{ "bfl",     BBO(16,BOF,0,1), BBOY_MASK, PPC,          { BI, BD } },
+{ "bbfl",    BBO(16,BOF,0,1), BBOY_MASK, POWER,                { BI, BD } },
+{ "bfa-",    BBO(16,BOF,1,0), BBOY_MASK, PPC,          { BI, BDMA } },
+{ "bfa+",    BBO(16,BOF,1,0), BBOY_MASK, PPC,          { BI, BDPA } },
+{ "bfa",     BBO(16,BOF,1,0), BBOY_MASK, PPC,          { BI, BDA } },
+{ "bbfa",    BBO(16,BOF,1,0), BBOY_MASK, POWER,                { BI, BDA } },
+{ "bfla-",   BBO(16,BOF,1,1), BBOY_MASK, PPC,          { BI, BDMA } },
+{ "bfla+",   BBO(16,BOF,1,1), BBOY_MASK, PPC,          { BI, BDPA } },
+{ "bfla",    BBO(16,BOF,1,1), BBOY_MASK, PPC,          { BI, BDA } },
+{ "bbfla",   BBO(16,BOF,1,1), BBOY_MASK, POWER,                { BI, BDA } },
+{ "bdzt-",   BBO(16,BODZT,0,0), BBOY_MASK, PPC,                { BI, BDM } },
+{ "bdzt+",   BBO(16,BODZT,0,0), BBOY_MASK, PPC,                { BI, BDP } },
+{ "bdzt",    BBO(16,BODZT,0,0), BBOY_MASK, PPC,                { BI, BD } },
+{ "bdztl-",  BBO(16,BODZT,0,1), BBOY_MASK, PPC,                { BI, BDM } },
+{ "bdztl+",  BBO(16,BODZT,0,1), BBOY_MASK, PPC,                { BI, BDP } },
+{ "bdztl",   BBO(16,BODZT,0,1), BBOY_MASK, PPC,                { BI, BD } },
+{ "bdzta-",  BBO(16,BODZT,1,0), BBOY_MASK, PPC,                { BI, BDMA } },
+{ "bdzta+",  BBO(16,BODZT,1,0), BBOY_MASK, PPC,                { BI, BDPA } },
+{ "bdzta",   BBO(16,BODZT,1,0), BBOY_MASK, PPC,                { BI, BDA } },
+{ "bdztla-", BBO(16,BODZT,1,1), BBOY_MASK, PPC,                { BI, BDMA } },
+{ "bdztla+", BBO(16,BODZT,1,1), BBOY_MASK, PPC,                { BI, BDPA } },
+{ "bdztla",  BBO(16,BODZT,1,1), BBOY_MASK, PPC,                { BI, BDA } },
+{ "bdzf-",   BBO(16,BODZF,0,0), BBOY_MASK, PPC,                { BI, BDM } },
+{ "bdzf+",   BBO(16,BODZF,0,0), BBOY_MASK, PPC,                { BI, BDP } },
+{ "bdzf",    BBO(16,BODZF,0,0), BBOY_MASK, PPC,                { BI, BD } },
+{ "bdzfl-",  BBO(16,BODZF,0,1), BBOY_MASK, PPC,                { BI, BDM } },
+{ "bdzfl+",  BBO(16,BODZF,0,1), BBOY_MASK, PPC,                { BI, BDP } },
+{ "bdzfl",   BBO(16,BODZF,0,1), BBOY_MASK, PPC,                { BI, BD } },
+{ "bdzfa-",  BBO(16,BODZF,1,0), BBOY_MASK, PPC,                { BI, BDMA } },
+{ "bdzfa+",  BBO(16,BODZF,1,0), BBOY_MASK, PPC,                { BI, BDPA } },
+{ "bdzfa",   BBO(16,BODZF,1,0), BBOY_MASK, PPC,                { BI, BDA } },
+{ "bdzfla-", BBO(16,BODZF,1,1), BBOY_MASK, PPC,                { BI, BDMA } },
+{ "bdzfla+", BBO(16,BODZF,1,1), BBOY_MASK, PPC,                { BI, BDPA } },
+{ "bdzfla",  BBO(16,BODZF,1,1), BBOY_MASK, PPC,                { BI, BDA } },
+{ "bc-",     B(16,0,0),        B_MASK,         PPC,            { BOE, BI, BDM } },
+{ "bc+",     B(16,0,0),        B_MASK,         PPC,            { BOE, BI, BDP } },
+{ "bc",             B(16,0,0), B_MASK,         PPC|POWER,      { BO, BI, BD } },
+{ "bcl-",    B(16,0,1),        B_MASK,         PPC,            { BOE, BI, BDM } },
+{ "bcl+",    B(16,0,1),        B_MASK,         PPC,            { BOE, BI, BDP } },
+{ "bcl",     B(16,0,1),        B_MASK,         PPC|POWER,      { BO, BI, BD } },
+{ "bca-",    B(16,1,0),        B_MASK,         PPC,            { BOE, BI, BDMA } },
+{ "bca+",    B(16,1,0),        B_MASK,         PPC,            { BOE, BI, BDPA } },
+{ "bca",     B(16,1,0),        B_MASK,         PPC|POWER,      { BO, BI, BDA } },
+{ "bcla-",   B(16,1,1),        B_MASK,         PPC,            { BOE, BI, BDMA } },
+{ "bcla+",   B(16,1,1),        B_MASK,         PPC,            { BOE, BI, BDPA } },
+{ "bcla",    B(16,1,1),        B_MASK,         PPC|POWER,      { BO, BI, BDA } },
+
+{ "sc",      SC(17,1,0), 0xffffffff,   PPC,            { 0 } },
+{ "svc",     SC(17,0,0), SC_MASK,      POWER,          { LEV, FL1, FL2 } },
+{ "svcl",    SC(17,0,1), SC_MASK,      POWER,          { LEV, FL1, FL2 } },
+{ "svca",    SC(17,1,0), SC_MASK,      POWER,          { SV } },
+{ "svcla",   SC(17,1,1), SC_MASK,      POWER,          { SV } },
+
+{ "b",      B(18,0,0), B_MASK,         PPC|POWER,      { LI } },
+{ "bl",      B(18,0,1),        B_MASK,         PPC|POWER,      { LI } },
+{ "ba",      B(18,1,0),        B_MASK,         PPC|POWER,      { LIA } },
+{ "bla",     B(18,1,1),        B_MASK,         PPC|POWER,      { LIA } },
+
+{ "mcrf",    XL(19,0), XLBB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } },
+
+{ "blr",     XLO(19,BOU,16,0), XLBOBIBB_MASK, PPC,     { 0 } },
+{ "br",      XLO(19,BOU,16,0), XLBOBIBB_MASK, POWER,   { 0 } },
+{ "blrl",    XLO(19,BOU,16,1), XLBOBIBB_MASK, PPC,     { 0 } },
+{ "brl",     XLO(19,BOU,16,1), XLBOBIBB_MASK, POWER,   { 0 } },
+{ "bdnzlr",  XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC,   { 0 } },
+{ "bdnzlr-", XLO(19,BODNZ,16,0), XLBOBIBB_MASK, PPC,   { 0 } },
+{ "bdnzlr+", XLO(19,BODNZP,16,0), XLBOBIBB_MASK, PPC,  { 0 } },
+{ "bdnzlrl", XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC,   { 0 } },
+{ "bdnzlrl-",XLO(19,BODNZ,16,1), XLBOBIBB_MASK, PPC,   { 0 } },
+{ "bdnzlrl+",XLO(19,BODNZP,16,1), XLBOBIBB_MASK, PPC,  { 0 } },
+{ "bdzlr",   XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC,    { 0 } },
+{ "bdzlr-",  XLO(19,BODZ,16,0), XLBOBIBB_MASK, PPC,    { 0 } },
+{ "bdzlr+",  XLO(19,BODZP,16,0), XLBOBIBB_MASK, PPC,   { 0 } },
+{ "bdzlrl",  XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC,    { 0 } },
+{ "bdzlrl-", XLO(19,BODZ,16,1), XLBOBIBB_MASK, PPC,    { 0 } },
+{ "bdzlrl+", XLO(19,BODZP,16,1), XLBOBIBB_MASK, PPC,   { 0 } },
+{ "bltlr",   XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltlr-",  XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltlr+",  XLOCB(19,BOTP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltr",    XLOCB(19,BOT,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bltlrl",  XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltlrl-", XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltlrl+", XLOCB(19,BOTP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltrl",   XLOCB(19,BOT,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bgtlr",   XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtlr-",  XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtlr+",  XLOCB(19,BOTP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtr",    XLOCB(19,BOT,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bgtlrl",  XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtlrl-", XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtlrl+", XLOCB(19,BOTP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtrl",   XLOCB(19,BOT,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "beqlr",   XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqlr-",  XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqlr+",  XLOCB(19,BOTP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqr",    XLOCB(19,BOT,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "beqlrl",  XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqlrl-", XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqlrl+", XLOCB(19,BOTP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqrl",   XLOCB(19,BOT,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bsolr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsolr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsolr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsor",    XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bsolrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsolrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsolrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsorl",   XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bunlr",   XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlr-",  XLOCB(19,BOT,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlr+",  XLOCB(19,BOTP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlrl",  XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlrl-", XLOCB(19,BOT,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunlrl+", XLOCB(19,BOTP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bger",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bgelrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgelrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgerl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnllr",   XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnllr-",  XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnllr+",  XLOCB(19,BOFP,CBLT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlr",    XLOCB(19,BOF,CBLT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnllrl",  XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnllrl-", XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnllrl+", XLOCB(19,BOFP,CBLT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlrl",   XLOCB(19,BOF,CBLT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "blelr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blelr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blelr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bler",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "blelrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blelrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blelrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blerl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnglr",   XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnglr-",  XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnglr+",  XLOCB(19,BOFP,CBGT,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngr",    XLOCB(19,BOF,CBGT,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnglrl",  XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnglrl-", XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnglrl+", XLOCB(19,BOFP,CBGT,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngrl",   XLOCB(19,BOF,CBGT,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnelr",   XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnelr-",  XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnelr+",  XLOCB(19,BOFP,CBEQ,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bner",    XLOCB(19,BOF,CBEQ,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnelrl",  XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnelrl-", XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnelrl+", XLOCB(19,BOFP,CBEQ,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnerl",   XLOCB(19,BOF,CBEQ,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnslr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnslr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnslr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsr",    XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnslrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnslrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnslrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsrl",   XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, POWER, { CR } },
+{ "bnulr",   XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulr-",  XLOCB(19,BOF,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulr+",  XLOCB(19,BOFP,CBSO,16,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulrl",  XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulrl-", XLOCB(19,BOF,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnulrl+", XLOCB(19,BOFP,CBSO,16,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "btlr",    XLO(19,BOT,16,0), XLBOBB_MASK, PPC,       { BI } },
+{ "btlr-",   XLO(19,BOT,16,0), XLBOBB_MASK, PPC,       { BI } },
+{ "btlr+",   XLO(19,BOTP,16,0), XLBOBB_MASK, PPC,      { BI } },
+{ "bbtr",    XLO(19,BOT,16,0), XLBOBB_MASK, POWER,     { BI } },
+{ "btlrl",   XLO(19,BOT,16,1), XLBOBB_MASK, PPC,       { BI } },
+{ "btlrl-",  XLO(19,BOT,16,1), XLBOBB_MASK, PPC,       { BI } },
+{ "btlrl+",  XLO(19,BOTP,16,1), XLBOBB_MASK, PPC,      { BI } },
+{ "bbtrl",   XLO(19,BOT,16,1), XLBOBB_MASK, POWER,     { BI } },
+{ "bflr",    XLO(19,BOF,16,0), XLBOBB_MASK, PPC,       { BI } },
+{ "bflr-",   XLO(19,BOF,16,0), XLBOBB_MASK, PPC,       { BI } },
+{ "bflr+",   XLO(19,BOFP,16,0), XLBOBB_MASK, PPC,      { BI } },
+{ "bbfr",    XLO(19,BOF,16,0), XLBOBB_MASK, POWER,     { BI } },
+{ "bflrl",   XLO(19,BOF,16,1), XLBOBB_MASK, PPC,       { BI } },
+{ "bflrl-",  XLO(19,BOF,16,1), XLBOBB_MASK, PPC,       { BI } },
+{ "bflrl+",  XLO(19,BOFP,16,1), XLBOBB_MASK, PPC,      { BI } },
+{ "bbfrl",   XLO(19,BOF,16,1), XLBOBB_MASK, POWER,     { BI } },
+{ "bdnztlr", XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC,    { BI } },
+{ "bdnztlr-",XLO(19,BODNZT,16,0), XLBOBB_MASK, PPC,    { BI } },
+{ "bdnztlr+",XLO(19,BODNZTP,16,0), XLBOBB_MASK, PPC,   { BI } },
+{ "bdnztlrl",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC,    { BI } },
+{ "bdnztlrl-",XLO(19,BODNZT,16,1), XLBOBB_MASK, PPC,   { BI } },
+{ "bdnztlrl+",XLO(19,BODNZTP,16,1), XLBOBB_MASK, PPC,  { BI } },
+{ "bdnzflr", XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC,    { BI } },
+{ "bdnzflr-",XLO(19,BODNZF,16,0), XLBOBB_MASK, PPC,    { BI } },
+{ "bdnzflr+",XLO(19,BODNZFP,16,0), XLBOBB_MASK, PPC,   { BI } },
+{ "bdnzflrl",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC,    { BI } },
+{ "bdnzflrl-",XLO(19,BODNZF,16,1), XLBOBB_MASK, PPC,   { BI } },
+{ "bdnzflrl+",XLO(19,BODNZFP,16,1), XLBOBB_MASK, PPC,  { BI } },
+{ "bdztlr",  XLO(19,BODZT,16,0), XLBOBB_MASK, PPC,     { BI } },
+{ "bdztlr-", XLO(19,BODZT,16,0), XLBOBB_MASK, PPC,     { BI } },
+{ "bdztlr+", XLO(19,BODZTP,16,0), XLBOBB_MASK, PPC,    { BI } },
+{ "bdztlrl", XLO(19,BODZT,16,1), XLBOBB_MASK, PPC,     { BI } },
+{ "bdztlrl-",XLO(19,BODZT,16,1), XLBOBB_MASK, PPC,     { BI } },
+{ "bdztlrl+",XLO(19,BODZTP,16,1), XLBOBB_MASK, PPC,    { BI } },
+{ "bdzflr",  XLO(19,BODZF,16,0), XLBOBB_MASK, PPC,     { BI } },
+{ "bdzflr-", XLO(19,BODZF,16,0), XLBOBB_MASK, PPC,     { BI } },
+{ "bdzflr+", XLO(19,BODZFP,16,0), XLBOBB_MASK, PPC,    { BI } },
+{ "bdzflrl", XLO(19,BODZF,16,1), XLBOBB_MASK, PPC,     { BI } },
+{ "bdzflrl-",XLO(19,BODZF,16,1), XLBOBB_MASK, PPC,     { BI } },
+{ "bdzflrl+",XLO(19,BODZFP,16,1), XLBOBB_MASK, PPC,    { BI } },
+{ "bclr",    XLLK(19,16,0), XLYBB_MASK,        PPC,            { BO, BI } },
+{ "bclrl",   XLLK(19,16,1), XLYBB_MASK,        PPC,            { BO, BI } },
+{ "bclr+",   XLYLK(19,16,1,0), XLYBB_MASK, PPC,                { BOE, BI } },
+{ "bclrl+",  XLYLK(19,16,1,1), XLYBB_MASK, PPC,                { BOE, BI } },
+{ "bclr-",   XLYLK(19,16,0,0), XLYBB_MASK, PPC,                { BOE, BI } },
+{ "bclrl-",  XLYLK(19,16,0,1), XLYBB_MASK, PPC,                { BOE, BI } },
+{ "bcr",     XLLK(19,16,0), XLBB_MASK, POWER,          { BO, BI } },
+{ "bcrl",    XLLK(19,16,1), XLBB_MASK, POWER,          { BO, BI } },
+
+{ "crnot",   XL(19,33), XL_MASK,       PPC,            { BT, BA, BBA } },
+{ "crnor",   XL(19,33),        XL_MASK,        PPC|POWER,      { BT, BA, BB } },
+
+{ "rfi",     XL(19,50),        0xffffffff,     PPC|POWER,      { 0 } },
+{ "rfci",    XL(19,51),        0xffffffff,     PPC,            { 0 } },
+
+{ "rfsvc",   XL(19,82),        0xffffffff,     POWER,          { 0 } },
+
+{ "crandc",  XL(19,129), XL_MASK,      PPC|POWER,      { BT, BA, BB } },
+
+{ "isync",   XL(19,150), 0xffffffff,   PPC,            { 0 } },
+{ "ics",     XL(19,150), 0xffffffff,   POWER,          { 0 } },
+
+{ "crclr",   XL(19,193), XL_MASK,      PPC,            { BT, BAT, BBA } },
+{ "crxor",   XL(19,193), XL_MASK,      PPC|POWER,      { BT, BA, BB } },
+
+{ "crnand",  XL(19,225), XL_MASK,      PPC|POWER,      { BT, BA, BB } },
+
+{ "crand",   XL(19,257), XL_MASK,      PPC|POWER,      { BT, BA, BB } },
+
+{ "crset",   XL(19,289), XL_MASK,      PPC,            { BT, BAT, BBA } },
+{ "creqv",   XL(19,289), XL_MASK,      PPC|POWER,      { BT, BA, BB } },
+
+{ "crorc",   XL(19,417), XL_MASK,      PPC|POWER,      { BT, BA, BB } },
+
+{ "crmove",  XL(19,449), XL_MASK,      PPC,            { BT, BA, BBA } },
+{ "cror",    XL(19,449), XL_MASK,      PPC|POWER,      { BT, BA, BB } },
+
+{ "bctr",    XLO(19,BOU,528,0), XLBOBIBB_MASK, PPC|POWER, { 0 } },
+{ "bctrl",   XLO(19,BOU,528,1), XLBOBIBB_MASK, PPC|POWER, { 0 } },
+{ "bltctr",  XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctr-", XLOCB(19,BOT,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctr+", XLOCB(19,BOTP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctrl", XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctrl-",XLOCB(19,BOT,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bltctrl+",XLOCB(19,BOTP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctr",  XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctr-", XLOCB(19,BOT,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctr+", XLOCB(19,BOTP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctrl", XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctrl-",XLOCB(19,BOT,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgtctrl+",XLOCB(19,BOTP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctr",  XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctr-", XLOCB(19,BOT,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctr+", XLOCB(19,BOTP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctrl", XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctrl-",XLOCB(19,BOT,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "beqctrl+",XLOCB(19,BOTP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctr",  XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bsoctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctr",  XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctr-", XLOCB(19,BOT,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctr+", XLOCB(19,BOTP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctrl", XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctrl-",XLOCB(19,BOT,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bunctrl+",XLOCB(19,BOTP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectr",  XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bgectrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctr",  XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctr-", XLOCB(19,BOF,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctr+", XLOCB(19,BOFP,CBLT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctrl", XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctrl-",XLOCB(19,BOF,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnlctrl+",XLOCB(19,BOFP,CBLT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectr",  XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "blectrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctr",  XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctr-", XLOCB(19,BOF,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctr+", XLOCB(19,BOFP,CBGT,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctrl", XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctrl-",XLOCB(19,BOF,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bngctrl+",XLOCB(19,BOFP,CBGT,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectr",  XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectr-", XLOCB(19,BOF,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectr+", XLOCB(19,BOFP,CBEQ,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectrl", XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectrl-",XLOCB(19,BOF,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnectrl+",XLOCB(19,BOFP,CBEQ,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctr",  XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnsctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctr",  XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctr-", XLOCB(19,BOF,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctr+", XLOCB(19,BOFP,CBSO,528,0), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctrl", XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctrl-",XLOCB(19,BOF,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "bnuctrl+",XLOCB(19,BOFP,CBSO,528,1), XLBOCBBB_MASK, PPC, { CR } },
+{ "btctr",   XLO(19,BOT,528,0), XLBOBB_MASK, PPC,      { BI } },
+{ "btctr-",  XLO(19,BOT,528,0), XLBOBB_MASK, PPC,      { BI } },
+{ "btctr+",  XLO(19,BOTP,528,0), XLBOBB_MASK, PPC,     { BI } },
+{ "btctrl",  XLO(19,BOT,528,1), XLBOBB_MASK, PPC,      { BI } },
+{ "btctrl-", XLO(19,BOT,528,1), XLBOBB_MASK, PPC,      { BI } },
+{ "btctrl+", XLO(19,BOTP,528,1), XLBOBB_MASK, PPC,     { BI } },
+{ "bfctr",   XLO(19,BOF,528,0), XLBOBB_MASK, PPC,      { BI } },
+{ "bfctr-",  XLO(19,BOF,528,0), XLBOBB_MASK, PPC,      { BI } },
+{ "bfctr+",  XLO(19,BOFP,528,0), XLBOBB_MASK, PPC,     { BI } },
+{ "bfctrl",  XLO(19,BOF,528,1), XLBOBB_MASK, PPC,      { BI } },
+{ "bfctrl-", XLO(19,BOF,528,1), XLBOBB_MASK, PPC,      { BI } },
+{ "bfctrl+", XLO(19,BOFP,528,1), XLBOBB_MASK, PPC,     { BI } },
+{ "bcctr",   XLLK(19,528,0), XLYBB_MASK, PPC,          { BO, BI } },
+{ "bcctr-",  XLYLK(19,528,0,0), XLYBB_MASK, PPC,       { BOE, BI } },
+{ "bcctr+",  XLYLK(19,528,1,0), XLYBB_MASK, PPC,       { BOE, BI } },
+{ "bcctrl",  XLLK(19,528,1), XLYBB_MASK, PPC,          { BO, BI } },
+{ "bcctrl-", XLYLK(19,528,0,1), XLYBB_MASK, PPC,       { BOE, BI } },
+{ "bcctrl+", XLYLK(19,528,1,1), XLYBB_MASK, PPC,       { BOE, BI } },
+{ "bcc",     XLLK(19,528,0), XLBB_MASK,        POWER,          { BO, BI } },
+{ "bccl",    XLLK(19,528,1), XLBB_MASK,        POWER,          { BO, BI } },
+
+{ "rlwimi",  M(20,0),  M_MASK,         PPC,            { RA,RS,SH,MBE,ME } },
+{ "rlimi",   M(20,0),  M_MASK,         POWER,          { RA,RS,SH,MBE,ME } },
+
+{ "rlwimi.", M(20,1),  M_MASK,         PPC,            { RA,RS,SH,MBE,ME } },
+{ "rlimi.",  M(20,1),  M_MASK,         POWER,          { RA,RS,SH,MBE,ME } },
+
+{ "rotlwi",  MME(21,31,0), MMBME_MASK, PPC,            { RA, RS, SH } },
+{ "clrlwi",  MME(21,31,0), MSHME_MASK, PPC,            { RA, RS, MB } },
+{ "rlwinm",  M(21,0),  M_MASK,         PPC,            { RA,RS,SH,MBE,ME } },
+{ "rlinm",   M(21,0),  M_MASK,         POWER,          { RA,RS,SH,MBE,ME } },
+{ "rotlwi.", MME(21,31,1), MMBME_MASK, PPC,            { RA,RS,SH } },
+{ "clrlwi.", MME(21,31,1), MSHME_MASK, PPC,            { RA, RS, MB } },
+{ "rlwinm.", M(21,1),  M_MASK,         PPC,            { RA,RS,SH,MBE,ME } },
+{ "rlinm.",  M(21,1),  M_MASK,         POWER,          { RA,RS,SH,MBE,ME } },
+
+{ "rlmi",    M(22,0),  M_MASK,         POWER|M601,     { RA,RS,RB,MBE,ME } },
+{ "rlmi.",   M(22,1),  M_MASK,         POWER|M601,     { RA,RS,RB,MBE,ME } },
+
+{ "rotlw",   MME(23,31,0), MMBME_MASK, PPC,            { RA, RS, RB } },
+{ "rlwnm",   M(23,0),  M_MASK,         PPC,            { RA,RS,RB,MBE,ME } },
+{ "rlnm",    M(23,0),  M_MASK,         POWER,          { RA,RS,RB,MBE,ME } },
+{ "rotlw.",  MME(23,31,1), MMBME_MASK, PPC,            { RA, RS, RB } },
+{ "rlwnm.",  M(23,1),  M_MASK,         PPC,            { RA,RS,RB,MBE,ME } },
+{ "rlnm.",   M(23,1),  M_MASK,         POWER,          { RA,RS,RB,MBE,ME } },
+
+{ "nop",     OP(24),   0xffffffff,     PPC,            { 0 } },
+{ "ori",     OP(24),   OP_MASK,        PPC,            { RA, RS, UI } },
+{ "oril",    OP(24),   OP_MASK,        POWER,          { RA, RS, UI } },
+
+{ "oris",    OP(25),   OP_MASK,        PPC,            { RA, RS, UI } },
+{ "oriu",    OP(25),   OP_MASK,        POWER,          { RA, RS, UI } },
+
+{ "xori",    OP(26),   OP_MASK,        PPC,            { RA, RS, UI } },
+{ "xoril",   OP(26),   OP_MASK,        POWER,          { RA, RS, UI } },
+
+{ "xoris",   OP(27),   OP_MASK,        PPC,            { RA, RS, UI } },
+{ "xoriu",   OP(27),   OP_MASK,        POWER,          { RA, RS, UI } },
+
+{ "andi.",   OP(28),   OP_MASK,        PPC,            { RA, RS, UI } },
+{ "andil.",  OP(28),   OP_MASK,        POWER,          { RA, RS, UI } },
+
+{ "andis.",  OP(29),   OP_MASK,        PPC,            { RA, RS, UI } },
+{ "andiu.",  OP(29),   OP_MASK,        POWER,          { RA, RS, UI } },
+
+{ "rotldi",  MD(30,0,0), MDMB_MASK,    PPC|B64,        { RA, RS, SH6 } },
+{ "clrldi",  MD(30,0,0), MDSH_MASK,    PPC|B64,        { RA, RS, MB6 } },
+{ "rldicl",  MD(30,0,0), MD_MASK,      PPC|B64,        { RA, RS, SH6, MB6 } },
+{ "rotldi.", MD(30,0,1), MDMB_MASK,    PPC|B64,        { RA, RS, SH6 } },
+{ "clrldi.", MD(30,0,1), MDSH_MASK,    PPC|B64,        { RA, RS, MB6 } },
+{ "rldicl.", MD(30,0,1), MD_MASK,      PPC|B64,        { RA, RS, SH6, MB6 } },
+
+{ "rldicr",  MD(30,1,0), MD_MASK,      PPC|B64,        { RA, RS, SH6, ME6 } },
+{ "rldicr.", MD(30,1,1), MD_MASK,      PPC|B64,        { RA, RS, SH6, ME6 } },
+
+{ "rldic",   MD(30,2,0), MD_MASK,      PPC|B64,        { RA, RS, SH6, MB6 } },
+{ "rldic.",  MD(30,2,1), MD_MASK,      PPC|B64,        { RA, RS, SH6, MB6 } },
+
+{ "rldimi",  MD(30,3,0), MD_MASK,      PPC|B64,        { RA, RS, SH6, MB6 } },
+{ "rldimi.", MD(30,3,1), MD_MASK,      PPC|B64,        { RA, RS, SH6, MB6 } },
+
+{ "rotld",   MDS(30,8,0), MDSMB_MASK,  PPC|B64,        { RA, RS, RB } },
+{ "rldcl",   MDS(30,8,0), MDS_MASK,    PPC|B64,        { RA, RS, RB, MB6 } },
+{ "rotld.",  MDS(30,8,1), MDSMB_MASK,  PPC|B64,        { RA, RS, RB } },
+{ "rldcl.",  MDS(30,8,1), MDS_MASK,    PPC|B64,        { RA, RS, RB, MB6 } },
+
+{ "rldcr",   MDS(30,9,0), MDS_MASK,    PPC|B64,        { RA, RS, RB, ME6 } },
+{ "rldcr.",  MDS(30,9,1), MDS_MASK,    PPC|B64,        { RA, RS, RB, ME6 } },
+
+{ "cmpw",    XCMPL(31,0,0), XCMPL_MASK, PPC,           { OBF, RA, RB } },
+{ "cmpd",    XCMPL(31,0,1), XCMPL_MASK, PPC|B64,       { OBF, RA, RB } },
+{ "cmp",     X(31,0),  XCMP_MASK,      PPC,            { BF, L, RA, RB } },
+{ "cmp",     X(31,0),  XCMPL_MASK,     POWER,          { BF, RA, RB } },
+
+{ "twlgt",   XTO(31,4,TOLGT), XTO_MASK, PPC,           { RA, RB } },
+{ "tlgt",    XTO(31,4,TOLGT), XTO_MASK, POWER,         { RA, RB } },
+{ "twllt",   XTO(31,4,TOLLT), XTO_MASK, PPC,           { RA, RB } },
+{ "tllt",    XTO(31,4,TOLLT), XTO_MASK, POWER,         { RA, RB } },
+{ "tweq",    XTO(31,4,TOEQ), XTO_MASK, PPC,            { RA, RB } },
+{ "teq",     XTO(31,4,TOEQ), XTO_MASK, POWER,          { RA, RB } },
+{ "twlge",   XTO(31,4,TOLGE), XTO_MASK, PPC,           { RA, RB } },
+{ "tlge",    XTO(31,4,TOLGE), XTO_MASK, POWER,         { RA, RB } },
+{ "twlnl",   XTO(31,4,TOLNL), XTO_MASK, PPC,           { RA, RB } },
+{ "tlnl",    XTO(31,4,TOLNL), XTO_MASK, POWER,         { RA, RB } },
+{ "twlle",   XTO(31,4,TOLLE), XTO_MASK, PPC,           { RA, RB } },
+{ "tlle",    XTO(31,4,TOLLE), XTO_MASK, POWER,         { RA, RB } },
+{ "twlng",   XTO(31,4,TOLNG), XTO_MASK, PPC,           { RA, RB } },
+{ "tlng",    XTO(31,4,TOLNG), XTO_MASK, POWER,         { RA, RB } },
+{ "twgt",    XTO(31,4,TOGT), XTO_MASK, PPC,            { RA, RB } },
+{ "tgt",     XTO(31,4,TOGT), XTO_MASK, POWER,          { RA, RB } },
+{ "twge",    XTO(31,4,TOGE), XTO_MASK, PPC,            { RA, RB } },
+{ "tge",     XTO(31,4,TOGE), XTO_MASK, POWER,          { RA, RB } },
+{ "twnl",    XTO(31,4,TONL), XTO_MASK, PPC,            { RA, RB } },
+{ "tnl",     XTO(31,4,TONL), XTO_MASK, POWER,          { RA, RB } },
+{ "twlt",    XTO(31,4,TOLT), XTO_MASK, PPC,            { RA, RB } },
+{ "tlt",     XTO(31,4,TOLT), XTO_MASK, POWER,          { RA, RB } },
+{ "twle",    XTO(31,4,TOLE), XTO_MASK, PPC,            { RA, RB } },
+{ "tle",     XTO(31,4,TOLE), XTO_MASK, POWER,          { RA, RB } },
+{ "twng",    XTO(31,4,TONG), XTO_MASK, PPC,            { RA, RB } },
+{ "tng",     XTO(31,4,TONG), XTO_MASK, POWER,          { RA, RB } },
+{ "twne",    XTO(31,4,TONE), XTO_MASK, PPC,            { RA, RB } },
+{ "tne",     XTO(31,4,TONE), XTO_MASK, POWER,          { RA, RB } },
+{ "trap",    XTO(31,4,TOU), 0xffffffff,        PPC,            { 0 } },
+{ "tw",      X(31,4),  X_MASK,         PPC,            { TO, RA, RB } },
+{ "t",       X(31,4),  X_MASK,         POWER,          { TO, RA, RB } },
+
+{ "subfc",   XO(31,8,0,0), XO_MASK,    PPC,            { RT, RA, RB } },
+{ "sf",      XO(31,8,0,0), XO_MASK,    POWER,          { RT, RA, RB } },
+{ "subc",    XO(31,8,0,0), XO_MASK,    PPC,            { RT, RB, RA } },
+{ "subfc.",  XO(31,8,0,1), XO_MASK,    PPC,            { RT, RA, RB } },
+{ "sf.",     XO(31,8,0,1), XO_MASK,    POWER,          { RT, RA, RB } },
+{ "subc.",   XO(31,8,0,1), XO_MASK,    PPC,            { RT, RB, RA } },
+{ "subfco",  XO(31,8,1,0), XO_MASK,    PPC,            { RT, RA, RB } },
+{ "sfo",     XO(31,8,1,0), XO_MASK,    POWER,          { RT, RA, RB } },
+{ "subco",   XO(31,8,1,0), XO_MASK,    PPC,            { RT, RB, RA } },
+{ "subfco.", XO(31,8,1,1), XO_MASK,    PPC,            { RT, RA, RB } },
+{ "sfo.",    XO(31,8,1,1), XO_MASK,    POWER,          { RT, RA, RB } },
+{ "subco.",  XO(31,8,1,1), XO_MASK,    PPC,            { RT, RB, RA } },
+
+{ "mulhdu",  XO(31,9,0,0), XO_MASK,    PPC|B64,        { RT, RA, RB } },
+{ "mulhdu.", XO(31,9,0,1), XO_MASK,    PPC|B64,        { RT, RA, RB } },
+
+{ "addc",    XO(31,10,0,0), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "a",       XO(31,10,0,0), XO_MASK,   POWER,          { RT, RA, RB } },
+{ "addc.",   XO(31,10,0,1), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "a.",      XO(31,10,0,1), XO_MASK,   POWER,          { RT, RA, RB } },
+{ "addco",   XO(31,10,1,0), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "ao",      XO(31,10,1,0), XO_MASK,   POWER,          { RT, RA, RB } },
+{ "addco.",  XO(31,10,1,1), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "ao.",     XO(31,10,1,1), XO_MASK,   POWER,          { RT, RA, RB } },
+
+{ "mulhwu",  XO(31,11,0,0), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "mulhwu.", XO(31,11,0,1), XO_MASK,   PPC,            { RT, RA, RB } },
+
+{ "mfcr",    X(31,19), XRARB_MASK,     POWER|PPC,      { RT } },
+
+{ "lwarx",   X(31,20), X_MASK,         PPC,            { RT, RA, RB } },
+
+{ "ldx",     X(31,21), X_MASK,         PPC|B64,        { RT, RA, RB } },
+
+{ "lwzx",    X(31,23), X_MASK,         PPC,            { RT, RA, RB } },
+{ "lx",      X(31,23), X_MASK,         POWER,          { RT, RA, RB } },
+
+{ "slw",     XRC(31,24,0), X_MASK,     PPC,            { RA, RS, RB } },
+{ "sl",      XRC(31,24,0), X_MASK,     POWER,          { RA, RS, RB } },
+{ "slw.",    XRC(31,24,1), X_MASK,     PPC,            { RA, RS, RB } },
+{ "sl.",     XRC(31,24,1), X_MASK,     POWER,          { RA, RS, RB } },
+
+{ "cntlzw",  XRC(31,26,0), XRB_MASK,   PPC,            { RA, RS } },
+{ "cntlz",   XRC(31,26,0), XRB_MASK,   POWER,          { RA, RS } },
+{ "cntlzw.", XRC(31,26,1), XRB_MASK,   PPC,            { RA, RS } },
+{ "cntlz.",  XRC(31,26,1), XRB_MASK,   POWER,          { RA, RS } },
+
+{ "sld",     XRC(31,27,0), X_MASK,     PPC|B64,        { RA, RS, RB } },
+{ "sld.",    XRC(31,27,1), X_MASK,     PPC|B64,        { RA, RS, RB } },
+
+{ "and",     XRC(31,28,0), X_MASK,     PPC|POWER,      { RA, RS, RB } },
+{ "and.",    XRC(31,28,1), X_MASK,     PPC|POWER,      { RA, RS, RB } },
+
+{ "maskg",   XRC(31,29,0), X_MASK,     POWER|M601,     { RA, RS, RB } },
+{ "maskg.",  XRC(31,29,1), X_MASK,     POWER|M601,     { RA, RS, RB } },
+
+{ "cmplw",   XCMPL(31,32,0), XCMPL_MASK, PPC,          { OBF, RA, RB } },
+{ "cmpld",   XCMPL(31,32,1), XCMPL_MASK, PPC|B64,      { OBF, RA, RB } },
+{ "cmpl",    X(31,32), XCMP_MASK,      PPC,            { BF, L, RA, RB } },
+{ "cmpl",    X(31,32), XCMPL_MASK,     POWER,          { BF, RA, RB } },
+
+{ "subf",    XO(31,40,0,0), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "sub",     XO(31,40,0,0), XO_MASK,   PPC,            { RT, RB, RA } },
+{ "subf.",   XO(31,40,0,1), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "sub.",    XO(31,40,0,1), XO_MASK,   PPC,            { RT, RB, RA } },
+{ "subfo",   XO(31,40,1,0), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "subo",    XO(31,40,1,0), XO_MASK,   PPC,            { RT, RB, RA } },
+{ "subfo.",  XO(31,40,1,1), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "subo.",   XO(31,40,1,1), XO_MASK,   PPC,            { RT, RB, RA } },
+
+{ "ldux",    X(31,53), X_MASK,         PPC|B64,        { RT, RAL, RB } },
+
+{ "dcbst",   X(31,54), XRT_MASK,       PPC,            { RA, RB } },
+
+{ "lwzux",   X(31,55), X_MASK,         PPC,            { RT, RAL, RB } },
+{ "lux",     X(31,55), X_MASK,         POWER,          { RT, RA, RB } },
+
+{ "cntlzd",  XRC(31,58,0), XRB_MASK,   PPC|B64,        { RA, RS } },
+{ "cntlzd.", XRC(31,58,1), XRB_MASK,   PPC|B64,        { RA, RS } },
+
+{ "andc",    XRC(31,60,0), X_MASK,     PPC|POWER,      { RA, RS, RB } },
+{ "andc.",   XRC(31,60,1), X_MASK,     PPC|POWER,      { RA, RS, RB } },
+
+{ "tdlgt",   XTO(31,68,TOLGT), XTO_MASK, PPC|B64,      { RA, RB } },
+{ "tdllt",   XTO(31,68,TOLLT), XTO_MASK, PPC|B64,      { RA, RB } },
+{ "tdeq",    XTO(31,68,TOEQ), XTO_MASK, PPC|B64,       { RA, RB } },
+{ "tdlge",   XTO(31,68,TOLGE), XTO_MASK, PPC|B64,      { RA, RB } },
+{ "tdlnl",   XTO(31,68,TOLNL), XTO_MASK, PPC|B64,      { RA, RB } },
+{ "tdlle",   XTO(31,68,TOLLE), XTO_MASK, PPC|B64,      { RA, RB } },
+{ "tdlng",   XTO(31,68,TOLNG), XTO_MASK, PPC|B64,      { RA, RB } },
+{ "tdgt",    XTO(31,68,TOGT), XTO_MASK, PPC|B64,       { RA, RB } },
+{ "tdge",    XTO(31,68,TOGE), XTO_MASK, PPC|B64,       { RA, RB } },
+{ "tdnl",    XTO(31,68,TONL), XTO_MASK, PPC|B64,       { RA, RB } },
+{ "tdlt",    XTO(31,68,TOLT), XTO_MASK, PPC|B64,       { RA, RB } },
+{ "tdle",    XTO(31,68,TOLE), XTO_MASK, PPC|B64,       { RA, RB } },
+{ "tdng",    XTO(31,68,TONG), XTO_MASK, PPC|B64,       { RA, RB } },
+{ "tdne",    XTO(31,68,TONE), XTO_MASK, PPC|B64,       { RA, RB } },
+{ "td",             X(31,68),  X_MASK,         PPC|B64,        { TO, RA, RB } },
+
+{ "mulhd",   XO(31,73,0,0), XO_MASK,   PPC|B64,        { RT, RA, RB } },
+{ "mulhd.",  XO(31,73,0,1), XO_MASK,   PPC|B64,        { RT, RA, RB } },
+
+{ "mulhw",   XO(31,75,0,0), XO_MASK,   PPC,            { RT, RA, RB } },
+{ "mulhw.",  XO(31,75,0,1), XO_MASK,   PPC,            { RT, RA, RB } },
+
+{ "mfmsr",   X(31,83), XRARB_MASK,     PPC|POWER,      { RT } },
+
+{ "ldarx",   X(31,84), X_MASK,         PPC|B64,        { RT, RA, RB } },
+
+{ "dcbf",    X(31,86), XRT_MASK,       PPC,            { RA, RB } },
+
+{ "lbzx",    X(31,87), X_MASK,         PPC|POWER,      { RT, RA, RB } },
+
+{ "neg",     XO(31,104,0,0), XORB_MASK,        PPC|POWER,      { RT, RA } },
+{ "neg.",    XO(31,104,0,1), XORB_MASK,        PPC|POWER,      { RT, RA } },
+{ "nego",    XO(31,104,1,0), XORB_MASK,        PPC|POWER,      { RT, RA } },
+{ "nego.",   XO(31,104,1,1), XORB_MASK,        PPC|POWER,      { RT, RA } },
+
+{ "mul",     XO(31,107,0,0), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "mul.",    XO(31,107,0,1), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "mulo",    XO(31,107,1,0), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "mulo.",   XO(31,107,1,1), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+
+{ "clf",     X(31,118), XRB_MASK,      POWER,          { RT, RA } },
+
+{ "lbzux",   X(31,119),        X_MASK,         PPC|POWER,      { RT, RAL, RB } },
+
+{ "not",     XRC(31,124,0), X_MASK,    PPC|POWER,      { RA, RS, RBS } },
+{ "nor",     XRC(31,124,0), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+{ "not.",    XRC(31,124,1), X_MASK,    PPC|POWER,      { RA, RS, RBS } },
+{ "nor.",    XRC(31,124,1), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+
+{ "subfe",   XO(31,136,0,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "sfe",     XO(31,136,0,0), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "subfe.",  XO(31,136,0,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "sfe.",    XO(31,136,0,1), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "subfeo",  XO(31,136,1,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "sfeo",    XO(31,136,1,0), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "subfeo.", XO(31,136,1,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "sfeo.",   XO(31,136,1,1), XO_MASK,  POWER,          { RT, RA, RB } },
+
+{ "adde",    XO(31,138,0,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "ae",      XO(31,138,0,0), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "adde.",   XO(31,138,0,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "ae.",     XO(31,138,0,1), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "addeo",   XO(31,138,1,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "aeo",     XO(31,138,1,0), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "addeo.",  XO(31,138,1,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "aeo.",    XO(31,138,1,1), XO_MASK,  POWER,          { RT, RA, RB } },
+
+{ "mtcr",    XFXM(31,144,0xff), XFXFXM_MASK|FXM_MASK, PPC|POWER, { RS }},
+{ "mtcrf",   X(31,144),        XFXFXM_MASK,    PPC|POWER,      { FXM, RS } },
+
+{ "mtmsr",   X(31,146),        XRARB_MASK,     PPC|POWER,      { RS } },
+
+{ "stdx",    X(31,149), X_MASK,                PPC|B64,        { RS, RA, RB } },
+
+{ "stwcx.",  XRC(31,150,1), X_MASK,    PPC,            { RS, RA, RB } },
+
+{ "stwx",    X(31,151), X_MASK,                PPC,            { RS, RA, RB } },
+{ "stx",     X(31,151), X_MASK,                POWER,          { RS, RA, RB } },
+
+{ "slq",     XRC(31,152,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "slq.",    XRC(31,152,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "sle",     XRC(31,153,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "sle.",    XRC(31,153,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "stdux",   X(31,181),        X_MASK,         PPC|B64,        { RS, RAS, RB } },
+
+{ "stwux",   X(31,183),        X_MASK,         PPC,            { RS, RAS, RB } },
+{ "stux",    X(31,183),        X_MASK,         POWER,          { RS, RA, RB } },
+
+{ "sliq",    XRC(31,184,0), X_MASK,    POWER|M601,     { RA, RS, SH } },
+{ "sliq.",   XRC(31,184,1), X_MASK,    POWER|M601,     { RA, RS, SH } },
+
+{ "subfze",  XO(31,200,0,0), XORB_MASK, PPC,           { RT, RA } },
+{ "sfze",    XO(31,200,0,0), XORB_MASK, POWER,         { RT, RA } },
+{ "subfze.", XO(31,200,0,1), XORB_MASK, PPC,           { RT, RA } },
+{ "sfze.",   XO(31,200,0,1), XORB_MASK, POWER,         { RT, RA } },
+{ "subfzeo", XO(31,200,1,0), XORB_MASK, PPC,           { RT, RA } },
+{ "sfzeo",   XO(31,200,1,0), XORB_MASK, POWER,         { RT, RA } },
+{ "subfzeo.",XO(31,200,1,1), XORB_MASK, PPC,           { RT, RA } },
+{ "sfzeo.",  XO(31,200,1,1), XORB_MASK, POWER,         { RT, RA } },
+
+{ "addze",   XO(31,202,0,0), XORB_MASK, PPC,           { RT, RA } },
+{ "aze",     XO(31,202,0,0), XORB_MASK, POWER,         { RT, RA } },
+{ "addze.",  XO(31,202,0,1), XORB_MASK, PPC,           { RT, RA } },
+{ "aze.",    XO(31,202,0,1), XORB_MASK, POWER,         { RT, RA } },
+{ "addzeo",  XO(31,202,1,0), XORB_MASK, PPC,           { RT, RA } },
+{ "azeo",    XO(31,202,1,0), XORB_MASK, POWER,         { RT, RA } },
+{ "addzeo.", XO(31,202,1,1), XORB_MASK, PPC,           { RT, RA } },
+{ "azeo.",   XO(31,202,1,1), XORB_MASK, POWER,         { RT, RA } },
+
+{ "mtsr",    X(31,210),        XRB_MASK|(1<<20), PPC|POWER|B32, { SR, RS } },
+
+{ "stdcx.",  XRC(31,214,1), X_MASK,    PPC|B64,        { RS, RA, RB } },
+
+{ "stbx",    X(31,215),        X_MASK,         PPC|POWER,      { RS, RA, RB } },
+
+{ "sllq",    XRC(31,216,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "sllq.",   XRC(31,216,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "sleq",    XRC(31,217,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "sleq.",   XRC(31,217,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "subfme",  XO(31,232,0,0), XORB_MASK, PPC,           { RT, RA } },
+{ "sfme",    XO(31,232,0,0), XORB_MASK, POWER,         { RT, RA } },
+{ "subfme.", XO(31,232,0,1), XORB_MASK, PPC,           { RT, RA } },
+{ "sfme.",   XO(31,232,0,1), XORB_MASK, POWER,         { RT, RA } },
+{ "subfmeo", XO(31,232,1,0), XORB_MASK, PPC,           { RT, RA } },
+{ "sfmeo",   XO(31,232,1,0), XORB_MASK, POWER,         { RT, RA } },
+{ "subfmeo.",XO(31,232,1,1), XORB_MASK, PPC,           { RT, RA } },
+{ "sfmeo.",  XO(31,232,1,1), XORB_MASK, POWER,         { RT, RA } },
+
+{ "mulld",   XO(31,233,0,0), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "mulld.",  XO(31,233,0,1), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "mulldo",  XO(31,233,1,0), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "mulldo.", XO(31,233,1,1), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+
+{ "addme",   XO(31,234,0,0), XORB_MASK, PPC,           { RT, RA } },
+{ "ame",     XO(31,234,0,0), XORB_MASK, POWER,         { RT, RA } },
+{ "addme.",  XO(31,234,0,1), XORB_MASK, PPC,           { RT, RA } },
+{ "ame.",    XO(31,234,0,1), XORB_MASK, POWER,         { RT, RA } },
+{ "addmeo",  XO(31,234,1,0), XORB_MASK, PPC,           { RT, RA } },
+{ "ameo",    XO(31,234,1,0), XORB_MASK, POWER,         { RT, RA } },
+{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPC,           { RT, RA } },
+{ "ameo.",   XO(31,234,1,1), XORB_MASK, POWER,         { RT, RA } },
+
+{ "mullw",   XO(31,235,0,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "muls",    XO(31,235,0,0), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "mullw.",  XO(31,235,0,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "muls.",   XO(31,235,0,1), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "mullwo",  XO(31,235,1,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "mulso",   XO(31,235,1,0), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "mullwo.", XO(31,235,1,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "mulso.",  XO(31,235,1,1), XO_MASK,  POWER,          { RT, RA, RB } },
+
+{ "mtsrin",  X(31,242),        XRA_MASK,       PPC|B32,        { RS, RB } },
+{ "mtsri",   X(31,242),        XRA_MASK,       POWER|B32,      { RS, RB } },
+
+{ "dcbtst",  X(31,246),        XRT_MASK,       PPC,            { RA, RB } },
+
+{ "stbux",   X(31,247),        X_MASK,         PPC|POWER,      { RS, RAS, RB } },
+
+{ "slliq",   XRC(31,248,0), X_MASK,    POWER|M601,     { RA, RS, SH } },
+{ "slliq.",  XRC(31,248,1), X_MASK,    POWER|M601,     { RA, RS, SH } },
+
+{ "doz",     XO(31,264,0,0), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "doz.",    XO(31,264,0,1), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "dozo",    XO(31,264,1,0), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "dozo.",   XO(31,264,1,1), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+
+{ "add",     XO(31,266,0,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "cax",     XO(31,266,0,0), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "add.",    XO(31,266,0,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "cax.",    XO(31,266,0,1), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "addo",    XO(31,266,1,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "caxo",    XO(31,266,1,0), XO_MASK,  POWER,          { RT, RA, RB } },
+{ "addo.",   XO(31,266,1,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "caxo.",   XO(31,266,1,1), XO_MASK,  POWER,          { RT, RA, RB } },
+
+{ "lscbx",   XRC(31,277,0), X_MASK,    POWER|M601,     { RT, RA, RB } },
+{ "lscbx.",  XRC(31,277,1), X_MASK,    POWER|M601,     { RT, RA, RB } },
+
+{ "dcbt",    X(31,278),        XRT_MASK,       PPC,            { RA, RB } },
+
+{ "lhzx",    X(31,279),        X_MASK,         PPC|POWER,      { RT, RA, RB } },
+
+{ "icbt",    X(31,262),        XRT_MASK,       PPC,            { RA, RB } },
+
+{ "eqv",     XRC(31,284,0), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+{ "eqv.",    XRC(31,284,1), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+
+{ "tlbie",   X(31,306),        XRTRA_MASK,     PPC,            { RB } },
+{ "tlbi",    X(31,306),        XRTRA_MASK,     POWER,          { RB } },
+
+{ "eciwx",   X(31,310), X_MASK,                PPC,            { RT, RA, RB } },
+
+{ "lhzux",   X(31,311),        X_MASK,         PPC|POWER,      { RT, RAL, RB } },
+
+{ "xor",     XRC(31,316,0), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+{ "xor.",    XRC(31,316,1), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+
+{ "mfdcr",   X(31,323),        X_MASK,         PPC,            { RT, SPR } },
+
+{ "div",     XO(31,331,0,0), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "div.",    XO(31,331,0,1), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "divo",    XO(31,331,1,0), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "divo.",   XO(31,331,1,1), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+
+{ "mfmq",    XSPR(31,339,0), XSPR_MASK,        POWER|M601,     { RT } },
+{ "mfxer",   XSPR(31,339,1), XSPR_MASK,        PPC|POWER,      { RT } },
+{ "mfrtcu",  XSPR(31,339,4), XSPR_MASK, PPC|POWER,     { RT } },
+{ "mfrtcl",  XSPR(31,339,5), XSPR_MASK, PPC|POWER,     { RT } },
+{ "mfdec",   XSPR(31,339,6), XSPR_MASK, POWER|M601,    { RT } },
+{ "mflr",    XSPR(31,339,8), XSPR_MASK,        PPC|POWER,      { RT } },
+{ "mfctr",   XSPR(31,339,9), XSPR_MASK,        PPC|POWER,      { RT } },
+{ "mftid",   XSPR(31,339,17), XSPR_MASK, POWER,                { RT } },
+{ "mfdsisr", XSPR(31,339,18), XSPR_MASK, PPC|POWER,    { RT } },
+{ "mfdar",   XSPR(31,339,19), XSPR_MASK, PPC|POWER,    { RT } },
+{ "mfdec",   XSPR(31,339,22), XSPR_MASK, PPC,          { RT } },
+{ "mfsdr0",  XSPR(31,339,24), XSPR_MASK, POWER,                { RT } },
+{ "mfsdr1",  XSPR(31,339,25), XSPR_MASK, PPC|POWER,    { RT } },
+{ "mfsrr0",  XSPR(31,339,26), XSPR_MASK, PPC|POWER,    { RT } },
+{ "mfsrr1",  XSPR(31,339,27), XSPR_MASK, PPC|POWER,    { RT } },
+{ "mfsprg",  XSPR(31,339,272), XSPRG_MASK, PPC,                { RT, SPRG } },
+{ "mfasr",   XSPR(31,339,280), XSPR_MASK, PPC|B64,     { RT } },
+{ "mfear",   XSPR(31,339,282), XSPR_MASK, PPC,         { RT } },
+{ "mfpvr",   XSPR(31,339,287), XSPR_MASK, PPC,         { RT } },
+{ "mfibatu", XSPR(31,339,528), XSPRBAT_MASK, PPC,      { RT, SPRBAT } },
+{ "mfibatl", XSPR(31,339,529), XSPRBAT_MASK, PPC,      { RT, SPRBAT } },
+{ "mfdbatu", XSPR(31,339,536), XSPRBAT_MASK, PPC,      { RT, SPRBAT } },
+{ "mfdbatl", XSPR(31,339,537), XSPRBAT_MASK, PPC,      { RT, SPRBAT } },
+{ "mfspr",   X(31,339),        X_MASK,         PPC|POWER,      { RT, SPR } },
+
+{ "lwax",    X(31,341),        X_MASK,         PPC|B64,        { RT, RA, RB } },
+
+{ "lhax",    X(31,343),        X_MASK,         PPC|POWER,      { RT, RA, RB } },
+
+{ "dccci",   X(31,454),        XRT_MASK,       PPC,            { RA, RB } },
+
+{ "abs",     XO(31,360,0,0), XORB_MASK, POWER|M601,    { RT, RA } },
+{ "abs.",    XO(31,360,0,1), XORB_MASK, POWER|M601,    { RT, RA } },
+{ "abso",    XO(31,360,1,0), XORB_MASK, POWER|M601,    { RT, RA } },
+{ "abso.",   XO(31,360,1,1), XORB_MASK, POWER|M601,    { RT, RA } },
+
+{ "divs",    XO(31,363,0,0), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "divs.",   XO(31,363,0,1), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "divso",   XO(31,363,1,0), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+{ "divso.",  XO(31,363,1,1), XO_MASK,  POWER|M601,     { RT, RA, RB } },
+
+{ "tlbia",   X(31,370),        0xffffffff,     PPC,            { 0 } },
+
+{ "mftbu",   XSPR(31,371,269), XSPR_MASK, PPC,         { RT } },
+{ "mftb",    X(31,371),        X_MASK,         PPC,            { RT, TBR } },
+
+{ "lwaux",   X(31,373),        X_MASK,         PPC|B64,        { RT, RAL, RB } },
+
+{ "lhaux",   X(31,375),        X_MASK,         PPC|POWER,      { RT, RAL, RB } },
+
+{ "sthx",    X(31,407),        X_MASK,         PPC|POWER,      { RS, RA, RB } },
+
+{ "lfqx",    X(31,791),        X_MASK,         POWER2,         { FRT, RA, RB } },
+
+{ "lfqux",   X(31,823),        X_MASK,         POWER2,         { FRT, RA, RB } },
+
+{ "stfqx",   X(31,919),        X_MASK,         POWER2,         { FRS, RA, RB } },
+
+{ "stfqux",  X(31,951),        X_MASK,         POWER2,         { FRS, RA, RB } },
+
+{ "orc",     XRC(31,412,0), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+{ "orc.",    XRC(31,412,1), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+
+{ "sradi",   XS(31,413,0), XS_MASK,    PPC|B64,        { RA, RS, SH6 } },
+{ "sradi.",  XS(31,413,1), XS_MASK,    PPC|B64,        { RA, RS, SH6 } },
+
+{ "slbie",   X(31,434),        XRTRA_MASK,     PPC|B64,        { RB } },
+
+{ "ecowx",   X(31,438),        X_MASK,         PPC,            { RT, RA, RB } },
+
+{ "sthux",   X(31,439),        X_MASK,         PPC|POWER,      { RS, RAS, RB } },
+
+{ "mr",             XRC(31,444,0), X_MASK,     PPC|POWER,      { RA, RS, RBS } },
+{ "or",      XRC(31,444,0), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+{ "mr.",     XRC(31,444,1), X_MASK,    PPC|POWER,      { RA, RS, RBS } },
+{ "or.",     XRC(31,444,1), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+
+{ "mtdcr",   X(31,451),        X_MASK,         PPC,            { SPR, RS } },
+
+{ "divdu",   XO(31,457,0,0), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "divdu.",  XO(31,457,0,1), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "divduo",  XO(31,457,1,0), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "divduo.", XO(31,457,1,1), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+
+{ "divwu",   XO(31,459,0,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "divwu.",  XO(31,459,0,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "divwuo",  XO(31,459,1,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "divwuo.", XO(31,459,1,1), XO_MASK,  PPC,            { RT, RA, RB } },
+
+{ "mtmq",    XSPR(31,467,0), XSPR_MASK,        POWER|M601,     { RS } },
+{ "mtxer",   XSPR(31,467,1), XSPR_MASK,        PPC|POWER,      { RS } },
+{ "mtlr",    XSPR(31,467,8), XSPR_MASK,        PPC|POWER,      { RS } },
+{ "mtctr",   XSPR(31,467,9), XSPR_MASK,        PPC|POWER,      { RS } },
+{ "mttid",   XSPR(31,467,17), XSPR_MASK, POWER,                { RS } },
+{ "mtdsisr", XSPR(31,467,18), XSPR_MASK, PPC|POWER,    { RS } },
+{ "mtdar",   XSPR(31,467,19), XSPR_MASK, PPC|POWER,    { RS } },
+{ "mtrtcu",  XSPR(31,467,20), XSPR_MASK, PPC|POWER,    { RS } },
+{ "mtrtcl",  XSPR(31,467,21), XSPR_MASK, PPC|POWER,    { RS } },
+{ "mtdec",   XSPR(31,467,22), XSPR_MASK, PPC|POWER,    { RS } },
+{ "mtsdr0",  XSPR(31,467,24), XSPR_MASK, POWER,                { RS } },
+{ "mtsdr1",  XSPR(31,467,25), XSPR_MASK, PPC|POWER,    { RS } },
+{ "mtsrr0",  XSPR(31,467,26), XSPR_MASK, PPC|POWER,    { RS } },
+{ "mtsrr1",  XSPR(31,467,27), XSPR_MASK, PPC|POWER,    { RS } },
+{ "mtsprg",  XSPR(31,467,272), XSPRG_MASK, PPC,                { SPRG, RS } },
+{ "mtasr",   XSPR(31,467,280), XSPR_MASK, PPC|B64,     { RS } },
+{ "mtear",   XSPR(31,467,282), XSPR_MASK, PPC,         { RS } },
+{ "mttbl",   XSPR(31,467,284), XSPR_MASK, PPC,         { RS } },
+{ "mttbu",   XSPR(31,467,285), XSPR_MASK, PPC,         { RS } },
+{ "mtibatu", XSPR(31,467,528), XSPRBAT_MASK, PPC,      { SPRBAT, RS } },
+{ "mtibatl", XSPR(31,467,529), XSPRBAT_MASK, PPC,      { SPRBAT, RS } },
+{ "mtdbatu", XSPR(31,467,536), XSPRBAT_MASK, PPC,      { SPRBAT, RS } },
+{ "mtdbatl", XSPR(31,467,537), XSPRBAT_MASK, PPC,      { SPRBAT, RS } },
+{ "mtspr",   X(31,467),        X_MASK,         PPC|POWER,      { SPR, RS } },
+
+{ "dcbi",    X(31,470),        XRT_MASK,       PPC,            { RA, RB } },
+
+{ "nand",    XRC(31,476,0), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+{ "nand.",   XRC(31,476,1), X_MASK,    PPC|POWER,      { RA, RS, RB } },
+
+{ "nabs",    XO(31,488,0,0), XORB_MASK, POWER|M601,    { RT, RA } },
+{ "nabs.",   XO(31,488,0,1), XORB_MASK, POWER|M601,    { RT, RA } },
+{ "nabso",   XO(31,488,1,0), XORB_MASK, POWER|M601,    { RT, RA } },
+{ "nabso.",  XO(31,488,1,1), XORB_MASK, POWER|M601,    { RT, RA } },
+
+{ "divd",    XO(31,489,0,0), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "divd.",   XO(31,489,0,1), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "divdo",   XO(31,489,1,0), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+{ "divdo.",  XO(31,489,1,1), XO_MASK,  PPC|B64,        { RT, RA, RB } },
+
+{ "divw",    XO(31,491,0,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "divw.",   XO(31,491,0,1), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "divwo",   XO(31,491,1,0), XO_MASK,  PPC,            { RT, RA, RB } },
+{ "divwo.",  XO(31,491,1,1), XO_MASK,  PPC,            { RT, RA, RB } },
+
+{ "slbia",   X(31,498),        0xffffffff,     PPC|B64,        { 0 } },
+
+{ "cli",     X(31,502), XRB_MASK,      POWER,          { RT, RA } },
+
+{ "mcrxr",   X(31,512),        XRARB_MASK|(3<<21), PPC|POWER,  { BF } },
+
+{ "clcs",    X(31,531), XRB_MASK,      POWER|M601,     { RT, RA } },
+
+{ "lswx",    X(31,533),        X_MASK,         PPC,            { RT, RA, RB } },
+{ "lsx",     X(31,533),        X_MASK,         POWER,          { RT, RA, RB } },
+
+{ "lwbrx",   X(31,534),        X_MASK,         PPC,            { RT, RA, RB } },
+{ "lbrx",    X(31,534),        X_MASK,         POWER,          { RT, RA, RB } },
+
+{ "lfsx",    X(31,535),        X_MASK,         PPC|POWER,      { FRT, RA, RB } },
+
+{ "srw",     XRC(31,536,0), X_MASK,    PPC,            { RA, RS, RB } },
+{ "sr",      XRC(31,536,0), X_MASK,    POWER,          { RA, RS, RB } },
+{ "srw.",    XRC(31,536,1), X_MASK,    PPC,            { RA, RS, RB } },
+{ "sr.",     XRC(31,536,1), X_MASK,    POWER,          { RA, RS, RB } },
+
+{ "rrib",    XRC(31,537,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "rrib.",   XRC(31,537,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "srd",     XRC(31,539,0), X_MASK,    PPC|B64,        { RA, RS, RB } },
+{ "srd.",    XRC(31,539,1), X_MASK,    PPC|B64,        { RA, RS, RB } },
+
+{ "maskir",  XRC(31,541,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "maskir.", XRC(31,541,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "tlbsync", X(31,566),        0xffffffff,     PPC,            { 0 } },
+
+{ "lfsux",   X(31,567),        X_MASK,         PPC|POWER,      { FRT, RAS, RB } },
+
+{ "mfsr",    X(31,595),        XRB_MASK|(1<<20), PPC|POWER|B32, { RT, SR } },
+
+{ "lswi",    X(31,597),        X_MASK,         PPC,            { RT, RA, NB } },
+{ "lsi",     X(31,597),        X_MASK,         POWER,          { RT, RA, NB } },
+
+{ "sync",    X(31,598), 0xffffffff,    PPC,            { 0 } },
+{ "dcs",     X(31,598), 0xffffffff,    POWER,          { 0 } },
+
+{ "lfdx",    X(31,599), X_MASK,                PPC|POWER,      { FRT, RA, RB } },
+
+{ "mfsri",   X(31,627), X_MASK,                POWER,          { RT, RA, RB } },
+
+{ "dclst",   X(31,630), XRB_MASK,      POWER,          { RS, RA } },
+
+{ "lfdux",   X(31,631), X_MASK,                PPC|POWER,      { FRT, RAS, RB } },
+
+{ "mfsrin",  X(31,659), XRA_MASK,      PPC|B32,        { RT, RB } },
+
+{ "stswx",   X(31,661), X_MASK,                PPC,            { RS, RA, RB } },
+{ "stsx",    X(31,661), X_MASK,                POWER,          { RS, RA, RB } },
+
+{ "stwbrx",  X(31,662), X_MASK,                PPC,            { RS, RA, RB } },
+{ "stbrx",   X(31,662), X_MASK,                POWER,          { RS, RA, RB } },
+
+{ "stfsx",   X(31,663), X_MASK,                PPC|POWER,      { FRS, RA, RB } },
+
+{ "srq",     XRC(31,664,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "srq.",    XRC(31,664,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "sre",     XRC(31,665,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "sre.",    XRC(31,665,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "stfsux",  X(31,695),        X_MASK,         PPC|POWER,      { FRS, RAS, RB } },
+
+{ "sriq",    XRC(31,696,0), X_MASK,    POWER|M601,     { RA, RS, SH } },
+{ "sriq.",   XRC(31,696,1), X_MASK,    POWER|M601,     { RA, RS, SH } },
+
+{ "stswi",   X(31,725),        X_MASK,         PPC,            { RS, RA, NB } },
+{ "stsi",    X(31,725),        X_MASK,         POWER,          { RS, RA, NB } },
+
+{ "stfdx",   X(31,727),        X_MASK,         PPC|POWER,      { FRS, RA, RB } },
+
+{ "srlq",    XRC(31,728,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "srlq.",   XRC(31,728,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "sreq",    XRC(31,729,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "sreq.",   XRC(31,729,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "stfdux",  X(31,759),        X_MASK,         PPC|POWER,      { FRS, RAS, RB } },
+
+{ "srliq",   XRC(31,760,0), X_MASK,    POWER|M601,     { RA, RS, SH } },
+{ "srliq.",  XRC(31,760,1), X_MASK,    POWER|M601,     { RA, RS, SH } },
+
+{ "lhbrx",   X(31,790),        X_MASK,         PPC|POWER,      { RT, RA, RB } },
+
+{ "sraw",    XRC(31,792,0), X_MASK,    PPC,            { RA, RS, RB } },
+{ "sra",     XRC(31,792,0), X_MASK,    POWER,          { RA, RS, RB } },
+{ "sraw.",   XRC(31,792,1), X_MASK,    PPC,            { RA, RS, RB } },
+{ "sra.",    XRC(31,792,1), X_MASK,    POWER,          { RA, RS, RB } },
+
+{ "srad",    XRC(31,794,0), X_MASK,    PPC|B64,        { RA, RS, RB } },
+{ "srad.",   XRC(31,794,1), X_MASK,    PPC|B64,        { RA, RS, RB } },
+
+{ "rac",     X(31,818),        X_MASK,         POWER,          { RT, RA, RB } },
+
+{ "srawi",   XRC(31,824,0), X_MASK,    PPC,            { RA, RS, SH } },
+{ "srai",    XRC(31,824,0), X_MASK,    POWER,          { RA, RS, SH } },
+{ "srawi.",  XRC(31,824,1), X_MASK,    PPC,            { RA, RS, SH } },
+{ "srai.",   XRC(31,824,1), X_MASK,    POWER,          { RA, RS, SH } },
+
+{ "eieio",   X(31,854),        0xffffffff,     PPC,            { 0 } },
+
+{ "sthbrx",  X(31,918),        X_MASK,         PPC|POWER,      { RS, RA, RB } },
+
+{ "sraq",    XRC(31,920,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "sraq.",   XRC(31,920,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "srea",    XRC(31,921,0), X_MASK,    POWER|M601,     { RA, RS, RB } },
+{ "srea.",   XRC(31,921,1), X_MASK,    POWER|M601,     { RA, RS, RB } },
+
+{ "extsh",   XRC(31,922,0), XRB_MASK,  PPC,            { RA, RS } },
+{ "exts",    XRC(31,922,0), XRB_MASK,  POWER,          { RA, RS } },
+{ "extsh.",  XRC(31,922,1), XRB_MASK,  PPC,            { RA, RS } },
+{ "exts.",   XRC(31,922,1), XRB_MASK,  POWER,          { RA, RS } },
+
+{ "sraiq",   XRC(31,952,0), X_MASK,    POWER|M601,     { RA, RS, SH } },
+{ "sraiq.",  XRC(31,952,1), X_MASK,    POWER|M601,     { RA, RS, SH } },
+
+{ "extsb",   XRC(31,954,0), XRB_MASK,  PPC,            { RA, RS} },
+{ "extsb.",  XRC(31,954,1), XRB_MASK,  PPC,            { RA, RS} },
+
+{ "iccci",   X(31,966),        XRT_MASK,       PPC,            { RA, RB } },
+
+{ "icbi",    X(31,982),        XRT_MASK,       PPC,            { RA, RB } },
+
+{ "stfiwx",  X(31,983),        X_MASK,         PPC,            { FRS, RA, RB } },
+
+{ "extsw",   XRC(31,986,0), XRB_MASK,  PPC,            { RA, RS } },
+{ "extsw.",  XRC(31,986,1), XRB_MASK,  PPC,            { RA, RS } },
+
+{ "dcbz",    X(31,1014), XRT_MASK,     PPC,            { RA, RB } },
+{ "dclz",    X(31,1014), XRT_MASK,     PPC,            { RA, RB } },
+
+{ "lwz",     OP(32),   OP_MASK,        PPC,            { RT, D, RA } },
+{ "l",      OP(32),    OP_MASK,        POWER,          { RT, D, RA } },
+
+{ "lwzu",    OP(33),   OP_MASK,        PPC,            { RT, D, RAL } },
+{ "lu",      OP(33),   OP_MASK,        POWER,          { RT, D, RA } },
+
+{ "lbz",     OP(34),   OP_MASK,        PPC|POWER,      { RT, D, RA } },
+
+{ "lbzu",    OP(35),   OP_MASK,        PPC|POWER,      { RT, D, RAL } },
+
+{ "stw",     OP(36),   OP_MASK,        PPC,            { RS, D, RA } },
+{ "st",      OP(36),   OP_MASK,        POWER,          { RS, D, RA } },
+
+{ "stwu",    OP(37),   OP_MASK,        PPC,            { RS, D, RAS } },
+{ "stu",     OP(37),   OP_MASK,        POWER,          { RS, D, RA } },
+
+{ "stb",     OP(38),   OP_MASK,        PPC|POWER,      { RS, D, RA } },
+
+{ "stbu",    OP(39),   OP_MASK,        PPC|POWER,      { RS, D, RAS } },
+
+{ "lhz",     OP(40),   OP_MASK,        PPC|POWER,      { RT, D, RA } },
+
+{ "lhzu",    OP(41),   OP_MASK,        PPC|POWER,      { RT, D, RAL } },
+
+{ "lha",     OP(42),   OP_MASK,        PPC|POWER,      { RT, D, RA } },
+
+{ "lhau",    OP(43),   OP_MASK,        PPC|POWER,      { RT, D, RAL } },
+
+{ "sth",     OP(44),   OP_MASK,        PPC|POWER,      { RS, D, RA } },
+
+{ "sthu",    OP(45),   OP_MASK,        PPC|POWER,      { RS, D, RAS } },
+
+{ "lmw",     OP(46),   OP_MASK,        PPC,            { RT, D, RAM } },
+{ "lm",      OP(46),   OP_MASK,        POWER,          { RT, D, RA } },
+
+{ "stmw",    OP(47),   OP_MASK,        PPC,            { RS, D, RA } },
+{ "stm",     OP(47),   OP_MASK,        POWER,          { RS, D, RA } },
+
+{ "lfs",     OP(48),   OP_MASK,        PPC|POWER,      { FRT, D, RA } },
+
+{ "lfsu",    OP(49),   OP_MASK,        PPC|POWER,      { FRT, D, RAS } },
+
+{ "lfd",     OP(50),   OP_MASK,        PPC|POWER,      { FRT, D, RA } },
+
+{ "lfdu",    OP(51),   OP_MASK,        PPC|POWER,      { FRT, D, RAS } },
+
+{ "stfs",    OP(52),   OP_MASK,        PPC|POWER,      { FRS, D, RA } },
+
+{ "stfsu",   OP(53),   OP_MASK,        PPC|POWER,      { FRS, D, RAS } },
+
+{ "stfd",    OP(54),   OP_MASK,        PPC|POWER,      { FRS, D, RA } },
+
+{ "stfdu",   OP(55),   OP_MASK,        PPC|POWER,      { FRS, D, RAS } },
+
+{ "lfq",     OP(56),   OP_MASK,        POWER2,         { FRT, D, RA } },
+
+{ "lfqu",    OP(57),   OP_MASK,        POWER2,         { FRT, D, RA } },
+
+{ "ld",      DSO(58,0),        DS_MASK,        PPC|B64,        { RT, DS, RA } },
+
+{ "ldu",     DSO(58,1), DS_MASK,       PPC|B64,        { RT, DS, RAL } },
+
+{ "lwa",     DSO(58,2), DS_MASK,       PPC|B64,        { RT, DS, RA } },
+
+{ "fdivs",   A(59,18,0), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fdivs.",  A(59,18,1), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+
+{ "fsubs",   A(59,20,0), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fsubs.",  A(59,20,1), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+
+{ "fadds",   A(59,21,0), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fadds.",  A(59,21,1), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+
+{ "fsqrts",  A(59,22,0), AFRAFRC_MASK, PPC,            { FRT, FRB } },
+{ "fsqrts.", A(59,22,1), AFRAFRC_MASK, PPC,            { FRT, FRB } },
+
+{ "fres",    A(59,24,0), AFRAFRC_MASK, PPC,            { FRT, FRB } },
+{ "fres.",   A(59,24,1), AFRAFRC_MASK, PPC,            { FRT, FRB } },
+
+{ "fmuls",   A(59,25,0), AFRB_MASK,    PPC,            { FRT, FRA, FRC } },
+{ "fmuls.",  A(59,25,1), AFRB_MASK,    PPC,            { FRT, FRA, FRC } },
+
+{ "fmsubs",  A(59,28,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fmsubs.", A(59,28,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+
+{ "fmadds",  A(59,29,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fmadds.", A(59,29,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+
+{ "fnmsubs", A(59,30,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fnmsubs.",A(59,30,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+
+{ "fnmadds", A(59,31,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fnmadds.",A(59,31,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+
+{ "stfq",    OP(60),   OP_MASK,        POWER2,         { FRS, D, RA } },
+
+{ "stfqu",   OP(61),   OP_MASK,        POWER2,         { FRS, D, RA } },
+
+{ "std",     DSO(62,0),        DS_MASK,        PPC|B64,        { RS, DS, RA } },
+
+{ "stdu",    DSO(62,1),        DS_MASK,        PPC|B64,        { RS, DS, RAS } },
+
+{ "fcmpu",   X(63,0),  X_MASK|(3<<21), PPC|POWER,      { BF, FRA, FRB } },
+
+{ "frsp",    XRC(63,12,0), XRA_MASK,   PPC|POWER,      { FRT, FRB } },
+{ "frsp.",   XRC(63,12,1), XRA_MASK,   PPC|POWER,      { FRT, FRB } },
+
+{ "fctiw",   XRC(63,14,0), XRA_MASK,   PPC,            { FRT, FRB } },
+{ "fcir",    XRC(63,14,0), XRA_MASK,   POWER2,         { FRT, FRB } },
+{ "fctiw.",  XRC(63,14,1), XRA_MASK,   PPC,            { FRT, FRB } },
+{ "fcir.",   XRC(63,14,1), XRA_MASK,   POWER2,         { FRT, FRB } },
+
+{ "fctiwz",  XRC(63,15,0), XRA_MASK,   PPC,            { FRT, FRB } },
+{ "fcirz",   XRC(63,15,0), XRA_MASK,   POWER2,         { FRT, FRB } },
+{ "fctiwz.", XRC(63,15,1), XRA_MASK,   PPC,            { FRT, FRB } },
+{ "fcirz.",  XRC(63,15,1), XRA_MASK,   POWER2,         { FRT, FRB } },
+
+{ "fdiv",    A(63,18,0), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fd",      A(63,18,0), AFRC_MASK,    POWER,          { FRT, FRA, FRB } },
+{ "fdiv.",   A(63,18,1), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fd.",     A(63,18,1), AFRC_MASK,    POWER,          { FRT, FRA, FRB } },
+
+{ "fsub",    A(63,20,0), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fs",      A(63,20,0), AFRC_MASK,    POWER,          { FRT, FRA, FRB } },
+{ "fsub.",   A(63,20,1), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fs.",     A(63,20,1), AFRC_MASK,    POWER,          { FRT, FRA, FRB } },
+
+{ "fadd",    A(63,21,0), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fa",      A(63,21,0), AFRC_MASK,    POWER,          { FRT, FRA, FRB } },
+{ "fadd.",   A(63,21,1), AFRC_MASK,    PPC,            { FRT, FRA, FRB } },
+{ "fa.",     A(63,21,1), AFRC_MASK,    POWER,          { FRT, FRA, FRB } },
+
+{ "fsqrt",   A(63,22,0), AFRAFRC_MASK, PPC|POWER2,     { FRT, FRB } },
+{ "fsqrt.",  A(63,22,1), AFRAFRC_MASK, PPC|POWER2,     { FRT, FRB } },
+
+{ "fsel",    A(63,23,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fsel.",   A(63,23,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+
+{ "fmul",    A(63,25,0), AFRB_MASK,    PPC,            { FRT, FRA, FRC } },
+{ "fm",      A(63,25,0), AFRB_MASK,    POWER,          { FRT, FRA, FRC } },
+{ "fmul.",   A(63,25,1), AFRB_MASK,    PPC,            { FRT, FRA, FRC } },
+{ "fm.",     A(63,25,1), AFRB_MASK,    POWER,          { FRT, FRA, FRC } },
+
+{ "frsqrte", A(63,26,0), AFRAFRC_MASK, PPC,            { FRT, FRB } },
+{ "frsqrte.",A(63,26,1), AFRAFRC_MASK, PPC,            { FRT, FRB } },
+
+{ "fmsub",   A(63,28,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fms",     A(63,28,0), A_MASK,       POWER,          { FRT,FRA,FRC,FRB } },
+{ "fmsub.",  A(63,28,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fms.",    A(63,28,1), A_MASK,       POWER,          { FRT,FRA,FRC,FRB } },
+
+{ "fmadd",   A(63,29,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fma",     A(63,29,0), A_MASK,       POWER,          { FRT,FRA,FRC,FRB } },
+{ "fmadd.",  A(63,29,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fma.",    A(63,29,1), A_MASK,       POWER,          { FRT,FRA,FRC,FRB } },
+
+{ "fnmsub",  A(63,30,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fnms",    A(63,30,0), A_MASK,       POWER,          { FRT,FRA,FRC,FRB } },
+{ "fnmsub.", A(63,30,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fnms.",   A(63,30,1), A_MASK,       POWER,          { FRT,FRA,FRC,FRB } },
+
+{ "fnmadd",  A(63,31,0), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fnma",    A(63,31,0), A_MASK,       POWER,          { FRT,FRA,FRC,FRB } },
+{ "fnmadd.", A(63,31,1), A_MASK,       PPC,            { FRT,FRA,FRC,FRB } },
+{ "fnma.",   A(63,31,1), A_MASK,       POWER,          { FRT,FRA,FRC,FRB } },
+
+{ "fcmpo",   X(63,30), X_MASK|(3<<21), PPC|POWER,      { BF, FRA, FRB } },
+
+{ "mtfsb1",  XRC(63,38,0), XRARB_MASK, PPC|POWER,      { BT } },
+{ "mtfsb1.", XRC(63,38,1), XRARB_MASK, PPC|POWER,      { BT } },
+
+{ "fneg",    XRC(63,40,0), XRA_MASK,   PPC|POWER,      { FRT, FRB } },
+{ "fneg.",   XRC(63,40,1), XRA_MASK,   PPC|POWER,      { FRT, FRB } },
+
+{ "mcrfs",   X(63,64), XRB_MASK|(3<<21)|(3<<16), PPC|POWER, { BF, BFA } },
+
+{ "mtfsb0",  XRC(63,70,0), XRARB_MASK, PPC|POWER,      { BT } },
+{ "mtfsb0.", XRC(63,70,1), XRARB_MASK, PPC|POWER,      { BT } },
+
+{ "fmr",     XRC(63,72,0), XRA_MASK,   PPC|POWER,      { FRT, FRB } },
+{ "fmr.",    XRC(63,72,1), XRA_MASK,   PPC|POWER,      { FRT, FRB } },
+
+{ "mtfsfi",  XRC(63,134,0), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } },
+{ "mtfsfi.", XRC(63,134,1), XRA_MASK|(3<<21)|(1<<11), PPC|POWER, { BF, U } },
+
+{ "fnabs",   XRC(63,136,0), XRA_MASK,  PPC|POWER,      { FRT, FRB } },
+{ "fnabs.",  XRC(63,136,1), XRA_MASK,  PPC|POWER,      { FRT, FRB } },
+
+{ "fabs",    XRC(63,264,0), XRA_MASK,  PPC|POWER,      { FRT, FRB } },
+{ "fabs.",   XRC(63,264,1), XRA_MASK,  PPC|POWER,      { FRT, FRB } },
+
+{ "mffs",    XRC(63,583,0), XRARB_MASK,        PPC|POWER,      { FRT } },
+{ "mffs.",   XRC(63,583,1), XRARB_MASK,        PPC|POWER,      { FRT } },
+
+{ "mtfsf",   XFL(63,711,0), XFL_MASK,  PPC|POWER,      { FLM, FRB } },
+{ "mtfsf.",  XFL(63,711,1), XFL_MASK,  PPC|POWER,      { FLM, FRB } },
+
+{ "fctid",   XRC(63,814,0), XRA_MASK,  PPC|B64,        { FRT, FRB } },
+{ "fctid.",  XRC(63,814,1), XRA_MASK,  PPC|B64,        { FRT, FRB } },
+
+{ "fctidz",  XRC(63,815,0), XRA_MASK,  PPC|B64,        { FRT, FRB } },
+{ "fctidz.", XRC(63,815,1), XRA_MASK,  PPC|B64,        { FRT, FRB } },
+
+{ "fcfid",   XRC(63,846,0), XRA_MASK,  PPC|B64,        { FRT, FRB } },
+{ "fcfid.",  XRC(63,846,1), XRA_MASK,  PPC|B64,        { FRT, FRB } },
+
+};
+
+const int powerpc_num_opcodes =
+  sizeof (powerpc_opcodes) / sizeof (powerpc_opcodes[0]);
+\f
+/* The macro table.  This is only used by the assembler.  */
+
+const struct powerpc_macro powerpc_macros[] = {
+{ "extldi",  4,   PPC|B64,     "rldicr %0,%1,%3,(%2)-1" },
+{ "extldi.", 4,   PPC|B64,     "rldicr. %0,%1,%3,(%2)-1" },
+{ "extrdi",  4,   PPC|B64,     "rldicl %0,%1,(%2)+(%3),64-(%2)" },
+{ "extrdi.", 4,   PPC|B64,     "rldicl. %0,%1,(%2)+(%3),64-(%2)" },
+{ "insrdi",  4,   PPC|B64,     "rldimi %0,%1,64-((%2)+(%3)),%3" },
+{ "insrdi.", 4,   PPC|B64,     "rldimi. %0,%1,64-((%2)+(%3)),%3" },
+{ "rotrdi",  3,   PPC|B64,     "rldicl %0,%1,64-(%2),0" },
+{ "rotrdi.", 3,   PPC|B64,     "rldicl. %0,%1,64-(%2),0" },
+{ "sldi",    3,   PPC|B64,     "rldicr %0,%1,%2,63-(%2)" },
+{ "sldi.",   3,   PPC|B64,     "rldicr. %0,%1,%2,63-(%2)" },
+{ "srdi",    3,   PPC|B64,     "rldicl %0,%1,64-(%2),%2" },
+{ "srdi.",   3,   PPC|B64,     "rldicl. %0,%1,64-(%2),%2" },
+{ "clrrdi",  3,   PPC|B64,     "rldicr %0,%1,0,63-(%2)" },
+{ "clrrdi.", 3,   PPC|B64,     "rldicr. %0,%1,0,63-(%2)" },
+{ "clrlsldi",4,   PPC|B64,     "rldic %0,%1,%3,(%2)-(%3)" },
+{ "clrlsldi.",4,  PPC|B64,     "rldic. %0,%1,%3,(%2)-(%3)" },
+
+{ "extlwi",  4,   PPC,         "rlwinm %0,%1,%3,0,(%2)-1" },
+{ "extlwi.", 4,   PPC,         "rlwinm. %0,%1,%3,0,(%2)-1" },
+{ "extrwi",  4,   PPC,         "rlwinm %0,%1,(%2)+(%3),32-(%2),31" },
+{ "extrwi.", 4,   PPC,         "rlwinm. %0,%1,(%2)+(%3),32-(%2),31" },
+{ "inslwi",  4,   PPC,         "rlwimi %0,%1,32-(%3),%3,(%2)+(%3)-1" },
+{ "inslwi.", 4,   PPC,         "rlwimi. %0,%1,32-(%3),%3,(%2)+(%3)-1" },
+{ "insrwi",  4,   PPC,         "rlwimi %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1" },
+{ "insrwi.", 4,   PPC,         "rlwimi. %0,%1,32-((%2)+(%3)),%3,(%2)+(%3)-1"},
+{ "rotrwi",  3,   PPC,         "rlwinm %0,%1,32-(%2),0,31" },
+{ "rotrwi.", 3,   PPC,         "rlwinm. %0,%1,32-(%2),0,31" },
+{ "slwi",    3,   PPC,         "rlwinm %0,%1,%2,0,31-(%2)" },
+{ "sli",     3,   POWER,       "rlinm %0,%1,%2,0,31-(%2)" },
+{ "slwi.",   3,   PPC,         "rlwinm. %0,%1,%2,0,31-(%2)" },
+{ "sli.",    3,   POWER,       "rlinm. %0,%1,%2,0,31-(%2)" },
+{ "srwi",    3,   PPC,         "rlwinm %0,%1,32-(%2),%2,31" },
+{ "sri",     3,   POWER,       "rlinm %0,%1,32-(%2),%2,31" },
+{ "srwi.",   3,   PPC,         "rlwinm. %0,%1,32-(%2),%2,31" },
+{ "sri.",    3,   POWER,       "rlinm. %0,%1,32-(%2),%2,31" },
+{ "clrrwi",  3,   PPC,         "rlwinm %0,%1,0,0,31-(%2)" },
+{ "clrrwi.", 3,   PPC,         "rlwinm. %0,%1,0,0,31-(%2)" },
+{ "clrlslwi",4,   PPC,         "rlwinm %0,%1,%3,(%2)-(%3),31-(%3)" },
+{ "clrlslwi.",4,  PPC,         "rlwinm. %0,%1,%3,(%2)-(%3),31-(%3)" },
+
+};
+
+const int powerpc_num_macros =
+  sizeof (powerpc_macros) / sizeof (powerpc_macros[0]);
diff --git a/arch/ppc/xmon/ppc.h b/arch/ppc/xmon/ppc.h
new file mode 100644 (file)
index 0000000..2345ecb
--- /dev/null
@@ -0,0 +1,240 @@
+/* ppc.h -- Header file for PowerPC opcode table
+   Copyright 1994 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Cygnus Support
+
+This file is part of GDB, GAS, and the GNU binutils.
+
+GDB, GAS, and the GNU binutils are free software; you can redistribute
+them and/or modify them under the terms of the GNU General Public
+License as published by the Free Software Foundation; either version
+1, or (at your option) any later version.
+
+GDB, GAS, and the GNU binutils are distributed in the hope that they
+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 file; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef PPC_H
+#define PPC_H
+
+/* The opcode table is an array of struct powerpc_opcode.  */
+
+struct powerpc_opcode
+{
+  /* The opcode name.  */
+  const char *name;
+
+  /* The opcode itself.  Those bits which will be filled in with
+     operands are zeroes.  */
+  unsigned long opcode;
+
+  /* The opcode mask.  This is used by the disassembler.  This is a
+     mask containing ones indicating those bits which must match the
+     opcode field, and zeroes indicating those bits which need not
+     match (and are presumably filled in by operands).  */
+  unsigned long mask;
+
+  /* One bit flags for the opcode.  These are used to indicate which
+     specific processors support the instructions.  The defined values
+     are listed below.  */
+  unsigned long flags;
+
+  /* An array of operand codes.  Each code is an index into the
+     operand table.  They appear in the order which the operands must
+     appear in assembly code, and are terminated by a zero.  */
+  unsigned char operands[8];
+};
+
+/* The table itself is sorted by major opcode number, and is otherwise
+   in the order in which the disassembler should consider
+   instructions.  */
+extern const struct powerpc_opcode powerpc_opcodes[];
+extern const int powerpc_num_opcodes;
+
+/* Values defined for the flags field of a struct powerpc_opcode.  */
+
+/* Opcode is defined for the PowerPC architecture.  */
+#define PPC_OPCODE_PPC (01)
+
+/* Opcode is defined for the POWER (RS/6000) architecture.  */
+#define PPC_OPCODE_POWER (02)
+
+/* Opcode is defined for the POWER2 (Rios 2) architecture.  */
+#define PPC_OPCODE_POWER2 (04)
+
+/* Opcode is only defined on 32 bit architectures.  */
+#define PPC_OPCODE_32 (010)
+
+/* Opcode is only defined on 64 bit architectures.  */
+#define PPC_OPCODE_64 (020)
+
+/* Opcode is supported by the Motorola PowerPC 601 processor.  The 601
+   is assumed to support all PowerPC (PPC_OPCODE_PPC) instructions,
+   but it also supports many additional POWER instructions.  */
+#define PPC_OPCODE_601 (040)
+
+/* A macro to extract the major opcode from an instruction.  */
+#define PPC_OP(i) (((i) >> 26) & 0x3f)
+\f
+/* The operands table is an array of struct powerpc_operand.  */
+
+struct powerpc_operand
+{
+  /* The number of bits in the operand.  */
+  int bits;
+
+  /* How far the operand is left shifted in the instruction.  */
+  int shift;
+
+  /* Insertion function.  This is used by the assembler.  To insert an
+     operand value into an instruction, check this field.
+
+     If it is NULL, execute
+         i |= (op & ((1 << o->bits) - 1)) << o->shift;
+     (i is the instruction which we are filling in, o is a pointer to
+     this structure, and op is the opcode value; this assumes twos
+     complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction and the operand value.  It will return the new value
+     of the instruction.  If the ERRMSG argument is not NULL, then if
+     the operand value is illegal, *ERRMSG will be set to a warning
+     string (the operand will be inserted in any case).  If the
+     operand value is legal, *ERRMSG will be unchanged (most operands
+     can accept any value).  */
+  unsigned long (*insert) PARAMS ((unsigned long instruction, long op,
+                                  const char **errmsg));
+
+  /* Extraction function.  This is used by the disassembler.  To
+     extract this operand type from an instruction, check this field.
+
+     If it is NULL, compute
+         op = ((i) >> o->shift) & ((1 << o->bits) - 1);
+        if ((o->flags & PPC_OPERAND_SIGNED) != 0
+            && (op & (1 << (o->bits - 1))) != 0)
+          op -= 1 << o->bits;
+     (i is the instruction, o is a pointer to this structure, and op
+     is the result; this assumes twos complement arithmetic).
+
+     If this field is not NULL, then simply call it with the
+     instruction value.  It will return the value of the operand.  If
+     the INVALID argument is not NULL, *INVALID will be set to
+     non-zero if this operand type can not actually be extracted from
+     this operand (i.e., the instruction does not match).  If the
+     operand is valid, *INVALID will not be changed.  */
+  long (*extract) PARAMS ((unsigned long instruction, int *invalid));
+
+  /* One bit syntax flags.  */
+  unsigned long flags;
+};
+
+/* Elements in the table are retrieved by indexing with values from
+   the operands field of the powerpc_opcodes table.  */
+
+extern const struct powerpc_operand powerpc_operands[];
+
+/* Values defined for the flags field of a struct powerpc_operand.  */
+
+/* This operand takes signed values.  */
+#define PPC_OPERAND_SIGNED (01)
+
+/* This operand takes signed values, but also accepts a full positive
+   range of values when running in 32 bit mode.  That is, if bits is
+   16, it takes any value from -0x8000 to 0xffff.  In 64 bit mode,
+   this flag is ignored.  */
+#define PPC_OPERAND_SIGNOPT (02)
+
+/* This operand does not actually exist in the assembler input.  This
+   is used to support extended mnemonics such as mr, for which two
+   operands fields are identical.  The assembler should call the
+   insert function with any op value.  The disassembler should call
+   the extract function, ignore the return value, and check the value
+   placed in the valid argument.  */
+#define PPC_OPERAND_FAKE (04)
+
+/* The next operand should be wrapped in parentheses rather than
+   separated from this one by a comma.  This is used for the load and
+   store instructions which want their operands to look like
+       reg,displacement(reg)
+   */
+#define PPC_OPERAND_PARENS (010)
+
+/* This operand may use the symbolic names for the CR fields, which
+   are
+       lt  0   gt  1   eq  2   so  3   un  3
+       cr0 0   cr1 1   cr2 2   cr3 3
+       cr4 4   cr5 5   cr6 6   cr7 7
+   These may be combined arithmetically, as in cr2*4+gt.  These are
+   only supported on the PowerPC, not the POWER.  */
+#define PPC_OPERAND_CR (020)
+
+/* This operand names a register.  The disassembler uses this to print
+   register names with a leading 'r'.  */
+#define PPC_OPERAND_GPR (040)
+
+/* This operand names a floating point register.  The disassembler
+   prints these with a leading 'f'.  */
+#define PPC_OPERAND_FPR (0100)
+
+/* This operand is a relative branch displacement.  The disassembler
+   prints these symbolically if possible.  */
+#define PPC_OPERAND_RELATIVE (0200)
+
+/* This operand is an absolute branch address.  The disassembler
+   prints these symbolically if possible.  */
+#define PPC_OPERAND_ABSOLUTE (0400)
+
+/* This operand is optional, and is zero if omitted.  This is used for
+   the optional BF and L fields in the comparison instructions.  The
+   assembler must count the number of operands remaining on the line,
+   and the number of operands remaining for the opcode, and decide
+   whether this operand is present or not.  The disassembler should
+   print this operand out only if it is not zero.  */
+#define PPC_OPERAND_OPTIONAL (01000)
+
+/* This flag is only used with PPC_OPERAND_OPTIONAL.  If this operand
+   is omitted, then for the next operand use this operand value plus
+   1, ignoring the next operand field for the opcode.  This wretched
+   hack is needed because the Power rotate instructions can take
+   either 4 or 5 operands.  The disassembler should print this operand
+   out regardless of the PPC_OPERAND_OPTIONAL field.  */
+#define PPC_OPERAND_NEXT (02000)
+
+/* This operand should be regarded as a negative number for the
+   purposes of overflow checking (i.e., the normal most negative
+   number is disallowed and one more than the normal most positive
+   number is allowed).  This flag will only be set for a signed
+   operand.  */
+#define PPC_OPERAND_NEGATIVE (04000)
+\f
+/* The POWER and PowerPC assemblers use a few macros.  We keep them
+   with the operands table for simplicity.  The macro table is an
+   array of struct powerpc_macro.  */
+
+struct powerpc_macro
+{
+  /* The macro name.  */
+  const char *name;
+
+  /* The number of operands the macro takes.  */
+  unsigned int operands;
+
+  /* One bit flags for the opcode.  These are used to indicate which
+     specific processors support the instructions.  The values are the
+     same as those for the struct powerpc_opcode flags field.  */
+  unsigned long flags;
+
+  /* A format string to turn the macro into a normal instruction.
+     Each %N in the string is replaced with operand number N (zero
+     based).  */
+  const char *format;
+};
+
+extern const struct powerpc_macro powerpc_macros[];
+extern const int powerpc_num_macros;
+
+#endif /* PPC_H */
diff --git a/arch/ppc/xmon/privinst.h b/arch/ppc/xmon/privinst.h
new file mode 100644 (file)
index 0000000..9a46f1a
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#define GETREG(reg)            \
+    static inline int get_ ## reg (void)       \
+       { int ret; asm volatile ("mf" #reg " %0" : "=r" (ret) :); return ret; }
+
+#define SETREG(reg)            \
+    static inline void set_ ## reg (int val)   \
+       { asm volatile ("mt" #reg " %0" : : "r" (val)); }
+
+GETREG(msr)
+SETREG(msr)
+GETREG(cr)
+
+#define GSETSPR(n, name)       \
+    static inline int get_ ## name (void) \
+       { int ret; asm volatile ("mfspr %0," #n : "=r" (ret) : ); return ret; } \
+    static inline void set_ ## name (int val) \
+       { asm volatile ("mtspr " #n ",%0" : : "r" (val)); }
+
+GSETSPR(0, mq)
+GSETSPR(1, xer)
+GSETSPR(4, rtcu)
+GSETSPR(5, rtcl)
+GSETSPR(8, lr)
+GSETSPR(9, ctr)
+GSETSPR(18, dsisr)
+GSETSPR(19, dar)
+GSETSPR(22, dec)
+GSETSPR(25, sdr1)
+GSETSPR(26, srr0)
+GSETSPR(27, srr1)
+GSETSPR(272, sprg0)
+GSETSPR(273, sprg1)
+GSETSPR(274, sprg2)
+GSETSPR(275, sprg3)
+GSETSPR(282, ear)
+GSETSPR(287, pvr)
+GSETSPR(528, bat0u)
+GSETSPR(529, bat0l)
+GSETSPR(530, bat1u)
+GSETSPR(531, bat1l)
+GSETSPR(532, bat2u)
+GSETSPR(533, bat2l)
+GSETSPR(534, bat3u)
+GSETSPR(535, bat3l)
+GSETSPR(1008, hid0)
+GSETSPR(1009, hid1)
+GSETSPR(1010, iabr)
+GSETSPR(1013, dabr)
+GSETSPR(1023, pir)
+
+static inline int get_sr(int n)
+{
+    int ret;
+
+    asm (" mfsrin %0,%1" : "=r" (ret) : "r" (n << 28));
+    return ret;
+}
+
+static inline void set_sr(int n, int val)
+{
+    asm ("mtsrin %0,%1" : : "r" (val), "r" (n << 28));
+}
+
+static inline void store_inst(void *p)
+{
+    asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
+}
+
+
diff --git a/arch/ppc/xmon/setjmp.c b/arch/ppc/xmon/setjmp.c
new file mode 100644 (file)
index 0000000..28352ba
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * NB this file must be compiled with -O2.
+ */
+
+int
+xmon_setjmp(long *buf)
+{
+    asm ("mflr 0; stw 0,0(%0);"
+        "stw 1,4(%0); stw 2,8(%0);"
+        "mfcr 0; stw 0,12(%0);"
+        "stmw 13,16(%0)"
+        : : "r" (buf));
+    /* XXX should save fp regs as well */
+    return 0;
+}
+
+void
+xmon_longjmp(long *buf, int val)
+{
+    if (val == 0)
+       val = 1;
+    asm ("lmw 13,16(%0);"
+        "lwz 0,12(%0); mtcrf 0x38,0;"
+        "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
+        "mtlr 0; mr 3,%1"
+        : : "r" (buf), "r" (val));
+}
diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
new file mode 100644 (file)
index 0000000..c46bcf2
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/string.h>
+#include <linux/config.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/prom.h>
+
+static volatile unsigned char *sccc, *sccd;
+unsigned long TXRDY, RXRDY;
+extern void xmon_printf(const char *fmt, ...);
+
+static int console = 0;
+
+void buf_access(void)
+{
+       if ( _machine == _MACH_chrp )
+               sccd[3] &= ~0x80;       /* reset DLAB */
+}
+
+void
+xmon_map_scc(void)
+{
+       volatile unsigned char *base;
+
+       if ( _machine == _MACH_Pmac )
+       {
+               struct device_node *np;
+#ifdef CHRP_ESCC
+               unsigned long addr = 0xc1013020;
+#else
+               unsigned long addr = 0xf3013030;
+#endif
+               TXRDY = 4;
+               RXRDY = 1;
+               
+               np = find_devices("mac-io");
+               if (np && np->n_addrs) {
+                       addr = np->addrs[0].address + 0x13000;
+                       /* use the B channel on the iMac, A channel on others */
+                       if (addr >= 0xf0000000)
+                               addr += 0x20; /* use A channel */
+               }
+               base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
+               sccc = base + (addr & ~PAGE_MASK);
+#ifdef CHRP_ESCC
+               sccd = sccc + (0xc1013030 - 0xc1013020);
+#else
+               sccd = sccc + (0xf3013030 - 0xf3013020);
+#endif
+       }
+       else
+       {
+               /* should already be mapped by the kernel boot */
+               sccc = (volatile unsigned char *) (isa_io_base + 0x3fd);
+               sccd = (volatile unsigned char *) (isa_io_base + 0x3f8);
+               TXRDY = 0x20;
+               RXRDY = 1;
+       }
+}
+
+static int scc_initialized = 0;
+
+void xmon_init_scc(void);
+extern void pmu_poll(void);
+
+int
+xmon_write(void *handle, void *ptr, int nb)
+{
+    char *p = ptr;
+    int i, ct;
+
+    if (!scc_initialized)
+       xmon_init_scc();
+    for (i = 0; i < nb; ++i) {
+       while ((*sccc & TXRDY) == 0)
+           if (adb_hardware == ADB_VIAPMU)
+               pmu_poll();
+       buf_access();
+       if ( console && (*p != '\r'))
+               printk("%c", *p);
+       ct = 0;
+       if ( *p == '\n')
+               ct = 1;
+       *sccd = *p++;
+       if ( ct )
+               xmon_write(handle, "\r", 1);
+    }
+    return i;
+}
+
+int
+xmon_read(void *handle, void *ptr, int nb)
+{
+    char *p = ptr;
+    int i;
+
+    if (!scc_initialized)
+       xmon_init_scc();
+    for (i = 0; i < nb; ++i) {
+       while ((*sccc & RXRDY) == 0)
+           if (adb_hardware == ADB_VIAPMU)
+               pmu_poll();
+       buf_access();
+#if 0  
+       if ( 0/*console*/ )
+               *p++ = ppc_md.kbd_getkeycode();
+       else
+#endif         
+               *p++ = *sccd;
+    }
+    return i;
+}
+
+static unsigned char scc_inittab[] = {
+    13, 0,             /* set baud rate divisor */
+    12, 1,
+    14, 1,             /* baud rate gen enable, src=rtxc */
+    11, 0x50,          /* clocks = br gen */
+    5,  0x6a,          /* tx 8 bits, assert RTS */
+    4,  0x44,          /* x16 clock, 1 stop */
+    3,  0xc1,          /* rx enable, 8 bits */
+};
+
+void
+xmon_init_scc()
+{
+       if ( _machine == _MACH_chrp )
+       {
+               sccd[3] = 0x83; eieio();        /* LCR = 8N1 + DLAB */
+               sccd[0] = 3; eieio();           /* DLL = 38400 baud */
+               sccd[1] = 0; eieio();
+               sccd[2] = 0; eieio();           /* FCR = 0 */
+               sccd[3] = 3; eieio();           /* LCR = 8N1 */
+               sccd[1] = 0; eieio();           /* IER = 0 */
+       }
+       else
+       {
+               int i, x;
+
+               for (i = 20000; i != 0; --i) {
+                       x = *sccc; eieio();
+               }
+               *sccc = 9; eieio();             /* reset A or B side */
+               *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
+               for (i = 0; i < sizeof(scc_inittab); ++i) {
+                       *sccc = scc_inittab[i];
+                       eieio();
+               }
+       }
+       scc_initialized = 1;
+}
+
+#if 0
+extern int (*prom_entry)(void *);
+
+int
+xmon_exit(void)
+{
+    struct prom_args {
+       char *service;
+    } args;
+
+    for (;;) {
+       args.service = "exit";
+       (*prom_entry)(&args);
+    }
+}
+#endif
+
+void *xmon_stdin;
+void *xmon_stdout;
+void *xmon_stderr;
+
+void
+xmon_init(void)
+{
+}
+
+int
+xmon_putc(int c, void *f)
+{
+    char ch = c;
+
+    if (c == '\n')
+       xmon_putc('\r', f);
+    return xmon_write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+xmon_putchar(int c)
+{
+    return xmon_putc(c, xmon_stdout);
+}
+
+int
+xmon_fputs(char *str, void *f)
+{
+    int n = strlen(str);
+
+    return xmon_write(f, str, n) == n? 0: -1;
+}
+
+int
+xmon_readchar(void)
+{
+    char ch;
+
+    for (;;) {
+       switch (xmon_read(xmon_stdin, &ch, 1)) {
+       case 1:
+           return ch;
+       case -1:
+           xmon_printf("read(stdin) returned -1\r\n", 0, 0);
+           return -1;
+       }
+    }
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int
+xmon_getchar(void)
+{
+    int c;
+
+    if (lineleft == 0) {
+       lineptr = line;
+       for (;;) {
+           c = xmon_readchar();
+           if (c == -1 || c == 4)
+               break;
+           if (c == '\r' || c == '\n') {
+               *lineptr++ = '\n';
+               xmon_putchar('\n');
+               break;
+           }
+           switch (c) {
+           case 0177:
+           case '\b':
+               if (lineptr > line) {
+                   xmon_putchar('\b');
+                   xmon_putchar(' ');
+                   xmon_putchar('\b');
+                   --lineptr;
+               }
+               break;
+           case 'U' & 0x1F:
+               while (lineptr > line) {
+                   xmon_putchar('\b');
+                   xmon_putchar(' ');
+                   xmon_putchar('\b');
+                   --lineptr;
+               }
+               break;
+           default:
+               if (lineptr >= &line[sizeof(line) - 1])
+                   xmon_putchar('\a');
+               else {
+                   xmon_putchar(c);
+                   *lineptr++ = c;
+               }
+           }
+       }
+       lineleft = lineptr - line;
+       lineptr = line;
+    }
+    if (lineleft == 0)
+       return -1;
+    --lineleft;
+    return *lineptr++;
+}
+
+char *
+xmon_fgets(char *str, int nb, void *f)
+{
+    char *p;
+    int c;
+
+    for (p = str; p < str + nb - 1; ) {
+       c = xmon_getchar();
+       if (c == -1) {
+           if (p == str)
+               return 0;
+           break;
+       }
+       *p++ = c;
+       if (c == '\n')
+           break;
+    }
+    *p = 0;
+    return str;
+}
diff --git a/arch/ppc/xmon/subr_prf.c b/arch/ppc/xmon/subr_prf.c
new file mode 100644 (file)
index 0000000..263538f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Written by Cort Dougan to replace the version written by
+ * Paul Mackerras that had copyright conflicts with Linux.
+ *
+ * This file makes liberal use of the standard linux utility
+ * routines to reduce the size of the binary.  We assume we can
+ * trust some parts of Linux inside the debugger.
+ *   -- Cort (cort@cs.nmt.edu)
+ *
+ * Copyright (C) 1999 Cort Dougan.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include "nonstdio.h"
+
+extern int xmon_write(void *, void *, int);
+
+void
+xmon_vfprintf(void *f, const char *fmt, va_list ap)
+{
+       char buf[2048];
+       vsprintf( buf, fmt, ap );
+       xmon_write( f, buf, strlen(buf) );
+}
+
+void
+xmon_printf(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       xmon_vfprintf(stdout, fmt, ap);
+       va_end(ap);
+}
+
+void
+xmon_fprintf(void *f, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       xmon_vfprintf(f, fmt, ap);
+       va_end(ap);
+}
+
diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
new file mode 100644 (file)
index 0000000..775aca5
--- /dev/null
@@ -0,0 +1,1323 @@
+/*
+ * Routines providing a simple monitor for use on the PowerMac.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <asm/string.h>
+#include "nonstdio.h"
+#include "privinst.h"
+
+#define scanhex        xmon_scanhex
+#define skipbl xmon_skipbl
+
+static unsigned adrs;
+static int size = 1;
+static unsigned ndump = 64;
+static unsigned nidump = 16;
+static int termch;
+
+static u_int bus_error_jmp[100];
+#define setjmp xmon_setjmp
+#define longjmp xmon_longjmp
+
+/* Breakpoint stuff */
+struct bpt {
+       unsigned address;
+       unsigned instr;
+       unsigned count;
+       unsigned char enabled;
+};
+
+#define NBPTS  16
+static struct bpt bpts[NBPTS];
+static struct bpt dabr;
+static struct bpt iabr;
+static unsigned bpinstr = 0x7fe00008;  /* trap */
+
+/* Prototypes */
+extern void (*debugger_fault_handler)(struct pt_regs *);
+static int cmds(struct pt_regs *);
+static int mread(unsigned, void *, int);
+static int mwrite(unsigned, void *, int);
+static void handle_fault(struct pt_regs *);
+static void byterev(unsigned char *, int);
+static void memex(void);
+static int bsesc(void);
+static void dump(void);
+static void prdump(unsigned, int);
+#ifdef __MWERKS__
+static void prndump(unsigned, int);
+static int nvreadb(unsigned);
+#endif
+static int ppc_inst_dump(unsigned, int);
+void print_address(unsigned);
+static int getsp(void);
+static void dump_hash_table(void);
+static void backtrace(struct pt_regs *);
+static void excprint(struct pt_regs *);
+static void prregs(struct pt_regs *);
+static void memops(int);
+static void memlocate(void);
+static void memzcan(void);
+static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);
+int skipbl(void);
+int scanhex(unsigned *valp);
+static void scannl(void);
+static int hexdigit(int);
+void getstring(char *, int);
+static void flush_input(void);
+static int inchar(void);
+static void take_input(char *);
+/* static void openforth(void); */
+static unsigned read_spr(int);
+static void write_spr(int, unsigned);
+static void super_regs(void);
+static void remove_bpts(void);
+static void insert_bpts(void);
+static struct bpt *at_breakpoint(unsigned pc);
+static void bpt_cmds(void);
+
+extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
+extern void printf(const char *fmt, ...);
+extern int putchar(int ch);
+extern int setjmp(u_int *);
+extern void longjmp(u_int *, int);
+
+#define GETWORD(v)     (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
+
+static char *help_string = "\
+Commands:\n\
+  d    dump bytes\n\
+  dc   dump characters\n\
+  di   dump instructions\n\
+  df   dump float values\n\
+  dd   dump double values\n\
+  e    print exception information\n\
+  h    dump hash table\n\
+  m    examine/change memory\n\
+  mm   move a block of memory\n\
+  ms   set a block of memory\n\
+  md   compare two blocks of memory\n\
+  r    print registers\n\
+  S    print special registers\n\
+  t    print backtrace\n\
+  x    exit monitor\n\
+";
+
+static int xmon_trace;
+#define SSTEP  1               /* stepping because of 's' command */
+#define BRSTEP 2               /* stepping over breakpoint */
+
+void
+xmon(struct pt_regs *excp)
+{
+       struct pt_regs regs;
+       int msr, cmd;
+
+       printk("Entering xmon kernel debugger.\n");
+       
+       if (excp == NULL) {
+               asm volatile ("stw      0,0(%0)\n\
+                       lwz     0,0(1)\n\
+                       stw     0,4(%0)\n\
+                       stmw    2,8(%0)" : : "r" (&regs));
+               regs.nip = regs.link = ((unsigned long *)regs.gpr[1])[1];
+               regs.msr = get_msr();
+               regs.ctr = get_ctr();
+               regs.xer = get_xer();
+               regs.ccr = get_cr();
+               regs.trap = 0;
+               excp = &regs;
+       }
+
+       msr = get_msr();
+       set_msr(msr & ~0x8000); /* disable interrupts */
+       remove_bpts();
+       excprint(excp);
+       cmd = cmds(excp);
+       if (cmd == 's') {
+               xmon_trace = SSTEP;
+               excp->msr |= 0x400;
+       } else if (at_breakpoint(excp->nip)) {
+               xmon_trace = BRSTEP;
+               excp->msr |= 0x400;
+       } else {
+               xmon_trace = 0;
+               insert_bpts();
+       }
+       set_msr(msr);           /* restore interrupt enable */
+}
+
+void
+xmon_irq(int irq, void *d, struct pt_regs *regs)
+{
+       printf("Keyboard interrupt\n");
+       xmon(regs);
+}
+
+int
+xmon_bpt(struct pt_regs *regs)
+{
+       struct bpt *bp;
+
+       bp = at_breakpoint(regs->nip);
+       if (!bp)
+               return 0;
+       if (bp->count) {
+               --bp->count;
+               remove_bpts();
+               excprint(regs);
+               xmon_trace = BRSTEP;
+               regs->msr |= 0x400;
+       } else {
+               xmon(regs);
+       }
+       return 1;
+}
+
+int
+xmon_sstep(struct pt_regs *regs)
+{
+       if (!xmon_trace)
+               return 0;
+       if (xmon_trace == BRSTEP) {
+               xmon_trace = 0;
+               insert_bpts();
+       } else {
+               xmon(regs);
+       }
+       return 1;
+}
+
+int
+xmon_dabr_match(struct pt_regs *regs)
+{
+       if (dabr.enabled && dabr.count) {
+               --dabr.count;
+               remove_bpts();
+               excprint(regs);
+               xmon_trace = BRSTEP;
+               regs->msr |= 0x400;
+       } else {
+               dabr.instr = regs->nip;
+               xmon(regs);
+       }
+       return 1;
+}
+
+int
+xmon_iabr_match(struct pt_regs *regs)
+{
+       if (iabr.enabled && iabr.count) {
+               --iabr.count;
+               remove_bpts();
+               excprint(regs);
+               xmon_trace = BRSTEP;
+               regs->msr |= 0x400;
+       } else {
+               xmon(regs);
+       }
+       return 1;
+}
+
+static struct bpt *
+at_breakpoint(unsigned pc)
+{
+       int i;
+       struct bpt *bp;
+
+       if (dabr.enabled && pc == dabr.instr)
+               return &dabr;
+       if (iabr.enabled && pc == iabr.address)
+               return &iabr;
+       bp = bpts;
+       for (i = 0; i < NBPTS; ++i, ++bp)
+               if (bp->enabled && pc == bp->address)
+                       return bp;
+       return 0;
+}
+
+static void
+insert_bpts()
+{
+       int i;
+       struct bpt *bp;
+
+       bp = bpts;
+       for (i = 0; i < NBPTS; ++i, ++bp) {
+               if (!bp->enabled)
+                       continue;
+               if (mread(bp->address, &bp->instr, 4) != 4
+                   || mwrite(bp->address, &bpinstr, 4) != 4) {
+                       printf("Couldn't insert breakpoint at %x, disabling\n",
+                              bp->address);
+                       bp->enabled = 0;
+               }
+       }
+       if (dabr.enabled)
+               set_dabr(dabr.address);
+       if (iabr.enabled)
+               set_iabr(iabr.address);
+}
+
+static void
+remove_bpts()
+{
+       int i;
+       struct bpt *bp;
+       unsigned instr;
+
+       set_dabr(0);
+       set_iabr(0);
+       bp = bpts;
+       for (i = 0; i < NBPTS; ++i, ++bp) {
+               if (!bp->enabled)
+                       continue;
+               if (mread(bp->address, &instr, 4) == 4
+                   && instr == bpinstr
+                   && mwrite(bp->address, &bp->instr, 4) != 4)
+                       printf("Couldn't remove breakpoint at %x\n",
+                              bp->address);
+       }
+}
+
+static char *last_cmd;
+
+/* Command interpreting routine */
+static int
+cmds(struct pt_regs *excp)
+{
+       int cmd;
+
+       last_cmd = NULL;
+       for(;;) {
+               printf("mon> ");
+               fflush(stdout);
+               flush_input();
+               termch = 0;
+               cmd = skipbl();
+               if( cmd == '\n' ) {
+                       if (last_cmd == NULL)
+                               continue;
+                       take_input(last_cmd);
+                       last_cmd = NULL;
+                       cmd = inchar();
+               }
+               switch (cmd) {
+               case 'm':
+                       cmd = inchar();
+                       switch (cmd) {
+                       case 'm':
+                       case 's':
+                       case 'd':
+                               memops(cmd);
+                               break;
+                       case 'l':
+                               memlocate();
+                               break;
+                       case 'z':
+                               memzcan();
+                               break;
+                       default:
+                               termch = cmd;
+                               memex();
+                       }
+                       break;
+               case 'd':
+                       dump();
+                       break;
+               case 'r':
+                       if (excp != NULL)
+                               prregs(excp);   /* print regs */
+                       break;
+               case 'e':
+                       if (excp == NULL)
+                               printf("No exception information\n");
+                       else
+                               excprint(excp);
+                       break;
+               case 'S':
+                       super_regs();
+                       break;
+               case 't':
+                       backtrace(excp);
+                       break;
+#if 0
+               case 'f':
+                       openforth();
+                       break;
+#endif
+               case 'h':
+                       dump_hash_table();
+                       break;
+               case 's':
+               case 'x':
+               case EOF:
+                       return cmd;
+               case '?':
+                       printf(help_string);
+                       break;
+               default:
+                       printf("Unrecognized command: ");
+                       if( ' ' < cmd && cmd <= '~' )
+                               putchar(cmd);
+                       else
+                               printf("\\x%x", cmd);
+                       printf(" (type ? for help)\n");
+                       break;
+               case 'b':
+                       bpt_cmds();
+                       break;
+               }
+       }
+}
+
+static void
+bpt_cmds(void)
+{
+       int cmd;
+       unsigned a;
+       int mode, i;
+       struct bpt *bp;
+
+       cmd = inchar();
+       switch (cmd) {
+       case 'd':
+               mode = 7;
+               cmd = inchar();
+               if (cmd == 'r')
+                       mode = 5;
+               else if (cmd == 'w')
+                       mode = 6;
+               else
+                       termch = cmd;
+               dabr.address = 0;
+               dabr.count = 0;
+               dabr.enabled = scanhex(&dabr.address);
+               scanhex(&dabr.count);
+               if (dabr.enabled)
+                       dabr.address = (dabr.address & ~7) | mode;
+               break;
+       case 'i':
+               iabr.address = 0;
+               iabr.count = 0;
+               iabr.enabled = scanhex(&iabr.address);
+               if (iabr.enabled)
+                       iabr.address |= 3;
+               scanhex(&iabr.count);
+               break;
+       case 'c':
+               if (!scanhex(&a)) {
+                       /* clear all breakpoints */
+                       for (i = 0; i < NBPTS; ++i)
+                               bpts[i].enabled = 0;
+                       iabr.enabled = 0;
+                       dabr.enabled = 0;
+                       printf("All breakpoints cleared\n");
+               } else {
+                       bp = at_breakpoint(a);
+                       if (bp == 0) {
+                               printf("No breakpoint at %x\n", a);
+                       } else {
+                               bp->enabled = 0;
+                       }
+               }
+               break;
+       default:
+               termch = cmd;
+               if (!scanhex(&a)) {
+                       /* print all breakpoints */
+                       printf("type  address   count\n");
+                       if (dabr.enabled) {
+                               printf("data %.8x %8x [", dabr.address & ~7,
+                                      dabr.count);
+                               if (dabr.address & 1)
+                                       printf("r");
+                               if (dabr.address & 2)
+                                       printf("w");
+                               printf("]\n");
+                       }
+                       if (iabr.enabled)
+                               printf("inst %.8x %8x\n", iabr.address & ~3,
+                                      iabr.count);
+                       for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
+                               if (bp->enabled)
+                                       printf("trap %.8x %8x\n", bp->address,
+                                              bp->count);
+                       break;
+               }
+               bp = at_breakpoint(a);
+               if (bp == 0) {
+                       for (bp = bpts; bp < &bpts[NBPTS]; ++bp)
+                               if (!bp->enabled)
+                                       break;
+                       if (bp >= &bpts[NBPTS]) {
+                               printf("Sorry, no free breakpoints\n");
+                               break;
+                       }
+               }
+               bp->enabled = 1;
+               bp->address = a;
+               bp->count = 0;
+               scanhex(&bp->count);
+               break;
+       }
+}
+
+static void
+backtrace(struct pt_regs *excp)
+{
+       unsigned sp;
+       unsigned stack[2];
+       struct pt_regs regs;
+       extern char int_return, syscall_ret_1, syscall_ret_2;
+       extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret;
+
+       if (excp != NULL)
+               sp = excp->gpr[1];
+       else
+               sp = getsp();
+       scanhex(&sp);
+       scannl();
+       for (; sp != 0; sp = stack[0]) {
+               if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
+                       break;
+               printf("%x ", stack[1]);
+               if (stack[1] == (unsigned) &int_return
+                   || stack[1] == (unsigned) &syscall_ret_1
+                   || stack[1] == (unsigned) &syscall_ret_2
+                   || stack[1] == (unsigned) &lost_irq_ret
+                   || stack[1] == (unsigned) &do_bottom_half_ret
+                   || stack[1] == (unsigned) &do_signal_ret) {
+                       if (mread(sp+16, &regs, sizeof(regs)) != sizeof(regs))
+                               break;
+                       printf("\nexception:%x [%x] %x ", regs.trap, sp+16,
+                              regs.nip);
+                       sp = regs.gpr[1];
+                       if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
+                               break;
+               }
+       }
+       printf("\n");
+}
+
+int
+getsp()
+{
+    int x;
+
+    asm("mr %0,1" : "=r" (x) :);
+    return x;
+}
+
+void
+excprint(struct pt_regs *fp)
+{
+       printf("vector: %x at pc = %x, msr = %x, sp = %x [%x]\n",
+              fp->trap, fp->nip, fp->msr, fp->gpr[1], fp);
+       if ((fp->trap == 0x300) || (fp->trap == 0x600) || (fp->trap == 0x200))
+               printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
+       if (current)
+               printf("current = %x, pid = %d, comm = %s\n",
+                      current, current->pid, current->comm);
+}
+
+void
+prregs(struct pt_regs *fp)
+{
+       int n;
+       unsigned base;
+
+       if (scanhex(&base))
+               fp = (struct pt_regs *) base;
+       for (n = 0; n < 32; ++n)
+               printf("R%.2d = %.8x%s", n, fp->gpr[n],
+                      (n & 3) == 3? "\n": "   ");
+       printf("pc  = %.8x   msr = %.8x   lr  = %.8x   cr  = %.8x\n",
+              fp->nip, fp->msr, fp->link, fp->ccr);
+       printf("ctr = %.8x   xer = %.8x   trap = %4x\n",
+              fp->ctr, fp->xer, fp->trap);
+}
+
+unsigned int
+read_spr(int n)
+{
+    unsigned int instrs[2];
+    int (*code)(void);
+
+    instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
+    instrs[1] = 0x4e800020;
+    store_inst(instrs);
+    store_inst(instrs+1);
+    code = (int (*)(void)) instrs;
+    return code();
+}
+
+void
+write_spr(int n, unsigned int val)
+{
+    unsigned int instrs[2];
+    int (*code)(unsigned int);
+
+    instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6);
+    instrs[1] = 0x4e800020;
+    store_inst(instrs);
+    store_inst(instrs+1);
+    code = (int (*)(unsigned int)) instrs;
+    code(val);
+}
+
+static unsigned int regno;
+extern char exc_prolog;
+extern char dec_exc;
+
+void
+super_regs()
+{
+       int i, cmd;
+       unsigned val;
+
+       cmd = skipbl();
+       if (cmd == '\n') {
+               printf("msr = %x, pvr = %x\n", get_msr(), get_pvr());
+               printf("sprg0-3 = %x %x %x %x\n", get_sprg0(), get_sprg1(),
+                      get_sprg2(), get_sprg3());
+               printf("srr0 = %x, srr1 = %x\n", get_srr0(), get_srr1());
+               printf("sr0-15 =");
+               for (i = 0; i < 16; ++i)
+                       printf(" %x", get_sr(i));
+               printf("\n");
+               asm("mr %0,1" : "=r" (i) :);
+               printf("sp = %x ", i);
+               asm("mr %0,2" : "=r" (i) :);
+               printf("toc = %x\n", i);
+               return;
+       }
+
+       scanhex(&regno);
+       switch (cmd) {
+       case 'w':
+               val = read_spr(regno);
+               scanhex(&val);
+               write_spr(regno, val);
+               /* fall through */
+       case 'r':
+               printf("spr %x = %x\n", regno, read_spr(regno));
+               break;
+       case 's':
+               val = get_sr(regno);
+               scanhex(&val);
+               set_sr(regno, val);
+               break;
+       case 'm':
+               val = get_msr();
+               scanhex(&val);
+               set_msr(val);
+               break;
+       }
+       scannl();
+}
+
+#if 0
+static void
+openforth()
+{
+    int c;
+    char *p;
+    char cmd[1024];
+    int args[5];
+    extern int (*prom_entry)(int *);
+
+    p = cmd;
+    c = skipbl();
+    while (c != '\n') {
+       *p++ = c;
+       c = inchar();
+    }
+    *p = 0;
+    args[0] = (int) "interpret";
+    args[1] = 1;
+    args[2] = 1;
+    args[3] = (int) cmd;
+    (*prom_entry)(args);
+    printf("\n");
+    if (args[4] != 0)
+       printf("error %x\n", args[4]);
+}
+#endif
+
+static void
+dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
+{
+       extern void *Hash;
+       extern unsigned long Hash_size;
+       unsigned *htab = Hash;
+       unsigned hsize = Hash_size;
+       unsigned v, hmask, va, last_va;
+       int found, last_found, i;
+       unsigned *hg, w1, last_w2, last_va0;
+
+       last_found = 0;
+       hmask = hsize / 64 - 1;
+       va = start;
+       start = (start >> 12) & 0xffff;
+       end = (end >> 12) & 0xffff;
+       for (v = start; v < end; ++v) {
+               found = 0;
+               hg = htab + (((v ^ seg) & hmask) * 16);
+               w1 = 0x80000000 | (seg << 7) | (v >> 10);
+               for (i = 0; i < 8; ++i, hg += 2) {
+                       if (*hg == w1) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found) {
+                       w1 ^= 0x40;
+                       hg = htab + ((~(v ^ seg) & hmask) * 16);
+                       for (i = 0; i < 8; ++i, hg += 2) {
+                               if (*hg == w1) {
+                                       found = 1;
+                                       break;
+                               }
+                       }
+               }
+               if (!(last_found && found && (hg[1] & ~0x180) == last_w2 + 4096)) {
+                       if (last_found) {
+                               if (last_va != last_va0)
+                                       printf(" ... %x", last_va);
+                               printf("\n");
+                       }
+                       if (found) {
+                               printf("%x to %x", va, hg[1]);
+                               last_va0 = va;
+                       }
+                       last_found = found;
+               }
+               if (found) {
+                       last_w2 = hg[1] & ~0x180;
+                       last_va = va;
+               }
+               va += 4096;
+       }
+       if (last_found)
+               printf(" ... %x\n", last_va);
+}
+static unsigned hash_ctx;
+static unsigned hash_start;
+static unsigned hash_end;
+
+static void
+dump_hash_table()
+{
+       int seg;
+       unsigned seg_start, seg_end;
+
+       hash_ctx = 0;
+       hash_start = 0;
+       hash_end = 0xfffff000;
+       scanhex(&hash_ctx);
+       scanhex(&hash_start);
+       scanhex(&hash_end);
+       printf("Mappings for context %x\n", hash_ctx);
+       seg_start = hash_start;
+       for (seg = hash_start >> 28; seg <= hash_end >> 28; ++seg) {
+               seg_end = (seg << 28) | 0x0ffff000;
+               if (seg_end > hash_end)
+                       seg_end = hash_end;
+               dump_hash_table_seg((hash_ctx << 4) + seg, seg_start, seg_end);
+               seg_start = seg_end + 0x1000;
+       }
+}
+
+/*
+ * Stuff for reading and writing memory safely
+ */
+extern inline void sync(void)
+{
+       asm volatile("sync; isync");
+}
+
+extern inline void __delay(unsigned int loops)
+{
+       if (loops != 0)
+               __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
+                                    "r" (loops) : "ctr");
+}
+
+int
+mread(unsigned adrs, void *buf, int size)
+{
+       volatile int n;
+       char *p, *q;
+
+       n = 0;
+       if( setjmp(bus_error_jmp) == 0 ){
+               debugger_fault_handler = handle_fault;
+               sync();
+               p = (char *) adrs;
+               q = (char *) buf;
+               switch (size) {
+               case 2: *(short *)q = *(short *)p;      break;
+               case 4: *(int *)q = *(int *)p;          break;
+               default:
+                       for( ; n < size; ++n ) {
+                               *q++ = *p++;
+                               sync();
+                       }
+               }
+               sync();
+               /* wait a little while to see if we get a machine check */
+               __delay(200);
+               n = size;
+       }
+       debugger_fault_handler = 0;
+       return n;
+}
+
+int
+mwrite(unsigned adrs, void *buf, int size)
+{
+       volatile int n;
+       char *p, *q;
+
+       n = 0;
+       if( setjmp(bus_error_jmp) == 0 ){
+               debugger_fault_handler = handle_fault;
+               sync();
+               p = (char *) adrs;
+               q = (char *) buf;
+               switch (size) {
+               case 2: *(short *)p = *(short *)q;      break;
+               case 4: *(int *)p = *(int *)q;          break;
+               default:
+                       for( ; n < size; ++n ) {
+                               *p++ = *q++;
+                               sync();
+                       }
+               }
+               sync();
+               n = size;
+       } else {
+               printf("*** Error writing address %x\n", adrs + n);
+       }
+       debugger_fault_handler = 0;
+       return n;
+}
+
+static int fault_type;
+static char *fault_chars[] = { "--", "**", "##" };
+
+static void
+handle_fault(struct pt_regs *regs)
+{
+       fault_type = regs->trap == 0x200? 0: regs->trap == 0x300? 1: 2;
+       longjmp(bus_error_jmp, 1);
+}
+
+#define SWAP(a, b, t)  ((t) = (a), (a) = (b), (b) = (t))
+
+void
+byterev(unsigned char *val, int size)
+{
+       int t;
+       
+       switch (size) {
+       case 2:
+               SWAP(val[0], val[1], t);
+               break;
+       case 4:
+               SWAP(val[0], val[3], t);
+               SWAP(val[1], val[2], t);
+               break;
+       }
+}
+
+static int brev;
+static int mnoread;
+
+void
+memex()
+{
+    int cmd, inc, i, nslash;
+    unsigned n;
+    unsigned char val[4];
+
+    last_cmd = "m\n";
+    scanhex(&adrs);
+    while ((cmd = skipbl()) != '\n') {
+       switch( cmd ){
+       case 'b':       size = 1;       break;
+       case 'w':       size = 2;       break;
+       case 'l':       size = 4;       break;
+       case 'r':       brev = !brev;   break;
+       case 'n':       mnoread = 1;    break;
+       case '.':       mnoread = 0;    break;
+       }
+    }
+    if( size <= 0 )
+       size = 1;
+    else if( size > 4 )
+       size = 4;
+    for(;;){
+       if (!mnoread)
+           n = mread(adrs, val, size);
+       printf("%.8x%c", adrs, brev? 'r': ' ');
+       if (!mnoread) {
+           if (brev)
+               byterev(val, size);
+           putchar(' ');
+           for (i = 0; i < n; ++i)
+               printf("%.2x", val[i]);
+           for (; i < size; ++i)
+               printf("%s", fault_chars[fault_type]);
+       }
+       putchar(' ');
+       inc = size;
+       nslash = 0;
+       for(;;){
+           if( scanhex(&n) ){
+               for (i = 0; i < size; ++i)
+                   val[i] = n >> (i * 8);
+               if (!brev)
+                   byterev(val, size);
+               mwrite(adrs, val, size);
+               inc = size;
+           }
+           cmd = skipbl();
+           if (cmd == '\n')
+               break;
+           inc = 0;
+           switch (cmd) {
+           case '\'':
+               for(;;){
+                   n = inchar();
+                   if( n == '\\' )
+                       n = bsesc();
+                   else if( n == '\'' )
+                       break;
+                   for (i = 0; i < size; ++i)
+                       val[i] = n >> (i * 8);
+                   if (!brev)
+                       byterev(val, size);
+                   mwrite(adrs, val, size);
+                   adrs += size;
+               }
+               adrs -= size;
+               inc = size;
+               break;
+           case ',':
+               adrs += size;
+               break;
+           case '.':
+               mnoread = 0;
+               break;
+           case ';':
+               break;
+           case 'x':
+           case EOF:
+               scannl();
+               return;
+           case 'b':
+           case 'v':
+               size = 1;
+               break;
+           case 'w':
+               size = 2;
+               break;
+           case 'l':
+               size = 4;
+               break;
+           case '^':
+               adrs -= size;
+               break;
+               break;
+           case '/':
+               if (nslash > 0)
+                   adrs -= 1 << nslash;
+               else
+                   nslash = 0;
+               nslash += 4;
+               adrs += 1 << nslash;
+               break;
+           case '\\':
+               if (nslash < 0)
+                   adrs += 1 << -nslash;
+               else
+                   nslash = 0;
+               nslash -= 4;
+               adrs -= 1 << -nslash;
+               break;
+           case 'm':
+               scanhex(&adrs);
+               break;
+           case 'n':
+               mnoread = 1;
+               break;
+           case 'r':
+               brev = !brev;
+               break;
+           case '<':
+               n = size;
+               scanhex(&n);
+               adrs -= n;
+               break;
+           case '>':
+               n = size;
+               scanhex(&n);
+               adrs += n;
+               break;
+           }
+       }
+       adrs += inc;
+    }
+}
+
+int
+bsesc()
+{
+       int c;
+
+       c = inchar();
+       switch( c ){
+       case 'n':       c = '\n';       break;
+       case 'r':       c = '\r';       break;
+       case 'b':       c = '\b';       break;
+       case 't':       c = '\t';       break;
+       }
+       return c;
+}
+
+#define isxdigit(c)    ('0' <= (c) && (c) <= '9' || 'a' <= (c) && (c) <= 'f' \
+                        || 'A' <= (c) && (c) <= 'F')
+void
+dump()
+{
+       int c;
+
+       c = inchar();
+       if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
+               termch = c;
+       scanhex(&adrs);
+       if( termch != '\n')
+               termch = 0;
+       if( c == 'i' ){
+               scanhex(&nidump);
+               if( nidump == 0 )
+                       nidump = 16;
+               adrs += ppc_inst_dump(adrs, nidump);
+               last_cmd = "di\n";
+       } else {
+               scanhex(&ndump);
+               if( ndump == 0 )
+                       ndump = 64;
+               prdump(adrs, ndump);
+               adrs += ndump;
+               last_cmd = "d\n";
+       }
+}
+
+void
+prdump(unsigned adrs, int ndump)
+{
+       register int n, m, c, r, nr;
+       unsigned char temp[16];
+
+       for( n = ndump; n > 0; ){
+               printf("%.8x", adrs);
+               putchar(' ');
+               r = n < 16? n: 16;
+               nr = mread(adrs, temp, r);
+               adrs += nr;
+               for( m = 0; m < r; ++m ){
+                       putchar((m & 3) == 0 && m > 0? '.': ' ');
+                       if( m < nr )
+                               printf("%.2x", temp[m]);
+                       else
+                               printf("%s", fault_chars[fault_type]);
+               }
+               for(; m < 16; ++m )
+                       printf("   ");
+               printf("  |");
+               for( m = 0; m < r; ++m ){
+                       if( m < nr ){
+                               c = temp[m];
+                               putchar(' ' <= c && c <= '~'? c: '.');
+                       } else
+                               putchar(' ');
+               }
+               n -= r;
+               for(; m < 16; ++m )
+                       putchar(' ');
+               printf("|\n");
+               if( nr < r )
+                       break;
+       }
+}
+
+int
+ppc_inst_dump(unsigned adr, int count)
+{
+       int nr, dotted;
+       unsigned first_adr;
+       unsigned long inst, last_inst;
+       unsigned char val[4];
+
+       dotted = 0;
+       for (first_adr = adr; count > 0; --count, adr += 4){
+               nr = mread(adr, val, 4);
+               if( nr == 0 ){
+                       const char *x = fault_chars[fault_type];
+                       printf("%.8x  %s%s%s%s\n", adr, x, x, x, x);
+                       break;
+               }
+               inst = GETWORD(val);
+               if (adr > first_adr && inst == last_inst) {
+                       if (!dotted) {
+                               printf(" ...\n");
+                               dotted = 1;
+                       }
+                       continue;
+               }
+               dotted = 0;
+               last_inst = inst;
+               printf("%.8x  ", adr);
+               printf("%.8x\t", inst);
+               print_insn_big_powerpc(stdout, inst, adr);      /* always returns 4 */
+               printf("\n");
+       }
+       return adr - first_adr;
+}
+
+void
+print_address(addr)
+unsigned addr;
+{
+       printf("0x%x", addr);
+}
+
+/*
+ * Memory operations - move, set, print differences
+ */
+static unsigned mdest;         /* destination address */
+static unsigned msrc;          /* source address */
+static unsigned mval;          /* byte value to set memory to */
+static unsigned mcount;                /* # bytes to affect */
+static unsigned mdiffs;                /* max # differences to print */
+
+void
+memops(int cmd)
+{
+       scanhex(&mdest);
+       if( termch != '\n' )
+               termch = 0;
+       scanhex(cmd == 's'? &mval: &msrc);
+       if( termch != '\n' )
+               termch = 0;
+       scanhex(&mcount);
+       switch( cmd ){
+       case 'm':
+               memmove((void *)mdest, (void *)msrc, mcount);
+               break;
+       case 's':
+               memset((void *)mdest, mval, mcount);
+               break;
+       case 'd':
+               if( termch != '\n' )
+                       termch = 0;
+               scanhex(&mdiffs);
+               memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs);
+               break;
+       }
+}
+
+void
+memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr)
+{
+       unsigned n, prt;
+
+       prt = 0;
+       for( n = nb; n > 0; --n )
+               if( *p1++ != *p2++ )
+                       if( ++prt <= maxpr )
+                               printf("%.8x %.2x # %.8x %.2x\n", (unsigned)p1 - 1,
+                                       p1[-1], (unsigned)p2 - 1, p2[-1]);
+       if( prt > maxpr )
+               printf("Total of %d differences\n", prt);
+}
+
+static unsigned mend;
+static unsigned mask;
+
+void
+memlocate()
+{
+       unsigned a, n;
+       unsigned char val[4];
+
+       last_cmd = "ml";
+       scanhex(&mdest);
+       if (termch != '\n') {
+               termch = 0;
+               scanhex(&mend);
+               if (termch != '\n') {
+                       termch = 0;
+                       scanhex(&mval);
+                       mask = ~0;
+                       if (termch != '\n') termch = 0;
+                       scanhex(&mask);
+               }
+       }
+       n = 0;
+       for (a = mdest; a < mend; a += 4) {
+               if (mread(a, val, 4) == 4
+                       && ((GETWORD(val) ^ mval) & mask) == 0) {
+                       printf("%.8x:  %.8x\n", a, GETWORD(val));
+                       if (++n >= 10)
+                               break;
+               }
+       }
+}
+
+static unsigned mskip = 0x1000;
+static unsigned mlim = 0xffffffff;
+
+void
+memzcan()
+{
+       unsigned char v;
+       unsigned a;
+       int ok, ook;
+
+       scanhex(&mdest);
+       if (termch != '\n') termch = 0;
+       scanhex(&mskip);
+       if (termch != '\n') termch = 0;
+       scanhex(&mlim);
+       ook = 0;
+       for (a = mdest; a < mlim; a += mskip) {
+               ok = mread(a, &v, 1);
+               if (ok && !ook) {
+                       printf("%.8x .. ", a);
+                       fflush(stdout);
+               } else if (!ok && ook)
+                       printf("%.8x\n", a - mskip);
+               ook = ok;
+               if (a + mskip < a)
+                       break;
+       }
+       if (ook)
+               printf("%.8x\n", a - mskip);
+}
+
+/* Input scanning routines */
+int
+skipbl()
+{
+       int c;
+
+       if( termch != 0 ){
+               c = termch;
+               termch = 0;
+       } else
+               c = inchar();
+       while( c == ' ' || c == '\t' )
+               c = inchar();
+       return c;
+}
+
+int
+scanhex(vp)
+unsigned *vp;
+{
+       int c, d;
+       unsigned v;
+
+       c = skipbl();
+       d = hexdigit(c);
+       if( d == EOF ){
+               termch = c;
+               return 0;
+       }
+       v = 0;
+       do {
+               v = (v << 4) + d;
+               c = inchar();
+               d = hexdigit(c);
+       } while( d != EOF );
+       termch = c;
+       *vp = v;
+       return 1;
+}
+
+void
+scannl()
+{
+       int c;
+
+       c = termch;
+       termch = 0;
+       while( c != '\n' )
+               c = inchar();
+}
+
+int
+hexdigit(c)
+{
+       if( '0' <= c && c <= '9' )
+               return c - '0';
+       if( 'A' <= c && c <= 'F' )
+               return c - ('A' - 10);
+       if( 'a' <= c && c <= 'f' )
+               return c - ('a' - 10);
+       return EOF;
+}
+
+void
+getstring(char *s, int size)
+{
+       int c;
+
+       c = skipbl();
+       do {
+               if( size > 1 ){
+                       *s++ = c;
+                       --size;
+               }
+               c = inchar();
+       } while( c != ' ' && c != '\t' && c != '\n' );
+       termch = c;
+       *s = 0;
+}
+
+static char line[256];
+static char *lineptr;
+
+void
+flush_input()
+{
+       lineptr = NULL;
+}
+
+int
+inchar()
+{
+       if (lineptr == NULL || *lineptr == 0) {
+               if (fgets(line, sizeof(line), stdin) == NULL) {
+                       lineptr = NULL;
+                       return EOF;
+               }
+               lineptr = line;
+       }
+       return *lineptr++;
+}
+
+void
+take_input(str)
+char *str;
+{
+       lineptr = str;
+}
index 7f6ec54f980a0dfec33d46adbac3b3c5931298df..3bfd6c436d18d10a6de6d190d709ce1a85dc33a8 100644 (file)
@@ -540,6 +540,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                if((!child->dumpable ||
                    (current->uid != child->euid) ||
                    (current->uid != child->uid) ||
+                   (current->uid != child->suid) ||
                    (current->gid != child->egid) ||
                    (current->gid != child->sgid) || 
                    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
index 086a473e392daa2843df0320662d1e9e3029a6f0..312a370a5d04d432a8c840cdb48e85824666ac7e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $
+/* $Id: sys_sunos.c,v 1.97 1999/05/24 19:40:39 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1198,7 +1198,7 @@ asmlinkage int sunos_readv(unsigned long fd, const struct iovec * vector, long c
 
        lock_kernel();
        ret = check_nonblock(sys_readv(fd,vector,count),fd);
-       lock_kernel();
+       unlock_kernel();
        return ret;
 }
 
index 4dd9651b3e2e1f457fd39fa2eeaec42d80cdb8ed..ea4da718719d0e707cf7f387e337bb8da55e8ac7 100644 (file)
@@ -603,6 +603,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
                if((!child->dumpable ||
                    (current->uid != child->euid) ||
                    (current->uid != child->uid) ||
+                   (current->uid != child->suid) ||
                    (current->gid != child->egid) ||
                    (current->gid != child->sgid) ||
                    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
index 82701cc9e4893b6173da25a99c8cdc63e6cc9ee1..0cce0a0943624256a6bd825b79da0f759828275b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.22 1998/10/26 20:01:13 davem Exp $
+/* $Id: sys_sunos32.c,v 1.25 1999/05/24 19:40:44 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -1347,7 +1347,7 @@ asmlinkage int sunos_readv(u32 fd, u32 vector, s32 count)
 
        lock_kernel();
        ret = check_nonblock(sys32_readv(fd, vector, count), fd);
-       lock_kernel();
+       unlock_kernel();
        return ret;
 }
 
index 242d1e914e39750e67d7a6e40d1ceacec90fa04a..885ef752f3e9c6ffe00a5798562eaf0036ce820e 100644 (file)
@@ -677,7 +677,10 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
                        struct device *d;
                        int i = 0;
                        
+                       read_lock_bh(&dev_base_lock);
                        for (d = dev_base; d; d = d->next) i++;
+                       read_unlock_bh(&dev_base_lock);
+
                        if (put_user (i, (int *)A(arg)))
                                return -EFAULT;
                        return 0;
index 0142ceb99d8cbcdc34b149a9671031168607cb66..6d160914b866b29195d275219f93205c98fbe50e 100644 (file)
@@ -275,9 +275,11 @@ __initfunc(void ide_init_cmd646 (ide_hwif_t *hwif))
        (void) pci_write_config_byte(dev, 0x58, 0x3f);
        (void) pci_write_config_byte(dev, 0x5b, 0x3f);
 
-       if (class_rev == 0x01) {
-               hwif->dmaproc = &cmd646_1_dmaproc;
-       } else {
-               hwif->dmaproc = &cmd646_dmaproc;
+       if (hwif->dma_base) {
+               if (class_rev == 0x01) {
+                       hwif->dmaproc = &cmd646_1_dmaproc;
+               } else {
+                       hwif->dmaproc = &cmd646_dmaproc;
+               }
        }
 }
index 39564e15e2300cb668d459d30c46a4d28af5c420..5263e2b65946d49b30f2f3889394caff085fbe21 100644 (file)
@@ -230,7 +230,6 @@ static void init_hwif_data (unsigned int index)
                drive->media                    = ide_disk;
                drive->select.all               = (unit<<4)|0xa0;
                drive->hwif                     = hwif;
-               init_waitqueue_head(&drive->wqueue);
                drive->ctl                      = 0x08;
                drive->ready_stat               = READY_STAT;
                drive->bad_wstat                = BAD_W_STAT;
@@ -956,6 +955,7 @@ static inline void do_special (ide_drive_t *drive)
 int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
 {
        byte stat;
+       int i;
        unsigned long flags;
 
        udelay(1);      /* spec allows drive 400ns to assert "BUSY" */
@@ -972,9 +972,18 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou
                }
                __restore_flags(flags); /* local CPU only */
        }
-       udelay(1);      /* allow status to settle, then read it again */
-       if (OK_STAT((stat = GET_STAT()), good, bad))
-               return 0;
+       /*
+        * Allow status to settle, then read it again.
+        * A few rare drives vastly violate the 400ns spec here,
+        * so we'll wait up to 10usec for a "good" status
+        * rather than expensively fail things immediately.
+        * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+        */
+       for (i = 0; i < 10; i++) {
+               udelay(1);
+               if (OK_STAT((stat = GET_STAT()), good, bad))
+                       return 0;
+       }
        ide_error(drive, "status error", stat);
        return 1;
 }
index 16881b0e63d87db0d1e458ae02f1f10c8340afc3..3752d4329f384ff36a12c3627e976878d83c40e9 100644 (file)
@@ -159,6 +159,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
   if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
     hex '  ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
   fi
+  dep_tristate 'IIC on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT
 fi
 
 endmenu
index 4062808b0f1a64b0c6352b770e23a02118af3d98..4cc45ecc3f9a54b04bb4622dbd120822aa0224dd 100644 (file)
@@ -330,6 +330,16 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_I2C_PARPORT),y)
+L_OBJS += i2c-parport.o
+L_I2C = y
+else
+  ifeq ($(CONFIG_I2C_PARPORT),m)
+    M_OBJS += i2c-parport.o
+    M_I2C = y
+  endif
+endif
+
 ifeq ($(CONFIG_VIDEO_BWQCAM),y)
 L_OBJS += bw-qcam.o
 else
index a59d32b16e54367fc8f69e72f74e9f653662470e..a5e8ff891dfac6bacb2403faba02d149f65a8957 100644 (file)
@@ -1,7 +1,7 @@
 #define BLOCKMOVE
 #define        Z_WAKE
 static char rcsid[] =
-"$Revision: 2.2.2.1 $$Date: 1999/04/08 16:17:43 $";
+"$Revision: 2.2.2.2 $$Date: 1999/05/21 17:18:15 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -21,7 +21,7 @@ static char rcsid[] =
  * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
  * and then fixed as suggested by Michael K. Johnson 12/12/92.
  *
- * This version does not support shared irq's.
+ * This version supports shared IRQ's (only for PCI boards).
  *
  * This module exports the following rs232 io functions:
  *   int cy_init(void);
@@ -31,6 +31,17 @@ static char rcsid[] =
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.2.2.2  1999/05/14 17:18:15 ivan
+ * /proc entry location changed to /proc/tty/driver/cyclades;
+ * Added support to shared IRQ's (only for PCI boards);
+ * Added support for Cobalt Qube2 systems;
+ * IRQ [de]allocation scheme revisited;
+ * BREAK implementation changed in order to make use of the 'break_ctl'
+ * TTY facility;
+ * Fixed typo in TTY structure field 'driver_name';
+ * Included a PCI bridge reset and EEPROM reload in the board 
+ * initialization code (for both Y and Z series).
+ *
  * Revision 2.2.2.1  1999/04/08 16:17:43 ivan
  * Fixed a bug in cy_wait_until_sent that was preventing the port to be 
  * closed properly after a SIGINT;
@@ -536,7 +547,7 @@ static char rcsid[] =
 #undef CY_16Y_HACK
 #undef CY_ENABLE_MONITORING
 #undef CY_PCI_DEBUG
-#define        CY_PROC
+#undef CY_PROC
 
 #if 0
 #define PAUSE __asm__("nop");
@@ -600,6 +611,14 @@ static char rcsid[] =
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 
+#ifdef CONFIG_COBALT_27
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#define        CACHED_TO_UNCACHED(x)   (((unsigned long)(x) & \
+                                 (unsigned long)0x1fffffff) + KSEG1)
+#endif
+
 #define cy_put_user    put_user
 
 static unsigned long cy_get_user(unsigned long *addr)
@@ -638,6 +657,7 @@ static DECLARE_TASK_QUEUE(tq_cyclades);
 static struct tty_driver cy_serial_driver, cy_callout_driver;
 static int serial_refcount;
 
+#ifndef CONFIG_COBALT_27
 static volatile int cy_irq_triggered;
 static volatile int cy_triggered;
 static int cy_wild_int_mask;
@@ -665,6 +685,8 @@ static unsigned char *cy_isa_addresses[] = {
 };
 #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
 
+#endif /* CONFIG_COBALT_27 */
+
 /* This is the per-card data structure containing address, irq, number of
    channels, etc. This driver supports a maximum of NR_CARDS cards.
 */
@@ -681,11 +703,6 @@ static struct tty_struct *serial_table[NR_PORTS];
 static struct termios *serial_termios[NR_PORTS];
 static struct termios *serial_termios_locked[NR_PORTS];
 
-/* This is the per-irq data structure,
-   it maps an irq to the corresponding card */
-
-static struct cyclades_card     *IRQ_cards[NR_IRQS];
-
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
  * lock it in case the copy_from_user blocks while swapping in a page,
@@ -790,7 +807,9 @@ static unsigned short       cy_pci_dev_id[] = {
 
 static void cy_start(struct tty_struct *);
 static void set_line_char(struct cyclades_port *);
+#ifndef CONFIG_COBALT_27
 static void cy_probe(int, void *, struct pt_regs *);
+#endif /* CONFIG_COBALT_27 */
 static void cyz_poll(unsigned long);
 #ifdef CYCLOM_SHOW_STATUS
 static void show_status(int);
@@ -959,6 +978,8 @@ cyy_issue_cmd(volatile ucchar *base_addr, u_char cmd, int index)
     return(0);
 } /* cyy_issue_cmd */
 
+#ifndef CONFIG_COBALT_27       /* ISA interrupt detection code */
+
 static int probe_ready;
 
 /*
@@ -1149,6 +1170,8 @@ cy_probe(int irq, void *dev_id, struct pt_regs *regs)
     return;
 } /* cy_probe */
 
+#endif /* CONFIG_COBALT_27 */
+
 /* The real interrupt service routine is called
    whenever the card wants its hand held--chars
    received, out buffer empty, modem change, etc.
@@ -1172,9 +1195,9 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
   int mdm_change;
   int mdm_status;
 
-    if((cinfo = IRQ_cards[irq]) == 0){
+    if((cinfo = (struct cyclades_card *)dev_id) == 0){
 #ifdef CY_DEBUG_INTERRUPTS
-printk("cy_interrupt: spurious interrupt %d\n\r", irq);
+       printk("cy_interrupt: spurious interrupt %d\n\r", irq);
 #endif
         return; /* spurious interrupt */
     }
@@ -1206,7 +1229,7 @@ printk("cy_interrupt: spurious interrupt %d\n\r", irq);
                 }
                 if (status & CySRReceive) { /* reception interrupt */
 #ifdef CY_DEBUG_INTERRUPTS
-printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
+                   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));
@@ -1333,7 +1356,7 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
                        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);
+                   printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
 #endif
 
                     /* determine the channel & change to that context */
@@ -1368,37 +1391,19 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
                         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.
-                           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);
+                    if (info->breakon || info->breakoff) {
+                       if (info->breakon) {
+                           cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
+                           cy_writeb((u_long)base_addr + (CyTDR<<index), 0x81);
+                           info->breakon = 0;
+                            char_count -= 2;
+                       }
+                       if (info->breakoff) {
+                           cy_writeb((u_long)base_addr + (CyTDR<<index), 0); 
+                           cy_writeb((u_long)base_addr + (CyTDR<<index), 0x83);
+                           info->breakoff = 0;
+                            char_count -= 2;
                        }
-                       /* 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;
                     }
 
                     while (char_count-- > 0){
@@ -1871,12 +1876,6 @@ cyz_poll(unsigned long arg)
                    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),
@@ -1946,26 +1945,35 @@ static int
 startup(struct cyclades_port * info)
 {
   unsigned long flags;
+  int retval = 0;
   unsigned char *base_addr;
   int card,chip,channel,index;
+  unsigned long page;
+
+    page = get_free_page(GFP_KERNEL);
+    if (!page)
+       return -ENOMEM;
+
+    save_flags(flags); cli();
 
     if (info->flags & ASYNC_INITIALIZED){
-        return 0;
+       free_page(page);
+       goto errout;
     }
 
     if (!info->type){
         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;
-        }
+       free_page(page);
+       goto errout;
     }
 
+    if (info->xmit_buf)
+       free_page(page);
+    else
+       info->xmit_buf = (unsigned char *) page;
+
     set_line_char(info);
 
     card = info->card;
@@ -1982,39 +1990,40 @@ startup(struct cyclades_port * info)
             card, chip, channel, (long)base_addr);/**/
 #endif
 
-       save_flags(flags); cli();
-           cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
+       cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
 
-           cy_writeb((ulong)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 */
 
-           cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
+       cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_RCVR|CyENB_XMTR,index);
 
-           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);
+       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 CY_DEBUG_DTR
-           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)));
+       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
 
-           cy_writeb((u_long)base_addr+(CySRER<<index),
-               cy_readb(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;
+       info->breakon = info->breakoff = 0;
+       memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+       info->idle_stats.in_use    =
+       info->idle_stats.recv_idle =
+       info->idle_stats.xmit_idle = jiffies;
 
-           if (info->tty){
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
-           }
-           info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-           memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
-           info->idle_stats.in_use    =
-           info->idle_stats.recv_idle =
-           info->idle_stats.xmit_idle = jiffies;
        restore_flags(flags);
+
     } else {
       struct FIRM_ID *firm_id;
       struct ZFW_CTRL *zfw_ctrl;
@@ -2022,6 +2031,8 @@ startup(struct cyclades_port * info)
       struct CH_CTRL *ch_ctrl;
       int retval;
 
+       restore_flags(flags);
+
        base_addr = (unsigned char*) (cy_card[card].base_addr);
 
         firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
@@ -2074,7 +2085,7 @@ startup(struct cyclades_port * info)
            clear_bit(TTY_IO_ERROR, &info->tty->flags);
        }
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
+       info->breakon = info->breakoff = 0;
        memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
        info->idle_stats.in_use    =
        info->idle_stats.recv_idle =
@@ -2085,6 +2096,10 @@ startup(struct cyclades_port * info)
        printk(" cyc startup done\n");
 #endif
        return 0;
+
+errout:
+       restore_flags(flags);
+       return retval;
 } /* startup */
 
 
@@ -3763,36 +3778,62 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
     return 0;
 } /* set_modem_info */
 
+/*
+ * cy_break() --- routine which turns the break handling on or off
+ */
 static void
-send_break( struct cyclades_port * info, int duration)
+cy_break(struct tty_struct *tty, int break_state)
 {
+    struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+    unsigned long flags;
+
+    if (serial_paranoia_check(info, tty->device, "cy_break"))
+       return;
 
+    save_flags(flags); cli();
     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);
+       if (break_state == -1) {
+           if (!info->breakon) {
+               info->breakon = 1;
+               if (!info->xmit_cnt ) {
+                   start_xmit(info);
+               }
+           }
+       } else {
+           if (!info->breakoff) {
+               info->breakoff = 1;
+               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],
+       int retval;
+
+       if (break_state == -1) {
+           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);
+               C_CM_SET_BREAK, 0L);
+           if (retval != 0) {
+               printk("cyc:cy_break (set) retval at %d was %x\n",
+                       __LINE__, retval);
+           }
+       } else {
+           retval = cyz_issue_cmd(&cy_card[info->card],
+               (info->line) - (cy_card[info->card].first_line),
+               C_CM_CLR_BREAK, 0L);
+           if (retval != 0) {
+               printk("cyc:cy_break (clr) retval at %d was %x\n",
+                       __LINE__, retval);
+           }
        }
-#endif
     }
-} /* send_break */
+    restore_flags(flags);
+
+} /* cy_break */
 
 static int
 get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
@@ -4026,21 +4067,6 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
        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;
-           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;
-           tty_wait_until_sent(tty,0);
-           send_break(info, arg ? arg*(HZ/10) : HZ/4);
-           break;
         case TIOCMGET:
             ret_val = get_modem_info(info, (unsigned int *) arg);
             break;
@@ -4091,7 +4117,13 @@ cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
             tty->stopped = 0;
             cy_start(tty);
     }
-#ifdef tytso_patch_94Nov25_1726
+#if 0
+    /*
+     * No need to wake up processes in open wait, since they
+     * sample the CLOCAL flag once, and don't recheck it.
+     * XXX  It's not clear whether the current behavior is correct
+     * or not.  Hence, this may change.....
+     */
     if (!(old_termios->c_cflag & CLOCAL) &&
         (tty->termios->c_cflag & CLOCAL))
             wake_up_interruptible(&info->open_wait);
@@ -4100,16 +4132,6 @@ cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
     return;
 } /* 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.
@@ -4467,6 +4489,7 @@ cyy_init_card(volatile ucchar *true_base_addr,int index))
     return chip_number;
 } /* cyy_init_card */
 
+#ifndef CONFIG_COBALT_27
 /*
  * ---------------------------------------------------------------------
  * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
@@ -4530,7 +4553,7 @@ cy_detect_isa(void))
 
                 /* allocate IRQ */
                 if(request_irq(cy_isa_irq, cyy_interrupt,
-                                  SA_INTERRUPT, "cyclomY", NULL))
+                                  SA_INTERRUPT, "Cyclom-Y", &cy_card[j]))
                 {
                         printk("Cyclom-Y/ISA found at 0x%lx ",
                                 (unsigned long) cy_isa_address);
@@ -4546,7 +4569,6 @@ cy_detect_isa(void))
                 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 */
@@ -4561,6 +4583,20 @@ cy_detect_isa(void))
         return(nboard);
 
 } /* cy_detect_isa */
+#endif /* CONFIG_COBALT_27 */
+
+static void plx_init(uclong addr, uclong initctl)
+{
+    /* Reset PLX */
+    cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
+    udelay(100L);
+    cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
+
+    /* Reload Config. Registers from EEPROM */
+    cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
+    udelay(100L);
+    cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
+}
 
 /*
  * ---------------------------------------------------------------------
@@ -4621,6 +4657,12 @@ cy_detect_pci(void))
                cy_pci_addr0  &= PCI_BASE_ADDRESS_MEM_MASK;
                cy_pci_addr2  &= PCI_BASE_ADDRESS_MEM_MASK;
 
+               if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) {
+                   printk("  Warning: PCI I/O bit incorrectly set. "
+                          "Ignoring it...\n");
+                   cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_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, ",
@@ -4673,7 +4715,7 @@ cy_detect_pci(void))
 
                 /* allocate IRQ */
                 if(request_irq(cy_pci_irq, cyy_interrupt,
-                       SA_INTERRUPT, "cyclomY", NULL))
+                       SA_SHIRQ, "Cyclom-Y", &cy_card[j]))
                 {
                         printk("Cyclom-Y/PCI found at 0x%lx ",
                            (ulong) cy_pci_addr2);
@@ -4689,13 +4731,14 @@ cy_detect_pci(void))
                 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 */
                plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
                switch (plx_ver) {
                    case PLX_9050:
 
+                   plx_init(cy_pci_addr0, 0x50);
+
                    cy_writew(cy_pci_addr0+0x4c, 
                        cy_readw(cy_pci_addr0+0x4c)|0x0040);
                    break;
@@ -4704,6 +4747,8 @@ cy_detect_pci(void))
                    case PLX_9080:
                    default: /* Old boards, use PLX_9060 */
 
+                   plx_init(cy_pci_addr0, 0x6c);
+
                    cy_writew(cy_pci_addr0+0x68, 
                        cy_readw(cy_pci_addr0+0x68)|0x0900);
                    break;
@@ -4742,9 +4787,18 @@ cy_detect_pci(void))
 #if !defined(__alpha__)
                 cy_pci_addr0 = (ulong)ioremap(cy_pci_addr0, CyPCI_Zctl);
 #endif
+
+               plx_init(cy_pci_addr0, 0x6c);
+
                mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) 
                           cy_pci_addr0)->mail_box_0);
                 cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
+
+               if (cy_pci_addr2 & ~PCI_BASE_ADDRESS_IO_MASK) {
+                   printk("  Warning: PCI I/O bit incorrectly set. "
+                          "Ignoring it...\n");
+                   cy_pci_addr2 &= PCI_BASE_ADDRESS_IO_MASK;
+               }
                if (mailbox == ZE_V1) {
 #if !defined(__alpha__)
                            cy_pci_addr2 = (ulong)ioremap(cy_pci_addr2, CyPCI_Ze_win);
@@ -4821,7 +4875,7 @@ cy_detect_pci(void))
                 /* 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))
+                       SA_SHIRQ,"Cyclades-Z",&cy_card[j]))
                    {
                        printk("Could not allocate IRQ%d ",
                            cy_pci_irq);
@@ -4839,7 +4893,6 @@ cy_detect_pci(void))
                 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 */
@@ -4905,7 +4958,7 @@ cy_detect_pci(void))
                 /* 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))
+                       SA_SHIRQ,"Cyclades-Z",&cy_card[j]))
                    {
                        printk("Could not allocate IRQ%d ",
                            cy_pci_irq);
@@ -4922,7 +4975,6 @@ cy_detect_pci(void))
                 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 */
@@ -4971,7 +5023,6 @@ show_version(void)
        __DATE__, __TIME__);
 } /* show_version */
 
-#ifdef CY_PROC
 static int 
 cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
                       int *eof, void *data)
@@ -5028,7 +5079,6 @@ done:
        len = 0;
     return len;
 }
-#endif
 
 /* The serial driver boot-time initialization code!
     Hardware I/O ports are mapped to character special devices on a
@@ -5062,13 +5112,15 @@ cy_init(void))
   struct proc_dir_entry *ent;
 #endif
 
+    init_bh(CYCLADES_BH, do_cyclades_bh);
+
     show_version();
 
     /* Initialize the tty_driver structure */
     
     memset(&cy_serial_driver, 0, sizeof(struct tty_driver));
     cy_serial_driver.magic = TTY_DRIVER_MAGIC;
-    cy_serial_driver.name = "cyclades";
+    cy_serial_driver.driver_name = "cyclades";
     cy_serial_driver.name = "ttyC";
     cy_serial_driver.major = CYCLADES_MAJOR;
     cy_serial_driver.minor_start = 0;
@@ -5083,6 +5135,7 @@ cy_init(void))
     cy_serial_driver.table = serial_table;
     cy_serial_driver.termios = serial_termios;
     cy_serial_driver.termios_locked = serial_termios_locked;
+
     cy_serial_driver.open = cy_open;
     cy_serial_driver.close = cy_close;
     cy_serial_driver.write = cy_write;
@@ -5098,7 +5151,9 @@ cy_init(void))
     cy_serial_driver.stop = cy_stop;
     cy_serial_driver.start = cy_start;
     cy_serial_driver.hangup = cy_hangup;
+    cy_serial_driver.break_ctl = cy_break;
     cy_serial_driver.wait_until_sent = cy_wait_until_sent;
+    cy_serial_driver.read_proc = cyclades_get_proc_info;
 
     /*
      * The callout device is just like normal device except for
@@ -5117,12 +5172,6 @@ cy_init(void))
     if (tty_register_driver(&cy_callout_driver))
             panic("Couldn't register Cyclades callout driver\n");
 
-    init_bh(CYCLADES_BH, do_cyclades_bh);
-
-    for (i = 0; i < NR_IRQS; i++) {
-            IRQ_cards[i] = 0;
-    }
-
     for (i = 0; i < NR_CARDS; i++) {
             /* base_addr=0 indicates board not found */
             cy_card[i].base_addr = 0;
@@ -5135,9 +5184,11 @@ cy_init(void))
        availability of cy_card and cy_port data structures and updating
        the cy_next_channel. */
 
+#ifndef CONFIG_COBALT_27
     /* look for isa boards */
     cy_isa_nboard = cy_detect_isa();
-    
+#endif /* CONFIG_COBALT_27 */
+
     /* look for pci boards */
     cy_pci_nboard = cy_detect_pci();
 
@@ -5279,9 +5330,9 @@ cy_init(void))
                               cy_callout_driver.init_termios;
                     info->normal_termios =
                               cy_serial_driver.init_termios;
-                    init_waitqueue(&info->open_wait);
-                    init_waitqueue(&info->close_wait);
-                    init_waitqueue(&info->shutdown_wait);
+                    init_waitqueue_head(&info->open_wait);
+                    init_waitqueue_head(&info->close_wait);
+                    init_waitqueue_head(&info->shutdown_wait);
                     /* info->session */
                     /* info->pgrp */
                     info->read_status_mask =
@@ -5323,6 +5374,7 @@ void
 cleanup_module(void)
 {
     int i;
+    int e1, e2;
     unsigned long flags;
 
     if (cyz_timeron){
@@ -5333,11 +5385,12 @@ cleanup_module(void)
     save_flags(flags); cli();
     remove_bh(CYCLADES_BH);
 
-    free_page((unsigned long)tmp_buf);
-    if (tty_unregister_driver(&cy_callout_driver))
-            printk("Couldn't unregister Cyclades callout driver\n");
-    if (tty_unregister_driver(&cy_serial_driver))
-            printk("Couldn't unregister Cyclades serial driver\n");
+    if ((e1 = tty_unregister_driver(&cy_serial_driver)))
+            printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
+               e1);
+    if ((e2 = tty_unregister_driver(&cy_callout_driver)))
+            printk("cyc: failed to unregister Cyclades callout driver (%d)\n", 
+               e2);
 
     restore_flags(flags);
 
@@ -5345,9 +5398,13 @@ cleanup_module(void)
         if (cy_card[i].base_addr != 0
            && cy_card[i].irq)
         {
-            free_irq(cy_card[i].irq,NULL);
+            free_irq(cy_card[i].irq, &cy_card[i]);
         }
     }
+    if (tmp_buf) {
+       free_page((unsigned long) tmp_buf);
+       tmp_buf = NULL;
+    }
 #ifdef CY_PROC
     remove_proc_entry("cyclades", 0);
 #endif
@@ -5358,6 +5415,7 @@ cleanup_module(void)
 void
 cy_setup(char *str, int *ints)
 {
+#ifndef CONFIG_COBALT_27
   int i, j;
 
     for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
@@ -5368,6 +5426,7 @@ cy_setup(char *str, int *ints)
             cy_isa_addresses[i++] = (unsigned char *)(ints[j]);
         }
     }
+#endif /* CONFIG_COBALT_27 */
 
 } /* cy_setup */
 #endif
diff --git a/drivers/char/i2c-parport.c b/drivers/char/i2c-parport.c
new file mode 100644 (file)
index 0000000..cafe38f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * I2C driver for parallel port
+ *
+ * Author: Phil Blundell <philb@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This driver implements a simple I2C protocol by bit-twiddling some
+ * signals on the parallel port.  Since the outputs on the parallel port
+ * aren't open collector, three lines rather than two are used:
+ *
+ *     D0      clock out
+ *     D1      data out
+ *     BUSY    data in 
+ */
+
+#include <linux/parport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <asm/spinlock.h>
+
+#define I2C_DELAY   10
+
+static int debug = 0;
+
+struct parport_i2c_bus
+{
+  struct i2c_bus i2c;
+  struct parport_i2c_bus *next;
+};
+
+static struct parport_i2c_bus *bus_list;
+
+#ifdef __SMP__
+static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+/* software I2C functions */
+
+static void i2c_setlines(struct i2c_bus *bus, int clk, int data)
+{
+  struct parport *p = bus->data;
+  parport_write_data(p, (clk?1:0) | (data?2:0)); 
+  udelay(I2C_DELAY);
+}
+
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+  struct parport *p = bus->data;
+  return (parport_read_status(p) & PARPORT_STATUS_BUSY) ? 0 : 1;
+}
+
+static struct i2c_bus parport_i2c_bus_template = 
+{
+  "...",
+  I2C_BUSID_PARPORT,
+  NULL,
+  
+  SPIN_LOCK_UNLOCKED,
+  
+  NULL,
+  NULL,
+       
+  i2c_setlines,
+  i2c_getdataline,
+  NULL,
+  NULL,
+};
+
+static void i2c_parport_attach(struct parport *port)
+{
+  struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus), 
+                                     GFP_KERNEL);
+  b->i2c = parport_i2c_bus_template;
+  b->i2c.data = port;
+  strncpy(b->i2c.name, port->name, 32);
+  spin_lock(&bus_list_lock);
+  b->next = bus_list;
+  bus_list = b;
+  spin_unlock(&bus_list_lock);
+  i2c_register_bus(&b->i2c);
+  if (debug)
+    printk(KERN_DEBUG "i2c: attached to %s\n", port->name);
+}
+
+static void i2c_parport_detach(struct parport *port)
+{
+  struct parport_i2c_bus *b, *old_b = NULL;
+  spin_lock(&bus_list_lock);
+  b = bus_list;
+  while (b)
+  {
+    if (b->i2c.data == port)
+    {
+      if (old_b)
+       old_b->next = b->next;
+      else
+       bus_list = b->next;
+      i2c_unregister_bus(&b->i2c);
+      kfree(b);
+      break;
+    }
+    old_b = b;
+    b = b->next;
+  }
+  spin_unlock(&bus_list_lock);
+  if (debug)
+    printk(KERN_DEBUG "i2c: detached from %s\n", port->name);
+}
+
+static struct parport_driver parport_i2c_driver = 
+{
+  "i2c",
+  i2c_parport_attach,
+  i2c_parport_detach
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init i2c_parport_init(void)
+#endif
+{
+  printk("I2C: driver for parallel port v0.1 philb@gnu.org\n");
+  parport_register_driver(&parport_i2c_driver);
+  return 0;
+}
+
+#ifdef MODULE
+MODULE_PARM(debug, "i");
+
+void cleanup_module(void)
+{
+  struct parport_i2c_bus *b = bus_list;
+  while (b)
+  {
+    struct parport_i2c_bus *next = b->next;
+    i2c_unregister_bus(&b->i2c);
+    kfree(b);
+    b = next;
+  }
+  parport_unregister_driver(&parport_i2c_driver);
+}
+#endif
index ad9d6f066d254eb050063e2abaf44c50a9172494..bd215a6370f80df462ea01e5de93d794da96f57a 100644 (file)
@@ -247,9 +247,10 @@ void handle_scancode(unsigned char scancode, int down)
                sysrq_pressed = !up_flag;
                return;
        } else if (sysrq_pressed) {
-               if (!up_flag)
+               if (!up_flag) {
                        handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
-               return;
+                       return;
+               }
        }
 #endif
 
@@ -474,7 +475,6 @@ static void scroll_back(void)
 
 static void boot_it(void)
 {
-       if (kbd->slockstate & ~shift_state) return;
        ctrl_alt_del();
 }
 
index df610b5b5584667347d1a92292898198deb853f3..52e3acbdb74a3e9ecd7b5088453288bb72ce0572 100644 (file)
@@ -19,34 +19,39 @@ dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG
 if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
     bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
     if [ "$CONFIG_HISAX_EURO" != "n" ]; then
-           bool 'Support for german tarifinfo' CONFIG_DE_AOC
-           bool 'Support for australian Microlink service (not for std. EURO)' CONFIG_HISAX_ML
+           bool 'Support for german chargeinfo' CONFIG_DE_AOC
+           bool 'Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
+           bool 'Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
     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 AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
+    bool 'HiSax Support for AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
     bool 'HiSax Support for Elsa cards' CONFIG_HISAX_ELSA
     bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
     bool 'HiSax Support for Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
     bool 'HiSax Support for ASUSCOM cards' CONFIG_HISAX_ASUSCOM
     bool 'HiSax Support for TELEINT cards' CONFIG_HISAX_TELEINT
-    bool 'HiSax Support for Sedlbauer speed card/win/star' CONFIG_HISAX_SEDLBAUER
+    bool 'HiSax Support for Sedlbauer speed card/win/star/fax' CONFIG_HISAX_SEDLBAUER
     bool 'HiSax Support for USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
     bool 'HiSax Support for MIC card' CONFIG_HISAX_MIC
     bool 'HiSax Support for NETjet card' CONFIG_HISAX_NETJET
     bool 'HiSax Support for Niccy PnP/PCI card' CONFIG_HISAX_NICCY
     if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
       if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
-        bool 'HiSax Support for SPARC Am7930' CONFIG_HISAX_AMD7930
-        bool 'HiSax Support for SPARC DBRI' CONFIG_HISAX_DBRI
+        bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930
       fi
     fi
 fi
 if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
        dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
        dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
+       dep_tristate 'Eicon.Diehl active card support (EXPERIMENTAL)' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
 fi
 dep_tristate 'AVM-B1 with CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
 if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
index 35d56d14222da29e6090b647da9774bb6e0ec1e6..36a1f5bb763cc292f0feaf2e7bdfa5dffd661f80 100644 (file)
@@ -1,6 +1,6 @@
 SUB_DIRS     :=
 MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000
+ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon
 
 L_OBJS :=
 LX_OBJS :=
@@ -33,6 +33,7 @@ else
     OX_OBJS += isdn_common.o
     ifdef CONFIG_ISDN_PPP
       O_OBJS += isdn_ppp.o
+      M_OBJS += isdn_bsdcomp.o
     endif
     ifdef CONFIG_ISDN_X25
       O_OBJS += isdn_x25iface.o
@@ -114,5 +115,15 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ISDN_DRV_EICON),y)
+  L_OBJS += eicon/eicon.o
+  SUB_DIRS += eicon
+  MOD_SUB_DIRS += eicon
+else
+  ifeq ($(CONFIG_ISDN_DRV_EICON),m)
+    MOD_SUB_DIRS += eicon
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
index 1298882584eeef9ca0e0f567d2e0a8bbdb04df85..5d35a12ecd3a68acad4d1d78a8bf4d69df10de70 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: act2000.h,v 1.5 1997/10/09 22:22:59 fritz Exp $
+/* $Id: act2000.h,v 1.7 1999/04/12 13:13:54 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
- * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
  * Thanks to Friedemann Baitinger and IBM Germany
  *
  * This program is free software; you can redistribute it and/or modify
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: act2000.h,v $
+ * Revision 1.7  1999/04/12 13:13:54  fritz
+ * Made cards pointer static to avoid name-clash.
+ *
+ * Revision 1.6  1998/11/05 22:12:38  fritz
+ * Changed mail-address.
+ *
  * Revision 1.5  1997/10/09 22:22:59  fritz
  * New HL<->LL interface:
  *   New BSENT callback with nr. of bytes included.
@@ -213,8 +219,6 @@ typedef struct act2000_card {
         char regname[35];                /* Name used for request_region     */
 } act2000_card;
 
-extern act2000_card *actcards;
-
 extern __inline__ void act2000_schedule_tx(act2000_card *card)
 {
         queue_task(&card->snd_tq, &tq_immediate);
index d19ff99e472039d11940d49a053d002fd7a54d1c..80f06b0808132b29ae6409ad8f938a26f10dd57c 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: act2000_isa.c,v 1.5 1998/02/12 23:06:47 keil Exp $
+/* $Id: act2000_isa.c,v 1.8 1999/01/05 18:29:25 he Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
- * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
  * Thanks to Friedemann Baitinger and IBM Germany
  *
  * This program is free software; you can redistribute it and/or modify
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: act2000_isa.c,v $
+ * Revision 1.8  1999/01/05 18:29:25  he
+ * merged remaining schedule_timeout() changes from 2.1.127
+ *
+ * Revision 1.7  1998/11/05 22:12:41  fritz
+ * Changed mail-address.
+ *
+ * Revision 1.6  1998/06/17 19:51:09  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
  * Revision 1.5  1998/02/12 23:06:47  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
index b7c01ee2b7b86dcce603f079667653bd319b0ab9..35a68e7d2ca04092f1edb49c51c077feca9bc10d 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: act2000_isa.h,v 1.1 1997/09/23 18:00:07 fritz Exp $
+/* $Id: act2000_isa.h,v 1.2 1998/11/05 22:12:43 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
- * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
  * Thanks to Friedemann Baitinger and IBM Germany
  *
  * This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: act2000_isa.h,v $
+ * Revision 1.2  1998/11/05 22:12:43  fritz
+ * Changed mail-address.
+ *
  * Revision 1.1  1997/09/23 18:00:07  fritz
  * New driver for IBM Active 2000.
  *
index d0310bcc0718d9d2198239961b04a690666f4e35..df2fd68d33a29cf32bfa90ee74c735f9391fef24 100644 (file)
@@ -1,9 +1,9 @@
-/* $Id: capi.c,v 1.7 1998/02/23 23:35:41 fritz Exp $
+/* $Id: capi.c,v 1.8 1998/11/05 22:12:46 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *        CAPI encoder/decoder
  *
- * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
  * Thanks to Friedemann Baitinger and IBM Germany
  *
  * This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: capi.c,v $
+ * Revision 1.8  1998/11/05 22:12:46  fritz
+ * Changed mail-address.
+ *
  * Revision 1.7  1998/02/23 23:35:41  fritz
  * Eliminated some compiler warnings.
  *
index 901f15ed4fc34b3c66dca1f92f7c4a022cbc00ab..69a1041005ffc1cb6394a92bdacbc8eeb7109e33 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: capi.h,v 1.4 1997/10/01 09:21:04 fritz Exp $
+/* $Id: capi.h,v 1.5 1998/11/05 22:12:48 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
- * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
  * Thanks to Friedemann Baitinger and IBM Germany
  *
  * This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: capi.h,v $
+ * Revision 1.5  1998/11/05 22:12:48  fritz
+ * Changed mail-address.
+ *
  * Revision 1.4  1997/10/01 09:21:04  fritz
  * Removed old compatibility stuff for 2.0.X kernels.
  * From now on, this code is for 2.1.X ONLY!
index 34a3be1d7e2c9442b9cde87acc84637d8847be47..2ec5e2fd4132a73ab0d6fe899338b5afddeef87e 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: module.c,v 1.7 1998/02/12 23:06:52 keil Exp $
+/* $Id: module.c,v 1.9 1999/04/12 13:13:56 fritz Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
- * Copyright 1997 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
  * Thanks to Friedemann Baitinger and IBM Germany
  *
  * This program is free software; you can redistribute it and/or modify
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: module.c,v $
+ * Revision 1.9  1999/04/12 13:13:56  fritz
+ * Made cards pointer static to avoid name-clash.
+ *
+ * Revision 1.8  1998/11/05 22:12:51  fritz
+ * Changed mail-address.
+ *
  * Revision 1.7  1998/02/12 23:06:52  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -57,7 +63,7 @@ static unsigned short isa_ports[] =
 };
 #define ISA_NRPORTS (sizeof(isa_ports)/sizeof(unsigned short))
 
-act2000_card *actcards = (act2000_card *) NULL;
+static act2000_card *cards = (act2000_card *) NULL;
 
 /* Parameters to be set by insmod */
 static int   act_bus  =  0;
@@ -589,7 +595,7 @@ act2000_logstat(struct act2000_card *card, char *str)
 static inline act2000_card *
 act2000_findcard(int driverid)
 {
-        act2000_card *p = actcards;
+        act2000_card *p = cards;
 
         while (p) {
                 if (p->myid == driverid)
@@ -714,8 +720,8 @@ act2000_alloccard(int bus, int port, int irq, char *id)
         card->bus = bus;
         card->port = port;
         card->irq = irq;
-        card->next = actcards;
-        actcards = card;
+        card->next = cards;
+        cards = card;
 }
 
 /*
@@ -805,9 +811,9 @@ act2000_addcard(int bus, int port, int irq, char *id)
                                       bus);
                }
        }
-       if (!actcards)
+       if (!cards)
                return 1;
-        p = actcards;
+        p = cards;
         while (p) {
                initialized = 0;
                if (!p->interface.statcallb) {
@@ -870,9 +876,9 @@ act2000_addcard(int bus, int port, int irq, char *id)
                                 kfree(p);
                                 p = q->next;
                         } else {
-                                actcards = p->next;
+                                cards = p->next;
                                 kfree(p);
-                                p = actcards;
+                                p = cards;
                         }
                        failed++;
                 }
@@ -890,9 +896,9 @@ int
 act2000_init(void)
 {
         printk(KERN_INFO "%s\n", DRIVERNAME);
-        if (!actcards)
+        if (!cards)
                act2000_addcard(act_bus, act_port, act_irq, act_id);
-        if (!actcards)
+        if (!cards)
                 printk(KERN_INFO "act2000: No cards defined yet\n");
         /* No symbols to export, hide all symbols */
         EXPORT_NO_SYMBOLS;
@@ -903,14 +909,14 @@ act2000_init(void)
 void
 cleanup_module(void)
 {
-        act2000_card *card = actcards;
+        act2000_card *card = cards;
         act2000_card *last;
         while (card) {
                 unregister_card(card);
                del_timer(&card->ptimer);
                 card = card->next;
         }
-        card = actcards;
+        card = cards;
         while (card) {
                 last = card;
                 card = card->next;
index dbf3606f4cee60311215a59763ba98b469d96d7f..ea4aeb369ebf6c9d11ca8bcdf5ea8bf3486c0faf 100644 (file)
@@ -1,11 +1,49 @@
 /*
- * $Id: b1capi.c,v 1.10 1998/02/13 07:09:10 calle Exp $
+ * $Id: b1capi.c,v 1.14 1999/04/15 19:49:29 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.14  1999/04/15 19:49:29  calle
+ * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ...
+ *
+ * Revision 1.13  1999/01/05 18:29:31  he
+ * merged remaining schedule_timeout() changes from 2.1.127
+ *
+ * Revision 1.12  1998/10/25 14:38:58  fritz
+ * Backported from MIPS (Cobalt).
+ *
+ * Revision 1.11  1998/03/29 16:05:58  calle
+ * changes from 2.0 tree merged.
+ *
+ * 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.10  1998/02/13 07:09:10  calle
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.14 $";
 
 /* ------------------------------------------------------------- */
 
@@ -84,7 +122,7 @@ int showcapimsgs = 0;                /* used in lli.c */
 int loaddebug = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-MODULE_PARM(showcapimsgs, "0-3i");
+MODULE_PARM(showcapimsgs, "0-5i");
 MODULE_PARM(loaddebug, "0-1i");
 
 /* ------------------------------------------------------------- */
@@ -150,10 +188,11 @@ 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";
+               case AVM_CARDTYPE_B1:    return "B1-ISA";
+               case AVM_CARDTYPE_B1PCI: return "B1-PCI";
+               case AVM_CARDTYPE_M1:    return "M1";
+               case AVM_CARDTYPE_M2:    return "M2";
+               case AVM_CARDTYPE_T1:    return "T1";
        }
 }
 
@@ -300,7 +339,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);
@@ -433,6 +472,7 @@ static void notify_handler(void *dummy)
 
 /* -------- card ready callback ------------------------------- */
 
+
 void avmb1_card_ready(avmb1_card * card)
 {
         struct capi_profile *profp =
@@ -441,6 +481,7 @@ void avmb1_card_ready(avmb1_card * card)
        __u16 appl;
        char *cardname, cname[20];
        __u32 flag;
+        int nbchan = profp->nbchannel;
 
        card->cversion.majorversion = 2;
        card->cversion.minorversion = 0;
@@ -453,9 +494,14 @@ void avmb1_card_ready(avmb1_card * card)
 
        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);
                }
@@ -553,8 +599,8 @@ int avmb1_registercard(int port, int irq, int cardtype, int allocio)
                                 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;
+               release_region(port, AVMB1_PORTLEN);
+               return -EBUSY;
        }
 
        card->cardstate = CARD_DETECTED;
@@ -578,8 +624,14 @@ int avmb1_detectcard(int port, int irq, int cardtype)
        if (!B1_valid_irq(irq, cardtype)) {
                printk(KERN_WARNING "b1capi: irq %d not valid for %s-card.\n",
                                irq, cardtype2str(cardtype));
-               return -EIO;
+               return -EINVAL;
+       }
+       if (!B1_valid_port(port, cardtype)) {
+               printk(KERN_WARNING "b1capi: port 0x%x not valid for %s-card.\n",
+                               port, cardtype2str(cardtype));
+               return -EINVAL;
        }
+       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);
@@ -591,10 +643,10 @@ int avmb1_detectcard(int port, int irq, int cardtype)
                case AVM_CARDTYPE_M1:
                case AVM_CARDTYPE_M2:
                case AVM_CARDTYPE_B1:
+               case AVM_CARDTYPE_B1PCI:
                        printk(KERN_NOTICE "b1capi: AVM-%s-Controller detected at 0x%x\n", cardtype2str(cardtype), port);
                        break;
                case AVM_CARDTYPE_T1:
-                       printk(KERN_NOTICE "b1capi: AVM-%s-Controller may be at 0x%x\n", cardtype2str(cardtype), port);
                        break;
        }
 
@@ -603,11 +655,11 @@ int avmb1_detectcard(int port, int irq, int cardtype)
 
 int avmb1_probecard(int port, int irq, int cardtype)
 {
-       if (check_region((unsigned short) port, AVMB1_PORTLEN)) {
+       if (check_region(port, AVMB1_PORTLEN)) {
                printk(KERN_WARNING
                       "b1capi: ports 0x%03x-0x%03x in use.\n",
                       port, port + AVMB1_PORTLEN);
-               return -EIO;
+               return -EBUSY;
        }
         return avmb1_detectcard(port, irq, cardtype);
 }
@@ -618,11 +670,16 @@ int avmb1_unregistercard(int cnr, int freeio)
        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);
@@ -667,6 +724,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;
 
@@ -686,13 +744,20 @@ static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
        memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params));
 
        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);
@@ -705,8 +770,6 @@ 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)
@@ -718,7 +781,7 @@ static __u16 capi_release(__u16 applid)
                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);
@@ -863,7 +926,43 @@ static int capi_manufacturer(unsigned int cmd, void *data)
                if ((rc = avmb1_probecard(cdef.port, cdef.irq, cdef.cardtype)) != 0)
                        return rc;
 
-               return avmb1_addcard(cdef.port, cdef.irq, cdef.cardtype);
+                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:
@@ -883,8 +982,7 @@ static int capi_manufacturer(unsigned int cmd, void *data)
                        return -ESRCH;
 
                if (ldef.t4file.len <= 0) {
-                       if (loaddebug)
-                               printk(KERN_DEBUG "b1capi: load: invalid parameter length of t4file is %d ?\n", ldef.t4file.len);
+                       printk(KERN_DEBUG "b1capi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
                        return -EINVAL;
                }
 
@@ -906,12 +1004,19 @@ 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 */
@@ -944,8 +1049,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, card->cardtype);
-               B1_enable_irq(card->port);
+               B1_setinterrupt(card->port, card->irq, card->cardtype);
                restore_flags(flags);
 
                if (loaddebug) {
@@ -956,7 +1060,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",
@@ -998,6 +1109,19 @@ static int capi_manufacturer(unsigned int cmd, void *data)
                        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;
 }
@@ -1035,6 +1159,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;
 }
@@ -1048,6 +1173,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;
                }
        }
index db6fe1453fe8d3165b53df28d7cd91d344ef1342..4d9fd647cdb601e08fecd8de6bf514c947f2c68b 100644 (file)
@@ -1,11 +1,46 @@
 /*
- * $Id: b1lli.c,v 1.6 1998/02/13 07:09:11 calle Exp $
+ * $Id: b1lli.c,v 1.10 1999/04/15 19:49:31 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.10  1999/04/15 19:49:31  calle
+ * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ...
+ *
+ * Revision 1.9  1999/01/05 18:33:23  he
+ * merged remaining 2.2pre{1,2} changes (jiffies and Config)
+ *
+ * Revision 1.8  1998/10/25 14:39:00  fritz
+ * Backported from MIPS (Cobalt).
+ *
+ * Revision 1.7  1998/03/29 16:06:00  calle
+ * changes from 2.0 tree merged.
+ *
+ * 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.6  1998/02/13 07:09:11  calle
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -41,6 +76,7 @@
  *
  * 
  */
+/* #define FASTLINK_DEBUG */
 
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
@@ -55,6 +91,8 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
+extern int showcapimsgs;
+
 /*
  * LLI Messages to the ISDN-ControllerISDN Controller 
  */
 #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
 #define B1_OUTSTAT             0x03
 #define B1_RESET               0x10
 #define B1_ANALYSE             0x04
-#define B1_IDENT               0x17  /* Hema card T1 */
-#define B1_IRQ_MASTER          0x12  /* Hema card T1 */
+
+/* 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,
+static inline unsigned char b1outp(unsigned int base,
                                   unsigned short offset,
                                   unsigned char value)
 {
@@ -165,22 +243,44 @@ static inline unsigned char b1outp(unsigned short base,
        return inb(base + B1_ANALYSE);
 }
 
-static inline int B1_rx_full(unsigned short base)
+static inline void t1outp(unsigned int base,
+                         unsigned short offset,
+                         unsigned char value)
+{
+       outb(value, base + offset);
+}
+
+static inline unsigned char t1inp(unsigned int base,
+                                 unsigned short offset)
+{
+       return inb(base + offset);
+}
+
+static inline int B1_isfastlink(unsigned int base)
+{
+       return (inb(base + T1_IDENT) & ~0x82) == 1;
+}
+static inline unsigned char B1_fifostatus(unsigned int base)
+{
+       return inb(base + T1_FIFOSTAT);
+}
+
+static inline int B1_rx_full(unsigned int base)
 {
        return inb(base + B1_INSTAT) & 0x1;
 }
 
-static inline unsigned char B1_get_byte(unsigned short base)
+static inline unsigned char B1_get_byte(unsigned int base)
 {
-       unsigned long i = jiffies + 5 * HZ;     /* maximum wait time 5 sec */
+       unsigned long i = jiffies + 1 * HZ;     /* maximum wait time 1 sec */
        while (!B1_rx_full(base) && time_before(jiffies, i));
        if (B1_rx_full(base))
                return inb(base + B1_READ);
-       printk(KERN_CRIT "b1lli: rx not full after 5 second\n");
+       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)
+static inline unsigned int B1_get_word(unsigned int base)
 {
        unsigned int val = 0;
        val |= B1_get_byte(base);
@@ -190,18 +290,18 @@ static inline unsigned int B1_get_word(unsigned short base)
        return val;
 }
 
-static inline int B1_tx_empty(unsigned short base)
+static inline int B1_tx_empty(unsigned int base)
 {
        return inb(base + B1_OUTSTAT) & 0x1;
 }
 
-static inline void B1_put_byte(unsigned short base, unsigned char val)
+static inline void B1_put_byte(unsigned int 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)
+static inline void B1_put_word(unsigned int base, unsigned int val)
 {
        B1_put_byte(base, val & 0xff);
        B1_put_byte(base, (val >> 8) & 0xff);
@@ -209,26 +309,95 @@ static inline void B1_put_word(unsigned short base, unsigned int val)
        B1_put_byte(base, (val >> 24) & 0xff);
 }
 
-static inline unsigned int B1_get_slice(unsigned short base,
+static inline unsigned int B1_get_slice(unsigned int base,
                                        unsigned char *dp)
 {
        unsigned int len, i;
+#ifdef FASTLINK_DEBUG
+       unsigned wcnt = 0, bcnt = 0;
+#endif
 
        len = i = B1_get_word(base);
-       while (i-- > 0)
-               *dp++ = B1_get_byte(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,
+static inline void B1_put_slice(unsigned int base,
                                unsigned char *dp, unsigned int len)
 {
-       B1_put_word(base, len);
-       while (len-- > 0)
-               B1_put_byte(base, *dp++);
+       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,
+static void b1_wr_reg(unsigned int base,
                       unsigned int reg,
                      unsigned int value)
 {
@@ -237,7 +406,7 @@ static void b1_wr_reg(unsigned short base,
         B1_put_word(base, value);
 }
 
-static inline unsigned int b1_rd_reg(unsigned short base,
+static inline unsigned int b1_rd_reg(unsigned int base,
                                      unsigned int reg)
 {
        B1_put_byte(base, READ_REGISTER);
@@ -246,14 +415,14 @@ static inline unsigned int b1_rd_reg(unsigned short base,
        
 }
 
-static inline void b1_set_test_bit(unsigned short base,
+static inline void b1_set_test_bit(unsigned int 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,
+static inline int b1_get_test_bit(unsigned int base,
                                   int cardtype)
 {
     return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0;
@@ -278,6 +447,26 @@ static int irq_table[16] =
  112,                          /* irq 15 */
 };
 
+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)
 {
        switch (cardtype) {
@@ -285,36 +474,76 @@ int B1_valid_irq(unsigned irq, int cardtype)
           case AVM_CARDTYPE_M1:
           case AVM_CARDTYPE_M2:
           case AVM_CARDTYPE_B1:
-               return irq_table[irq] != 0;
+               return irq_table[irq & 0xf] != 0;
           case AVM_CARDTYPE_T1:
-               return irq == 5;
+               return hema_irq_table[irq & 0xf] != 0;
+          case AVM_CARDTYPE_B1PCI:
+               return 1;
        }
 }
 
-unsigned char B1_assign_irq(unsigned short base, unsigned irq, int cardtype)
+int B1_valid_port(unsigned port, int cardtype)
+{
+   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_B1PCI:
+               return 1;
+          case AVM_CARDTYPE_T1:
+               return ((port & 0x7) == 0) && ((port & 0x30) != 0x30);
+   }
+}
+
+void B1_setinterrupt(unsigned int base,
+                                unsigned irq, int cardtype)
 {
        switch (cardtype) {
           case AVM_CARDTYPE_T1:
-             return b1outp(base, B1_IRQ_MASTER, 0x08);
+              t1outp(base, B1_INSTAT, 0x00);
+              t1outp(base, B1_INSTAT, 0x02);
+             t1outp(base, T1_IRQMASTER, 0x08);
+             break;
           default:
           case AVM_CARDTYPE_M1:
           case AVM_CARDTYPE_M2:
           case AVM_CARDTYPE_B1:
-             return b1outp(base, B1_RESET, irq_table[irq]);
+             b1outp(base, B1_INSTAT, 0x00);
+             b1outp(base, B1_RESET, irq_table[irq]);
+             b1outp(base, B1_INSTAT, 0x02);
+             break;
+          case AVM_CARDTYPE_B1PCI:
+             b1outp(base, B1_INSTAT, 0x00);
+             b1outp(base, B1_RESET, 0xf0);
+             b1outp(base, B1_INSTAT, 0x02);
+             break;
         }
 }
 
-unsigned char B1_enable_irq(unsigned short base)
+unsigned char B1_disable_irq(unsigned int base)
 {
-       return b1outp(base, B1_INSTAT, 0x02);
+       return b1outp(base, B1_INSTAT, 0x00);
 }
 
-unsigned char B1_disable_irq(unsigned short base)
+void T1_disable_irq(unsigned int base)
 {
-       return b1outp(base, B1_INSTAT, 0x00);
+      t1outp(base, T1_IRQMASTER, 0x00);
 }
 
-void B1_reset(unsigned short base)
+void B1_reset(unsigned int base)
 {
        b1outp(base, B1_RESET, 0);
        udelay(55 * 2 * 1000);  /* 2 TIC's */
@@ -326,7 +555,19 @@ void B1_reset(unsigned short base)
        udelay(55 * 2 * 1000);  /* 2 TIC's */
 }
 
-int B1_detect(unsigned short base, int cardtype)
+void T1_reset(unsigned int 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 int base, int cardtype)
 {
        int onoff, i;
 
@@ -372,10 +613,79 @@ int B1_detect(unsigned short base, int cardtype)
        return 0;
 }
 
+int T1_detectandinit(unsigned int base, unsigned irq, int cardnr)
+{
+       unsigned char cregs[8];
+       unsigned char reverse_cardnr;
+       unsigned long flags;
+       unsigned char dummy;
+       int 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;
+
+       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);
+
+       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;
 
-int B1_load_t4file(unsigned short base, avmb1_t4file * t4file)
+int B1_load_t4file(unsigned int base, avmb1_t4file * t4file)
 {
        /*
         * Data is in user space !!!
@@ -414,7 +724,7 @@ int B1_load_t4file(unsigned short base, avmb1_t4file * t4file)
        return 0;
 }
 
-int B1_load_config(unsigned short base, avmb1_t4file * config)
+int B1_load_config(unsigned int base, avmb1_t4file * config)
 {
        /*
         * Data is in user space !!!
@@ -470,7 +780,7 @@ int B1_load_config(unsigned short base, avmb1_t4file * config)
        return 0;
 }
 
-int B1_loaded(unsigned short base)
+int B1_loaded(unsigned int base)
 {
        int i;
        unsigned char ans;
@@ -482,7 +792,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);
@@ -494,11 +804,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;
 }
 
@@ -519,7 +830,7 @@ static inline void parse_version(avmb1_card * card)
  * ------------------------------------------------------------------- 
  */
 
-void B1_send_init(unsigned short port,
+void B1_send_init(unsigned int port,
             unsigned int napps, unsigned int nncci, unsigned int cardnr)
 {
        unsigned long flags;
@@ -533,7 +844,7 @@ void B1_send_init(unsigned short port,
        restore_flags(flags);
 }
 
-void B1_send_register(unsigned short port,
+void B1_send_register(unsigned int port,
                      __u16 appid, __u32 nmsg,
                      __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize)
 {
@@ -550,7 +861,7 @@ void B1_send_register(unsigned short port,
        restore_flags(flags);
 }
 
-void B1_send_release(unsigned short port,
+void B1_send_release(unsigned int port,
                     __u16 appid)
 {
        unsigned long flags;
@@ -562,9 +873,7 @@ void B1_send_release(unsigned short port,
        restore_flags(flags);
 }
 
-extern int showcapimsgs;
-
-void B1_send_message(unsigned short port, struct sk_buff *skb)
+void B1_send_message(unsigned int port, struct sk_buff *skb)
 {
        unsigned long flags;
        __u16 len = CAPIMSG_LEN(skb->data);
@@ -630,6 +939,7 @@ void B1_handle_interrupt(avmb1_card * card)
        unsigned NCCI;
        unsigned WindowSize;
 
+t1retry:
        if (!B1_rx_full(card->port))
                return;
 
@@ -704,7 +1014,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);
 
@@ -716,19 +1026,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;
 
@@ -737,13 +1051,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) 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]);
                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 b5c45acfdc77ecad2363bf8b17f31972598d9d48..5bdf8505b25855406525e1c945f9f5cbb92a4f3b 100644 (file)
@@ -1,11 +1,29 @@
 /*
- * $Id: b1pci.c,v 1.5 1998/01/31 11:14:43 calle Exp $
+ * $Id: b1pci.c,v 1.9 1999/04/15 19:49:32 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.9  1999/04/15 19:49:32  calle
+ * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ...
+ *
+ * Revision 1.8  1998/06/17 19:51:16  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.7  1998/03/29 16:06:02  calle
+ * changes from 2.0 tree merged.
+ *
+ * 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.6  1998/02/25 09:15:36  fritz
+ * apply Martin's pci driver patch to isdn drivers (vgerCVS)
+ *
  * Revision 1.5  1998/01/31 11:14:43  calle
  * merged changes to 2.0 tree, prepare 2.1.82 to work.
  *
@@ -44,7 +62,7 @@
 #define PCI_DEVICE_ID_AVM_B1   0x700
 #endif
 
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.9 $";
 
 /* ------------------------------------------------------------- */
 
@@ -93,13 +111,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, AVM_CARDTYPE_B1)) != 0) {
+               if ((rc = avmb1_probecard(ioaddr, irq, AVM_CARDTYPE_B1PCI)) != 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, AVM_CARDTYPE_B1)) < 0)
+               if ((rc = avmb1_addcard(ioaddr, irq, AVM_CARDTYPE_B1PCI)) < 0)
                        return rc;
        }
        return 0;
index f4f5c70391254ec9a0a46f2c68433c0b60bd80a7..69ed317f3a7b3694db46bd6f9f50a35fa4dea383 100644 (file)
@@ -1,11 +1,23 @@
 /*
- * $Id: capi.c,v 1.10 1998/02/13 07:09:13 calle Exp $
+ * $Id: capi.c,v 1.13 1998/08/28 04:32:25 calle Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capi.c,v $
+ * Revision 1.13  1998/08/28 04:32:25  calle
+ * Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1
+ * driver running with 2.1.118.
+ *
+ * Revision 1.12  1998/05/26 22:39:34  he
+ * sync'ed with 2.1.102 where appropriate (CAPABILITY changes)
+ * concap typo
+ * cleared dev.tbusy in isdn_net BCONN status callback
+ *
+ * Revision 1.11  1998/03/09 17:46:37  he
+ * merged in 2.1.89 changes
+ *
  * Revision 1.10  1998/02/13 07:09:13  calle
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -237,6 +249,9 @@ capi_poll(struct file *file, poll_table * wait)
                return POLLERR;
 
        cdev = &capidevs[minor];
+#if (LINUX_VERSION_CODE < 0x020159) /* 2.1.89 */
+#define poll_wait(f,wq,w) poll_wait((wq),(w))
+#endif
        poll_wait(file, &(cdev->recv_wait), wait);
        mask = POLLOUT | POLLWRNORM;
        if (!skb_queue_empty(&cdev->recv_queue))
@@ -464,7 +479,9 @@ static struct file_operations capi_fops =
        capi_ioctl,
        NULL,                   /* capi_mmap */
        capi_open,
-       NULL,                   /* flush */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
+        NULL,                   /* capi_flush */
+#endif
        capi_release,
        NULL,                   /* capi_fsync */
        NULL,                   /* capi_fasync */
@@ -484,7 +501,16 @@ static struct capi_interface_user cuser = {
 
 int capi_init(void)
 {
+#if LINUX_VERSION_CODE >= 131841
+       int j;
+#endif
+       
        memset(capidevs, 0, sizeof(capidevs));
+#if LINUX_VERSION_CODE >= 131841
+       for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) {
+               init_waitqueue_head(&capidevs[j].recv_wait);
+       }
+#endif
 
        if (register_chrdev(capi_major, "capi20", &capi_fops)) {
                printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
@@ -496,6 +522,7 @@ int capi_init(void)
                unregister_chrdev(capi_major, "capi20");
                return -EIO;
        }
+       
        return 0;
 }
 
index 8941a0a645a49889920131c9c754531c704dfdc9..bd57255b674cf4d1045a8ba3d76f1946d2be7ac6 100644 (file)
@@ -22,7 +22,11 @@ struct capidev {
        int is_registered;
        __u16 applid;
        struct sk_buff_head recv_queue;
+#if LINUX_VERSION_CODE < 131841
+       struct wait_queue *recv_wait;
+#else
        wait_queue_head_t recv_wait;
+#endif
        __u16 errcode;
 };
 
index 1d4a7c2e863cb15092c387869a4cdb2e339708e6..7eb0c33cfa98719d0ea1821f30e8af25f038c825 100644 (file)
@@ -1,11 +1,36 @@
 /*
- * $Id: capidrv.c,v 1.11 1998/02/13 07:09:15 calle Exp $
+ * $Id: capidrv.c,v 1.13 1998/06/26 15:12:55 fritz Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.c,v $
+ * Revision 1.13  1998/06/26 15:12:55  fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 1.12  1998/03/29 16:06:03  calle
+ * changes from 2.0 tree merged.
+ *
+ * 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.11  1998/02/13 07:09:15  calle
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.11 $";
+static char *revision = "$Revision: 1.13 $";
 int debugmode = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -378,8 +403,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 ------------------------------------------ */
@@ -512,15 +537,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)
@@ -529,15 +554,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);
 
 }
 
@@ -567,46 +592,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)
@@ -615,8 +651,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);
@@ -624,8 +660,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);
 }
 
 /* ------------------------------------------------------------------ */
@@ -642,7 +678,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);
@@ -667,34 +703,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)
@@ -703,8 +740,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;
@@ -718,8 +755,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);
 }
 
 /* ------------------------------------------------------------------- */
@@ -752,8 +789,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) {
@@ -789,7 +826,8 @@ static void handle_controller(_cmsg * cmsg)
                      handle_dtrace_data(card, direction, 0, data, len);
                      break;
                   }
-                  printk(KERN_INFO "capidrv: %s from controller 0x%x layer 0x%x, ignored\n",
+                  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;
@@ -805,7 +843,8 @@ static void handle_controller(_cmsg * cmsg)
                      default: s = "unkown error"; break;
                   }
                   if (s)
-                  printk(KERN_INFO "capidrv: %s from controller 0x%x function %d: %s\n",
+                  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);
@@ -822,14 +861,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);
 }
@@ -842,12 +883,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;
@@ -869,7 +910,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,
@@ -877,6 +919,7 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
 
        switch (card->interface.statcallb(&cmd)) {
        case 0:
+       case 3:
                /* No device matching this call.
                 * and isdn_common.c has send a HANGUP command
                 * which is ignored in state ST_PLCI_INCOMING,
@@ -886,7 +929,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,
@@ -903,7 +947,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,
@@ -920,7 +965,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,
@@ -963,7 +1009,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);
                }
@@ -981,7 +1028,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);
@@ -994,7 +1042,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);
@@ -1007,7 +1056,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);
@@ -1040,7 +1090,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,
@@ -1080,7 +1130,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 */
@@ -1096,18 +1147,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;
@@ -1142,8 +1196,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 */
@@ -1167,9 +1221,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);
                }
@@ -1192,7 +1247,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);
@@ -1242,7 +1298,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);
@@ -1251,6 +1308,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;
@@ -1264,18 +1324,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);
 }
@@ -1293,7 +1356,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);
@@ -1314,7 +1378,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) {
@@ -1348,7 +1413,8 @@ static void handle_dtrace_data(capidrv_contr *card,
     isdn_ctrl cmd;
 
     if (!len) {
-       printk(KERN_DEBUG "avmb1_q931_data: len == %d\n", len);
+       printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
+                               card->contrnr, len);
        return;
     }
 
@@ -1393,7 +1459,8 @@ 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;
@@ -1414,7 +1481,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,
@@ -1424,7 +1492,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,
@@ -1486,10 +1555,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,
@@ -1517,19 +1587,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;
                }
@@ -1568,23 +1641,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);
@@ -1592,46 +1668,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;
@@ -1645,8 +1729,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;
 }
 
@@ -1663,15 +1747,15 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
        __u16 datahandle;
 
        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;
        }
        datahandle = nccip->datahandle;
@@ -1691,13 +1775,14 @@ static int if_sendbuf(int id, int channel, int doack, 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);
                        (void)capidrv_del_ack(nccip, datahandle);
                        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
                memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen);
                memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
@@ -1729,8 +1814,8 @@ static int if_readstat(__u8 *buf, int len, int user, int id, int channel)
        __u8 *p;
 
        if (!card) {
-               printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
-                      id);
+               printk(KERN_ERR "capidrv-%d: if_readstat called with invalid driverId %d!\n",
+                      card->contrnr, id);
                return -ENODEV;
        }
 
@@ -1776,7 +1861,7 @@ static void enable_dchannel_trace(capidrv_contr *card)
        avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
        avmversion[2] |= version.minormanuversion & 0x0f;
 
-        if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
+        if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 6)) {
                printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
                capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
                                           card->msgid++,
@@ -1878,7 +1963,8 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
        printk(KERN_INFO "%s: now up (%d B channels)\n",
                card->name, card->nbchan);
 
-        enable_dchannel_trace(card);
+        if (card->nbchan == 2)  /* no T1 */
+               enable_dchannel_trace(card);
 
        return 0;
 }
@@ -1965,8 +2051,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..2e5abf04b8cbc12657cafcd02e4385db8bfbbd55 100644 (file)
@@ -1,11 +1,22 @@
 /*
- * $Id: capidrv.h,v 1.1 1997/03/04 21:50:33 calle Exp $
+ * $Id: capidrv.h,v 1.2 1998/03/29 16:06:06 calle Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.h,v $
+ * Revision 1.2  1998/03/29 16:06:06  calle
+ * changes from 2.0 tree merged.
+ *
+ * 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 41ad2b6263123c0dc29789c9cbacb4d2283f744f..15f4715596fe1ed9fafe97e33607db47d5fb520e 100644 (file)
@@ -1,11 +1,14 @@
 /*
- * $Id: compat.h,v 1.3 1997/11/04 06:12:15 calle Exp $
+ * $Id: compat.h,v 1.4 1998/10/25 14:39:02 fritz Exp $
  * 
  * Headerfile for Compartibility between different kernel versions
  * 
  * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: compat.h,v $
+ * Revision 1.4  1998/10/25 14:39:02  fritz
+ * Backported from MIPS (Cobalt).
+ *
  * Revision 1.3  1997/11/04 06:12:15  calle
  * capi.c: new read/write in file_ops since 2.1.60
  * capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
@@ -32,6 +35,7 @@
 #define __COMPAT_H__
 
 #include <linux/version.h>
+#include <asm/segment.h>
 #include <linux/isdnif.h>
 
 #ifndef LinuxVersionCode
diff --git a/drivers/isdn/eicon/Makefile b/drivers/isdn/eicon/Makefile
new file mode 100644 (file)
index 0000000..306aac0
--- /dev/null
@@ -0,0 +1,13 @@
+L_OBJS :=
+M_OBJS :=
+O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o
+
+O_TARGET :=
+ifeq ($(CONFIG_ISDN_DRV_EICON),y)
+  O_TARGET += eicon.o
+else
+  O_TARGET += eicon.o
+  M_OBJS   = eicon.o
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h
new file mode 100644 (file)
index 0000000..9552d2b
--- /dev/null
@@ -0,0 +1,528 @@
+/* $Id: eicon.h,v 1.5 1999/03/29 11:19:41 armin Exp $
+ *
+ * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ *
+ * Copyright 1998    by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998,99 by Armin Schindler (mac@melware.de) 
+ * Copyright 1999    Cytronics & Melware (info@melware.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: eicon.h,v $
+ * Revision 1.5  1999/03/29 11:19:41  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.4  1999/03/02 12:37:42  armin
+ * Added some important checks.
+ * Analog Modem with DSP.
+ * Channels will be added to Link-Level after loading firmware.
+ *
+ * Revision 1.3  1999/01/24 20:14:07  armin
+ * Changed and added debug stuff.
+ * Better data sending. (still problems with tty's flip buffer)
+ *
+ * Revision 1.2  1999/01/10 18:46:04  armin
+ * Bug with wrong values in HLC fixed.
+ * Bytes to send are counted and limited now.
+ *
+ * Revision 1.1  1999/01/01 18:09:41  armin
+ * First checkin of new eicon driver.
+ * DIVA-Server BRI/PCI and PRI/PCI are supported.
+ * Old diehl code is obsolete.
+ *
+ *
+ */
+
+
+#ifndef eicon_h
+#define eicon_h
+
+#define EICON_IOCTL_SETMMIO   0
+#define EICON_IOCTL_GETMMIO   1
+#define EICON_IOCTL_SETIRQ    2
+#define EICON_IOCTL_GETIRQ    3
+#define EICON_IOCTL_LOADBOOT  4
+#define EICON_IOCTL_ADDCARD   5
+#define EICON_IOCTL_GETTYPE   6
+#define EICON_IOCTL_LOADPCI   7 
+#define EICON_IOCTL_LOADISA   8 
+#define EICON_IOCTL_GETVER    9 
+
+#define EICON_IOCTL_MANIF    90 
+
+#define EICON_IOCTL_FREEIT   97
+#define EICON_IOCTL_TEST     98
+#define EICON_IOCTL_DEBUGVAR 99
+
+/* Bus types */
+#define EICON_BUS_ISA          1
+#define EICON_BUS_MCA          2
+#define EICON_BUS_PCI          3
+
+/* Constants for describing Card-Type */
+#define EICON_CTYPE_S            0
+#define EICON_CTYPE_SX           1
+#define EICON_CTYPE_SCOM         2
+#define EICON_CTYPE_QUADRO       3
+#define EICON_CTYPE_S2M          4
+#define EICON_CTYPE_MAESTRA      5
+#define EICON_CTYPE_MAESTRAQ     6
+#define EICON_CTYPE_MAESTRAQ_U   7
+#define EICON_CTYPE_MAESTRAP     8
+#define EICON_CTYPE_ISABRI       0x10
+#define EICON_CTYPE_ISAPRI       0x20
+#define EICON_CTYPE_MASK         0x0f
+#define EICON_CTYPE_QUADRO_NR(n) (n<<4)
+
+#define MAX_HEADER_LEN 10
+
+/* Struct for adding new cards */
+typedef struct eicon_cdef {
+        int membase;
+        int irq;
+        char id[10];
+} eicon_cdef;
+
+#define EICON_ISA_BOOT_MEMCHK 1
+#define EICON_ISA_BOOT_NORMAL 2
+
+/* Struct for downloading protocol via ioctl for ISA cards */
+typedef struct {
+       /* start-up parameters */
+       unsigned char tei;
+       unsigned char nt2;
+       unsigned char skip1;
+       unsigned char WatchDog;
+       unsigned char Permanent;
+       unsigned char XInterface;
+       unsigned char StableL2;
+       unsigned char NoOrderCheck;
+       unsigned char HandsetType;
+       unsigned char skip2;
+       unsigned char LowChannel;
+       unsigned char ProtVersion;
+       unsigned char Crc4;
+       unsigned char Loopback;
+       unsigned char oad[32];
+       unsigned char osa[32];
+       unsigned char spid[32];
+       unsigned char boot_opt;
+       unsigned long bootstrap_len;
+       unsigned long firmware_len;
+       unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */
+} eicon_isa_codebuf;
+
+/* Struct for downloading protocol via ioctl for PCI cards */
+typedef struct {
+        /* start-up parameters */
+        unsigned char tei;
+        unsigned char nt2;
+        unsigned char WatchDog;
+        unsigned char Permanent;
+        unsigned char XInterface;
+        unsigned char StableL2;
+        unsigned char NoOrderCheck;
+        unsigned char HandsetType;
+        unsigned char LowChannel;
+        unsigned char ProtVersion;
+        unsigned char Crc4;
+        unsigned char NoHscx30Mode;  /* switch PRI into No HSCX30 test mode */
+        unsigned char Loopback;      /* switch card into Loopback mode */
+        struct q931_link_s
+        {
+          unsigned char oad[32];
+          unsigned char osa[32];
+          unsigned char spid[32];
+        } l[2];
+        unsigned long protocol_len;
+       unsigned int  dsp_code_num;
+        unsigned long dsp_code_len[9];
+        unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */
+} eicon_pci_codebuf;
+
+/* Data for downloading protocol via ioctl */
+typedef union {
+       eicon_isa_codebuf isa;
+       eicon_pci_codebuf pci;
+} eicon_codebuf;
+
+/* Data for Management interface */
+typedef struct {
+       int count;
+       int pos;
+       int length[50];
+       unsigned char data[700]; 
+} eicon_manifbuf;
+
+
+#ifdef __KERNEL__
+
+/* Kernel includes */
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+
+#include <linux/isdnif.h>
+
+typedef struct {
+  __u16 length __attribute__ ((packed)); /* length of data/parameter field */
+  __u8  P[1];                          /* data/parameter field */
+} eicon_PBUFFER;
+
+#include "eicon_isa.h"
+
+/* Macro for delay via schedule() */
+#define SLEEP(j) {                     \
+  current->state = TASK_INTERRUPTIBLE; \
+  schedule_timeout(j);                 \
+}
+
+#endif /* KERNEL */
+
+
+#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_COMBIFILE_FORMAT_VERSION_BCD    0x0100
+
+#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_FILE_FORMAT_VERSION_BCD         0x0100
+
+typedef struct tag_dsp_combifile_header
+{
+  char                  format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
+  __u16                  format_version_bcd             __attribute__ ((packed));
+  __u16                  header_size                    __attribute__ ((packed));
+  __u16                  combifile_description_size     __attribute__ ((packed));
+  __u16                  directory_entries              __attribute__ ((packed));
+  __u16                  directory_size                 __attribute__ ((packed));
+  __u16                  download_count                 __attribute__ ((packed));
+  __u16                  usage_mask_size                __attribute__ ((packed));
+} t_dsp_combifile_header;
+
+typedef struct tag_dsp_combifile_directory_entry
+{
+  __u16                  card_type_number               __attribute__ ((packed));
+  __u16                  file_set_number                __attribute__ ((packed));
+} t_dsp_combifile_directory_entry;
+
+typedef struct tag_dsp_file_header
+{
+  char                  format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
+  __u16                 format_version_bcd              __attribute__ ((packed));
+  __u16                 download_id                     __attribute__ ((packed));
+  __u16                 download_flags                  __attribute__ ((packed));
+  __u16                 required_processing_power       __attribute__ ((packed));
+  __u16                 interface_channel_count         __attribute__ ((packed));
+  __u16                 header_size                     __attribute__ ((packed));
+  __u16                 download_description_size       __attribute__ ((packed));
+  __u16                 memory_block_table_size         __attribute__ ((packed));
+  __u16                 memory_block_count              __attribute__ ((packed));
+  __u16                 segment_table_size              __attribute__ ((packed));
+  __u16                 segment_count                   __attribute__ ((packed));
+  __u16                 symbol_table_size               __attribute__ ((packed));
+  __u16                 symbol_count                    __attribute__ ((packed));
+  __u16                 total_data_size_dm              __attribute__ ((packed));
+  __u16                 data_block_count_dm             __attribute__ ((packed));
+  __u16                 total_data_size_pm              __attribute__ ((packed));
+  __u16                 data_block_count_pm             __attribute__ ((packed));
+} t_dsp_file_header;
+
+typedef struct tag_dsp_memory_block_desc
+{
+  __u16                 alias_memory_block;
+  __u16                 memory_type;
+  __u16                 address;
+  __u16                 size;             /* DSP words */
+} t_dsp_memory_block_desc;
+
+typedef struct tag_dsp_segment_desc
+{
+  __u16                 memory_block;
+  __u16                 attributes;
+  __u16                 base;
+  __u16                 size;
+  __u16                 alignment;        /* ==0 -> no other legal start address than base */
+} t_dsp_segment_desc;
+
+typedef struct tag_dsp_symbol_desc
+{
+  __u16                 symbol_id;
+  __u16                 segment;
+  __u16                 offset;
+  __u16                 size;             /* DSP words */
+} t_dsp_symbol_desc;
+
+typedef struct tag_dsp_data_block_header
+{
+  __u16                 attributes;
+  __u16                 segment;
+  __u16                 offset;
+  __u16                 size;             /* DSP words */
+} t_dsp_data_block_header;
+
+typedef struct tag_dsp_download_desc      /* be sure to keep native alignment for MAESTRA's */
+{
+  __u16                 download_id;
+  __u16                 download_flags;
+  __u16                 required_processing_power;
+  __u16                 interface_channel_count;
+  __u16                 excess_header_size;
+  __u16                 memory_block_count;
+  __u16                 segment_count;
+  __u16                 symbol_count;
+  __u16                 data_block_count_dm;
+  __u16                 data_block_count_pm;
+  __u8  *            p_excess_header_data               __attribute__ ((packed));
+  char  *            p_download_description             __attribute__ ((packed));
+  t_dsp_memory_block_desc  *p_memory_block_table        __attribute__ ((packed));
+  t_dsp_segment_desc  *p_segment_table                  __attribute__ ((packed));
+  t_dsp_symbol_desc  *p_symbol_table                    __attribute__ ((packed));
+  __u16 *            p_data_blocks_dm                   __attribute__ ((packed));
+  __u16 *            p_data_blocks_pm                   __attribute__ ((packed));
+} t_dsp_download_desc;
+
+
+#ifdef __KERNEL__
+
+typedef struct {
+  __u8                  Req;            /* pending request          */
+  __u8                  Rc;             /* return code received     */
+  __u8                  Ind;            /* indication received      */
+  __u8                  ReqCh;          /* channel of current Req   */
+  __u8                  RcCh;           /* channel of current Rc    */
+  __u8                  IndCh;          /* channel of current Ind   */
+  __u8                  D3Id;           /* ID used by this entity   */
+  __u8                  B2Id;           /* ID used by this entity   */
+  __u8                  GlobalId;       /* reserved field           */
+  __u8                  XNum;           /* number of X-buffers      */
+  __u8                  RNum;           /* number of R-buffers      */
+  struct sk_buff_head   X;              /* X-buffer queue           */
+  struct sk_buff_head   R;              /* R-buffer queue           */
+  __u8                  RNR;            /* receive not ready flag   */
+  __u8                  complete;       /* receive complete status  */
+  __u8                  busy;           /* busy flag                */
+  __u16                 ref;            /* saved reference          */
+} entity;
+
+
+typedef struct {
+       int            No;               /* Channel Number              */
+       unsigned short callref;          /* Call Reference              */
+       unsigned short fsm_state;        /* Current D-Channel state     */
+       unsigned short eazmask;          /* EAZ-Mask for this Channel   */
+       unsigned int   queued;           /* User-Data Bytes in TX queue */
+       unsigned int   waitq;            /* User-Data Bytes in wait queue */
+       unsigned int   waitpq;           /* User-Data Bytes in packet queue */
+       unsigned short plci;
+       unsigned short ncci;
+       unsigned char  l2prot;           /* Layer 2 protocol            */
+       unsigned char  l3prot;           /* Layer 3 protocol            */
+       entity          e;               /* Entity                      */
+       char            cpn[32];         /* remember cpn                */
+       char            oad[32];         /* remember oad                */
+       unsigned char   cause[2];        /* Last Cause                  */
+       unsigned char   si1;
+       unsigned char   si2;
+} eicon_chan;
+
+typedef struct {
+       eicon_chan *ptr;
+} eicon_chan_ptr;
+
+#include "eicon_pci.h"
+
+#define EICON_FLAGS_RUNNING  1 /* Cards driver activated */
+#define EICON_FLAGS_PVALID   2 /* Cards port is valid    */
+#define EICON_FLAGS_IVALID   4 /* Cards irq is valid     */
+#define EICON_FLAGS_MVALID   8 /* Cards membase is valid */
+#define EICON_FLAGS_LOADED   8 /* Firmware loaded        */
+
+#define EICON_BCH            2 /* # of channels per card */
+
+/* D-Channel states */
+#define EICON_STATE_NULL     0
+#define EICON_STATE_ICALL    1
+#define EICON_STATE_OCALL    2
+#define EICON_STATE_IWAIT    3
+#define EICON_STATE_OWAIT    4
+#define EICON_STATE_IBWAIT   5
+#define EICON_STATE_OBWAIT   6
+#define EICON_STATE_BWAIT    7
+#define EICON_STATE_BHWAIT   8
+#define EICON_STATE_BHWAIT2  9
+#define EICON_STATE_DHWAIT  10
+#define EICON_STATE_DHWAIT2 11
+#define EICON_STATE_BSETUP  12
+#define EICON_STATE_ACTIVE  13
+#define EICON_STATE_ICALLW  14
+#define EICON_STATE_LISTEN  15
+#define EICON_STATE_WMCONN  16
+
+#define EICON_MAX_QUEUED  8000 /* 2 * maxbuff */
+
+#define EICON_LOCK_TX 0
+#define EICON_LOCK_RX 1
+
+typedef struct {
+       int dummy;
+} eicon_mca_card;
+
+typedef union {
+       eicon_isa_card isa;
+       eicon_pci_card pci;
+       eicon_mca_card mca;
+} eicon_hwif;
+
+typedef struct {
+       __u8 ret;
+       __u8 id;
+       __u8 ch;
+} eicon_ack;
+
+typedef struct {
+       __u8 code;
+       __u8 id;
+       __u8 ch;
+} eicon_req;
+
+typedef struct {
+       __u8 ret;
+       __u8 id;
+       __u8 ch;
+       __u8 more;
+} eicon_indhdr;
+
+typedef struct msn_entry {
+       char eaz;
+        char msn[16];
+        struct msn_entry * next;
+} msn_entry;
+
+/*
+ * Per card driver data
+ */
+typedef struct eicon_card {
+       eicon_hwif hwif;                 /* Hardware dependant interface     */
+        u_char ptype;                    /* Protocol type (1TR6 or Euro)     */
+        u_char bus;                      /* Bustype (ISA, MCA, PCI)          */
+        u_char type;                     /* Cardtype (EICON_CTYPE_...)       */
+       struct eicon_card *qnext;        /* Pointer to next quadro adapter   */
+        int Feature;                     /* Protocol Feature Value           */
+        struct eicon_card *next;        /* Pointer to next device struct    */
+        int myid;                        /* Driver-Nr. assigned by linklevel */
+        unsigned long flags;             /* Statusflags                      */
+        unsigned long ilock;             /* Semaphores for IRQ-Routines      */
+       struct sk_buff_head rcvq;        /* Receive-Message queue            */
+       struct sk_buff_head sndq;        /* Send-Message queue               */
+       struct sk_buff_head rackq;       /* Req-Ack-Message queue            */
+       struct sk_buff_head sackq;       /* Data-Ack-Message queue           */
+       u_char *ack_msg;                 /* Ptr to User Data in User skb     */
+       __u16 need_b3ack;                /* Flag: Need ACK for current skb   */
+       struct sk_buff *sbuf;            /* skb which is currently sent      */
+       struct tq_struct snd_tq;         /* Task struct for xmit bh          */
+       struct tq_struct rcv_tq;         /* Task struct for rcv bh           */
+       struct tq_struct ack_tq;         /* Task struct for ack bh           */
+       msn_entry *msn_list;
+       unsigned short msgnum;           /* Message number for sending       */
+       eicon_chan*     IdTable[256];    /* Table to find entity   */
+       __u16  ref_in;
+       __u16  ref_out;
+       int    nchannels;                /* Number of B-Channels             */
+       int    ReadyInt;                 /* Ready Interrupt                  */
+       eicon_chan *bch;                 /* B-Channel status/control         */
+       char   status_buf[256];          /* Buffer for status messages       */
+       char   *status_buf_read;
+       char   *status_buf_write;
+       char   *status_buf_end;
+        isdn_if interface;               /* Interface to upper layer         */
+        char regname[35];                /* Name used for request_region     */
+} eicon_card;
+
+/* -----------------------------------------------------------**
+** The PROTOCOL_FEATURE_STRING                                **
+** defines capabilities and                                   **
+** features of the actual protocol code. It's used as a bit   **
+** mask.                                                      **
+** The following Bits are defined:                            **
+** -----------------------------------------------------------*/
+#define PROTCAP_TELINDUS  0x0001  /* Telindus Variant of protocol code   */
+#define PROTCAP_MANIF     0x0002  /* Management interface implemented    */
+#define PROTCAP_V_42      0x0004  /* V42 implemented                     */
+#define PROTCAP_V90D      0x0008  /* V.90D (implies up to 384k DSP code) */
+#define PROTCAP_EXTD_FAX  0x0010  /* Extended FAX (ECM, 2D, T6, Polling) */
+#define PROTCAP_FREE4     0x0020  /* not used                            */
+#define PROTCAP_FREE5     0x0040  /* not used                            */
+#define PROTCAP_FREE6     0x0080  /* not used                            */
+#define PROTCAP_FREE7     0x0100  /* not used                            */
+#define PROTCAP_FREE8     0x0200  /* not used                            */
+#define PROTCAP_FREE9     0x0400  /* not used                            */
+#define PROTCAP_FREE10    0x0800  /* not used                            */
+#define PROTCAP_FREE11    0x1000  /* not used                            */
+#define PROTCAP_FREE12    0x2000  /* not used                            */
+#define PROTCAP_FREE13    0x4000  /* not used                            */
+#define PROTCAP_EXTENSION 0x8000  /* used for future extentions          */
+
+#include "eicon_idi.h"
+
+extern eicon_card *cards;
+extern char *eicon_ctype_name[];
+
+
+extern __inline__ void eicon_schedule_tx(eicon_card *card)
+{
+        queue_task(&card->snd_tq, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+}
+
+extern __inline__ void eicon_schedule_rx(eicon_card *card)
+{
+        queue_task(&card->rcv_tq, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+}
+
+extern __inline__ void eicon_schedule_ack(eicon_card *card)
+{
+        queue_task(&card->ack_tq, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+}
+
+extern char *eicon_find_eaz(eicon_card *, char);
+extern int eicon_addcard(int, int, int, char *);
+extern void eicon_io_transmit(eicon_card *card);
+extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs);
+extern void eicon_io_rcv_dispatch(eicon_card *ccard);
+extern void eicon_io_ack_dispatch(eicon_card *ccard);
+extern ulong DebugVar;
+
+#endif  /* __KERNEL__ */
+
+#endif /* eicon_h */
diff --git a/drivers/isdn/eicon/eicon_dsp.h b/drivers/isdn/eicon/eicon_dsp.h
new file mode 100644 (file)
index 0000000..94a4595
--- /dev/null
@@ -0,0 +1,304 @@
+/* $Id: eicon_dsp.h,v 1.2 1999/03/29 11:19:42 armin Exp $
+ *
+ * ISDN lowlevel-module for Eicon.Diehl active cards.
+ *        DSP definitions
+ *
+ * Copyright 1999    by Armin Schindler (mac@melware.de)
+ * Copyright 1999    Cytronics & Melware (info@melware.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: eicon_dsp.h,v $
+ * Revision 1.2  1999/03/29 11:19:42  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.1  1999/03/02 12:18:54  armin
+ * First checkin of DSP defines for audio features.
+ *
+ *
+ */
+
+#ifndef DSP_H
+#define DSP_H
+
+#define DSP_UDATA_REQUEST_RECONFIGURE           0
+/*
+parameters:
+  <word> reconfigure delay (in 8kHz samples)
+  <word> reconfigure code
+  <byte> reconfigure hdlc preamble flags
+*/
+
+#define DSP_RECONFIGURE_TX_FLAG             0x8000
+#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG    0x4000
+#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG   0x2000
+#define DSP_RECONFIGURE_HDLC_FLAG           0x1000
+#define DSP_RECONFIGURE_SYNC_FLAG           0x0800
+#define DSP_RECONFIGURE_PROTOCOL_MASK       0x00ff
+#define DSP_RECONFIGURE_IDLE                0
+#define DSP_RECONFIGURE_V25                 1
+#define DSP_RECONFIGURE_V21_CH2             2
+#define DSP_RECONFIGURE_V27_2400            3
+#define DSP_RECONFIGURE_V27_4800            4
+#define DSP_RECONFIGURE_V29_7200            5
+#define DSP_RECONFIGURE_V29_9600            6
+#define DSP_RECONFIGURE_V33_12000           7
+#define DSP_RECONFIGURE_V33_14400           8
+#define DSP_RECONFIGURE_V17_7200            9
+#define DSP_RECONFIGURE_V17_9600            10
+#define DSP_RECONFIGURE_V17_12000           11
+#define DSP_RECONFIGURE_V17_14400           12
+
+/*
+data indications if transparent framer
+  <byte> data 0
+  <byte> data 1
+  ...
+
+data indications if HDLC framer
+  <byte> data 0
+  <byte> data 1
+  ...
+  <byte> CRC 0
+  <byte> CRC 1
+  <byte> preamble flags
+*/
+
+#define DSP_UDATA_REQUEST_SWITCH_FRAMER         1
+/*
+parameters:
+  <byte> transmit framer type
+  <byte> receive framer type
+*/
+
+#define DSP_REQUEST_SWITCH_FRAMER_HDLC          0
+#define DSP_REQUEST_SWITCH_FRAMER_TRANSPARENT   1
+#define DSP_REQUEST_SWITCH_FRAMER_ASYNC         2
+
+
+#define DSP_UDATA_REQUEST_CLEARDOWN             2
+/*
+parameters:
+  - none -
+*/
+
+
+#define DSP_UDATA_REQUEST_TX_CONFIRMATION_ON    3
+/*
+parameters:
+  - none -
+*/
+
+
+#define DSP_UDATA_REQUEST_TX_CONFIRMATION_OFF   4
+/*
+parameters:
+  - none -
+*/
+
+
+#define DSP_UDATA_INDICATION_SYNC               0
+/*
+returns:
+  <word> time of sync (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_OFF            1
+/*
+returns:
+  <word> time of DCD off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_ON             2
+/*
+returns:
+  <word> time of DCD on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s, max of tx and rx speed)
+  <word> roundtrip delay (ms)
+  <dword> connected speed tx (bit/s)
+  <dword> connected speed rx (bit/s)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_OFF            3
+/*
+returns:
+  <word> time of CTS off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_ON             4
+/*
+returns:
+  <word> time of CTS on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s, max of tx and rx speed)
+  <word> roundtrip delay (ms)
+  <dword> connected speed tx (bit/s)
+  <dword> connected speed rx (bit/s)
+*/
+
+typedef struct eicon_dsp_ind {
+       __u16   time            __attribute__ ((packed));
+       __u8    norm            __attribute__ ((packed));
+       __u16   options         __attribute__ ((packed));
+       __u32   speed           __attribute__ ((packed));
+       __u16   delay           __attribute__ ((packed));
+       __u32   txspeed         __attribute__ ((packed));
+       __u32   rxspeed         __attribute__ ((packed));
+} eicon_dsp_ind;
+
+#define DSP_CONNECTED_NORM_UNSPECIFIED      0
+#define DSP_CONNECTED_NORM_V21              1
+#define DSP_CONNECTED_NORM_V23              2
+#define DSP_CONNECTED_NORM_V22              3
+#define DSP_CONNECTED_NORM_V22_BIS          4
+#define DSP_CONNECTED_NORM_V32_BIS          5
+#define DSP_CONNECTED_NORM_V34              6
+#define DSP_CONNECTED_NORM_V8               7
+#define DSP_CONNECTED_NORM_BELL_212A        8
+#define DSP_CONNECTED_NORM_BELL_103         9
+#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
+#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
+#define DSP_CONNECTED_NORM_V90              12
+#define DSP_CONNECTED_NORM_V21_CH2          13
+#define DSP_CONNECTED_NORM_V27_TER          14
+#define DSP_CONNECTED_NORM_V29              15
+#define DSP_CONNECTED_NORM_V33              16
+#define DSP_CONNECTED_NORM_V17              17
+
+#define DSP_CONNECTED_OPTION_TRELLIS             0x0001
+#define DSP_CONNECTED_OPTION_V42_TRANS           0x0002
+#define DSP_CONNECTED_OPTION_V42_LAPM            0x0004
+#define DSP_CONNECTED_OPTION_SHORT_TRAIN         0x0008
+#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
+
+
+#define DSP_UDATA_INDICATION_DISCONNECT         5
+/*
+returns:
+  <byte> cause
+*/
+
+#define DSP_DISCONNECT_CAUSE_NONE               0x00
+#define DSP_DISCONNECT_CAUSE_BUSY_TONE          0x01
+#define DSP_DISCONNECT_CAUSE_CONGESTION_TONE    0x02
+#define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY    0x03
+#define DSP_DISCONNECT_CAUSE_CLEARDOWN          0x04
+#define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT   0x05
+
+
+#define DSP_UDATA_INDICATION_TX_CONFIRMATION    6
+/*
+returns:
+  <word> confirmation number
+*/
+
+
+#define DSP_UDATA_REQUEST_SEND_DTMF_DIGITS      16
+/*
+parameters:
+  <word> tone duration (ms)
+  <word> gap duration (ms)
+  <byte> digit 0 tone code
+  ...
+  <byte> digit n tone code
+*/
+
+#define DSP_SEND_DTMF_DIGITS_HEADER_LENGTH      5
+
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_697_HZ    0x00
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_770_HZ    0x01
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_852_HZ    0x02
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_941_HZ    0x03
+#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_MASK      0x03
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ  0x00
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ  0x04
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ  0x08
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ  0x0c
+#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_MASK     0x0c
+
+#define DSP_DTMF_DIGIT_TONE_CODE_0              0x07
+#define DSP_DTMF_DIGIT_TONE_CODE_1              0x00
+#define DSP_DTMF_DIGIT_TONE_CODE_2              0x04
+#define DSP_DTMF_DIGIT_TONE_CODE_3              0x08
+#define DSP_DTMF_DIGIT_TONE_CODE_4              0x01
+#define DSP_DTMF_DIGIT_TONE_CODE_5              0x05
+#define DSP_DTMF_DIGIT_TONE_CODE_6              0x09
+#define DSP_DTMF_DIGIT_TONE_CODE_7              0x02
+#define DSP_DTMF_DIGIT_TONE_CODE_8              0x06
+#define DSP_DTMF_DIGIT_TONE_CODE_9              0x0a
+#define DSP_DTMF_DIGIT_TONE_CODE_STAR           0x03
+#define DSP_DTMF_DIGIT_TONE_CODE_HASHMARK       0x0b
+#define DSP_DTMF_DIGIT_TONE_CODE_A              0x0c
+#define DSP_DTMF_DIGIT_TONE_CODE_B              0x0d
+#define DSP_DTMF_DIGIT_TONE_CODE_C              0x0e
+#define DSP_DTMF_DIGIT_TONE_CODE_D              0x0f
+
+
+#define DSP_UDATA_INDICATION_DTMF_DIGITS_SENT   16
+/*
+returns:
+  - none -
+  One indication will be sent for every request.
+*/
+
+
+#define DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER  17
+/*
+parameters:
+  <word> tone duration (ms)
+  <word> gap duration (ms)
+*/
+
+#define DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER 18
+/*
+parameters:
+  - none -
+*/
+
+#define DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED 17
+/*
+returns:
+  <byte> digit 0 tone code
+  ...
+  <byte> digit n tone code
+*/
+
+#define DSP_DTMF_DIGITS_RECEIVED_HEADER_LENGTH  1
+
+
+#define DSP_UDATA_INDICATION_MODEM_CALLING_TONE 18
+/*
+returns:
+  - none -
+*/
+
+#define DSP_UDATA_INDICATION_FAX_CALLING_TONE   19
+/*
+returns:
+  - none -
+*/
+
+#define DSP_UDATA_INDICATION_ANSWER_TONE        20
+/*
+returns:
+  - none -
+*/
+
+#endif /* DSP_H */
+
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
new file mode 100644 (file)
index 0000000..a28f316
--- /dev/null
@@ -0,0 +1,1479 @@
+/* $Id: eicon_idi.c,v 1.9 1999/03/29 11:19:42 armin Exp $
+ *
+ * ISDN lowlevel-module for Eicon.Diehl active cards.
+ *        IDI interface 
+ *
+ * Copyright 1998,99 by Armin Schindler (mac@melware.de)
+ * Copyright 1999    Cytronics & Melware (info@melware.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: eicon_idi.c,v $
+ * Revision 1.9  1999/03/29 11:19:42  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.8  1999/03/02 12:37:43  armin
+ * Added some important checks.
+ * Analog Modem with DSP.
+ * Channels will be added to Link-Level after loading firmware.
+ *
+ * Revision 1.7  1999/02/03 18:34:35  armin
+ * Channel selection for outgoing calls w/o CHI.
+ * Added channel # in debug messages.
+ * L2 Transparent should work with 800 byte/packet now.
+ *
+ * Revision 1.6  1999/01/26 07:18:59  armin
+ * Bug with wrong added CPN fixed.
+ *
+ * Revision 1.5  1999/01/24 20:14:11  armin
+ * Changed and added debug stuff.
+ * Better data sending. (still problems with tty's flip buffer)
+ *
+ * Revision 1.4  1999/01/10 18:46:05  armin
+ * Bug with wrong values in HLC fixed.
+ * Bytes to send are counted and limited now.
+ *
+ * Revision 1.3  1999/01/05 14:49:34  armin
+ * Added experimental usage of full BC and HLC for
+ * speech, 3.1kHz audio, fax gr.2/3
+ *
+ * Revision 1.2  1999/01/04 13:19:29  armin
+ * Channel status with listen-request wrong - fixed.
+ *
+ * Revision 1.1  1999/01/01 18:09:41  armin
+ * First checkin of new eicon driver.
+ * DIVA-Server BRI/PCI and PRI/PCI are supported.
+ * Old diehl code is obsolete.
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "eicon.h"
+#include "eicon_idi.h"
+#include "eicon_dsp.h"
+
+#undef EICON_FULL_SERVICE_OKTETT
+
+char *eicon_idi_revision = "$Revision: 1.9 $";
+
+eicon_manifbuf *manbuf;
+
+static char BC_Speech[3] =     { 0x80, 0x90, 0xa3 };
+static char BC_31khz[3] =      { 0x90, 0x90, 0xa3 };
+static char BC_64k[2] =        { 0x88, 0x90 };
+static char BC_video[3] =      { 0x91, 0x90, 0xa5 };
+
+#ifdef EICON_FULL_SERVICE_OKTETT
+/* 
+static char HLC_telephony[2] = { 0x91, 0x81 }; 
+*/
+static char HLC_faxg3[2] =     { 0x91, 0x84 };
+#endif
+
+int eicon_idi_manage_assign(eicon_card *card);
+int eicon_idi_manage_remove(eicon_card *card);
+
+int
+idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
+{
+       int l = 0;
+  if (!signet) {
+       /* Signal Layer */
+       reqbuf->XBuffer.P[l++] = CAI;
+       reqbuf->XBuffer.P[l++] = 1;
+       reqbuf->XBuffer.P[l++] = 0;
+       reqbuf->XBuffer.P[l++] = KEY;
+       reqbuf->XBuffer.P[l++] = 3;
+       reqbuf->XBuffer.P[l++] = 'I';
+       reqbuf->XBuffer.P[l++] = '4';
+       reqbuf->XBuffer.P[l++] = 'L';
+       reqbuf->XBuffer.P[l++] = SHIFT|6;
+       reqbuf->XBuffer.P[l++] = SIN;
+       reqbuf->XBuffer.P[l++] = 2;
+       reqbuf->XBuffer.P[l++] = 0;
+       reqbuf->XBuffer.P[l++] = 0;
+       reqbuf->XBuffer.P[l++] = 0; /* end */
+       reqbuf->Req = ASSIGN;
+       reqbuf->ReqCh = 0;
+       reqbuf->ReqId = 0;
+       reqbuf->XBuffer.length = l;
+       reqbuf->Reference = 0; /* Sig Entity */
+  }
+  else {
+       /* Network Layer */
+       reqbuf->XBuffer.P[l++] = CAI;
+       reqbuf->XBuffer.P[l++] = 1;
+       reqbuf->XBuffer.P[l++] = chan->e.D3Id;
+       reqbuf->XBuffer.P[l++] = LLC;
+       reqbuf->XBuffer.P[l++] = 2;
+       switch(chan->l2prot) {
+               case ISDN_PROTO_L2_HDLC:
+                       reqbuf->XBuffer.P[l++] = 2;
+                       break;
+               case ISDN_PROTO_L2_X75I:
+               case ISDN_PROTO_L2_X75UI:
+               case ISDN_PROTO_L2_X75BUI:
+                       reqbuf->XBuffer.P[l++] = 5; 
+                       break;
+               case ISDN_PROTO_L2_TRANS:
+               case ISDN_PROTO_L2_MODEM:
+                       reqbuf->XBuffer.P[l++] = 2;
+                       break;
+               default:
+                       reqbuf->XBuffer.P[l++] = 1;
+       }
+       switch(chan->l3prot) {
+               case ISDN_PROTO_L3_TRANS:
+               default:
+                       reqbuf->XBuffer.P[l++] = 4;
+       }
+       reqbuf->XBuffer.P[l++] = 0; /* end */
+       reqbuf->Req = ASSIGN;
+       reqbuf->ReqCh = 0;
+       reqbuf->ReqId = 0x20;
+       reqbuf->XBuffer.length = l;
+       reqbuf->Reference = 1; /* Net Entity */
+  }
+   return(0);
+}
+
+int
+idi_put_req(eicon_REQ *reqbuf, int rq, int signet)
+{
+       reqbuf->Req = rq;
+       reqbuf->ReqCh = 0;
+       reqbuf->ReqId = 1;
+       reqbuf->XBuffer.length = 1;
+       reqbuf->XBuffer.P[0] = 0;
+       reqbuf->Reference = signet;
+   return(0);
+}
+
+int
+idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
+{
+       int l = 9;
+       reqbuf->Req = CALL_RES;
+       reqbuf->ReqCh = 0;
+       reqbuf->ReqId = 1;
+       reqbuf->XBuffer.P[0] = CAI;
+       reqbuf->XBuffer.P[1] = 6;
+       reqbuf->XBuffer.P[2] = 9;
+       reqbuf->XBuffer.P[3] = 0;
+       reqbuf->XBuffer.P[4] = 0;
+       reqbuf->XBuffer.P[5] = 0;
+       reqbuf->XBuffer.P[6] = 32;
+       reqbuf->XBuffer.P[7] = 3;
+       switch(chan->l2prot) {
+               case ISDN_PROTO_L2_X75I:
+               case ISDN_PROTO_L2_X75UI:
+               case ISDN_PROTO_L2_X75BUI:
+               case ISDN_PROTO_L2_HDLC:
+                       reqbuf->XBuffer.P[1] = 1;
+                       reqbuf->XBuffer.P[2] = 0x05;
+                       l = 4;
+                       break;
+               case ISDN_PROTO_L2_V11096:
+                       reqbuf->XBuffer.P[2] = 0x0d;
+                       reqbuf->XBuffer.P[3] = 5;
+                       reqbuf->XBuffer.P[4] = 0;
+                       break;
+               case ISDN_PROTO_L2_V11019:
+                       reqbuf->XBuffer.P[2] = 0x0d;
+                       reqbuf->XBuffer.P[3] = 6;
+                       reqbuf->XBuffer.P[4] = 0;
+                       break;
+               case ISDN_PROTO_L2_V11038:
+                       reqbuf->XBuffer.P[2] = 0x0d;
+                       reqbuf->XBuffer.P[3] = 7;
+                       reqbuf->XBuffer.P[4] = 0;
+                       break;
+               case ISDN_PROTO_L2_MODEM:
+                       reqbuf->XBuffer.P[2] = 0x11;
+                       reqbuf->XBuffer.P[3] = 7;
+                       reqbuf->XBuffer.P[4] = 0;
+                       reqbuf->XBuffer.P[5] = 0;
+                       reqbuf->XBuffer.P[6] = 128;
+                       reqbuf->XBuffer.P[7] = 0;
+                       break;
+       }
+       reqbuf->XBuffer.P[8] = 0;
+       reqbuf->XBuffer.length = l;
+       reqbuf->Reference = 0; /* Sig Entity */
+       if (DebugVar & 8)
+               printk(KERN_DEBUG"idi_req: Ch%d: Call_Res\n", chan->No);
+   return(0);
+}
+
+int
+idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
+{
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+       eicon_REQ *reqbuf;
+       eicon_chan_ptr *chan2;
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+                return -ENOMEM; 
+       }
+
+       chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+       chan2->ptr = chan;
+
+       reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+       if (DebugVar & 8)
+               printk(KERN_DEBUG "idi_req: Ch%d: 0x%02x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
+       if (layer) cmd |= 0x700;
+       switch(cmd) {
+               case ASSIGN:
+               case ASSIGN|0x700:
+                       idi_assign_req(reqbuf, layer, chan);
+                       break;
+               case REMOVE:
+               case REMOVE|0x700:
+                       idi_put_req(reqbuf, REMOVE, layer);
+                       break;
+               case INDICATE_REQ:
+                       idi_put_req(reqbuf, INDICATE_REQ, 0);
+                       break;
+               case HANGUP:
+                       idi_put_req(reqbuf, HANGUP, 0);
+                       break;
+               case REJECT:
+                       idi_put_req(reqbuf, REJECT, 0);
+                       break;
+               case CALL_ALERT:
+                       idi_put_req(reqbuf, CALL_ALERT, 0);
+                       break;
+               case CALL_RES:
+                       idi_call_res_req(reqbuf, chan);
+                       break;
+               case IDI_N_CONNECT|0x700:
+                       idi_put_req(reqbuf, IDI_N_CONNECT, 1);
+                       break;
+               case IDI_N_CONNECT_ACK|0x700:
+                       idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1);
+                       break;
+               case IDI_N_DISC|0x700:
+                       idi_put_req(reqbuf, IDI_N_DISC, 1);
+                       break;
+               case IDI_N_DISC_ACK|0x700:
+                       idi_put_req(reqbuf, IDI_N_DISC_ACK, 1);
+                       break;
+               default:
+                       if (DebugVar & 1)
+                               printk(KERN_ERR "idi_req: Ch%d: Unknown request\n", chan->No);
+                       return(-1);
+       }
+
+       skb_queue_tail(&chan->e.X, skb);
+       skb_queue_tail(&card->sndq, skb2); 
+       eicon_schedule_tx(card);
+       return(0);
+}
+
+int
+eicon_idi_listen_req(eicon_card *card, eicon_chan *chan)
+{
+       if (DebugVar & 16)
+               printk(KERN_DEBUG"idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
+       if (!chan->e.D3Id) {
+               idi_do_req(card, chan, ASSIGN, 0); 
+       }
+       if (chan->fsm_state == EICON_STATE_NULL) {
+               idi_do_req(card, chan, INDICATE_REQ, 0);
+               chan->fsm_state = EICON_STATE_LISTEN;
+       }
+  return(0);
+}
+
+unsigned char
+idi_si2bc(int si1, int si2, char *bc, char *hlc)
+{
+  hlc[0] = 0;
+  switch(si1) {
+       case 1:
+               bc[0] = 0x90;           /* 3,1 kHz audio */
+               bc[1] = 0x90;           /* 64 kbit/s */
+               bc[2] = 0xa3;           /* G.711 A-law */
+#ifdef EICON_FULL_SERVICE_OKTETT
+               if (si2 == 1) {
+                       bc[0] = 0x80;   /* Speech */
+                       hlc[0] = 0x02;  /* hlc len */
+                       hlc[1] = 0x91;  /* first hic */
+                       hlc[2] = 0x81;  /* Telephony */
+               }
+#endif
+               return(3);
+       case 2:
+               bc[0] = 0x90;           /* 3,1 kHz audio */
+               bc[1] = 0x90;           /* 64 kbit/s */
+               bc[2] = 0xa3;           /* G.711 A-law */
+#ifdef EICON_FULL_SERVICE_OKTETT
+               if (si2 == 2) {
+                       hlc[0] = 0x02;  /* hlc len */
+                       hlc[1] = 0x91;  /* first hic */
+                       hlc[2] = 0x84;  /* Fax Gr.2/3 */
+               }
+#endif
+               return(3);
+       case 5:
+       case 7:
+       default:
+               bc[0] = 0x88;
+               bc[1] = 0x90;
+               return(2);
+  }
+ return (0);
+}
+
+int
+idi_hangup(eicon_card *card, eicon_chan *chan)
+{
+       if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
+           (chan->fsm_state == EICON_STATE_WMCONN)) {
+               if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1);
+       }
+       if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
+       idi_do_req(card, chan, HANGUP, 0);
+       chan->fsm_state = EICON_STATE_NULL;
+       if (DebugVar & 8)
+               printk(KERN_DEBUG"idi_req: Ch%d: Hangup\n", chan->No);
+  return(0);
+}
+
+int
+idi_connect_res(eicon_card *card, eicon_chan *chan)
+{
+  chan->fsm_state = EICON_STATE_IWAIT;
+  idi_do_req(card, chan, CALL_RES, 0);
+  idi_do_req(card, chan, ASSIGN, 1);
+  return(0);
+}
+
+int
+idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
+                    char *eazmsn, int si1, int si2)
+{
+       int l = 0;
+       int i;
+       unsigned char tmp;
+       unsigned char bc[5];
+       unsigned char hlc[5];
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+       eicon_REQ *reqbuf;
+       eicon_chan_ptr *chan2;
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+                return -ENOMEM; 
+       }
+
+       chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+       chan2->ptr = chan;
+
+       reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+       reqbuf->Req = CALL_REQ;
+       reqbuf->ReqCh = 0;
+       reqbuf->ReqId = 1;
+
+       reqbuf->XBuffer.P[l++] = CPN;
+       reqbuf->XBuffer.P[l++] = strlen(phone) + 1;
+       reqbuf->XBuffer.P[l++] = 0xc1;
+       for(i=0; i<strlen(phone);i++) 
+               reqbuf->XBuffer.P[l++] = phone[i];
+
+       reqbuf->XBuffer.P[l++] = OAD;
+       reqbuf->XBuffer.P[l++] = strlen(eazmsn) + 2;
+       reqbuf->XBuffer.P[l++] = 0x01;
+       reqbuf->XBuffer.P[l++] = 0x81;
+       for(i=0; i<strlen(eazmsn);i++) 
+               reqbuf->XBuffer.P[l++] = eazmsn[i];
+
+       if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
+               reqbuf->XBuffer.P[l++] = BC;
+               reqbuf->XBuffer.P[l++] = tmp;
+               for(i=0; i<tmp;i++) 
+                       reqbuf->XBuffer.P[l++] = bc[i];
+               if ((tmp=hlc[0])) {
+                       reqbuf->XBuffer.P[l++] = HLC;
+                       reqbuf->XBuffer.P[l++] = tmp;
+                       for(i=1; i<=tmp;i++) 
+                               reqbuf->XBuffer.P[l++] = hlc[i];
+               }
+       }
+        reqbuf->XBuffer.P[l++] = CAI;
+        reqbuf->XBuffer.P[l++] = 6;
+        reqbuf->XBuffer.P[l++] = 0x09;
+       reqbuf->XBuffer.P[l++] = 0;
+       reqbuf->XBuffer.P[l++] = 0;
+       reqbuf->XBuffer.P[l++] = 0;
+       reqbuf->XBuffer.P[l++] = 32;
+       reqbuf->XBuffer.P[l++] = 3;
+        switch(chan->l2prot) {
+               case ISDN_PROTO_L2_X75I:
+               case ISDN_PROTO_L2_X75UI:
+               case ISDN_PROTO_L2_X75BUI:
+                case ISDN_PROTO_L2_HDLC:
+                        reqbuf->XBuffer.P[l-6] = 5;
+                        reqbuf->XBuffer.P[l-7] = 1;
+                       l -= 5; 
+                        break;
+                case ISDN_PROTO_L2_V11096:
+                        reqbuf->XBuffer.P[l-7] = 3;
+                        reqbuf->XBuffer.P[l-6] = 0x0d;
+                        reqbuf->XBuffer.P[l-5] = 5;
+                        reqbuf->XBuffer.P[l-4] = 0;
+                        l -= 3;
+                        break;
+                case ISDN_PROTO_L2_V11019:
+                        reqbuf->XBuffer.P[l-7] = 3;
+                        reqbuf->XBuffer.P[l-6] = 0x0d;
+                        reqbuf->XBuffer.P[l-5] = 6;
+                        reqbuf->XBuffer.P[l-4] = 0;
+                        l -= 3;
+                        break;
+                case ISDN_PROTO_L2_V11038:
+                        reqbuf->XBuffer.P[l-7] = 3;
+                        reqbuf->XBuffer.P[l-6] = 0x0d;
+                        reqbuf->XBuffer.P[l-5] = 7;
+                        reqbuf->XBuffer.P[l-4] = 0;
+                        l -= 3;
+                        break;
+                case ISDN_PROTO_L2_MODEM:
+                       reqbuf->XBuffer.P[l-6] = 0x11;
+                       reqbuf->XBuffer.P[l-5] = 7;
+                       reqbuf->XBuffer.P[l-4] = 0;
+                       reqbuf->XBuffer.P[l-3] = 0;
+                       reqbuf->XBuffer.P[l-2] = 128;
+                       reqbuf->XBuffer.P[l-1] = 0;
+                        break;
+        }
+       
+       reqbuf->XBuffer.P[l++] = 0; /* end */
+       reqbuf->XBuffer.length = l;
+       reqbuf->Reference = 0; /* Sig Entity */
+
+       skb_queue_tail(&chan->e.X, skb);
+       skb_queue_tail(&card->sndq, skb2); 
+       eicon_schedule_tx(card);
+
+       if (DebugVar & 8)
+               printk(KERN_DEBUG"idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
+   return(0);
+}
+
+
+void
+idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsigned char *buffer, int len)
+{
+       int i,j;
+       int pos = 0;
+       int codeset = 0;
+       int wlen = 0;
+       int lock = 0;
+       __u8 w;
+       __u16 code;
+       isdn_ctrl cmd;
+
+  memset(message, 0, sizeof(idi_ind_message));
+
+  if ((!len) || (!buffer[pos])) return;
+  while(pos <= len) {
+       w = buffer[pos++];
+       if (!w) return;
+       if (w & 0x80) {
+               wlen = 0;
+       }
+       else {
+               wlen = buffer[pos++];
+       }
+
+       if (pos > len) return;
+
+       if (lock & 0x80) lock &= 0x7f;
+       else codeset = lock;
+
+       if((w&0xf0) == SHIFT) {
+               codeset = w;
+               if(!(codeset & 0x08)) lock = codeset & 7;
+               codeset &= 7;
+               lock |= 0x80;
+       }
+       else {
+               if (w==ESC && wlen >=2) {
+                       code = buffer[pos++]|0x800;
+                       wlen--;
+               }
+               else code = w;
+               code |= (codeset<<8);
+
+               switch(code) {
+                       case OAD:
+                               j = 1;
+                               if (wlen) {
+                                       message->plan = buffer[pos++];
+                                       if (message->plan &0x80) 
+                                               message->screen = 0;
+                                       else {
+                                               message->screen = buffer[pos++];
+                                               j = 2;
+                                       }
+                               }
+                               for(i=0; i < wlen-j; i++) 
+                                       message->oad[i] = buffer[pos++];
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, 
+                                               message->plan, message->screen, message->oad);
+                               break;
+                       case RDN:
+                               j = 1;
+                               if (wlen) {
+                                       if (!(buffer[pos++] & 0x80)) {
+                                               pos++; 
+                                               j = 2;
+                                       }
+                               }
+                               for(i=0; i < wlen-j; i++) 
+                                       message->rdn[i] = buffer[pos++];
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: RDN= %s\n", chan->No, 
+                                               message->rdn);
+                               break;
+                       case CPN:
+                               for(i=0; i < wlen; i++) 
+                                       message->cpn[i] = buffer[pos++];
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
+                                               (__u8)message->cpn[0], message->cpn + 1);
+                               break;
+                       case DSA:
+                               pos++;
+                               for(i=0; i < wlen-1; i++) 
+                                       message->dsa[i] = buffer[pos++];
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
+                               break;
+                       case OSA:
+                               pos++;
+                               for(i=0; i < wlen-1; i++) 
+                                       message->osa[i] = buffer[pos++];
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
+                               break;
+                       case BC:
+                               for(i=0; i < wlen; i++) 
+                                       message->bc[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
+                                               message->bc[0],message->bc[1],message->bc[2]);
+                               break;
+                       case 0x800|BC:
+                               for(i=0; i < wlen; i++) 
+                                       message->e_bc[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
+                               break;
+                       case LLC:
+                               for(i=0; i < wlen; i++) 
+                                       message->llc[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
+                                               message->llc[1],message->llc[2],message->llc[3]);
+                               break;
+                       case HLC:
+                               for(i=0; i < wlen; i++) 
+                                       message->hlc[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
+                                               message->hlc[0], message->hlc[1],
+                                               message->hlc[2], message->hlc[3], message->hlc[4]);
+                               break;
+                       case DSP:
+                       case 0x600|DSP:
+                               for(i=0; i < wlen; i++) 
+                                       message->display[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: Display: %s\n", chan->No,
+                                               message->display);
+                               break;
+                       case 0x600|KEY:
+                               for(i=0; i < wlen; i++) 
+                                       message->keypad[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: Keypad: %s\n", chan->No,
+                                               message->keypad);
+                               break;
+                       case NI:
+                       case 0x600|NI:
+                               if (wlen) {
+                                       if (DebugVar & 4) {
+                                               switch(buffer[pos] & 127) {
+                                                       case 0:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: User suspended.\n", chan->No);
+                                                               break;
+                                                       case 1:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: User resumed.\n", chan->No);
+                                                               break;
+                                                       case 2:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Bearer service change.\n", chan->No);
+                                                               break;
+                                                       default:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Notification %x.\n", 
+                                                                               chan->No, buffer[pos] & 127);
+                                               }
+                                       }
+                                       pos += wlen;
+                               }
+                               break;
+                       case PI:
+                       case 0x600|PI:
+                               if (wlen > 1) {
+                                       if (DebugVar & 4) {
+                                               switch(buffer[pos+1] & 127) {
+                                                       case 1:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
+                                                               break;
+                                                       case 2:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
+                                                               break;
+                                                       case 3:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
+                                                               break;
+                                                       case 4:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
+                                                               break;
+                                                       case 5:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
+                                                               break;
+                                                       case 8:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: In-band information available.\n", chan->No);
+                                                               break;
+                                                       default:
+                                                               printk(KERN_DEBUG"idi_inf: Ch%d: Unknown Progress %x.\n", 
+                                                                               chan->No, buffer[pos+1] & 127);
+                                               }
+                                       }
+                               }
+                               pos += wlen;
+                               break;
+                       case CAU:
+                               for(i=0; i < wlen; i++) 
+                                       message->cau[i] = buffer[pos++];
+                               memcpy(&chan->cause, &message->cau, 2);
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: CAU=%d %d\n", chan->No,
+                                               message->cau[0],message->cau[1]);
+                               break;
+                       case 0x800|CAU:
+                               for(i=0; i < wlen; i++) 
+                                       message->e_cau[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
+                                               message->e_cau[0],message->e_cau[1]);
+                               break;
+                       case 0x800|CHI:
+                               for(i=0; i < wlen; i++) 
+                                       message->e_chi[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
+                                               message->e_cau[0]);
+                               break;
+                       case 0x800|0x7a:
+                               pos ++;
+                               message->e_mt=buffer[pos++];
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
+                               break;
+                       case DT:
+                               for(i=0; i < wlen; i++) 
+                                       message->dt[i] = buffer[pos++];
+                               if (DebugVar & 4)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
+                                               message->dt[2], message->dt[1], message->dt[0],
+                                               message->dt[3], message->dt[4], message->dt[5]);
+                               break;
+                       case 0x600|SIN:
+                               for(i=0; i < wlen; i++) 
+                                       message->sin[i] = buffer[pos++];
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: SIN=%d %d\n", chan->No,
+                                               message->sin[0],message->sin[1]);
+                               break;
+                       case 0x600|CPS:
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
+                               pos += wlen;
+                               break;
+                       case 0x600|CIF:
+                               for (i = 0; i < wlen; i++)
+                                       if (buffer[pos + i] != '0') break;
+                               memcpy(&cmd.parm.num, &buffer[pos + i], wlen - i);
+                               cmd.parm.num[wlen - i] = 0;
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
+                               pos += wlen;
+                               cmd.driver = ccard->myid;
+                               cmd.command = ISDN_STAT_CINF;
+                               cmd.arg = chan->No;
+                               ccard->interface.statcallb(&cmd);
+                               break;
+                       case 0x600|DATE:
+                               if (DebugVar & 2)
+                                       printk(KERN_DEBUG"idi_inf: Ch%d: Date in ind\n", chan->No);
+                               pos += wlen;
+                               break;
+                       case 0xe08: 
+                       case 0xe7a: 
+                       case 0xe04: 
+                       case 0xe00: 
+                               /* *** TODO *** */
+                       case CHA:
+                               /* Charge advice */
+                       case FTY:
+                       case 0x600|FTY:
+                       case CHI:
+                       case 0x800:
+                               /* Not yet interested in this */
+                               pos += wlen;
+                               break;
+                       case 0x880:
+                               /* Managment Information Element */
+                               if (!manbuf) {
+                                       if (DebugVar & 1)
+                                               printk(KERN_WARNING"idi_err: manbuf not allocated\n");
+                               }
+                               else {
+                                       memcpy(&manbuf->data[manbuf->pos], &buffer[pos], wlen);
+                                       manbuf->length[manbuf->count] = wlen;
+                                       manbuf->count++;
+                                       manbuf->pos += wlen;
+                               }
+                               pos += wlen;
+                               break;
+                       default:
+                               pos += wlen;
+                               if (DebugVar & 6)
+                                       printk(KERN_WARNING"idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", 
+                                               chan->No, code, wlen);
+               }
+       }
+  }
+}
+
+void
+idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2)
+{
+  si1[0] = 0;
+  si2[0] = 0;
+  if (memcmp(bc, BC_Speech, 3) == 0) {         /* Speech */
+       si1[0] = 1;
+#ifdef EICON_FULL_SERVICE_OKTETT
+       si2[0] = 1;
+#endif
+  }
+  if (memcmp(bc, BC_31khz, 3) == 0) {          /* 3.1kHz audio */
+       si1[0] = 1;
+#ifdef EICON_FULL_SERVICE_OKTETT
+       si2[0] = 2;
+       if (memcmp(hlc, HLC_faxg3, 2) == 0) {   /* Fax Gr.2/3 */
+               si1[0] = 2;
+       }
+#endif
+  }
+  if (memcmp(bc, BC_64k, 2) == 0) {            /* unrestricted 64 kbits */
+       si1[0] = 7;
+  }
+  if (memcmp(bc, BC_video, 3) == 0) {          /* video */
+       si1[0] = 4;
+  }
+}
+
+void
+idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
+{
+       isdn_ctrl cmd;
+       eicon_dsp_ind *p = (eicon_dsp_ind *) (&buffer[1]);
+        static char *connmsg[] =
+        {"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34",
+         "V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90",
+         "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17"};
+
+       switch (buffer[0]) {
+               case DSP_UDATA_INDICATION_SYNC:
+                       if (DebugVar & 16)
+                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
+                       break;
+               case DSP_UDATA_INDICATION_DCD_OFF:
+                       if (DebugVar & 8)
+                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
+                       break;
+               case DSP_UDATA_INDICATION_DCD_ON:
+                       if ((chan->l2prot == ISDN_PROTO_L2_MODEM) &&
+                           (chan->fsm_state == EICON_STATE_WMCONN)) {
+                               chan->fsm_state = EICON_STATE_ACTIVE;
+                               cmd.driver = ccard->myid;
+                               cmd.command = ISDN_STAT_BCONN;
+                               cmd.arg = chan->No;
+                               sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]);
+                               ccard->interface.statcallb(&cmd);
+                       }
+                       if (DebugVar & 8) {
+                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
+                               printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+                                           p->norm, p->options, p->speed, p->delay); 
+                           }
+                       break;
+               case DSP_UDATA_INDICATION_CTS_OFF:
+                       if (DebugVar & 8)
+                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
+                       break;
+               case DSP_UDATA_INDICATION_CTS_ON:
+                       if (DebugVar & 8) {
+                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
+                               printk(KERN_DEBUG"idi_ind: Ch%d: %d %d %d %d\n", chan->No,
+                                           p->norm, p->options, p->speed, p->delay); 
+                       }
+                       break;
+               case DSP_UDATA_INDICATION_DISCONNECT:
+                       if (DebugVar & 8)
+                               printk(KERN_DEBUG"idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
+                       break;
+               default:
+                       if (DebugVar & 8)
+                               printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
+       }
+}
+
+void
+idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
+{
+       int tmp;
+       int free_buff;
+       struct sk_buff *skb2;
+        eicon_IND *ind = (eicon_IND *)skb->data;
+       eicon_chan *chan;
+       idi_ind_message message;
+       isdn_ctrl cmd;
+
+       if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+               dev_kfree_skb(skb);
+               return;
+       }
+       
+       if ((DebugVar & 128) || 
+          ((DebugVar & 16) && (ind->Ind != 8))) {
+               printk(KERN_DEBUG "idi_hdl: Ch%d: Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n", chan->No,
+                       ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
+       }
+
+       free_buff = 1;
+       /* Signal Layer */
+       if (chan->e.D3Id == ind->IndId) {
+               idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
+               switch(ind->Ind) {
+                       case HANGUP:
+                               if (DebugVar & 8)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: Hangup\n", chan->No);
+                               while((skb2 = skb_dequeue(&chan->e.X))) {
+                                       dev_kfree_skb(skb2);
+                               }
+                               chan->e.busy = 0;
+                               chan->queued = 0;
+                               chan->waitq = 0;
+                               chan->waitpq = 0;
+                               chan->fsm_state = EICON_STATE_NULL;
+                               if (message.e_cau[0] & 0x7f) {
+                                       cmd.driver = ccard->myid;
+                                       cmd.arg = chan->No;
+                                       sprintf(cmd.parm.num,"E%02x%02x", 
+                                               chan->cause[0]&0x7f, message.e_cau[0]&0x7f); 
+                                       cmd.command = ISDN_STAT_CAUSE;
+                                       ccard->interface.statcallb(&cmd);
+                               }
+                               chan->cause[0] = 0; 
+                               cmd.driver = ccard->myid;
+                               cmd.arg = chan->No;
+                               cmd.command = ISDN_STAT_DHUP;
+                               ccard->interface.statcallb(&cmd);
+                               eicon_idi_listen_req(ccard, chan);
+                               break;
+                       case INDICATE_IND:
+                               if (DebugVar & 8)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: Indicate_Ind\n", chan->No);
+                               chan->fsm_state = EICON_STATE_ICALL;
+                               idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2);
+                               strcpy(chan->cpn, message.cpn + 1);
+                               if (strlen(message.dsa)) {
+                                       strcat(chan->cpn, ".");
+                                       strcat(chan->cpn, message.dsa);
+                               }
+                               strcpy(chan->oad, message.oad);
+                               try_stat_icall_again: 
+                               cmd.driver = ccard->myid;
+                               cmd.command = ISDN_STAT_ICALL;
+                               cmd.arg = chan->No;
+                               cmd.parm.setup.si1 = chan->si1;
+                               cmd.parm.setup.si2 = chan->si2;
+                               strcpy(cmd.parm.setup.eazmsn, chan->cpn);
+                               strcpy(cmd.parm.setup.phone, chan->oad);
+                               cmd.parm.setup.plan = message.plan;
+                               cmd.parm.setup.screen = message.screen;
+                               tmp = ccard->interface.statcallb(&cmd);
+                               switch(tmp) {
+                                       case 0: /* no user responding */
+                                               idi_do_req(ccard, chan, HANGUP, 0);
+                                               break;
+                                       case 1: /* alert */
+                                               if (DebugVar & 8)
+                                                       printk(KERN_DEBUG"idi_req: Ch%d: Call Alert\n", chan->No);
+                                               if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_ICALLW)) {
+                                                       chan->fsm_state = EICON_STATE_ICALL;
+                                                       idi_do_req(ccard, chan, CALL_ALERT, 0);
+                                               }
+                                               break;
+                                       case 2: /* reject */
+                                               if (DebugVar & 8)
+                                                       printk(KERN_DEBUG"idi_req: Ch%d: Call Reject\n", chan->No);
+                                               idi_do_req(ccard, chan, REJECT, 0);
+                                               break;
+                                       case 3: /* incomplete number */
+                                               if (DebugVar & 8)
+                                                       printk(KERN_DEBUG"idi_req: Ch%d: Incomplete Number\n", chan->No);
+                                               switch(ccard->type) {
+                                                       case EICON_CTYPE_MAESTRAP:
+                                                       case EICON_CTYPE_S2M:
+                                                               /* TODO (other protocols) */
+                                                               chan->fsm_state = EICON_STATE_ICALLW;
+                                                               break;
+                                                       default:
+                                                               idi_do_req(ccard, chan, HANGUP, 0);
+                                               }
+                                               break;
+                               }
+                               break;
+                       case INFO_IND:
+                               if (DebugVar & 8)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: Info_Ind\n", chan->No);
+                               if ((chan->fsm_state == EICON_STATE_ICALLW) &&
+                                   (message.cpn[0])) {
+                                       strcat(chan->cpn, message.cpn + 1);
+                                       goto try_stat_icall_again;
+                               }
+                               break;
+                       case CALL_IND:
+                               if (DebugVar & 8)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: Call_Ind\n", chan->No);
+                               if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_IWAIT)) {
+                                       chan->fsm_state = EICON_STATE_IBWAIT;
+                                       cmd.driver = ccard->myid;
+                                       cmd.command = ISDN_STAT_DCONN;
+                                       cmd.arg = chan->No;
+                                       ccard->interface.statcallb(&cmd);
+                                       idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+                               } else
+                               idi_hangup(ccard, chan);
+                               break;
+                       case CALL_CON:
+                               if (DebugVar & 8)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: Call_Con\n", chan->No);
+                               if (chan->fsm_state == EICON_STATE_OCALL) {
+                                       chan->fsm_state = EICON_STATE_OBWAIT;
+                                       cmd.driver = ccard->myid;
+                                       cmd.command = ISDN_STAT_DCONN;
+                                       cmd.arg = chan->No;
+                                       ccard->interface.statcallb(&cmd);
+                                       idi_do_req(ccard, chan, ASSIGN, 1); 
+                                       idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+                               } else
+                               idi_hangup(ccard, chan);
+                               break;
+                       case AOC_IND:
+                               if (DebugVar & 8)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: Advice of Charge\n", chan->No);
+                               break;
+                       default:
+                               if (DebugVar & 8)
+                                       printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
+               }
+       }
+       /* Network Layer */
+       else if (chan->e.B2Id == ind->IndId) {
+
+               if (chan->No == ccard->nchannels) {
+                       /* Management Indication */
+                       idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
+                       chan->fsm_state = 1;
+               } 
+               else
+               switch(ind->Ind) {
+                       case IDI_N_CONNECT_ACK:
+                               if (DebugVar & 16)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
+                               if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
+                                       chan->fsm_state = EICON_STATE_WMCONN;
+                                       break;
+                               }
+                               chan->fsm_state = EICON_STATE_ACTIVE;
+                               cmd.driver = ccard->myid;
+                               cmd.command = ISDN_STAT_BCONN;
+                               cmd.arg = chan->No;
+                               ccard->interface.statcallb(&cmd);
+                               break; 
+                       case IDI_N_CONNECT:
+                               if (DebugVar & 16)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_Connect\n", chan->No);
+                               if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
+                               if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
+                                       chan->fsm_state = EICON_STATE_WMCONN;
+                                       break;
+                               }
+                               chan->fsm_state = EICON_STATE_ACTIVE;
+                               cmd.driver = ccard->myid;
+                               cmd.command = ISDN_STAT_BCONN;
+                               cmd.arg = chan->No;
+                               ccard->interface.statcallb(&cmd);
+                               break; 
+                       case IDI_N_DISC:
+                               if (DebugVar & 16)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC\n", chan->No);
+                               if (chan->e.B2Id) {
+                                       idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
+                                       idi_do_req(ccard, chan, REMOVE, 1);
+                               }
+                               chan->queued = 0;
+                               chan->waitq = 0;
+                               chan->waitpq = 0;
+                               if (chan->fsm_state == EICON_STATE_ACTIVE) {
+                                       cmd.driver = ccard->myid;
+                                       cmd.command = ISDN_STAT_BHUP;
+                                       cmd.arg = chan->No;
+                                       ccard->interface.statcallb(&cmd);
+                               }
+                               break; 
+                       case IDI_N_DISC_ACK:
+                               if (DebugVar & 16)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+                               break; 
+                       case IDI_N_DATA_ACK:
+                               if (DebugVar & 16)
+                                       printk(KERN_DEBUG"idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
+                               break;
+                       case IDI_N_DATA:
+                               skb_pull(skb, sizeof(eicon_IND) - 1);
+                               if (DebugVar & 128)
+                                       printk(KERN_DEBUG"idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
+                               ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
+                               free_buff = 0; 
+                               break; 
+                       case IDI_N_UDATA:
+                               idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
+                               break; 
+                       default:
+                               if (DebugVar & 8)
+                                       printk(KERN_WARNING "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
+               }
+       }
+       else {
+               if (DebugVar & 1)
+                       printk(KERN_ERR "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
+       }
+   if (free_buff) dev_kfree_skb(skb);
+}
+
+void
+idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
+{
+       int j;
+        eicon_RC *ack = (eicon_RC *)skb->data;
+       eicon_chan *chan;
+       isdn_ctrl cmd;
+
+       if ((ack->Rc != ASSIGN_OK) && (ack->Rc != OK)) {
+               if ((chan = ccard->IdTable[ack->RcId]) != NULL) {
+                       chan->e.busy = 0;
+                       if (DebugVar & 24)
+                               printk(KERN_ERR "eicon_ack: Ch%d: Not OK: Rc=%d Id=%d Ch=%d\n", chan->No, 
+                                       ack->Rc, ack->RcId, ack->RcCh);
+                       if (chan->No == ccard->nchannels) { /* Management */
+                               chan->fsm_state = 2;
+                       } else {        /* any other channel */
+                                       /* card reports error: we hangup */
+                               idi_hangup(ccard, chan);
+                               cmd.driver = ccard->myid;
+                               cmd.command = ISDN_STAT_DHUP;
+                               cmd.arg = chan->No;
+                               ccard->interface.statcallb(&cmd);
+                       }
+               }
+       } 
+       else {
+               if ((chan = ccard->IdTable[ack->RcId]) != NULL) {
+                       if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
+                               if (DebugVar & 16)
+                                       printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, 
+                                               ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
+                       } else {        
+                               if (chan->No == ccard->nchannels) { /* Management */
+                                       if (chan->e.Req == 0x04) chan->fsm_state = 1;
+                               }
+                               if (chan->e.ReqCh) {
+                                       switch(chan->e.Req & 0x0f) {
+                                               case IDI_N_MDATA:
+                                               case IDI_N_DATA:
+                                                       chan->queued -= chan->waitq;
+                                                       if (chan->queued < 0) chan->queued = 0;
+                                                       if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
+                                                               cmd.driver = ccard->myid;
+                                                               cmd.command = ISDN_STAT_BSENT;
+                                                               cmd.arg = chan->No;
+                                                               cmd.parm.length = chan->waitpq;
+                                                               chan->waitpq = 0;
+                                                               ccard->interface.statcallb(&cmd);
+                                                       }
+                                                       break;
+                                               default:
+                                                       if (DebugVar & 16)
+                                                               printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No,
+                                                                       ack->RcId, ack->RcCh, ack->Reference);
+                                       }
+                               } 
+                               else {
+                                       if (DebugVar & 16)
+                                               printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No,
+                                                       ack->RcId, ack->RcCh, ack->Reference);
+                               }
+
+                               if (chan->e.Req == REMOVE) {
+                                       if (ack->Reference == chan->e.ref) {
+                                               ccard->IdTable[ack->RcId] = NULL;
+                                               if (DebugVar & 16)
+                                                       printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%d Ch=%d (%s)\n", chan->No,
+                                                               ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
+                                               if (!chan->e.ReqCh) 
+                                                       chan->e.D3Id = 0;
+                                               else
+                                                       chan->e.B2Id = 0;
+                                       }
+                                       else {
+                                               if (DebugVar & 16)
+                                                       printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
+                                                               ack->Reference, chan->e.ref);
+                                       }
+                               }
+                               chan->e.busy = 0;
+                       }
+               }
+               else {
+                       for(j = 0; j < ccard->nchannels + 1; j++) {
+                               if (ccard->bch[j].e.ref == ack->Reference) {
+                                       if (!ccard->bch[j].e.ReqCh) 
+                                               ccard->bch[j].e.D3Id  = ack->RcId;
+                                       else
+                                               ccard->bch[j].e.B2Id  = ack->RcId;
+                                       ccard->IdTable[ack->RcId] = &ccard->bch[j];
+                                       ccard->bch[j].e.busy = 0;
+                                       ccard->bch[j].e.ref = 0;
+                                       if (DebugVar & 16)
+                                               printk(KERN_DEBUG"idi_ack: Ch%d: Id %d assigned (%s)\n", j, 
+                                                       ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
+                                       break;
+                               }
+                       }               
+                       if (j > ccard->nchannels) {
+                               if (DebugVar & 24)
+                                       printk(KERN_DEBUG"idi_ack: Ch??: ref %d not found for Id %d\n", 
+                                               ack->Reference, ack->RcId);
+                       }
+               }
+       }
+  dev_kfree_skb(skb);
+  eicon_schedule_tx(ccard);
+}
+
+int
+idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb)
+{
+        struct sk_buff *xmit_skb;
+        struct sk_buff *skb2;
+        eicon_REQ *reqbuf;
+        eicon_chan_ptr *chan2;
+        int len, plen = 0, offset = 0;
+       unsigned long flags;
+
+        if (chan->fsm_state != EICON_STATE_ACTIVE) {
+               if (DebugVar & 1)
+                       printk(KERN_DEBUG"idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
+                return -ENODEV;
+       }
+
+        len = skb->len;
+       if (len > 2138) /* too much for the shared memory */
+               return -1;
+        if (!len)
+                return 0;
+       if (chan->queued + len > ((chan->l2prot == ISDN_PROTO_L2_TRANS) ? 4000 : EICON_MAX_QUEUED))
+               return 0;
+       if (DebugVar & 128)
+               printk(KERN_DEBUG"idi_snd: Ch%d: %d bytes\n", chan->No, len);
+       save_flags(flags);
+       cli();
+       while(offset < len) {
+
+               plen = ((len - offset) > 270) ? 270 : len - offset;
+
+               xmit_skb = alloc_skb(plen + sizeof(eicon_REQ), GFP_ATOMIC);
+               skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+               if ((!skb) || (!skb2)) {
+                       restore_flags(flags);
+                       if (DebugVar & 1)
+                               printk(KERN_WARNING "idi_err: Ch%d: alloc_skb failed\n", chan->No);
+                       return -ENOMEM;
+               }
+
+               chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+               chan2->ptr = chan;
+
+               reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ));
+               if (((len - offset) > 270) &&
+                       (chan->l2prot != ISDN_PROTO_L2_TRANS)) {
+                       reqbuf->Req = IDI_N_MDATA;
+               } else {
+                       reqbuf->Req = IDI_N_DATA;
+                       if (ack) reqbuf->Req |= N_D_BIT;
+               }       
+               reqbuf->ReqCh = 0;
+               reqbuf->ReqId = 1;
+               memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen);
+               reqbuf->XBuffer.length = plen;
+               reqbuf->Reference = 1; /* Net Entity */
+
+               skb_queue_tail(&chan->e.X, xmit_skb);
+               skb_queue_tail(&card->sndq, skb2); 
+
+               offset += plen;
+       }
+       chan->queued += len;
+       restore_flags(flags);
+       eicon_schedule_tx(card);
+        dev_kfree_skb(skb);
+        return len;
+}
+
+
+
+int
+eicon_idi_manage_assign(eicon_card *card)
+{
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+        eicon_REQ  *reqbuf;
+        eicon_chan     *chan;
+        eicon_chan_ptr *chan2;
+
+        chan = &(card->bch[card->nchannels]);
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "idi_err: alloc_skb failed\n");
+                return -ENOMEM;
+        }
+
+        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+        chan2->ptr = chan;
+
+        reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+
+        reqbuf->XBuffer.P[0] = 0;
+        reqbuf->Req = ASSIGN;
+        reqbuf->ReqCh = 0;
+        reqbuf->ReqId = 0xe0;
+        reqbuf->XBuffer.length = 1;
+        reqbuf->Reference = 2; /* Man Entity */
+
+        skb_queue_tail(&chan->e.X, skb);
+        skb_queue_tail(&card->sndq, skb2);
+        eicon_schedule_tx(card);
+        return(0);
+}
+
+
+int
+eicon_idi_manage_remove(eicon_card *card)
+{
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+        eicon_REQ  *reqbuf;
+        eicon_chan     *chan;
+        eicon_chan_ptr *chan2;
+
+        chan = &(card->bch[card->nchannels]);
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "idi_err: alloc_skb failed\n");
+                return -ENOMEM;
+        }
+
+        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+        chan2->ptr = chan;
+
+        reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+
+        reqbuf->Req = REMOVE;
+        reqbuf->ReqCh = 0;
+        reqbuf->ReqId = 1;
+        reqbuf->XBuffer.length = 0;
+        reqbuf->Reference = 2; /* Man Entity */
+
+        skb_queue_tail(&chan->e.X, skb);
+        skb_queue_tail(&card->sndq, skb2);
+        eicon_schedule_tx(card);
+        return(0);
+}
+
+
+int
+eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
+{
+       int l = 0;
+       int ret = 0;
+       int timeout;
+       int i;
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+        eicon_REQ  *reqbuf;
+        eicon_chan     *chan;
+        eicon_chan_ptr *chan2;
+
+        chan = &(card->bch[card->nchannels]);
+
+       if (chan->e.D3Id) return -EBUSY;
+       chan->e.D3Id = 1;
+       while((skb2 = skb_dequeue(&chan->e.X)))
+               dev_kfree_skb(skb2);
+       chan->e.busy = 0;
+       if ((ret = eicon_idi_manage_assign(card))) {
+               chan->e.D3Id = 0;
+               return(ret); 
+       }
+
+        timeout = jiffies + 50;
+        while (timeout > jiffies) {
+                if (chan->e.B2Id) break;
+                SLEEP(10);
+        }
+        if (!chan->e.B2Id) {
+               chan->e.D3Id = 0;
+               return -EIO;
+       }
+
+       chan->fsm_state = 0;
+
+       if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "idi_err: alloc_manifbuf failed\n");
+               chan->e.D3Id = 0;
+               return -ENOMEM;
+       }
+       if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) {
+               chan->e.D3Id = 0;
+               return -EFAULT;
+       }
+
+        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
+        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
+
+        if ((!skb) || (!skb2)) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "idi_err_manif: alloc_skb failed\n");
+               kfree(manbuf);
+               chan->e.D3Id = 0;
+                return -ENOMEM;
+        }
+
+        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
+        chan2->ptr = chan;
+
+        reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
+
+        reqbuf->XBuffer.P[l++] = ESC;
+        reqbuf->XBuffer.P[l++] = 6;
+        reqbuf->XBuffer.P[l++] = 0x80;
+       for (i = 0; i < manbuf->length[0]; i++)
+               reqbuf->XBuffer.P[l++] = manbuf->data[i];
+        reqbuf->XBuffer.P[1] = manbuf->length[0] + 1;
+
+        reqbuf->XBuffer.P[l++] = 0;
+        reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */
+        reqbuf->ReqCh = 0;
+        reqbuf->ReqId = 1;
+        reqbuf->XBuffer.length = l;
+        reqbuf->Reference = 2; /* Man Entity */
+
+        skb_queue_tail(&chan->e.X, skb);
+        skb_queue_tail(&card->sndq, skb2);
+
+       manbuf->count = 0;
+       manbuf->pos = 0;
+
+        eicon_schedule_tx(card);
+
+        timeout = jiffies + 50;
+        while (timeout > jiffies) {
+                if (chan->fsm_state) break;
+                SLEEP(10);
+        }
+        if ((!chan->fsm_state) || (chan->fsm_state == 2)) {
+               eicon_idi_manage_remove(card);
+               kfree(manbuf);
+               chan->e.D3Id = 0;
+               return -EIO;
+       }
+
+       if ((ret = eicon_idi_manage_remove(card))) {
+               chan->e.D3Id = 0;
+               return(ret);
+       }
+
+       if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) {
+               chan->e.D3Id = 0;
+               return -EFAULT;
+       }
+
+       kfree(manbuf);
+       chan->e.D3Id = 0;
+  return(0);
+}
diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h
new file mode 100644 (file)
index 0000000..a0605cd
--- /dev/null
@@ -0,0 +1,248 @@
+/* $Id: eicon_idi.h,v 1.4 1999/03/29 11:19:44 armin Exp $
+ *
+ * ISDN lowlevel-module for the Eicon.Diehl active cards.
+ * IDI-Interface
+ *
+ * Copyright 1998,99 by Armin Schindler (mac@melware.de)
+ * Copyright 1999    Cytronics & Melware (info@melware.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: eicon_idi.h,v $
+ * Revision 1.4  1999/03/29 11:19:44  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.3  1999/03/02 12:37:45  armin
+ * Added some important checks.
+ * Analog Modem with DSP.
+ * Channels will be added to Link-Level after loading firmware.
+ *
+ * Revision 1.2  1999/01/24 20:14:18  armin
+ * Changed and added debug stuff.
+ * Better data sending. (still problems with tty's flip buffer)
+ *
+ * Revision 1.1  1999/01/01 18:09:42  armin
+ * First checkin of new eicon driver.
+ * DIVA-Server BRI/PCI and PRI/PCI are supported.
+ * Old diehl code is obsolete.
+ *
+ *
+ */
+
+#ifndef IDI_H
+#define IDI_H
+
+
+#define ASSIGN  0x01
+#define REMOVE  0xff
+       
+#define CALL_REQ 1      /* call request                             */
+#define CALL_CON 1      /* call confirmation                        */
+#define CALL_IND 2      /* incoming call connected                  */
+#define LISTEN_REQ 2    /* listen request                           */
+#define HANGUP 3        /* hangup request/indication                */
+#define SUSPEND 4       /* call suspend request/confirm             */
+#define RESUME 5        /* call resume request/confirm              */
+#define SUSPEND_REJ 6   /* suspend rejected indication              */
+#define USER_DATA 8     /* user data for user to user signaling     */
+#define CONGESTION 9    /* network congestion indication            */
+#define INDICATE_REQ 10 /* request to indicate an incoming call     */
+#define INDICATE_IND 10 /* indicates that there is an incoming call */
+#define CALL_RES 11     /* accept an incoming call                  */
+#define CALL_ALERT 12   /* send ALERT for incoming call             */
+#define INFO_REQ 13     /* INFO request                             */
+#define INFO_IND 13     /* INFO indication                          */
+#define REJECT 14       /* reject an incoming call                  */
+#define RESOURCES 15    /* reserve B-Channel hardware resources     */
+#define TEL_CTRL 16     /* Telephone control request/indication     */
+#define STATUS_REQ 17   /* Request D-State (returned in INFO_IND)   */
+#define FAC_REG_REQ 18  /* connection idependent fac registration   */
+#define FAC_REG_ACK 19  /* fac registration acknowledge             */
+#define FAC_REG_REJ 20  /* fac registration reject                  */
+#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call       */
+#define AOC_IND       26/* Advice of Charge                         */
+
+#define IDI_N_MDATA         (0x01)
+#define IDI_N_CONNECT       (0x02)
+#define IDI_N_CONNECT_ACK   (0x03)
+#define IDI_N_DISC          (0x04)
+#define IDI_N_DISC_ACK      (0x05)
+#define IDI_N_RESET         (0x06)
+#define IDI_N_RESET_ACK     (0x07)
+#define IDI_N_DATA          (0x08)
+#define IDI_N_EDATA         (0x09)
+#define IDI_N_UDATA         (0x0a)
+#define IDI_N_BDATA         (0x0b)
+#define IDI_N_DATA_ACK      (0x0c)
+#define IDI_N_EDATA_ACK     (0x0d)
+
+#define N_Q_BIT         0x10    /* Q-bit for req/ind                */
+#define N_M_BIT         0x20    /* M-bit for req/ind                */
+#define N_D_BIT         0x40    /* D-bit for req/ind                */
+
+
+#define SHIFT 0x90              /* codeset shift                    */
+#define MORE 0xa0               /* more data                        */
+#define CL 0xb0                 /* congestion level                 */
+
+        /* codeset 0                                                */
+
+#define BC  0x04                /* Bearer Capability                */
+#define CAU 0x08                /* cause                            */
+#define CAD 0x0c                /* Connected address                */
+#define CAI 0x10                /* call identity                    */
+#define CHI 0x18                /* channel identification           */
+#define LLI 0x19                /* logical link id                  */
+#define CHA 0x1a                /* charge advice                    */
+#define FTY 0x1c
+#define PI  0x1e               /* Progress Indicator               */
+#define NI  0x27               /* Notification Indicator           */
+#define DT  0x29                /* ETSI date/time                   */
+#define KEY 0x2c                /* keypad information element       */
+#define DSP 0x28                /* display                          */
+#define OAD 0x6c                /* origination address              */
+#define OSA 0x6d                /* origination sub-address          */
+#define CPN 0x70                /* called party number              */
+#define DSA 0x71                /* destination sub-address          */
+#define RDN 0x74               /* redirecting number               */
+#define LLC 0x7c                /* low layer compatibility          */
+#define HLC 0x7d                /* high layer compatibility         */
+#define UUI 0x7e                /* user user information            */
+#define ESC 0x7f                /* escape extension                 */
+
+#define DLC 0x20                /* data link layer configuration    */
+#define NLC 0x21                /* network layer configuration      */
+
+        /* codeset 6                                                */
+
+#define SIN 0x01                /* service indicator                */
+#define CIF 0x02                /* charging information             */
+#define DATE 0x03               /* date                             */
+#define CPS 0x07                /* called party status              */
+
+/*------------------------------------------------------------------*/
+/* return code coding                                               */
+/*------------------------------------------------------------------*/
+
+#define UNKNOWN_COMMAND         0x01    /* unknown command          */
+#define WRONG_COMMAND           0x02    /* wrong command            */
+#define WRONG_ID                0x03    /* unknown task/entity id   */
+#define WRONG_CH                0x04    /* wrong task/entity id     */
+#define UNKNOWN_IE              0x05    /* unknown information el.  */
+#define WRONG_IE                0x06    /* wrong information el.    */
+#define OUT_OF_RESOURCES        0x07    /* card out of res.         */
+#define N_FLOW_CONTROL          0x10    /* Flow-Control, retry      */
+#define ASSIGN_RC               0xe0    /* ASSIGN acknowledgement   */
+#define ASSIGN_OK               0xef    /* ASSIGN OK                */
+#define OK_FC                   0xfc    /* Flow-Control RC          */
+#define READY_INT               0xfd    /* Ready interrupt          */
+#define TIMER_INT               0xfe    /* timer interrupt          */
+#define OK                      0xff    /* command accepted         */
+
+/*------------------------------------------------------------------*/
+
+typedef struct {
+       char cpn[32];
+       char oad[32];
+       char dsa[32];
+       char osa[32];
+       __u8 plan;
+       __u8 screen;
+       __u8 sin[4];
+       __u8 chi[4];
+       __u8 e_chi[4];
+       __u8 bc[12];
+       __u8 e_bc[12];
+       __u8 llc[18];
+       __u8 hlc[5];
+       __u8 cau[4];
+       __u8 e_cau[2];
+       __u8 e_mt;
+       __u8 dt[6];
+       char display[83];
+       char keypad[35];
+       char rdn[32];
+} idi_ind_message;
+
+typedef struct { 
+  __u16 next            __attribute__ ((packed));
+  __u8  Req             __attribute__ ((packed));
+  __u8  ReqId           __attribute__ ((packed));
+  __u8  ReqCh           __attribute__ ((packed));
+  __u8  Reserved1       __attribute__ ((packed));
+  __u16 Reference       __attribute__ ((packed));
+  __u8  Reserved[8]     __attribute__ ((packed));
+  eicon_PBUFFER XBuffer; 
+} eicon_REQ;
+
+typedef struct {
+  __u16 next            __attribute__ ((packed));
+  __u8  Rc              __attribute__ ((packed));
+  __u8  RcId            __attribute__ ((packed));
+  __u8  RcCh            __attribute__ ((packed));
+  __u8  Reserved1       __attribute__ ((packed));
+  __u16 Reference       __attribute__ ((packed));
+  __u8  Reserved2[8]    __attribute__ ((packed));
+} eicon_RC;
+
+typedef struct {
+  __u16 next            __attribute__ ((packed));
+  __u8  Ind             __attribute__ ((packed));
+  __u8  IndId           __attribute__ ((packed));
+  __u8  IndCh           __attribute__ ((packed));
+  __u8  MInd            __attribute__ ((packed));
+  __u16 MLength         __attribute__ ((packed));
+  __u16 Reference       __attribute__ ((packed));
+  __u8  RNR             __attribute__ ((packed));
+  __u8  Reserved        __attribute__ ((packed));
+  __u32 Ack             __attribute__ ((packed));
+  eicon_PBUFFER RBuffer;
+} eicon_IND;
+
+typedef struct {
+  __u16 NextReq  __attribute__ ((packed));  /* pointer to next Req Buffer */
+  __u16 NextRc   __attribute__ ((packed));  /* pointer to next Rc Buffer  */
+  __u16 NextInd  __attribute__ ((packed));  /* pointer to next Ind Buffer */
+  __u8 ReqInput  __attribute__ ((packed));  /* number of Req Buffers sent */
+  __u8 ReqOutput  __attribute__ ((packed)); /* number of Req Buffers returned */
+  __u8 ReqReserved  __attribute__ ((packed));/*number of Req Buffers reserved */
+  __u8 Int  __attribute__ ((packed));       /* ISDN-P interrupt           */
+  __u8 XLock  __attribute__ ((packed));     /* Lock field for arbitration */
+  __u8 RcOutput  __attribute__ ((packed));  /* number of Rc buffers received */
+  __u8 IndOutput  __attribute__ ((packed)); /* number of Ind buffers received */
+  __u8 IMask  __attribute__ ((packed));     /* Interrupt Mask Flag        */
+  __u8 Reserved1[2]  __attribute__ ((packed)); /* reserved field, do not use */
+  __u8 ReadyInt  __attribute__ ((packed));  /* request field for ready int */
+  __u8 Reserved2[12]  __attribute__ ((packed)); /* reserved field, do not use */
+  __u8 InterfaceType  __attribute__ ((packed)); /* interface type 1=16K    */
+  __u16 Signature  __attribute__ ((packed));    /* ISDN-P initialized ind  */
+  __u8 B[1];                            /* buffer space for Req,Ind and Rc */
+} eicon_pr_ram;
+
+
+extern int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer);
+extern int idi_hangup(eicon_card *card, eicon_chan *chan);
+extern int idi_connect_res(eicon_card *card, eicon_chan *chan);
+extern int eicon_idi_listen_req(eicon_card *card, eicon_chan *chan);
+extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
+                           char *eazmsn, int si1, int si2);
+
+extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
+extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
+extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
+extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb);
+
+#endif
diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c
new file mode 100644 (file)
index 0000000..1c69d37
--- /dev/null
@@ -0,0 +1,755 @@
+/* $Id: eicon_io.c,v 1.1 1999/03/29 11:19:45 armin Exp $
+ *
+ * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * Code for communicating with hardware.
+ *
+ * Copyright 1999    by Armin Schindler (mac@melware.de)
+ * Copyright 1999    Cytronics & Melware (info@melware.de)
+ *
+ * Thanks to   Eicon Technology Diehl GmbH & Co. oHG for 
+ *             documents, informations and hardware. 
+ *
+ * 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: eicon_io.c,v $
+ * Revision 1.1  1999/03/29 11:19:45  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ *
+ */
+
+
+#include "eicon.h"
+
+void
+eicon_io_rcv_dispatch(eicon_card *ccard) {
+        struct sk_buff *skb, *skb2, *skb_new;
+        eicon_IND *ind, *ind2, *ind_new;
+        eicon_chan *chan;
+
+        if (!ccard) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "eicon_io_rcv_dispatch: NULL card!\n");
+                return;
+        }
+
+       while((skb = skb_dequeue(&ccard->rcvq))) {
+               ind = (eicon_IND *)skb->data;
+
+               if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+                       if (DebugVar & 1) {
+                               switch(ind->Ind) {
+                                       case IDI_N_DISC_ACK: 
+                                               /* doesn't matter if this happens */ 
+                                               break;
+                                       default: 
+                                               printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%d\n", ind->Ind, ind->IndId);
+                                               printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
+                                                       ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
+                               }
+                       }
+                       dev_kfree_skb(skb);
+                       continue;
+               }
+
+               if (chan->e.complete) { /* check for rec-buffer chaining */
+                       if (ind->MLength == ind->RBuffer.length) {
+                               chan->e.complete = 1;
+                               idi_handle_ind(ccard, skb);
+                               continue;
+                       }
+                       else {
+                               chan->e.complete = 0;
+                               ind->Ind = ind->MInd;
+                               skb_queue_tail(&chan->e.R, skb);
+                               continue;
+                       }
+               }
+               else {
+                       if (!(skb2 = skb_dequeue(&chan->e.R))) {
+                               chan->e.complete = 1;
+                               if (DebugVar & 1)
+                                       printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n");
+                               dev_kfree_skb(skb);
+                               dev_kfree_skb(skb2);
+                               continue;       
+                       }
+                       ind2 = (eicon_IND *)skb2->data;
+                       skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length),
+                                       GFP_ATOMIC);
+                       ind_new = (eicon_IND *)skb_put(skb_new,
+                                       ((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length));
+                       ind_new->Ind = ind2->Ind;
+                       ind_new->IndId = ind2->IndId;
+                       ind_new->IndCh = ind2->IndCh;
+                       ind_new->MInd = ind2->MInd;
+                       ind_new->MLength = ind2->MLength;
+                       ind_new->RBuffer.length = ind2->RBuffer.length + ind->RBuffer.length;
+                       memcpy(&ind_new->RBuffer.P, &ind2->RBuffer.P, ind2->RBuffer.length);
+                       memcpy((&ind_new->RBuffer.P)+ind2->RBuffer.length, &ind->RBuffer.P, ind->RBuffer.length);
+                       dev_kfree_skb(skb);
+                       dev_kfree_skb(skb2);
+                       if (ind->MLength == ind->RBuffer.length) {
+                               chan->e.complete = 2;
+                               idi_handle_ind(ccard, skb_new);
+                               continue;
+                       }
+                       else {
+                               chan->e.complete = 0;
+                               skb_queue_tail(&chan->e.R, skb_new);
+                               continue;
+                       }
+               }
+       }
+}
+
+void
+eicon_io_ack_dispatch(eicon_card *ccard) {
+        struct sk_buff *skb;
+
+        if (!ccard) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "eicon_io_ack_dispatch: NULL card!\n");
+                return;
+        }
+       while((skb = skb_dequeue(&ccard->rackq))) {
+               idi_handle_ack(ccard, skb);
+       }
+}
+
+
+/*
+ *  IO-Functions for different card-types
+ */
+
+u8 ram_inb(eicon_card *card, void *adr) {
+        eicon_pci_card *pcard;
+        eicon_isa_card *icard;
+        u32 addr = (u32) adr;
+       
+       pcard = &card->hwif.pci;
+       icard = &card->hwif.isa;
+
+        switch(card->type) {
+                case EICON_CTYPE_MAESTRA:
+                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
+                        return(inb((u16)pcard->PCIreg + M_DATA));
+                case EICON_CTYPE_MAESTRAP:
+                case EICON_CTYPE_S2M:
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+                        return(readb(addr));
+        }
+ return(0);
+}
+
+u16 ram_inw(eicon_card *card, void *adr) {
+        eicon_pci_card *pcard;
+        eicon_isa_card *icard;
+        u32 addr = (u32) adr;
+       
+       pcard = &card->hwif.pci;
+       icard = &card->hwif.isa;
+
+        switch(card->type) {
+                case EICON_CTYPE_MAESTRA:
+                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
+                        return(inw((u16)pcard->PCIreg + M_DATA));
+                case EICON_CTYPE_MAESTRAP:
+                case EICON_CTYPE_S2M:
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+                        return(readw(addr));
+        }
+ return(0);
+}
+
+void ram_outb(eicon_card *card, void *adr, u8 data) {
+        eicon_pci_card *pcard;
+        eicon_isa_card *icard;
+        u32 addr = (u32) adr;
+
+       pcard = &card->hwif.pci;
+       icard = &card->hwif.isa;
+
+        switch(card->type) {
+                case EICON_CTYPE_MAESTRA:
+                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
+                        outb((u8)data, (u16)pcard->PCIreg + M_DATA);
+                        break;
+                case EICON_CTYPE_MAESTRAP:
+                case EICON_CTYPE_S2M:
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+                        writeb(data, addr);
+                        break;
+        }
+}
+
+void ram_outw(eicon_card *card, void *adr , u16 data) {
+        eicon_pci_card *pcard;
+        eicon_isa_card *icard;
+        u32 addr = (u32) adr;
+
+       pcard = &card->hwif.pci;
+       icard = &card->hwif.isa;
+
+        switch(card->type) {
+                case EICON_CTYPE_MAESTRA:
+                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
+                        outw((u16)data, (u16)pcard->PCIreg + M_DATA);
+                        break;
+                case EICON_CTYPE_MAESTRAP:
+                case EICON_CTYPE_S2M:
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+                        writew(data, addr);
+                        break;
+        }
+}
+
+void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) {
+        int i;
+        switch(card->type) {
+                case EICON_CTYPE_MAESTRA:
+                        for(i = 0; i < len; i++) {
+                                writeb(ram_inb(card, adr + i), adrto + i);
+                        }
+                        break;
+                case EICON_CTYPE_MAESTRAP:
+                        memcpy(adrto, adr, len);
+                        break;
+                case EICON_CTYPE_S2M:
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+                        memcpy_fromio(adrto, adr, len);
+                        break;
+        }
+}
+
+void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) {
+        int i;
+        switch(card->type) {
+                case EICON_CTYPE_MAESTRA:
+                        for(i = 0; i < len; i++) {
+                                ram_outb(card, adrto + i, readb(adr + i));
+                        }
+                        break;
+                case EICON_CTYPE_MAESTRAP:
+                        memcpy(adrto, adr, len);
+                        break;
+                case EICON_CTYPE_S2M:
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+                        memcpy_toio(adrto, adr, len);
+                        break;
+        }
+}
+
+/*
+ *  Transmit-Function
+ */
+void
+eicon_io_transmit(eicon_card *ccard) {
+        eicon_pci_card *pci_card;
+        eicon_isa_card *isa_card;
+        struct sk_buff *skb;
+        struct sk_buff *skb2;
+        unsigned long flags;
+        char *ram, *reg, *cfg;
+       eicon_pr_ram  *prram = 0;
+       eicon_isa_com   *com = 0;
+       eicon_REQ *ReqOut = 0;
+       eicon_REQ *reqbuf = 0;
+       eicon_chan *chan;
+       eicon_chan_ptr *chan2;
+       int ReqCount;
+       int scom = 0;
+       int tmp = 0;
+       int quloop = 1;
+
+       pci_card = &ccard->hwif.pci;
+       isa_card = &ccard->hwif.isa;
+
+        if (!ccard) {
+               if (DebugVar & 1)
+                       printk(KERN_WARNING "eicon_transmit: NULL card!\n");
+                return;
+        }
+
+       switch(ccard->type) {
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+                       scom = 1;
+                       com = (eicon_isa_com *)isa_card->shmem;
+                       break;
+               case EICON_CTYPE_S2M:
+                       scom = 0;
+                       prram = (eicon_pr_ram *)isa_card->shmem;
+                       break;
+               case EICON_CTYPE_MAESTRAP:
+                       scom = 0;
+                       ram = (char *)pci_card->PCIram;
+                       reg = (char *)pci_card->PCIreg;
+                       cfg = (char *)pci_card->PCIcfg;
+                       prram = (eicon_pr_ram *)ram;
+                       break;
+               case EICON_CTYPE_MAESTRA:
+                       scom = 0;
+                       ram = (char *)pci_card->PCIram;
+                       reg = (char *)pci_card->PCIreg;
+                       cfg = (char *)pci_card->PCIcfg;
+                       prram = 0;
+                       break;
+               default:
+                       printk(KERN_WARNING "eicon_transmit: unsupported card-type!\n");
+                       return;
+       }
+
+       ReqCount = 0;
+       if (!(skb2 = skb_dequeue(&ccard->sndq)))
+               quloop = 0; 
+       while(quloop) { 
+                save_flags(flags);
+                cli();
+               if (scom) {
+                       if (ram_inb(ccard, &com->Req)) {
+                               if (!ccard->ReadyInt) {
+                                       tmp = ram_inb(ccard, &com->ReadyInt) + 1;
+                                       ram_outb(ccard, &com->ReadyInt, tmp);
+                                       ccard->ReadyInt++;
+                               }
+                               restore_flags(flags);
+                               skb_queue_head(&ccard->sndq, skb2);
+                               if (DebugVar & 32)
+                                       printk(KERN_INFO "eicon: transmit: Card not ready\n");
+                               return;
+                       }
+               } else {
+                       if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) {
+                               restore_flags(flags);
+                               skb_queue_head(&ccard->sndq, skb2);
+                               if (DebugVar & 32)
+                                       printk(KERN_INFO "eicon: transmit: Card not ready\n");
+                               return;
+                       }
+               }
+               restore_flags(flags);
+               chan2 = (eicon_chan_ptr *)skb2->data;
+               chan = chan2->ptr;
+               if (!chan->e.busy) {
+                if((skb = skb_dequeue(&chan->e.X))) { 
+                       save_flags(flags);
+                       cli();
+                       reqbuf = (eicon_REQ *)skb->data;
+                       if (scom) {
+                               ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
+                               ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
+                               ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh);
+                               
+                       } else {
+                               /* get address of next available request buffer */
+                               ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)];
+                               ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length);
+                               ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
+                               ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh);
+                               ram_outb(ccard, &ReqOut->Req, reqbuf->Req); 
+                       }
+
+                       if (reqbuf->ReqId &0x1f) { /* if this is no ASSIGN */
+
+                               if (!reqbuf->Reference) { /* Signal Layer */
+                                       if (scom)
+                                               ram_outb(ccard, &com->ReqId, chan->e.D3Id); 
+                                       else
+                                               ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); 
+
+                                       chan->e.ReqCh = 0; 
+                               }
+                               else {                  /* Net Layer */
+                                       if (scom)
+                                               ram_outb(ccard, &com->ReqId, chan->e.B2Id); 
+                                       else
+                                               ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); 
+
+                                       chan->e.ReqCh = 1;
+                                       if (((reqbuf->Req & 0x0f) == 0x08) ||
+                                          ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
+                                               chan->waitq = reqbuf->XBuffer.length;
+                                               chan->waitpq += reqbuf->XBuffer.length;
+                                       }
+                               }
+
+                       } else {        /* It is an ASSIGN */
+
+                               if (scom)
+                                       ram_outb(ccard, &com->ReqId, reqbuf->ReqId); 
+                               else
+                                       ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); 
+
+                               if (!reqbuf->Reference) 
+                                       chan->e.ReqCh = 0; 
+                                else
+                                       chan->e.ReqCh = 1; 
+                       } 
+                       if (scom)
+                               chan->e.ref = ccard->ref_out++;
+                       else
+                               chan->e.ref = ram_inw(ccard, &ReqOut->Reference);
+
+                       chan->e.Req = reqbuf->Req;
+                       ReqCount++; 
+                       if (scom)
+                               ram_outb(ccard, &com->Req, reqbuf->Req); 
+                       else
+                               ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); 
+
+                       chan->e.busy = 1; 
+                       restore_flags(flags);
+                       if (DebugVar & 32)
+                               printk(KERN_DEBUG "eicon: Req=%x Id=%x Ch=%x Len=%x Ref=%d\n", 
+                                                       reqbuf->Req, 
+                                                       ram_inb(ccard, &ReqOut->ReqId),
+                                                       reqbuf->ReqCh, reqbuf->XBuffer.length,
+                                                       chan->e.ref); 
+                       dev_kfree_skb(skb);
+                }
+                dev_kfree_skb(skb2);
+               } 
+               else {
+               skb_queue_tail(&ccard->sackq, skb2);
+               if (DebugVar & 32)
+                       printk(KERN_INFO "eicon: transmit: busy chan %d\n", chan->No); 
+               }
+
+               if (scom)
+                       quloop = 0;
+               else
+                       if (!(skb2 = skb_dequeue(&ccard->sndq)))
+                               quloop = 0;
+
+       }
+       if (!scom)
+               ram_outb(ccard, &prram->ReqInput, (__u8)(ram_inb(ccard, &prram->ReqInput) + ReqCount)); 
+
+       while((skb = skb_dequeue(&ccard->sackq))) { 
+               skb_queue_tail(&ccard->sndq, skb);
+       }
+}
+
+
+/*
+ * IRQ handler 
+ */
+void
+eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
+       eicon_card *ccard = (eicon_card *)dev_id;
+        eicon_pci_card *pci_card;
+        eicon_isa_card *isa_card;
+       char *ram = 0;
+       char *reg = 0;
+       char *cfg = 0;  
+       eicon_pr_ram  *prram = 0;
+       eicon_isa_com   *com = 0;
+        eicon_RC *RcIn;
+        eicon_IND *IndIn;
+       struct sk_buff *skb;
+        int Count = 0;
+       int Rc = 0;
+       int Ind = 0;
+       unsigned char *irqprobe = 0;
+       int scom = 0;
+       int tmp = 0;
+
+
+        if (!ccard) {
+                printk(KERN_WARNING "eicon_irq: spurious interrupt %d\n", irq);
+                return;
+        }
+
+       if (ccard->type == EICON_CTYPE_QUADRO) {
+               tmp = 4;
+               while(tmp) {
+                       com = (eicon_isa_com *)ccard->hwif.isa.shmem;
+                       if ((readb(ccard->hwif.isa.intack))) { /* quadro found */
+                               break;
+                       }
+                       ccard = ccard->qnext;
+                       tmp--;
+               }
+       }
+
+       pci_card = &ccard->hwif.pci;
+       isa_card = &ccard->hwif.isa;
+
+       switch(ccard->type) {
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+                       scom = 1;
+                       com = (eicon_isa_com *)isa_card->shmem;
+                       irqprobe = &isa_card->irqprobe;
+                       break;
+               case EICON_CTYPE_S2M:
+                       scom = 0;
+                       prram = (eicon_pr_ram *)isa_card->shmem;
+                       irqprobe = &isa_card->irqprobe;
+                       break;
+               case EICON_CTYPE_MAESTRAP:
+                       scom = 0;
+                       ram = (char *)pci_card->PCIram;
+                       reg = (char *)pci_card->PCIreg;
+                       cfg = (char *)pci_card->PCIcfg;
+                       irqprobe = &pci_card->irqprobe;
+                       prram = (eicon_pr_ram *)ram;
+                       break;
+               case EICON_CTYPE_MAESTRA:
+                       scom = 0;
+                       ram = (char *)pci_card->PCIram;
+                       reg = (char *)pci_card->PCIreg;
+                       cfg = (char *)pci_card->PCIcfg;
+                       irqprobe = &pci_card->irqprobe;
+                       prram = 0;
+                       break;
+               default:
+                       printk(KERN_WARNING "eicon_irq: unsupported card-type!\n");
+                       return;
+       }
+
+       if (*irqprobe) {
+               switch(ccard->type) {
+                       case EICON_CTYPE_S:
+                       case EICON_CTYPE_SX:
+                       case EICON_CTYPE_SCOM:
+                       case EICON_CTYPE_QUADRO:
+                               if (readb(isa_card->intack)) {
+                                       writeb(0, &com->Rc);
+                                       writeb(0, isa_card->intack);
+                               }
+                               (*irqprobe)++;
+                               break;
+                       case EICON_CTYPE_S2M:
+                               if (readb(isa_card->intack)) {
+                                       writeb(0, &prram->RcOutput);
+                                       writeb(0, isa_card->intack);
+                               }
+                               (*irqprobe)++;
+                               break;
+                       case EICON_CTYPE_MAESTRAP:
+                               if (readb(&ram[0x3fe])) { 
+                                       writeb(0, &prram->RcOutput);
+                                       writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
+                                       writew(0, &cfg[MP_IRQ_RESET + 2]);
+                                       writeb(0, &ram[0x3fe]);
+                                       } 
+                               *irqprobe = 0;
+                               break;
+                       case EICON_CTYPE_MAESTRA:
+                               outb(0x08, pci_card->PCIreg + M_RESET);
+                               *irqprobe = 0;
+                               break;
+               }
+               return;
+       }
+
+       switch(ccard->type) {
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+               case EICON_CTYPE_S2M:
+                       if (!(readb(isa_card->intack))) { /* card did not interrupt */
+                               if (DebugVar & 1)
+                                       printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n");
+                               return;
+                       } 
+                       break;
+               case EICON_CTYPE_MAESTRAP:
+                       if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
+                               if (DebugVar & 1)
+                                       printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n");
+                               return;
+                       } 
+                       break;
+               case EICON_CTYPE_MAESTRA:
+                       outw(0x3fe, pci_card->PCIreg + M_ADDR);
+                       if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */
+                               if (DebugVar & 1)
+                                       printk(KERN_DEBUG "eicon: IRQ: card tells no interrupt!\n");
+                               return;
+                       } 
+                       break;
+       }
+
+    if (scom) {
+
+        /* if a return code is available ...  */
+       if ((tmp = ram_inb(ccard, &com->Rc))) {
+               eicon_RC *ack;
+               if (tmp == READY_INT) {
+                       if (DebugVar & 64)
+                               printk(KERN_INFO "eicon: IRQ Rc=READY_INT\n");
+                       if (ccard->ReadyInt) {
+                               ccard->ReadyInt--;
+                               ram_outb(ccard, &com->Rc, 0);
+                       }
+               } else {
+                       skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
+                       ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+                       ack->Rc = tmp;
+                       ack->RcId = ram_inb(ccard, &com->RcId);
+                       ack->RcCh = ram_inb(ccard, &com->RcCh);
+                       ack->Reference = ccard->ref_in++;
+                       if (DebugVar & 64)
+                               printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n",
+                                       tmp,ack->RcId,ack->RcCh,ack->Reference);
+                       skb_queue_tail(&ccard->rackq, skb);
+                       eicon_schedule_ack(ccard);
+                       ram_outb(ccard, &com->Req, 0);
+                       ram_outb(ccard, &com->Rc, 0);
+               }
+
+       } else {
+
+               /* if an indication is available ...  */
+               if ((tmp = ram_inb(ccard, &com->Ind))) {
+                       eicon_IND *ind;
+                       int len = ram_inw(ccard, &com->RBuffer.length);
+                       skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
+                       ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+                       ind->Ind = tmp;
+                       ind->IndId = ram_inb(ccard, &com->IndId);
+                       ind->IndCh = ram_inb(ccard, &com->IndCh);
+                       ind->MInd  = ram_inb(ccard, &com->MInd);
+                       ind->MLength = ram_inw(ccard, &com->MLength);
+                       ind->RBuffer.length = len; 
+                       if (DebugVar & 64)
+                               printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
+                               tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
+                       ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len);
+                       skb_queue_tail(&ccard->rcvq, skb);
+                       eicon_schedule_rx(ccard);
+                       ram_outb(ccard, &com->Ind, 0);
+               }
+       }
+
+    } else {
+
+        /* if return codes are available ...  */
+        if((Count = ram_inb(ccard, &prram->RcOutput))) {
+               eicon_RC *ack;
+                /* get the buffer address of the first return code */
+                RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &prram->NextRc)];
+                /* for all return codes do ...  */
+                while(Count--) {
+
+                        if((Rc=ram_inb(ccard, &RcIn->Rc))) {
+                               skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
+                               ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+                               ack->Rc = Rc;
+                               ack->RcId = ram_inb(ccard, &RcIn->RcId);
+                               ack->RcCh = ram_inb(ccard, &RcIn->RcCh);
+                               ack->Reference = ram_inw(ccard, &RcIn->Reference);
+                               if (DebugVar & 64)
+                                       printk(KERN_INFO "eicon: IRQ Rc=%d Id=%d Ch=%d Ref=%d\n",
+                                               Rc,ack->RcId,ack->RcCh,ack->Reference);
+                               ram_outb(ccard, &RcIn->Rc, 0);
+                                skb_queue_tail(&ccard->rackq, skb);
+                                eicon_schedule_ack(ccard);
+                        }
+                        /* get buffer address of next return code   */
+                        RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &RcIn->next)];
+                }
+                /* clear all return codes (no chaining!) */
+                ram_outb(ccard, &prram->RcOutput, 0);
+        }
+
+        /* if indications are available ... */
+        if((Count = ram_inb(ccard, &prram->IndOutput))) {
+               eicon_IND *ind;
+                /* get the buffer address of the first indication */
+                IndIn = (eicon_IND *)&prram->B[ram_inw(ccard, &prram->NextInd)];
+                /* for all indications do ... */
+                while(Count--) {
+                       Ind = ram_inb(ccard, &IndIn->Ind);
+                       if(Ind) {
+                               int len = ram_inw(ccard, &IndIn->RBuffer.length);
+                               skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
+                               ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+                               ind->Ind = Ind;
+                               ind->IndId = ram_inb(ccard, &IndIn->IndId);
+                               ind->IndCh = ram_inb(ccard, &IndIn->IndCh);
+                               ind->MInd  = ram_inb(ccard, &IndIn->MInd);
+                               ind->MLength = ram_inw(ccard, &IndIn->MLength);
+                               ind->RBuffer.length = len;
+                               if (DebugVar & 64)
+                                       printk(KERN_INFO "eicon: IRQ Ind=%d Id=%d Ch=%d MInd=%d MLen=%d Len=%d\n",
+                                       Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
+                                ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len);
+                               skb_queue_tail(&ccard->rcvq, skb);
+                               eicon_schedule_rx(ccard);
+                               ram_outb(ccard, &IndIn->Ind, 0);
+                        }
+                        /* get buffer address of next indication  */
+                        IndIn = (eicon_IND *)&prram->B[ram_inw(ccard, &IndIn->next)];
+                }
+                ram_outb(ccard, &prram->IndOutput, 0);
+        }
+
+    } 
+
+       /* clear interrupt */
+       switch(ccard->type) {
+               case EICON_CTYPE_QUADRO:
+                       writeb(0, isa_card->intack);
+                       writeb(0, &com[0x401]);
+                       break;
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_S2M:
+                       writeb(0, isa_card->intack);
+                       break;
+               case EICON_CTYPE_MAESTRAP:
+                       writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
+                       writew(0, &cfg[MP_IRQ_RESET + 2]); 
+                       writeb(0, &ram[0x3fe]); 
+                       break;
+               case EICON_CTYPE_MAESTRA:
+                       outb(0x08, pci_card->PCIreg + M_RESET);
+                       outw(0x3fe, pci_card->PCIreg + M_ADDR);
+                       outb(0, pci_card->PCIreg + M_DATA);
+                       break;
+       }
+
+  return;
+}
+
diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c
new file mode 100644 (file)
index 0000000..184f1c3
--- /dev/null
@@ -0,0 +1,432 @@
+/* $Id: eicon_isa.c,v 1.5 1999/04/01 12:48:33 armin Exp $
+ *
+ * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * Hardware-specific code for old ISA cards.
+ *
+ * Copyright 1998    by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998,99 by Armin Schindler (mac@melware.de)
+ * Copyright 1999    Cytronics & Melware (info@melware.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: eicon_isa.c,v $
+ * Revision 1.5  1999/04/01 12:48:33  armin
+ * Changed some log outputs.
+ *
+ * Revision 1.4  1999/03/29 11:19:46  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.3  1999/03/02 12:37:45  armin
+ * Added some important checks.
+ * Analog Modem with DSP.
+ * Channels will be added to Link-Level after loading firmware.
+ *
+ * Revision 1.2  1999/01/24 20:14:19  armin
+ * Changed and added debug stuff.
+ * Better data sending. (still problems with tty's flip buffer)
+ *
+ * Revision 1.1  1999/01/01 18:09:43  armin
+ * First checkin of new eicon driver.
+ * DIVA-Server BRI/PCI and PRI/PCI are supported.
+ * Old diehl code is obsolete.
+ *
+ *
+ */
+
+#include "eicon.h"
+#include "eicon_isa.h"
+
+#define check_shmem   check_region
+#define release_shmem release_region
+#define request_shmem request_region
+
+char *eicon_isa_revision = "$Revision: 1.5 $";
+
+/* Mask for detecting invalid IRQ parameter */
+static int eicon_isa_valid_irq[] = {
+       0x1c1c, /* 2, 3, 4, 10, 11, 12 (S)*/
+       0x1c1c, /* 2, 3, 4, 10, 11, 12 (SX) */
+       0x1cbc, /* 2, 3, 4, 5, 7, 10, 11, 12 (SCOM) */
+       0x1cbc, /* 2, 3, 4, 5, 6, 10, 11, 12 (Quadro) */
+       0x1cbc  /* 2, 3, 4, 5, 7, 10, 11, 12 (S2M) */
+};
+
+static void
+eicon_isa_release_shmem(eicon_isa_card *card) {
+       if (card->mvalid)
+               release_shmem((unsigned long)card->shmem, card->ramsize);
+       card->mvalid = 0;
+}
+
+static void
+eicon_isa_release_irq(eicon_isa_card *card) {
+       if (!card->master)
+               return;
+       if (card->ivalid)
+               free_irq(card->irq, card);
+       card->ivalid = 0;
+}
+
+void
+eicon_isa_release(eicon_isa_card *card) {
+       eicon_isa_release_irq(card);
+       eicon_isa_release_shmem(card);
+}
+
+void
+eicon_isa_printpar(eicon_isa_card *card) {
+       switch (card->type) {
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+               case EICON_CTYPE_S2M:
+                       printk(KERN_INFO "Eicon %s at 0x%lx, irq %d\n",
+                              eicon_ctype_name[card->type],
+                              (unsigned long)card->shmem,
+                              card->irq);
+       }
+}
+
+int
+eicon_isa_find_card(int Mem, int Irq, char * Id)
+{
+       int primary = 1;
+
+       if (!strlen(Id))
+               return -1;
+
+       /* Check for valid membase address */
+       if ((Mem < 0x0c0000) ||
+           (Mem > 0x0fc000) ||
+           (Mem & 0xfff)) { 
+               printk(KERN_WARNING "eicon_isa: illegal membase 0x%x for %s\n",
+                        Mem, Id);
+               return -1;
+       }
+       if (check_shmem(Mem, RAMSIZE)) {
+               printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem);
+               return -1;
+       }
+
+        writew(0x55aa, Mem + 0x402);
+        if (readw(Mem + 0x402) != 0x55aa) primary = 0;
+       writew(0, Mem + 0x402);
+       if (readw(Mem + 0x402) != 0) primary = 0;
+
+       printk(KERN_INFO "Eicon: Driver-ID: %s\n", Id);
+       if (primary) {
+               printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem);
+               writeb(0, Mem + 0x3ffe);
+               return EICON_CTYPE_ISAPRI;
+       } else {
+               printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem);
+               writeb(0, Mem + 0x400);
+               return EICON_CTYPE_ISABRI;
+       }
+       return -1;
+}
+
+int
+eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
+       int     tmp;
+       int               timeout;
+       eicon_isa_codebuf cbuf;
+       unsigned char     *code;
+       eicon_isa_boot    *boot;
+
+       if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))
+               return -EFAULT;
+
+       /* Allocate code-buffer and copy code from userspace */
+       if (cbuf.bootstrap_len > 1024) {
+               printk(KERN_WARNING "eicon_isa_boot: Invalid startup-code size %ld\n",
+                      cbuf.bootstrap_len);
+               return -EINVAL;
+       }
+       if (!(code = kmalloc(cbuf.bootstrap_len, GFP_KERNEL))) {
+               printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffer\n");
+               return -ENOMEM;
+       }
+       if (copy_from_user(code, &cb->code, cbuf.bootstrap_len)) {
+               kfree(code);
+               return -EFAULT;
+       }
+
+       switch(card->type) {
+               case EICON_CTYPE_S:
+               case EICON_CTYPE_SX:
+               case EICON_CTYPE_SCOM:
+               case EICON_CTYPE_QUADRO:
+               case EICON_CTYPE_ISABRI:
+                       card->ramsize  = RAMSIZE;
+                       card->intack   = (__u8 *)card->shmem + INTACK;
+                       card->startcpu = (__u8 *)card->shmem + STARTCPU;
+                       card->stopcpu  = (__u8 *)card->shmem + STOPCPU;
+                       break;
+               case EICON_CTYPE_S2M:
+               case EICON_CTYPE_ISAPRI:
+                       card->ramsize  = RAMSIZE_P;
+                       card->intack   = (__u8 *)card->shmem + INTACK_P;
+                       card->startcpu = (__u8 *)card->shmem + STARTCPU_P;
+                       card->stopcpu  = (__u8 *)card->shmem + STOPCPU_P;
+                       break;
+               default:
+                       printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type);
+                       return -EINVAL;
+       }
+
+       /* Register shmem */
+       if (check_shmem((unsigned long)card->shmem, card->ramsize)) {
+               printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
+                       (unsigned long)card->shmem);
+               kfree(code);
+               return -EBUSY;
+       }
+       request_shmem((unsigned long)card->shmem, card->ramsize, "Eicon ISA ISDN");
+       card->mvalid = 1;
+
+       /* clear any pending irq's */
+       readb(card->intack);
+       /* set reset-line active */
+       writeb(0, card->stopcpu); 
+       /* clear irq-requests */
+       writeb(0, card->intack);
+       readb(card->intack);
+
+       /* Copy code into card */
+       memcpy_toio(&card->shmem->c, code, cbuf.bootstrap_len);
+
+       /* Check for properly loaded code */
+       if (!check_signature((unsigned long)&card->shmem->c, code, 1020)) {
+               printk(KERN_WARNING "eicon_isa_boot: Could not load startup-code\n");
+               eicon_isa_release_shmem(card);
+               kfree(code);
+               return -EIO;
+       }
+       /* if 16k-ramsize, duplicate the reset-jump-code */
+       if (card->ramsize == RAMSIZE_P)
+               memcpy_toio((__u8 *)card->shmem + 0x3ff0, &code[0x3f0], 12);
+
+       kfree(code);
+       boot = &card->shmem->boot;
+
+       /* Delay 0.2 sec. */
+       SLEEP(20);
+
+       /* Start CPU */
+       writeb(cbuf.boot_opt, &boot->ctrl);
+       writeb(0, card->startcpu); 
+
+       /* Delay 0.2 sec. */
+       SLEEP(20);
+
+       timeout = jiffies + (HZ * 22);
+       while (timeout > jiffies) {
+               if (readb(&boot->ctrl) == 0)
+                       break;
+               SLEEP(10);
+       }
+       if (readb(&boot->ctrl) != 0) {
+               printk(KERN_WARNING "eicon_isa_boot: CPU test failed\n");
+               eicon_isa_release_shmem(card);
+               return -EIO;
+       }
+
+       /* Check for memory-test errors */
+       if (readw(&boot->ebit)) {
+               printk(KERN_WARNING "eicon_isa_boot: memory test failed (bit 0x%04x at 0x%08x)\n",
+                      readw(&boot->ebit), readl(&boot->eloc));
+               eicon_isa_release_shmem(card);
+               return -EIO;
+       }
+
+        /* Check card type and memory size */
+        tmp = readb(&boot->card);
+       if ((tmp < 0) || (tmp > 4)) {
+               printk(KERN_WARNING "eicon_isa_boot: Type detect failed\n");
+               eicon_isa_release_shmem(card);
+               return -EIO;
+       }
+       card->type = tmp;
+       ((eicon_card *)card->card)->type = tmp;
+
+        tmp = readb(&boot->msize);
+        if (tmp != 8 && tmp != 16 && tmp != 24 &&
+            tmp != 32 && tmp != 48 && tmp != 60) {
+                printk(KERN_WARNING "eicon_isa_boot: invalid memsize\n");
+               eicon_isa_release_shmem(card);
+                return -EIO;
+        }
+       printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); 
+       if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
+               tmp = eicon_addcard(card->type, (unsigned long)card->shmem, card->irq, 
+                                       ((eicon_card *)card->card)->regname);
+               printk(KERN_INFO "Eicon: %d adapters added\n", tmp);
+       }
+       return 0;
+}
+
+int
+eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) {
+       eicon_isa_boot    *boot;
+       int               tmp;
+       int               timeout;
+       int               j;
+       eicon_isa_codebuf cbuf;
+       unsigned char     *code;
+       unsigned char     *p;
+
+       if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))
+               return -EFAULT;
+
+       if (!(code = kmalloc(cbuf.firmware_len, GFP_KERNEL))) {
+               printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffer\n");
+               return -ENOMEM;
+       }
+
+       if (copy_from_user(code, &cb->code, cbuf.firmware_len)) {
+               kfree(code);
+               return -EFAULT;
+       }
+
+       boot = &card->shmem->boot;
+
+       if ((!card->ivalid) && card->master) {
+               card->irqprobe = 1;
+               /* Check for valid IRQ */
+               if ((card->irq < 0) || (card->irq > 15) || 
+                   (!((1 << card->irq) & eicon_isa_valid_irq[card->type & 0x0f]))) {
+                       printk(KERN_WARNING "eicon_isa_boot: illegal irq: %d\n", card->irq);
+                       eicon_isa_release_shmem(card);
+                       kfree(code);
+                       return -EINVAL;
+               }
+               /* Register irq */
+               if (!request_irq(card->irq, &eicon_irq, 0, "Eicon ISA ISDN", card))
+                       card->ivalid = 1;
+               else {
+                       printk(KERN_WARNING "eicon_isa_boot: irq %d already in use.\n",
+                              card->irq);
+                       eicon_isa_release_shmem(card);
+                       kfree(code);
+                       return -EBUSY;
+               }
+       }
+
+        tmp = readb(&boot->msize);
+        if (tmp != 8 && tmp != 16 && tmp != 24 &&
+            tmp != 32 && tmp != 48 && tmp != 60) {
+                printk(KERN_WARNING "eicon_isa_boot: invalid memsize\n");
+               eicon_isa_release_shmem(card);
+                return -EIO;
+        }
+
+       eicon_isa_printpar(card);
+
+       /* Download firmware */
+       printk(KERN_INFO "%s %dkB, loading firmware ...\n", 
+              eicon_ctype_name[card->type],
+              tmp * 16);
+       tmp = cbuf.firmware_len >> 8;
+       p = code;
+       while (tmp--) {
+               memcpy_toio(&boot->b, p, 256);
+               writeb(1, &boot->ctrl);
+               timeout = jiffies + 10;
+               while (timeout > jiffies) {
+                       if (readb(&boot->ctrl) == 0)
+                               break;
+                       SLEEP(2);
+               }
+               if (readb(&boot->ctrl)) {
+                       printk(KERN_WARNING "eicon_isa_boot: download timeout at 0x%x\n", p-code);
+                       eicon_isa_release(card);
+                       kfree(code);
+                       return -EIO;
+               }
+               p += 256;
+       }
+       kfree(code);
+
+       /* Initialize firmware parameters */
+       memcpy_toio(&card->shmem->c[8], &cbuf.tei, 14);
+       memcpy_toio(&card->shmem->c[32], &cbuf.oad, 96);
+       memcpy_toio(&card->shmem->c[128], &cbuf.oad, 96);
+       
+       /* Start firmware, wait for signature */
+       writeb(2, &boot->ctrl);
+       timeout = jiffies + (5*HZ);
+       while (timeout > jiffies) {
+               if (readw(&boot->signature) == 0x4447)
+                       break;
+               SLEEP(2);
+       }
+       if (readw(&boot->signature) != 0x4447) {
+               printk(KERN_WARNING "eicon_isa_boot: firmware selftest failed %04x\n",
+                      readw(&boot->signature));
+               eicon_isa_release(card);
+               return -EIO;
+       }
+
+       card->channels = readb(&card->shmem->c[0x3f6]);
+
+       /* clear irq-requests, reset irq-count */
+       readb(card->intack);
+       writeb(0, card->intack);
+
+       if (card->master) {
+               card->irqprobe = 1;
+               /* Trigger an interrupt and check if it is delivered */
+               tmp = readb(&card->shmem->com.ReadyInt);
+               tmp ++;
+               writeb(tmp, &card->shmem->com.ReadyInt);
+               timeout = jiffies + 20;
+               while (timeout > jiffies) {
+                       if (card->irqprobe > 1)
+                               break;
+                       SLEEP(2);
+               }
+               if (card->irqprobe == 1) {
+                       printk(KERN_WARNING "eicon_isa_boot: IRQ test failed\n");
+                       eicon_isa_release(card);
+                       return -EIO;
+               }
+       }
+       writeb(card->irq, &card->shmem->com.Int);
+
+       /* initializing some variables */
+       ((eicon_card *)card->card)->ReadyInt = 0;
+       ((eicon_card *)card->card)->ref_in  = 1;
+       ((eicon_card *)card->card)->ref_out = 1;
+       for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
+       for(j=0; j< (card->channels + 1); j++) {
+               ((eicon_card *)card->card)->bch[j].e.busy = 0;
+               ((eicon_card *)card->card)->bch[j].e.D3Id = 0;
+               ((eicon_card *)card->card)->bch[j].e.B2Id = 0;
+               ((eicon_card *)card->card)->bch[j].e.ref = 0;
+               ((eicon_card *)card->card)->bch[j].e.Req = 0;
+               ((eicon_card *)card->card)->bch[j].e.complete = 1;
+               ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
+       }
+
+       printk(KERN_INFO "Eicon: Supported channels: %d\n", card->channels); 
+       printk(KERN_INFO "%s successfully started\n", eicon_ctype_name[card->type]);
+
+       /* Enable normal IRQ processing */
+       card->irqprobe = 0;
+       return 0;
+}
diff --git a/drivers/isdn/eicon/eicon_isa.h b/drivers/isdn/eicon/eicon_isa.h
new file mode 100644 (file)
index 0000000..5b0dc1a
--- /dev/null
@@ -0,0 +1,144 @@
+/* $Id: eicon_isa.h,v 1.3 1999/03/29 11:19:47 armin Exp $
+ *
+ * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ *
+ * Copyright 1998    by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998,99 by Armin Schindler (mac@melware.de)
+ * Copyright 1999    Cytronics & Melware (info@melware.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: eicon_isa.h,v $
+ * Revision 1.3  1999/03/29 11:19:47  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.2  1999/03/02 12:37:46  armin
+ * Added some important checks.
+ * Analog Modem with DSP.
+ * Channels will be added to Link-Level after loading firmware.
+ *
+ * Revision 1.1  1999/01/01 18:09:44  armin
+ * First checkin of new eicon driver.
+ * DIVA-Server BRI/PCI and PRI/PCI are supported.
+ * Old diehl code is obsolete.
+ *
+ *
+ */
+
+#ifndef eicon_isa_h
+#define eicon_isa_h
+
+#ifdef __KERNEL__
+
+/* Factory defaults for ISA-Cards */
+#define EICON_ISA_MEMBASE 0xd0000
+#define EICON_ISA_IRQ     3
+/* shmem offset for Quadro parts */
+#define EICON_ISA_QOFFSET 0x0800
+
+typedef struct {
+        __u16 length __attribute__ ((packed));   /* length of data/parameter field         */
+        __u8  P[270];                            /* data/parameter field                   */
+} eicon_scom_PBUFFER;
+
+/* General communication buffer */
+typedef struct {
+        __u8   Req;                                /* request register                       */
+       __u8   ReqId;                              /* request task/entity identification     */
+       __u8   Rc;                                 /* return code register                   */
+       __u8   RcId;                               /* return code task/entity identification */
+       __u8   Ind;                                /* Indication register                    */
+       __u8   IndId;                              /* Indication task/entity identification  */
+       __u8   IMask;                              /* Interrupt Mask Flag                    */
+       __u8   RNR;                                /* Receiver Not Ready (set by PC)         */
+       __u8   XLock;                              /* XBuffer locked Flag                    */
+       __u8   Int;                                /* ISDN interrupt                         */
+       __u8   ReqCh;                              /* Channel field for layer-3 Requests     */
+       __u8   RcCh;                               /* Channel field for layer-3 Returncodes  */
+       __u8   IndCh;                              /* Channel field for layer-3 Indications  */
+       __u8   MInd;                               /* more data indication field             */
+       __u16  MLength;                            /* more data total packet length          */
+       __u8   ReadyInt;                           /* request field for ready interrupt      */
+       __u8   Reserved[12];                       /* reserved space                         */
+       __u8   IfType;                             /* 1 = 16k-Interface                      */
+       __u16  Signature __attribute__ ((packed)); /* ISDN adapter Signature                 */
+       eicon_scom_PBUFFER XBuffer;                /* Transmit Buffer                        */
+       eicon_scom_PBUFFER RBuffer;                /* Receive Buffer                         */
+} eicon_isa_com;
+
+/* struct for downloading firmware */
+typedef struct {
+       __u8  ctrl;
+       __u8  card;
+       __u8  msize;
+       __u8  fill0;
+       __u16 ebit __attribute__ ((packed));
+       __u32 eloc __attribute__ ((packed));
+       __u8  reserved[20];
+       __u16 signature __attribute__ ((packed));
+       __u8  fill[224];
+       __u8  b[256];
+} eicon_isa_boot;
+
+/* Shared memory */
+typedef union {
+       unsigned char  c[0x400];
+       eicon_isa_com  com;
+       eicon_isa_boot boot;
+} eicon_isa_shmem;
+
+/*
+ * card's description
+ */
+typedef struct {
+       int               ramsize;
+       int               irq;      /* IRQ                        */
+       void*             card;
+       eicon_isa_shmem*  shmem;    /* Shared-memory area         */
+       unsigned char*    intack;   /* Int-Acknowledge            */
+       unsigned char*    stopcpu;  /* Writing here stops CPU     */
+       unsigned char*    startcpu; /* Writing here starts CPU    */
+       unsigned char     type;     /* card type                  */
+       int               channels; /* No. of channels            */
+       unsigned char     irqprobe; /* Flag: IRQ-probing          */
+       unsigned char     mvalid;   /* Flag: Memory is valid      */
+       unsigned char     ivalid;   /* Flag: IRQ is valid         */
+       unsigned char     master;   /* Flag: Card ist Quadro 1/4  */
+       void*             generic;  /* Ptr to generic card struct */
+} eicon_isa_card;
+
+/* Offsets for special locations on standard cards */
+#define INTACK     0x03fe 
+#define STOPCPU    0x0400
+#define STARTCPU   0x0401
+#define RAMSIZE    0x0400
+/* Offsets for special location on PRI card */
+#define INTACK_P   0x3ffc
+#define STOPCPU_P  0x3ffe
+#define STARTCPU_P 0x3fff
+#define RAMSIZE_P  0x4000
+
+
+extern int eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb);
+extern int eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb);
+extern void eicon_isa_release(eicon_isa_card *card);
+extern void eicon_isa_printpar(eicon_isa_card *card);
+extern void eicon_isa_transmit(eicon_isa_card *card);
+extern int eicon_isa_find_card(int Mem, int Irq, char * Id);
+
+#endif  /* __KERNEL__ */
+
+#endif /* eicon_isa_h */
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
new file mode 100644 (file)
index 0000000..c14d91d
--- /dev/null
@@ -0,0 +1,1210 @@
+/* $Id: eicon_mod.c,v 1.5 1999/04/01 12:48:35 armin Exp $
+ *
+ * ISDN lowlevel-module for Eicon.Diehl active cards.
+ * 
+ * Copyright 1997    by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1998,99 by Armin Schindler (mac@melware.de) 
+ * Copyright 1999    Cytronics & Melware (info@melware.de)
+ * 
+ * Thanks to    Eicon Technology Diehl GmbH & Co. oHG for
+ *              documents, informations and hardware.
+ *
+ *              Deutsche Telekom AG for S2M support.
+ *
+ * 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: eicon_mod.c,v $
+ * Revision 1.5  1999/04/01 12:48:35  armin
+ * Changed some log outputs.
+ *
+ * Revision 1.4  1999/03/29 11:19:47  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.3  1999/03/02 12:37:47  armin
+ * Added some important checks.
+ * Analog Modem with DSP.
+ * Channels will be added to Link-Level after loading firmware.
+ *
+ * Revision 1.2  1999/01/24 20:14:21  armin
+ * Changed and added debug stuff.
+ * Better data sending. (still problems with tty's flip buffer)
+ *
+ * Revision 1.1  1999/01/01 18:09:44  armin
+ * First checkin of new eicon driver.
+ * DIVA-Server BRI/PCI and PRI/PCI are supported.
+ * Old diehl code is obsolete.
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "eicon.h"
+
+#define INCLUDE_INLINE_FUNCS
+
+static eicon_card *cards = (eicon_card *) NULL;
+
+static char *eicon_revision = "$Revision: 1.5 $";
+
+extern char *eicon_pci_revision;
+extern char *eicon_isa_revision;
+extern char *eicon_idi_revision;
+
+#ifdef MODULE
+#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
+#endif
+
+#define EICON_CTRL_VERSION 1
+
+ulong DebugVar;
+
+/* Parameters to be set by insmod */
+static int   membase      = -1;
+static int   irq          = -1;
+static char *id           = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+MODULE_DESCRIPTION(             "Driver for Eicon.Diehl active ISDN cards");
+MODULE_AUTHOR(                  "Armin Schindler");
+MODULE_SUPPORTED_DEVICE(        "ISDN subsystem");
+MODULE_PARM_DESC(membase,      "Base address of first ISA card");
+MODULE_PARM_DESC(irq,          "IRQ of first card");
+MODULE_PARM_DESC(id,                   "ID-String of first card");
+MODULE_PARM(membase,           "i");
+MODULE_PARM(irq,               "i");
+MODULE_PARM(id,                "s");
+
+char *eicon_ctype_name[] = {
+        "ISDN-S",
+        "ISDN-SX",
+        "ISDN-SCOM",
+        "ISDN-QUADRO",
+        "ISDN-S2M",
+        "DIVA Server BRI/PCI",
+        "DIVA Server 4BRI/PCI",
+        "DIVA Server 4BRI/PCI",
+        "DIVA Server PRI/PCI"
+};
+
+static int
+getrel(char *p)
+{
+        int v = 0;
+       char *tmp = 0;
+
+       if ((tmp = strchr(p, '.')))
+               p = tmp + 1;
+        while (p[0] >= '0' && p[0] <= '9') {
+                v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0');
+               p++;
+       }
+        return v;
+
+
+}
+
+static char *
+eicon_getrev(const char *revision)
+{
+       char *rev;
+       char *p;
+       if ((p = strchr(revision, ':'))) {
+               rev = p + 2;
+               p = strchr(rev, '$');
+               *--p = 0;
+       } else rev = "?.??";
+       return rev;
+
+}
+
+static eicon_chan *
+find_channel(eicon_card *card, int channel)
+{
+       if ((channel >= 0) && (channel < card->nchannels))
+               return &(card->bch[channel]);
+       if (DebugVar & 1)
+               printk(KERN_WARNING "eicon: Invalid channel %d\n", channel);
+       return NULL;
+}
+
+/*
+ * Free MSN list
+ */
+static void
+eicon_clear_msn(eicon_card *card)
+{
+        struct msn_entry *p = card->msn_list;
+        struct msn_entry *q;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+        card->msn_list = NULL;
+       restore_flags(flags);
+        while (p) {
+                q  = p->next;
+                kfree(p);
+                p = q;
+        }
+}
+
+/*
+ * Find an MSN entry in the list.
+ * If ia5 != 0, return IA5-encoded EAZ, else
+ * return a bitmask with corresponding bit set.
+ */
+static __u16
+eicon_find_msn(eicon_card *card, char *msn, int ia5)
+{
+        struct msn_entry *p = card->msn_list;
+       __u8 eaz = '0';
+
+       while (p) {
+               if (!strcmp(p->msn, msn)) {
+                       eaz = p->eaz;
+                       break;
+               }
+               p = p->next;
+       }
+       if (!ia5)
+               return (1 << (eaz - '0'));
+       else
+               return eaz;
+}
+
+/*
+ * Find an EAZ entry in the list.
+ * return a string with corresponding msn.
+ */
+char *
+eicon_find_eaz(eicon_card *card, char eaz)
+{
+        struct msn_entry *p = card->msn_list;
+
+       while (p) {
+               if (p->eaz == eaz)
+                       return(p->msn);
+               p = p->next;
+       }
+       return("\0");
+}
+
+#if 0
+/*
+ * Add or delete an MSN to the MSN list
+ *
+ * First character of msneaz is EAZ, rest is MSN.
+ * If length of eazmsn is 1, delete that entry.
+ */
+static int
+eicon_set_msn(eicon_card *card, char *eazmsn)
+{
+        struct msn_entry *p = card->msn_list;
+        struct msn_entry *q = NULL;
+       unsigned long flags;
+       int i;
+       
+       if (!strlen(eazmsn))
+               return 0;
+       if (strlen(eazmsn) > 16)
+               return -EINVAL;
+       for (i = 0; i < strlen(eazmsn); i++)
+               if (!isdigit(eazmsn[i]))
+                       return -EINVAL;
+        if (strlen(eazmsn) == 1) {
+               /* Delete a single MSN */
+               while (p) {
+                       if (p->eaz == eazmsn[0]) {
+                               save_flags(flags);
+                               cli();
+                               if (q)
+                                       q->next = p->next;
+                               else
+                                       card->msn_list = p->next;
+                               restore_flags(flags);
+                               kfree(p);
+                               if (DebugVar & 8)
+                                       printk(KERN_DEBUG
+                                              "Mapping for EAZ %c deleted\n",
+                                              eazmsn[0]);
+                               return 0;
+                       }
+                       q = p;
+                       p = p->next;
+               }
+               return 0;
+        }
+       /* Add a single MSN */
+       while (p) {
+               /* Found in list, replace MSN */
+               if (p->eaz == eazmsn[0]) {
+                       save_flags(flags);
+                       cli();
+                       strcpy(p->msn, &eazmsn[1]);
+                       restore_flags(flags);
+                       if (DebugVar & 8)
+                               printk(KERN_DEBUG
+                                      "Mapping for EAZ %c changed to %s\n",
+                                      eazmsn[0],
+                                      &eazmsn[1]);
+                       return 0;
+               }
+               p = p->next;
+       }
+       /* Not found in list, add new entry */
+       p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+       p->eaz = eazmsn[0];
+       strcpy(p->msn, &eazmsn[1]);
+       p->next = card->msn_list;
+       save_flags(flags);
+       cli();
+       card->msn_list = p;
+       restore_flags(flags);
+       if (DebugVar & 8)
+               printk(KERN_DEBUG
+                      "Mapping %c -> %s added\n",
+                      eazmsn[0],
+                      &eazmsn[1]);
+       return 0;
+}
+#endif
+
+static void
+eicon_rcv_dispatch(struct eicon_card *card)
+{
+       switch (card->bus) {
+               case EICON_BUS_ISA:
+               case EICON_BUS_PCI:
+                       eicon_io_rcv_dispatch(card);
+                       break;
+               case EICON_BUS_MCA:
+               default:
+                       if (DebugVar & 1)
+                               printk(KERN_WARNING
+                                      "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
+       }
+}
+
+static void
+eicon_ack_dispatch(struct eicon_card *card)
+{
+       switch (card->bus) {
+               case EICON_BUS_ISA:
+               case EICON_BUS_PCI:
+                       eicon_io_ack_dispatch(card);
+                       break;
+               case EICON_BUS_MCA:
+               default:
+                       if (DebugVar & 1)
+                               printk(KERN_WARNING
+                                       "eicon_ack_dispatch: Illegal bustype %d\n", card->bus);
+       }
+}
+
+static void
+eicon_transmit(struct eicon_card *card)
+{
+       switch (card->bus) {
+               case EICON_BUS_ISA:
+               case EICON_BUS_PCI:
+                       eicon_io_transmit(card);
+                       break;
+               case EICON_BUS_MCA:
+               default:
+                       if (DebugVar & 1)
+                               printk(KERN_WARNING
+                                      "eicon_transmit: Illegal bustype %d\n", card->bus);
+       }
+}
+
+static int
+eicon_command(eicon_card * card, isdn_ctrl * c)
+{
+        ulong a;
+        eicon_chan *chan;
+       eicon_cdef cdef;
+       isdn_ctrl cmd;
+       char tmp[17];
+       int ret = 0;
+       unsigned long flags;
+        switch (c->command) {
+               case ISDN_CMD_IOCTL:
+                       memcpy(&a, c->parm.num, sizeof(ulong));
+                       switch (c->arg) {
+                               case EICON_IOCTL_GETVER:
+                                       return(EICON_CTRL_VERSION);
+                               case EICON_IOCTL_GETTYPE:
+                                       return(card->type);
+                               case EICON_IOCTL_GETMMIO:
+                                       switch (card->bus) {
+                                               case EICON_BUS_ISA:
+                                                       return (int)card->hwif.isa.shmem;
+#if CONFIG_PCI
+                                               case EICON_BUS_PCI:
+                                                       return card->hwif.pci.PCIram;
+#endif
+                                               default:
+                                                       if (DebugVar & 1)
+                                                               printk(KERN_WARNING
+                                                                      "eicon: Illegal BUS type %d\n",
+                                                              card->bus);
+                                                       ret = -ENODEV;
+                                       }
+                               case EICON_IOCTL_SETMMIO:
+                                       if (card->flags & EICON_FLAGS_LOADED)
+                                               return -EBUSY;
+                                       switch (card->bus) {
+                                               case EICON_BUS_ISA:
+                                                       if (eicon_isa_find_card(a,
+                                                               card->hwif.isa.irq,
+                                                               card->regname) < 0)
+                                                               return -EFAULT;
+                                                       card->hwif.isa.shmem = (eicon_isa_shmem *)a;
+                                                       return 0;
+                                               default:
+                                                       if (DebugVar & 1)
+                                                               printk(KERN_WARNING
+                                                                       "eicon: Illegal BUS type %d\n",
+                                                              card->bus);
+                                                       ret = -ENODEV;
+                                       }                                       
+                               case EICON_IOCTL_GETIRQ:
+                                       switch (card->bus) {
+                                               case EICON_BUS_ISA:
+                                                       return card->hwif.isa.irq;
+#if CONFIG_PCI
+                                               case EICON_BUS_PCI:
+                                                       return card->hwif.pci.irq;
+#endif
+                                               default:
+                                                       if (DebugVar & 1)
+                                                               printk(KERN_WARNING
+                                                                      "eicon: Illegal BUS type %d\n",
+                                                              card->bus);
+                                                       ret = -ENODEV;
+                                       }
+                               case EICON_IOCTL_SETIRQ:
+                                       if (card->flags & EICON_FLAGS_LOADED)
+                                               return -EBUSY;
+                                       if ((a < 2) || (a > 15))
+                                               return -EFAULT;
+                                       switch (card->bus) {
+                                               case EICON_BUS_ISA:
+                                                       card->hwif.isa.irq = a;
+                                                       return 0;
+                                               default:
+                                                       if (DebugVar & 1)
+                                                               printk(KERN_WARNING
+                                                                       "eicon: Illegal BUS type %d\n",
+                                                              card->bus);
+                                                       ret = -ENODEV;
+                                       }                                       
+                               case EICON_IOCTL_LOADBOOT:
+                                       if (card->flags & EICON_FLAGS_RUNNING)
+                                               return -EBUSY;  
+                                       switch (card->bus) {
+                                               case EICON_BUS_ISA:
+                                                       ret = eicon_isa_bootload(
+                                                               &(card->hwif.isa),
+                                                               &(((eicon_codebuf *)a)->isa));
+                                                       break;
+                                               default:
+                                                       if (DebugVar & 1)
+                                                               printk(KERN_WARNING
+                                                                      "eicon: Illegal BUS type %d\n",
+                                                              card->bus);
+                                                       ret = -ENODEV;
+                                       }
+                                       return ret;
+                               case EICON_IOCTL_LOADISA:
+                                       if (card->flags & EICON_FLAGS_RUNNING)
+                                               return -EBUSY;  
+                                       switch (card->bus) {
+                                               case EICON_BUS_ISA:
+                                                       ret = eicon_isa_load(
+                                                               &(card->hwif.isa),
+                                                               &(((eicon_codebuf *)a)->isa));
+                                                       if (!ret) {
+                                                                card->flags |= EICON_FLAGS_LOADED;
+                                                                card->flags |= EICON_FLAGS_RUNNING;
+                                                               if (card->hwif.isa.channels > 1) {
+                                                                       cmd.command = ISDN_STAT_ADDCH;
+                                                                       cmd.driver = card->myid;
+                                                                       cmd.arg = card->hwif.isa.channels - 1;
+                                                                       card->interface.statcallb(&cmd);
+                                                               }
+                                                               cmd.command = ISDN_STAT_RUN;    
+                                                               cmd.driver = card->myid;        
+                                                               cmd.arg = 0;                    
+                                                               card->interface.statcallb(&cmd);
+                                                       }
+                                                       break;
+                                               default:
+                                                       if (DebugVar & 1)
+                                                               printk(KERN_WARNING
+                                                                      "eicon: Illegal BUS type %d\n",
+                                                              card->bus);
+                                                       ret = -ENODEV;
+                                       }
+                                       return ret;
+
+                               case EICON_IOCTL_MANIF:
+                                       if (!card->flags & EICON_FLAGS_RUNNING)
+                                               return -ENODEV;
+                                       if (!card->Feature & PROTCAP_MANIF)
+                                               return -ENODEV;
+                                       ret = eicon_idi_manage(
+                                               card, 
+                                               (eicon_manifbuf *)a);
+                                       return ret;
+#if CONFIG_PCI 
+                               case EICON_IOCTL_LOADPCI:
+                                               if (card->flags & EICON_FLAGS_RUNNING)
+                                                       return -EBUSY;  
+                                                if (card->bus == EICON_BUS_PCI) {
+                                                       switch(card->type) {
+                                                               case EICON_CTYPE_MAESTRA:
+                                                                       ret = eicon_pci_load_bri(
+                                                                               &(card->hwif.pci),
+                                                                               &(((eicon_codebuf *)a)->pci)); 
+                                                                       break;
+
+                                                               case EICON_CTYPE_MAESTRAP:
+                                                                       ret = eicon_pci_load_pri(
+                                                                               &(card->hwif.pci),
+                                                                               &(((eicon_codebuf *)a)->pci)); 
+                                                                       break;
+                                                       }
+                                                        if (!ret) {
+                                                                card->flags |= EICON_FLAGS_LOADED;
+                                                                card->flags |= EICON_FLAGS_RUNNING;
+                                                               if (card->hwif.pci.channels > 1) {
+                                                                       cmd.command = ISDN_STAT_ADDCH;
+                                                                       cmd.driver = card->myid;
+                                                                       cmd.arg = card->hwif.pci.channels - 1;
+                                                                       card->interface.statcallb(&cmd);
+                                                               }
+                                                               cmd.command = ISDN_STAT_RUN;    
+                                                               cmd.driver = card->myid;        
+                                                               cmd.arg = 0;                    
+                                                               card->interface.statcallb(&cmd);
+                                                       } 
+                                                        return ret;
+                                               } else return -ENODEV;
+#endif
+#if 0
+                               case EICON_IOCTL_SETMSN:
+                                       if ((ret = copy_from_user(tmp, (char *)a, sizeof(tmp))))
+                                               return -EFAULT;
+                                       if ((ret = eicon_set_msn(card, tmp)))
+                                               return ret;
+#if 0
+                                       if (card->flags & EICON_FLAGS_RUNNING)
+                                               return(eicon_capi_manufacturer_req_msn(card));
+#endif
+                                       return 0;
+#endif
+                               case EICON_IOCTL_ADDCARD:
+                                       if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef))))
+                                               return -EFAULT;
+                                       if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id)))
+                                               return -EIO;
+                                       return 0;
+                               case EICON_IOCTL_DEBUGVAR:
+                                       DebugVar = a;
+                                       printk(KERN_DEBUG"Eicon: Debug Value set to %ld\n", DebugVar);
+                                       return 0;
+#ifdef MODULE
+                               case EICON_IOCTL_FREEIT:
+                                       while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT;
+                                       MOD_INC_USE_COUNT;
+                                       return 0;
+#endif
+                               default:
+                                       return -EINVAL;
+                       }
+                       break;
+               case ISDN_CMD_DIAL:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       save_flags(flags);
+                       cli();
+                       if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) {
+                               restore_flags(flags);
+                               if (DebugVar & 1)
+                                       printk(KERN_WARNING "Dial on channel %d with state %d\n",
+                                       chan->No, chan->fsm_state);
+                               return -EBUSY;
+                       }
+                       if (card->ptype == ISDN_PTYPE_EURO)
+                               tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1);
+                       else
+                               tmp[0] = c->parm.setup.eazmsn[0];
+                       chan->fsm_state = EICON_STATE_OCALL;
+                       chan->callref = 0xffff;
+                       restore_flags(flags);
+                       
+                       ret = idi_connect_req(card, chan, c->parm.setup.phone,
+                                                    c->parm.setup.eazmsn,
+                                                    c->parm.setup.si1,
+                                                    c->parm.setup.si2);
+                       if (ret) {
+                               cmd.driver = card->myid;
+                               cmd.command = ISDN_STAT_DHUP;
+                               cmd.arg &= 0x1f;
+                               card->interface.statcallb(&cmd);
+                       }
+                       return ret;
+               case ISDN_CMD_ACCEPTD:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       if (chan->fsm_state == EICON_STATE_ICALL) { 
+                               idi_connect_res(card, chan);
+                       }
+                       return 0;
+               case ISDN_CMD_ACCEPTB:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       return 0;
+               case ISDN_CMD_HANGUP:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       idi_hangup(card, chan);
+                       return 0;
+               case ISDN_CMD_SETEAZ:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       if (strlen(c->parm.num)) {
+                               if (card->ptype == ISDN_PTYPE_EURO) {
+                                       chan->eazmask = eicon_find_msn(card, c->parm.num, 0);
+                               }
+                               if (card->ptype == ISDN_PTYPE_1TR6) {
+                                       int i;
+                                       chan->eazmask = 0;
+                                       for (i = 0; i < strlen(c->parm.num); i++)
+                                               if (isdigit(c->parm.num[i]))
+                                                       chan->eazmask |= (1 << (c->parm.num[i] - '0'));
+                               }
+                       } else
+                               chan->eazmask = 0x3ff;
+                       eicon_idi_listen_req(card, chan);
+                       return 0;
+               case ISDN_CMD_CLREAZ:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       chan->eazmask = 0;
+                       eicon_idi_listen_req(card, chan);
+                       return 0;
+               case ISDN_CMD_SETL2:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       chan->l2prot = (c->arg >> 8);
+                       return 0;
+               case ISDN_CMD_GETL2:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       return chan->l2prot;
+               case ISDN_CMD_SETL3:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
+                               if (DebugVar & 1)
+                                       printk(KERN_WARNING "L3 protocol unknown\n");
+                               return -1;
+                       }
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       chan->l3prot = (c->arg >> 8);
+                       return 0;
+               case ISDN_CMD_GETL3:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (!(chan = find_channel(card, c->arg & 0x1f)))
+                               break;
+                       return chan->l3prot;
+               case ISDN_CMD_GETEAZ:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (DebugVar & 1)
+                               printk(KERN_DEBUG "eicon CMD_GETEAZ not implemented\n");
+                       return 0;
+               case ISDN_CMD_SETSIL:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (DebugVar & 1)
+                               printk(KERN_DEBUG "eicon CMD_SETSIL not implemented\n");
+                       return 0;
+               case ISDN_CMD_GETSIL:
+                       if (!card->flags & EICON_FLAGS_RUNNING)
+                               return -ENODEV;
+                       if (DebugVar & 1)
+                               printk(KERN_DEBUG "eicon CMD_GETSIL not implemented\n");
+                       return 0;
+               case ISDN_CMD_LOCK:
+                       MOD_INC_USE_COUNT;
+                       return 0;
+               case ISDN_CMD_UNLOCK:
+                       MOD_DEC_USE_COUNT;
+                       return 0;
+        }
+       
+        return -EINVAL;
+}
+
+/*
+ * Find card with given driverId
+ */
+static inline eicon_card *
+eicon_findcard(int driverid)
+{
+        eicon_card *p = cards;
+
+        while (p) {
+                if (p->myid == driverid)
+                        return p;
+                p = p->next;
+        }
+        return (eicon_card *) 0;
+}
+
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl * c)
+{
+        eicon_card *card = eicon_findcard(c->driver);
+
+        if (card)
+                return (eicon_command(card, c));
+        printk(KERN_ERR
+             "eicon: if_command %d called with invalid driverId %d!\n",
+               c->command, c->driver);
+        return -ENODEV;
+}
+
+static int
+if_writecmd(const u_char * buf, int len, int user, int id, int channel)
+{
+        eicon_card *card = eicon_findcard(id);
+
+        if (card) {
+                if (!card->flags & EICON_FLAGS_RUNNING)
+                        return -ENODEV;
+                return (len);
+        }
+        printk(KERN_ERR
+               "eicon: if_writecmd called with invalid driverId!\n");
+        return -ENODEV;
+}
+
+static int
+if_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+#if 0
+       /* Not yet used */
+        eicon_card *card = eicon_findcard(id);
+       
+        if (card) {
+                if (!card->flags & EICON_FLAGS_RUNNING)
+                        return -ENODEV;
+                return (eicon_readstatus(buf, len, user, card));
+        }
+        printk(KERN_ERR
+               "eicon: if_readstatus called with invalid driverId!\n");
+#endif
+        return -ENODEV;
+}
+
+static int
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
+{
+        eicon_card *card = eicon_findcard(id);
+       eicon_chan *chan;
+       
+        if (card) {
+                if (!card->flags & EICON_FLAGS_RUNNING) {
+                       dev_kfree_skb(skb);
+                        return -ENODEV;
+               }
+               if (!(chan = find_channel(card, channel))) {
+                       dev_kfree_skb(skb);
+                       return -ENODEV;
+               }
+               if (chan->fsm_state == EICON_STATE_ACTIVE)
+                       return (idi_send_data(card, chan, ack, skb));
+               else {
+                       dev_kfree_skb(skb);
+                       return -ENODEV;
+               }
+        }
+        printk(KERN_ERR
+               "eicon: if_sendbuf called with invalid driverId!\n");
+       dev_kfree_skb(skb);
+        return -ENODEV;
+}
+
+
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list.
+ */
+static void
+eicon_alloccard(int Type, int membase, int irq, char *id)
+{
+       int i;
+       int j;
+       int qloop;
+       char qid[5];
+        eicon_card *card;
+#if CONFIG_PCI
+       eicon_pci_card *pcic;
+#endif
+
+       qloop = (Type == EICON_CTYPE_QUADRO)?2:0;
+       for (i = 0; i <= qloop; i++) {
+               if (!(card = (eicon_card *) kmalloc(sizeof(eicon_card), GFP_KERNEL))) {
+                       printk(KERN_WARNING
+                              "eicon: (%s) Could not allocate card-struct.\n", id);
+                       return;
+               }
+               memset((char *) card, 0, sizeof(eicon_card));
+               skb_queue_head_init(&card->sndq);
+               skb_queue_head_init(&card->rcvq);
+               skb_queue_head_init(&card->rackq);
+               skb_queue_head_init(&card->sackq);
+               card->snd_tq.routine = (void *) (void *) eicon_transmit;
+               card->snd_tq.data = card;
+               card->rcv_tq.routine = (void *) (void *) eicon_rcv_dispatch;
+               card->rcv_tq.data = card;
+               card->ack_tq.routine = (void *) (void *) eicon_ack_dispatch;
+               card->ack_tq.data = card;
+               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_L2_TRANS |
+                       ISDN_FEATURE_L3_TRANS |
+                       ISDN_FEATURE_P_UNKNOWN;
+               card->interface.hl_hdrlen = 20;
+               card->ptype = ISDN_PTYPE_UNKNOWN;
+               strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+               card->myid = -1;
+               card->type = Type;
+               switch (Type) {
+                       case EICON_CTYPE_QUADRO:
+                               if (membase == -1)
+                                       membase = EICON_ISA_MEMBASE;
+                               if (irq == -1)
+                                       irq = EICON_ISA_IRQ;
+                               card->bus = EICON_BUS_ISA;
+                               card->hwif.isa.card = (void *)card;
+                               card->hwif.isa.shmem = (eicon_isa_shmem *)(membase + (i+1) * EICON_ISA_QOFFSET);
+                               card->hwif.isa.master = 0;
+                               strcpy(card->interface.id, id);
+                               if (id[strlen(id) - 1] == 'a') {
+                                       card->interface.id[strlen(id) - 1] = 'a' + i + 1;
+                               } else {
+                                       sprintf(qid, "_%c",'2' + i);
+                                       strcat(card->interface.id, qid);
+                               }
+                               printk(KERN_INFO "Eicon: Quadro: Driver-Id %s added.\n",
+                                       card->interface.id);
+                               if (i == 0) {
+                                       eicon_card *p = cards;
+                                       while(p) {
+                                               if ((p->hwif.isa.master) && (p->hwif.isa.irq == irq)) {
+                                                       p->qnext = card;
+                                                       break;
+                                               }
+                                               p = p->next;
+                                       }
+                                       if (!p) {
+                                               printk(KERN_WARNING "eicon_alloccard: Quadro Master not found.\n");
+                                               kfree(card);
+                                               return;
+                                       }
+                               } else {
+                                       cards->qnext = card;
+                               }
+                               card->hwif.isa.irq = irq;
+                               card->hwif.isa.type = Type;
+                               card->nchannels = 2;
+                               card->interface.channels = 1;
+                               break;
+#if CONFIG_PCI
+                       case EICON_CTYPE_MAESTRA:
+                               (eicon_pci_card *)pcic = (eicon_pci_card *)membase;
+                                card->bus = EICON_BUS_PCI;
+                               card->interface.features |=
+                                       ISDN_FEATURE_L2_V11096 |
+                                       ISDN_FEATURE_L2_V11019 |
+                                       ISDN_FEATURE_L2_V11038 |
+                                       ISDN_FEATURE_L2_MODEM;
+                                card->hwif.pci.card = (void *)card;
+                               card->hwif.pci.PCIreg = pcic->PCIreg;
+                               card->hwif.pci.PCIcfg = pcic->PCIcfg;
+                                card->hwif.pci.master = 1;
+                                card->hwif.pci.mvalid = pcic->mvalid;
+                                card->hwif.pci.ivalid = 0;
+                                card->hwif.pci.irq = irq;
+                                card->hwif.pci.type = Type;
+                               card->flags = 0;
+                                card->nchannels = 2;
+                               card->interface.channels = 1;
+                               break;
+
+                       case EICON_CTYPE_MAESTRAP:
+                               (eicon_pci_card *)pcic = (eicon_pci_card *)membase;
+                                card->bus = EICON_BUS_PCI;
+                               card->interface.features |=
+                                       ISDN_FEATURE_L2_V11096 |
+                                       ISDN_FEATURE_L2_V11019 |
+                                       ISDN_FEATURE_L2_V11038 |
+                                       ISDN_FEATURE_L2_MODEM;
+                                card->hwif.pci.card = (void *)card;
+                                card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
+                               card->hwif.pci.PCIreg = pcic->PCIreg;
+                               card->hwif.pci.PCIram = pcic->PCIram;
+                               card->hwif.pci.PCIcfg = pcic->PCIcfg;
+                                card->hwif.pci.master = 1;
+                                card->hwif.pci.mvalid = pcic->mvalid;
+                                card->hwif.pci.ivalid = 0;
+                                card->hwif.pci.irq = irq;
+                                card->hwif.pci.type = Type;
+                               card->flags = 0;
+                                card->nchannels = 30;
+                               card->interface.channels = 1;
+                               break;
+#endif
+                       case EICON_CTYPE_ISABRI:
+                               if (membase == -1)
+                                       membase = EICON_ISA_MEMBASE;
+                               if (irq == -1)
+                                       irq = EICON_ISA_IRQ;
+                               card->bus = EICON_BUS_ISA;
+                               card->hwif.isa.card = (void *)card;
+                               card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+                               card->hwif.isa.master = 1;
+                               card->hwif.isa.irq = irq;
+                               card->hwif.isa.type = Type;
+                               card->nchannels = 2;
+                               card->interface.channels = 1;
+                               break;
+                       case EICON_CTYPE_ISAPRI:
+                               if (membase == -1)
+                                       membase = EICON_ISA_MEMBASE;
+                               if (irq == -1)
+                                       irq = EICON_ISA_IRQ;
+                               card->bus = EICON_BUS_ISA;
+                               card->hwif.isa.card = (void *)card;
+                               card->hwif.isa.shmem = (eicon_isa_shmem *)membase;
+                               card->hwif.isa.master = 1;
+                               card->hwif.isa.irq = irq;
+                               card->hwif.isa.type = Type;
+                               card->nchannels = 30;
+                               card->interface.channels = 1;
+                               break;
+                       default:
+                               printk(KERN_WARNING "eicon_alloccard: Invalid type %d\n", Type);
+                               kfree(card);
+                               return;
+               }
+               if (!(card->bch = (eicon_chan *) kmalloc(sizeof(eicon_chan) * (card->nchannels + 1)
+                                                        , GFP_KERNEL))) {
+                       printk(KERN_WARNING
+                              "eicon: (%s) Could not allocate bch-struct.\n", id);
+                       kfree(card);
+                       return;
+               }
+               for (j=0; j< (card->nchannels + 1); j++) {
+                       memset((char *)&card->bch[j], 0, sizeof(eicon_chan));
+                       card->bch[j].plci = 0x8000;
+                       card->bch[j].ncci = 0x8000;
+                       card->bch[j].l2prot = ISDN_PROTO_L2_X75I;
+                       card->bch[j].l3prot = ISDN_PROTO_L3_TRANS;
+                       card->bch[j].e.D3Id = 0;
+                       card->bch[j].e.B2Id = 0;
+                       card->bch[j].e.Req = 0;
+                       card->bch[j].No = j;
+                       skb_queue_head_init(&card->bch[j].e.X);
+                       skb_queue_head_init(&card->bch[j].e.R);
+               }
+               card->next = cards;
+               cards = card;
+       }
+}
+
+/*
+ * register card at linklevel
+ */
+static int
+eicon_registercard(eicon_card * card)
+{
+        switch (card->bus) {
+               case EICON_BUS_ISA:
+                       /* TODO something to print */
+                       break;
+               case EICON_BUS_PCI:
+#if CONFIG_PCI
+                       eicon_pci_printpar(&card->hwif.pci); 
+                       break;
+#endif
+               case EICON_BUS_MCA:
+               default:
+                       if (DebugVar & 1)
+                               printk(KERN_WARNING
+                                      "eicon_registercard: Illegal BUS type %d\n",
+                              card->bus);
+                       return -1;
+        }
+        if (!register_isdn(&card->interface)) {
+                printk(KERN_WARNING
+                       "eicon_registercard: Unable to register %s\n",
+                       card->interface.id);
+                return -1;
+        }
+        card->myid = card->interface.channels;
+        sprintf(card->regname, "%s", card->interface.id);
+        return 0;
+}
+
+#ifdef MODULE
+static void
+unregister_card(eicon_card * card)
+{
+        isdn_ctrl cmd;
+
+        cmd.command = ISDN_STAT_UNLOAD;
+        cmd.driver = card->myid;
+        card->interface.statcallb(&cmd);
+        switch (card->bus) {
+               case EICON_BUS_ISA:
+                       eicon_isa_release(&card->hwif.isa);
+                       break;
+               case EICON_BUS_PCI:
+#if CONFIG_PCI
+                       eicon_pci_release(&card->hwif.pci);
+                       break;
+#endif
+               case EICON_BUS_MCA:
+               default:
+                       if (DebugVar & 1)
+                               printk(KERN_WARNING
+                                      "eicon: Invalid BUS type %d\n",
+                              card->bus);
+                       break;
+        }
+}
+#endif /* MODULE */
+
+static void
+eicon_freecard(eicon_card *card) {
+       eicon_clear_msn(card);
+       kfree(card->bch);
+       kfree(card);
+}
+
+int
+eicon_addcard(int Type, int membase, int irq, char *id)
+{
+       eicon_card *p;
+       eicon_card *q = NULL;
+       int registered;
+       int added = 0;
+       int failed = 0;
+
+       if (!Type) /* ISA */
+               if ((Type = eicon_isa_find_card(membase, irq, id)) < 0)
+                       return 0;
+       eicon_alloccard(Type, membase, irq, id);
+        p = cards;
+        while (p) {
+               registered = 0;
+               if (!p->interface.statcallb) {
+                       /* Not yet registered.
+                        * Try to register and activate it.
+                        */
+                       added++;
+                       switch (p->bus) {
+                               case EICON_BUS_ISA:
+                                       if (eicon_registercard(p))
+                                               break;
+                                       registered = 1;
+                                       break;
+                               case EICON_BUS_PCI:
+#if CONFIG_PCI
+                                       if (eicon_registercard(p))
+                                               break;
+                                       registered = 1;
+                                       break;
+#endif
+                               case EICON_BUS_MCA:
+                               default:
+                                       if (DebugVar & 1)
+                                               printk(KERN_WARNING
+                                                      "eicon: addcard: Invalid BUS type %d\n",
+                                              p->bus);
+                       }
+               } else
+                       /* Card already registered */
+                       registered = 1;
+                if (registered) {
+                       /* Init OK, next card ... */
+                        q = p;
+                        p = p->next;
+                } else {
+                        /* registering failed, remove card from list, free memory */
+                        printk(KERN_WARNING
+                               "eicon: Initialization of %s failed\n",
+                               p->interface.id);
+                        if (q) {
+                                q->next = p->next;
+                                eicon_freecard(p);
+                                p = q->next;
+                        } else {
+                                cards = p->next;
+                                eicon_freecard(p);
+                                p = cards;
+                        }
+                       failed++;
+                }
+       }
+        return (added - failed);
+}
+
+#define DRIVERNAME "Eicon active ISDN driver"
+#define DRIVERRELEASE "1"
+
+#ifdef MODULE
+#define eicon_init init_module
+#endif
+
+__initfunc(int
+eicon_init(void))
+{
+       int tmp = 0;
+       int release = 0;
+       char tmprev[50];
+
+       DebugVar = 1;
+
+        printk(KERN_INFO "%s Rev: ", DRIVERNAME);
+       strcpy(tmprev, eicon_revision);
+       printk("%s/", eicon_getrev(tmprev));
+       release += getrel(tmprev);
+       strcpy(tmprev, eicon_pci_revision);
+       printk("%s/", eicon_getrev(tmprev));
+       release += getrel(tmprev);
+       strcpy(tmprev, eicon_isa_revision);
+       printk("%s/", eicon_getrev(tmprev));
+       release += getrel(tmprev);
+       strcpy(tmprev, eicon_idi_revision);
+       printk("%s\n", eicon_getrev(tmprev));
+       release += getrel(tmprev);
+       sprintf(tmprev,"%d", release);
+        printk(KERN_INFO "%s Release: %s.%s\n", DRIVERNAME,
+               DRIVERRELEASE, tmprev);
+
+       tmp = eicon_addcard(0, membase, irq, id);
+#if CONFIG_PCI
+       tmp += eicon_pci_find_card(id);
+#endif
+        if (!cards) {
+#ifdef MODULE
+                printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n");
+#endif
+               return -ENODEV;
+
+       } else
+               printk(KERN_INFO "Eicon: %d card%s added\n", tmp, (tmp>1)?"s":"");
+        /* No symbols to export, hide all symbols */
+        EXPORT_NO_SYMBOLS;
+        return 0;
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+        eicon_card *card = cards;
+        eicon_card *last;
+        while (card) {
+                unregister_card(card); 
+                card = card->next;
+        }
+        card = cards;
+        while (card) {
+                last = card;
+                card = card->next;
+               eicon_freecard(last);
+        }
+        printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
+}
+
+#else
+__initfunc(void
+eicon_setup(char *str, int *ints))
+{
+        int i, argc;
+
+        argc = ints[0];
+        i = 1;
+        if (argc) {
+               membase = irq = -1;
+               if (argc) {
+                       membase = ints[i];
+                       i++;
+                       argc--;
+               }
+               if (argc) {
+                       irq = ints[i];
+                       i++;
+                       argc--;
+               }
+               if (strlen(str)) {
+                       strcpy(id, str);
+               } else {
+                       strcpy(id, "eicon");
+               } 
+               /* eicon_addcard(0, membase, irq, id); */
+                       printk(KERN_INFO "eicon: membase=0x%x irq=%d id=%s\n", membase, irq, id);
+       }
+}
+#endif
diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c
new file mode 100644 (file)
index 0000000..0029c3b
--- /dev/null
@@ -0,0 +1,951 @@
+/* $Id: eicon_pci.c,v 1.6 1999/04/01 12:48:37 armin Exp $
+ *
+ * ISDN low-level module for Eicon.Diehl active ISDN-Cards.
+ * Hardware-specific code for PCI cards.
+ *
+ * Copyright 1998,99 by Armin Schindler (mac@melware.de)
+ * Copyright 1999    Cytronics & Melware (info@melware.de)
+ *
+ * Thanks to   Eicon Technology Diehl GmbH & Co. oHG for 
+ *             documents, informations and hardware. 
+ *
+ *             Deutsche Telekom AG for S2M support.
+ *
+ * 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: eicon_pci.c,v $
+ * Revision 1.6  1999/04/01 12:48:37  armin
+ * Changed some log outputs.
+ *
+ * Revision 1.5  1999/03/29 11:19:49  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.4  1999/03/02 12:37:48  armin
+ * Added some important checks.
+ * Analog Modem with DSP.
+ * Channels will be added to Link-Level after loading firmware.
+ *
+ * Revision 1.3  1999/01/24 20:14:24  armin
+ * Changed and added debug stuff.
+ * Better data sending. (still problems with tty's flip buffer)
+ *
+ * Revision 1.2  1999/01/10 18:46:06  armin
+ * Bug with wrong values in HLC fixed.
+ * Bytes to send are counted and limited now.
+ *
+ * Revision 1.1  1999/01/01 18:09:45  armin
+ * First checkin of new eicon driver.
+ * DIVA-Server BRI/PCI and PRI/PCI are supported.
+ * Old diehl code is obsolete.
+ *
+ *
+ */
+
+#include <linux/pci.h>
+
+#include "eicon.h"
+#include "eicon_pci.h"
+
+
+char *eicon_pci_revision = "$Revision: 1.6 $";
+
+#if CONFIG_PCI          /* intire stuff is only for PCI */
+
+#undef EICON_PCI_DEBUG 
+
+int eicon_pci_find_card(char *ID)
+{
+  if (pci_present()) { 
+    struct pci_dev *pdev = NULL;  
+    int pci_nextindex=0, pci_cards=0, pci_akt=0; 
+    int pci_type = PCI_MAESTRA;
+    int NoMorePCICards = FALSE;
+    char *ram, *reg, *cfg;     
+    unsigned int pram=0, preg=0, pcfg=0;
+    char did[12];
+    eicon_pci_card *aparms;
+
+   if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) {
+                  printk(KERN_WARNING
+                      "eicon_pci: Could not allocate card-struct.\n");
+                  return 0;
+   }
+
+  for (pci_cards = 0; pci_cards < 0x0f; pci_cards++)
+  {
+  do {
+      if ((pdev = pci_find_device(PCI_VENDOR_EICON,          
+                                  pci_type,                  
+                                  pdev)))                    
+       {
+              pci_nextindex++;
+              break;
+       }
+       else {
+              pci_nextindex = 0;
+              switch (pci_type) /* switch to next card type */
+               {
+               case PCI_MAESTRA:
+                 pci_type = PCI_MAESTRAQ; break;
+               case PCI_MAESTRAQ:
+                 pci_type = PCI_MAESTRAQ_U; break;
+               case PCI_MAESTRAQ_U:
+                 pci_type = PCI_MAESTRAP; break;
+               default:
+               case PCI_MAESTRAP:
+                 NoMorePCICards = TRUE;
+               }
+       }
+     }
+     while (!NoMorePCICards);
+     if (NoMorePCICards)
+        {
+           if (pci_cards < 1) {
+           printk(KERN_INFO "Eicon: No supported PCI cards found.\n");
+          kfree(aparms);       
+           return 0;
+           }
+           else
+           {
+           printk(KERN_INFO "Eicon: %d PCI card%s registered.\n",
+                       pci_cards, (pci_cards > 1) ? "s":"");
+          kfree(aparms);       
+           return (pci_cards);
+           }
+        }
+
+   pci_akt = 0;
+   switch(pci_type)
+   {
+    case PCI_MAESTRA:
+         printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n");
+          aparms->type = EICON_CTYPE_MAESTRA;
+
+          aparms->irq = pdev->irq;
+          preg = pdev->base_address[2] & 0xfffffffc;
+          pcfg = pdev->base_address[1] & 0xffffff80;
+
+#ifdef EICON_PCI_DEBUG
+          printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
+          printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg);
+          printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg);
+#endif
+        pci_akt = 1;
+         break;
+
+    case PCI_MAESTRAQ:
+    case PCI_MAESTRAQ_U:
+         printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n");
+         pci_cards--;
+        pci_akt = 0;
+         break;
+
+    case PCI_MAESTRAP:
+         printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n");
+          aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/
+          aparms->irq = pdev->irq;
+          pram = pdev->base_address[0] & 0xfffff000;
+          preg = pdev->base_address[2] & 0xfffff000;
+          pcfg = pdev->base_address[4] & 0xfffff000;
+
+#ifdef EICON_PCI_DEBUG
+          printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
+          printk(KERN_DEBUG "eicon_pci: ram=0x%x\n",
+               (pram));
+          printk(KERN_DEBUG "eicon_pci: reg=0x%x\n",
+               (preg));
+          printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n",
+               (pcfg));
+#endif
+         pci_akt = 1;
+         break;        
+    default:
+         printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n");
+         pci_cards--;
+        pci_akt = 0;
+        break;
+   }
+
+       if (pci_akt) {
+               /* remapping memory */
+               switch(pci_type)
+               {
+               case PCI_MAESTRA:
+                       aparms->PCIreg = (unsigned int) preg;
+                       aparms->PCIcfg = (unsigned int) pcfg;
+                       if (check_region((aparms->PCIreg), 0x20)) {
+                               printk(KERN_WARNING "eicon_pci: reg port already in use !\n");
+                               aparms->PCIreg = 0;
+                               break;  
+                       } else {
+                               request_region(aparms->PCIreg, 0x20, "eicon reg");
+                       }
+                       if (check_region((aparms->PCIcfg), 0x100)) {
+                               printk(KERN_WARNING "eicon_pci: cfg port already in use !\n");
+                               aparms->PCIcfg = 0;
+                               break;  
+                       } else {
+                               request_region(aparms->PCIcfg, 0x100, "eicon cfg");
+                       }
+                       break;
+               case PCI_MAESTRAQ:
+               case PCI_MAESTRAQ_U:
+               case PCI_MAESTRAP:
+                       aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000);
+                       ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET);
+                       reg =  ioremap(preg, 0x4000);
+                       cfg =  ioremap(pcfg, 0x1000);   
+                       aparms->PCIram = (unsigned int) ram;
+                       aparms->PCIreg = (unsigned int) reg;
+                       aparms->PCIcfg = (unsigned int) cfg;
+                       break;
+                }
+               if ((!aparms->PCIreg) || (!aparms->PCIcfg)) {
+                       printk(KERN_ERR "eicon_pci: Card could not be added !\n");
+                       pci_cards--;
+               } else {
+                       aparms->mvalid = 1;
+       
+                       sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards);
+
+                       printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did);
+
+                       if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) {
+                               printk(KERN_ERR "eicon_pci: Card could not be added !\n");
+                               pci_cards--;
+                       }
+               }
+       }
+
+  }
+ } else
+       printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n");
+ return 0;
+}
+
+/*
+ * Checks protocol file id for "F#xxxx" string fragment to
+ * extract the features, supported by this protocol version.
+ * binary representation of the feature string value is returned
+ * in *value. The function returns 0 if feature string was not
+ * found or has a wrong format, else 1.
+ */
+static int GetProtFeatureValue(char *sw_id, int *value)
+{
+  __u8 i, offset;
+
+  while (*sw_id)
+  {
+    if ((sw_id[0] == 'F') && (sw_id[1] == '#'))
+    {
+      sw_id = &sw_id[2];
+      for (i=0, *value=0; i<4; i++, sw_id++)
+      {
+        if ((*sw_id >= '0') && (*sw_id <= '9'))
+        {
+          offset = '0';
+        }
+        else if ((*sw_id >= 'A') && (*sw_id <= 'F'))
+        {
+          offset = 'A' + 10;
+        }
+        else if ((*sw_id >= 'a') && (*sw_id <= 'f'))
+        {
+          offset = 'a' + 10;
+        }
+        else
+        {
+          return 0;
+        }
+        *value |= (*sw_id - offset) << (4*(3-i));
+      }
+      return 1;
+    }
+    else
+    {
+      sw_id++;
+    }
+  }
+  return 0;
+}
+
+
+void
+eicon_pci_printpar(eicon_pci_card *card) {
+        switch (card->type) {
+                case EICON_CTYPE_MAESTRA:
+                       printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n",
+                               eicon_ctype_name[card->type],
+                               (unsigned int)card->PCIreg,
+                               (unsigned int)card->PCIcfg,
+                               card->irq); 
+                       break;
+                case EICON_CTYPE_MAESTRAQ:
+                case EICON_CTYPE_MAESTRAQ_U:
+                case EICON_CTYPE_MAESTRAP:
+                       printk(KERN_INFO "%s at 0x%x, irq %d\n",
+                               eicon_ctype_name[card->type],
+                               (unsigned int)card->shmem,
+                               card->irq); 
+#ifdef EICON_PCI_DEBUG
+                       printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram);
+                       printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg);
+                       printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); 
+#endif
+                       break;
+       }
+}
+
+
+static void
+eicon_pci_release_shmem(eicon_pci_card *card) {
+       if (!card->master)
+               return;
+       if (card->mvalid) {
+               switch (card->type) {
+                       case EICON_CTYPE_MAESTRA:
+                               /* reset board */
+                               outb(0, card->PCIcfg + 0x4c);   /* disable interrupts from PLX */
+                               outb(0, card->PCIreg + M_RESET);
+                               SLEEP(20);
+                               outb(0, card->PCIreg + M_ADDRH);
+                               outw(0, card->PCIreg + M_ADDR);
+                               outw(0, card->PCIreg + M_DATA);
+
+                               release_region(card->PCIreg, 0x20);
+                               release_region(card->PCIcfg, 0x100);
+                               break;
+                       case EICON_CTYPE_MAESTRAQ:
+                       case EICON_CTYPE_MAESTRAQ_U:
+                       case EICON_CTYPE_MAESTRAP:
+                               /* reset board */
+                               writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
+                               SLEEP(20);
+                               writeb(0, card->PCIreg + MP_RESET);
+                               SLEEP(20);
+
+                               iounmap((void *)card->shmem);
+                               iounmap((void *)card->PCIreg);
+                               iounmap((void *)card->PCIcfg);
+                               break;
+               }
+       }
+       card->mvalid = 0;
+}
+
+static void
+eicon_pci_release_irq(eicon_pci_card *card) {
+       if (!card->master)
+               return;
+       if (card->ivalid)
+               free_irq(card->irq, card);
+       card->ivalid = 0;
+}
+
+void
+eicon_pci_release(eicon_pci_card *card) {
+        eicon_pci_release_irq(card);
+        eicon_pci_release_shmem(card);
+}
+
+/*
+ * Upload buffer content to adapters shared memory
+ * on verify error, 1 is returned and a message is printed on screen
+ * else 0 is returned
+ * Can serve IO-Type and Memory type adapters
+ */
+int eicon_upload(t_dsp_download_space   *p_para,
+            __u16                 length,   /* byte count */
+            __u8                  *buffer,
+            int                   verify)
+{
+  __u32               i, dwdata = 0, val = 0, timeout;
+  __u16               data;
+  eicon_pci_boot *boot = 0;
+
+  switch (p_para->type) /* actions depend on type of union */
+  {
+    case DL_PARA_IO_TYPE:
+      for (i=0; i<length; i+=2)
+      {
+       outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
+       outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); 
+       /* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */
+       outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); 
+      }
+      if (verify) /* check written block */
+      {
+        for (i=0; i<length; i+=2)
+        {
+         outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
+          outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); 
+          data = inw(p_para->dat.io.ioDATA);
+          if (data != *(u16 *)&buffer[i])
+          {
+            p_para->dat.io.r3addr  += i;
+            p_para->dat.io.BadData  = data;
+            p_para->dat.io.GoodData = *(u16 *)&buffer[i];
+            return 1;
+          }
+        }
+      }
+      break;
+
+    case DL_PARA_MEM_TYPE:
+      boot = p_para->dat.mem.boot;
+      writel(p_para->dat.mem.r3addr, &boot->addr);
+      for (i=0; i<length; i+=4)
+      {
+        writel(((u32 *)buffer)[i >> 2], &boot->data[i]);
+      }
+      if (verify) /* check written block */
+      {
+        for (i=0; i<length; i+=4)
+        {
+          dwdata = readl(&boot->data[i]);
+          if (((u32 *)buffer)[i >> 2] != dwdata)
+          {
+            p_para->dat.mem.r3addr  += i;
+            p_para->dat.mem.BadData  = dwdata;
+            p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2];
+            return 1;
+          }
+        }
+      }
+      writel(((length + 3) / 4), &boot->len);  /* len in dwords */
+      writel(2, &boot->cmd);
+
+       timeout = jiffies + 20;
+       while (timeout > jiffies) {
+               val = readl(&boot->cmd);
+               if (!val) break;
+               SLEEP(2);
+       }
+       if (val)
+         {
+               p_para->dat.mem.timeout = 1;
+               return 1;
+        }
+      break;
+  }
+  return 0;
+}
+
+
+/* show header information of code file */
+static
+int eicon_pci_print_hdr(unsigned char *code, int offset)
+{
+  unsigned char hdr[80];
+  int i, fvalue = 0;
+
+  i = 0;
+  while ((i < (sizeof(hdr) -1))
+          && (code[offset + i] != '\0')
+          && (code[offset + i] != '\r')
+          && (code[offset + i] != '\n'))
+   {
+     hdr[i] = code[offset + i];
+     i++;
+   }
+   hdr[i] = '\0';
+   printk(KERN_DEBUG "Eicon: loading %s\n", hdr);
+   if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue);
+    else return(0);
+}
+
+
+/*
+ * Configure a card, download code into BRI card,
+ * check if we get interrupts and return 0 on succes.
+ * Return -ERRNO on failure.
+ */
+int
+eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
+        int               i,j;
+        int               timeout;
+       unsigned int      offset, offp=0, size, length;
+       int               signature = 0;
+       int               FeatureValue = 0;
+        eicon_pci_codebuf cbuf;
+       t_dsp_download_space dl_para;
+       t_dsp_download_desc  dsp_download_table;
+        unsigned char     *code;
+       unsigned int      reg;
+       unsigned int      cfg;
+
+        if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
+                return -EFAULT;
+
+       reg = card->PCIreg;
+       cfg = card->PCIcfg;
+
+       /* reset board */
+       outb(0, reg + M_RESET);
+       SLEEP(10);
+       outb(0, reg + M_ADDRH);
+       outw(0, reg + M_ADDR);
+       outw(0, reg + M_DATA);
+
+#ifdef EICON_PCI_DEBUG
+        printk(KERN_DEBUG "eicon_pci: reset card\n");
+#endif
+
+       /* clear shared memory */
+       outb(0xff, reg + M_ADDRH);
+       outw(0, reg + M_ADDR);
+       for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA);
+       SLEEP(10);
+
+#ifdef EICON_PCI_DEBUG
+        printk(KERN_DEBUG "eicon_pci: clear shared memory\n");
+#endif
+
+       /* download protocol and dsp file */
+
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
+#endif
+
+               /* Allocate code-buffer */
+               if (!(code = kmalloc(400, GFP_KERNEL))) {
+                printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
+                       return -ENOMEM;
+        }
+
+       /* prepare protocol upload */
+       dl_para.type            = DL_PARA_IO_TYPE;
+       dl_para.dat.io.ioADDR   = reg + M_ADDR;
+       dl_para.dat.io.ioADDRH  = reg + M_ADDRH;
+       dl_para.dat.io.ioDATA   = reg + M_DATA;
+
+       for (j = 0; j <= cbuf.dsp_code_num; j++) 
+        {      
+          if (j == 0)  size = cbuf.protocol_len;
+                  else size = cbuf.dsp_code_len[j];
+
+               offset = 0;
+
+               if (j == 0) dl_para.dat.io.r3addr = 0;
+               if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE +
+                                       ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
+               if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE;
+               if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32);
+
+           do  /* download block of up to 400 bytes */
+            {
+              length = ((size - offset) >= 400) ? 400 : (size - offset);
+
+               if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
+                       kfree(code);
+                       return -EFAULT;
+               }
+
+               if ((offset == 0) && (j < 2)) {
+                       FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); 
+#ifdef EICON_PCI_DEBUG
+       if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue);
+#endif
+                       if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
+                               printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
+                               kfree(code);
+                               return -EFAULT;
+                       }
+                       ((eicon_card *)card->card)->Feature = FeatureValue;
+               }
+
+               if (eicon_upload(&dl_para, length, code, 1))
+               {
+                  printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
+                 kfree(code);
+                  return -EIO;
+               }
+              /* move onto next block */
+              offset += length;
+             dl_para.dat.io.r3addr += length;
+            } while (offset < size);
+
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset);
+#endif
+       offp += size;
+       }
+       kfree(code);    
+
+       /* clear signature */
+       outb(0xff, reg + M_ADDRH);
+       outw(0x1e, reg + M_ADDR);
+       outw(0, reg + M_DATA);
+
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
+#endif
+       /* copy configuration data into shared memory */
+       outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA);
+       outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA);
+       outw(10,reg + M_ADDR); outb(0, reg + M_DATA);
+       outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA);
+       outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA);
+       outw(13,reg + M_ADDR); outb(0, reg + M_DATA);                 /* XInterface */
+       outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA);
+       outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA);
+       outw(16,reg + M_ADDR); outb(0, reg + M_DATA);                 /* HandsetType */
+       outw(17,reg + M_ADDR); outb(0, reg + M_DATA);                 /* SigFlags */
+       outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA);
+       outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA);
+       outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA);
+       outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA);
+
+       for (i=0;i<32;i++)
+       {
+               outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA);
+               outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA);
+               outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA);
+               outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA);
+               outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA);
+               outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA);
+       }
+
+#ifdef EICON_PCI_DEBUG
+           printk(KERN_ERR "eicon_pci: starting CPU...\n");
+#endif
+       /* let the CPU run */
+       outw(0x08, reg + M_RESET);
+
+        timeout = jiffies + (5*HZ);
+        while (timeout > jiffies) {
+          outw(0x1e, reg + M_ADDR);    
+           signature = inw(reg + M_DATA);
+           if (signature == DIVAS_SIGNATURE) break;
+           SLEEP(2);
+         }
+        if (signature != DIVAS_SIGNATURE)
+         {
+#ifdef EICON_PCI_DEBUG
+           printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE);
+#endif
+           printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n");
+           return -EIO; 
+         }
+#ifdef EICON_PCI_DEBUG
+        printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
+#endif
+
+        /* get serial number and number of channels supported by card */
+       outb(0xff, reg + M_ADDRH);
+       outw(0x3f6, reg + M_ADDR);
+        card->channels = inw(reg + M_DATA);
+        card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26);
+        printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
+        printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
+
+        /* test interrupt */
+        card->irqprobe = 1;
+
+        if (!card->ivalid) {
+                if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card))
+                 {
+                  printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
+                  return -EIO;
+                 }
+        }
+        card->ivalid = 1;
+
+#ifdef EICON_PCI_DEBUG
+        printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
+#endif
+        /* Trigger an interrupt and check if it is delivered */
+        outb(0x41, cfg + 0x4c);                /* enable PLX for interrupts */
+       outb(0x89, reg + M_RESET);      /* place int request */
+
+        timeout = jiffies + 20;
+        while (timeout > jiffies) {
+          if (card->irqprobe != 1) break;
+          SLEEP(5);
+         }
+        if (card->irqprobe == 1) {
+           free_irq(card->irq, card); 
+           card->ivalid = 0; 
+           printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
+           return -EIO;
+         }
+
+   /* initializing some variables */
+   ((eicon_card *)card->card)->ReadyInt = 0;
+   for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
+   for(j=0; j< (card->channels + 1); j++) {
+                ((eicon_card *)card->card)->bch[j].e.busy = 0;
+                ((eicon_card *)card->card)->bch[j].e.D3Id = 0;
+                ((eicon_card *)card->card)->bch[j].e.B2Id = 0;
+                ((eicon_card *)card->card)->bch[j].e.ref = 0;
+                ((eicon_card *)card->card)->bch[j].e.Req = 0;
+                ((eicon_card *)card->card)->bch[j].e.complete = 1;
+                ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
+   }
+
+   printk(KERN_INFO "Eicon: Card successfully started\n");
+
+ return 0;
+}
+
+
+/*
+ * Configure a card, download code into PRI card,
+ * check if we get interrupts and return 0 on succes.
+ * Return -ERRNO on failure.
+ */
+int
+eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
+        eicon_pci_boot    *boot;
+       eicon_pr_ram  *prram;
+        int               i,j;
+        int               timeout;
+       int               FeatureValue = 0;
+       unsigned int      offset, offp=0, size, length;
+       unsigned long int signature = 0;
+       t_dsp_download_space dl_para;
+       t_dsp_download_desc  dsp_download_table;
+        eicon_pci_codebuf cbuf;
+        unsigned char     *code;
+       unsigned char     req_int;
+       char *ram, *reg, *cfg;  
+
+        if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
+                return -EFAULT;
+
+        boot = &card->shmem->boot;
+       ram = (char *)card->PCIram;
+       reg = (char *)card->PCIreg;
+       cfg = (char *)card->PCIcfg;
+       prram = (eicon_pr_ram *)ram;
+
+       /* reset board */
+       writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
+       SLEEP(20);
+       writeb(0, card->PCIreg + MP_RESET);
+       SLEEP(20);
+
+       /* set command count to 0 */
+       writel(0, &boot->reserved); 
+
+       /* check if CPU increments the life word */
+        i = readw(&boot->live);
+        SLEEP(20);
+        if (i == readw(&boot->live)) {
+           printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n");
+           return -EIO;
+         }
+#ifdef EICON_PCI_DEBUG
+        printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n");
+#endif
+
+       /* download firmware : DSP and Protocol */
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
+#endif
+
+               /* Allocate code-buffer */
+               if (!(code = kmalloc(400, GFP_KERNEL))) {
+                printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
+                       return -ENOMEM;
+        }
+
+       /* prepare protocol upload */
+       dl_para.type            = DL_PARA_MEM_TYPE;
+       dl_para.dat.mem.boot    = boot;
+
+        for (j = 0; j <= cbuf.dsp_code_num; j++)
+         {
+          if (j==0) size = cbuf.protocol_len;
+               else size = cbuf.dsp_code_len[j];       
+
+           if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */
+
+               if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR;
+               if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE +
+                                       ((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
+               if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE;
+               if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32);
+
+           offset = 0;
+           do  /* download block of up to 400 bytes */
+            {
+              length = ((size - offset) >= 400) ? 400 : (size - offset);
+
+               if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
+                       kfree(code);
+                       return -EFAULT;
+               }
+
+               if ((offset == 0) && (j < 2)) {
+                       FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); 
+#ifdef EICON_PCI_DEBUG
+       if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue);
+#endif
+                       if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
+                               printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
+                               kfree(code);
+                               return -EFAULT;
+                       }
+                       ((eicon_card *)card->card)->Feature = FeatureValue;
+               }
+
+               if (eicon_upload(&dl_para, length, code, 1))
+               {
+                 if (dl_para.dat.mem.timeout == 0)
+                         printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
+                       else
+                         printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n");
+                 kfree(code);
+                  return -EIO;
+               }
+
+              /* move onto next block */
+              offset += length;
+             dl_para.dat.mem.r3addr += length;
+            } while (offset < size);
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset);
+#endif
+        offp += size;
+         }
+        kfree(code);   
+
+       /* initialize the adapter data structure */
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
+#endif
+        /* clear out config space */
+        for (i = 0; i < 256; i++) writeb(0, &ram[i]);
+
+        /* copy configuration down to the card */
+        writeb(cbuf.tei, &ram[8]);
+        writeb(cbuf.nt2, &ram[9]);
+        writeb(0, &ram[10]);
+        writeb(cbuf.WatchDog, &ram[11]);
+        writeb(cbuf.Permanent, &ram[12]);
+        writeb(cbuf.XInterface, &ram[13]);
+        writeb(cbuf.StableL2, &ram[14]);
+        writeb(cbuf.NoOrderCheck, &ram[15]);
+        writeb(cbuf.HandsetType, &ram[16]);
+        writeb(0, &ram[17]);
+        writeb(cbuf.LowChannel, &ram[18]);
+        writeb(cbuf.ProtVersion, &ram[19]);
+        writeb(cbuf.Crc4, &ram[20]);
+        for (i = 0; i < 32; i++)
+         {
+           writeb(cbuf.l[0].oad[i], &ram[32 + i]);
+           writeb(cbuf.l[0].osa[i], &ram[64 + i]);
+           writeb(cbuf.l[0].spid[i], &ram[96 + i]);
+           writeb(cbuf.l[1].oad[i], &ram[128 + i]);
+           writeb(cbuf.l[1].osa[i], &ram[160 + i]);
+           writeb(cbuf.l[1].spid[i], &ram[192 + i]);
+         }
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: configured card OK\n");
+#endif
+
+       /* start adapter */
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: tell card to start...\n");
+#endif
+        writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */
+        writel(3, &boot->cmd); /* DIVAS_START_CMD */
+
+        /* wait till card ACKs */
+        timeout = jiffies + (5*HZ);
+        while (timeout > jiffies) {
+           signature = readl(&boot->signature);
+           if ((signature >> 16) == DIVAS_SIGNATURE) break;
+           SLEEP(2);
+         }
+        if ((signature >> 16) != DIVAS_SIGNATURE)
+         {
+#ifdef EICON_PCI_DEBUG
+           printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE);
+#endif
+           printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n");
+           return -EIO;
+         }
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
+#endif
+
+       /* get serial number and number of channels supported by card */
+        card->channels = readb(&ram[0x3f6]);
+        card->serial = readl(&ram[0x3f0]);
+        printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
+        printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
+
+       /* test interrupt */
+       readb(&ram[0x3fe]);
+        writeb(0, &ram[0x3fe]); /* reset any pending interrupt */
+       readb(&ram[0x3fe]);
+
+        writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
+        writew(0, &cfg[MP_IRQ_RESET + 2]);
+
+        card->irqprobe = 1;
+
+       if (!card->ivalid) {
+               if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) 
+                {
+                 printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
+                 return -EIO;
+                }
+       }
+       card->ivalid = 1;
+
+        req_int = readb(&prram->ReadyInt);
+#ifdef EICON_PCI_DEBUG
+       printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
+#endif
+        req_int++;
+        /* Trigger an interrupt and check if it is delivered */
+        writeb(req_int, &prram->ReadyInt);
+
+        timeout = jiffies + 20;
+        while (timeout > jiffies) {
+          if (card->irqprobe != 1) break;
+          SLEEP(2);
+         }
+        if (card->irqprobe == 1) {
+           free_irq(card->irq, card);
+          card->ivalid = 0;
+           printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
+           return -EIO;
+         }
+
+   /* initializing some variables */
+   ((eicon_card *)card->card)->ReadyInt = 0;
+   for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
+   for(j=0; j< (card->channels + 1); j++) {
+               ((eicon_card *)card->card)->bch[j].e.busy = 0;
+               ((eicon_card *)card->card)->bch[j].e.D3Id = 0;
+               ((eicon_card *)card->card)->bch[j].e.B2Id = 0;
+               ((eicon_card *)card->card)->bch[j].e.ref = 0;
+               ((eicon_card *)card->card)->bch[j].e.Req = 0;
+                ((eicon_card *)card->card)->bch[j].e.complete = 1;
+                ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
+   }
+
+   printk(KERN_INFO "Eicon: Card successfully started\n");
+
+ return 0;
+}
+
+#endif /* CONFIG_PCI */
+
diff --git a/drivers/isdn/eicon/eicon_pci.h b/drivers/isdn/eicon/eicon_pci.h
new file mode 100644 (file)
index 0000000..a23faad
--- /dev/null
@@ -0,0 +1,188 @@
+/* $Id: eicon_pci.h,v 1.3 1999/03/29 11:19:51 armin Exp $
+ *
+ * ISDN low-level module for Eicon.Diehl active ISDN-Cards (PCI part).
+ *
+ * Copyright 1998,99 by Armin Schindler (mac@melware.de)
+ * Copyright 1999    Cytronics & Melware (info@melware.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: eicon_pci.h,v $
+ * Revision 1.3  1999/03/29 11:19:51  armin
+ * I/O stuff now in seperate file (eicon_io.c)
+ * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
+ *
+ * Revision 1.2  1999/03/02 12:37:50  armin
+ * Added some important checks.
+ * Analog Modem with DSP.
+ * Channels will be added to Link-Level after loading firmware.
+ *
+ * Revision 1.1  1999/01/01 18:09:46  armin
+ * First checkin of new eicon driver.
+ * DIVA-Server BRI/PCI and PRI/PCI are supported.
+ * Old diehl code is obsolete.
+ *
+ *
+ */
+
+#ifndef eicon_pci_h
+#define eicon_pci_h
+
+#ifdef __KERNEL__
+
+
+#define PCI_VENDOR_EICON        0x1133
+#define PCI_DIVA_PRO20          0xe001 /* Not supported */
+#define PCI_DIVA20              0xe002 /* Not supported */
+#define PCI_DIVA_PRO20_U        0xe003 /* Not supported */
+#define PCI_DIVA20_U            0xe004 /* Not supported */
+#define PCI_MAESTRA             0xe010
+#define PCI_MAESTRAQ            0xe012
+#define PCI_MAESTRAQ_U          0xe013
+#define PCI_MAESTRAP            0xe014
+
+#define DIVA_PRO20          1
+#define DIVA20              2
+#define DIVA_PRO20_U        3
+#define DIVA20_U            4
+#define MAESTRA             5
+#define MAESTRAQ            6
+#define MAESTRAQ_U          7
+#define MAESTRAP            8
+
+#define TRUE  1
+#define FALSE 0
+
+#define DIVAS_SIGNATURE 0x4447
+
+
+/* MAESTRA BRI PCI */
+
+#define M_RESET                0x10            /* offset of reset register */
+#define M_DATA         0x00            /* offset of data register */
+#define M_ADDR         0x04            /* offset of address register */
+#define M_ADDRH                0x0c            /* offset of high address register */
+
+#define M_DSP_CODE_LEN            0xbf7d0000
+#define M_DSP_CODE                0xbf7d0004  /* max 128K DSP-Code */ 
+#define M_DSP_CODE_BASE           0xbf7a0000  
+#define M_MAX_DSP_CODE_SIZE       0x00050000  /* max 320K DSP-Code (Telindus) */
+
+
+
+/* MAESTRA PRI PCI */
+
+#define MP_SHARED_RAM_OFFSET 0x1000  /* offset of shared RAM base in the DRAM memory bar */
+
+#define MP_IRQ_RESET     0xc18       /* offset of interrupt status register in the CONFIG memory bar */
+#define MP_IRQ_RESET_VAL 0xfe        /* value to clear an interrupt */
+
+#define MP_PROTOCOL_ADDR 0xa0011000  /* load address of protocol code */
+#define MP_DSP_ADDR      0xa03c0000  /* load address of DSP code */
+#define MP_MAX_PROTOCOL_CODE_SIZE  0x000a0000   /* max 640K Protocol-Code */
+#define MP_DSP_CODE_BASE           0xa03a0000
+#define MP_MAX_DSP_CODE_SIZE       0x00060000   /* max 384K DSP-Code */
+
+#define MP_RESET         0x20        /* offset of RESET register in the DEVICES memory bar */
+
+/* RESET register bits */
+#define _MP_S2M_RESET    0x10        /* active lo   */
+#define _MP_LED2         0x08        /* 1 = on      */
+#define _MP_LED1         0x04        /* 1 = on      */
+#define _MP_DSP_RESET    0x02        /* active lo   */
+#define _MP_RISC_RESET   0x81        /* active hi, bit 7 for compatibility with old boards */
+
+/* boot interface structure */
+typedef struct {
+       __u32 cmd       __attribute__ ((packed));
+       __u32 addr      __attribute__ ((packed));
+       __u32 len       __attribute__ ((packed));
+       __u32 err       __attribute__ ((packed));
+       __u32 live      __attribute__ ((packed));
+       __u32 reserved[(0x1020>>2)-6] __attribute__ ((packed));
+       __u32 signature __attribute__ ((packed));
+       __u8 data[1];    /* real interface description */
+} eicon_pci_boot;
+
+
+#define DL_PARA_IO_TYPE   0
+#define DL_PARA_MEM_TYPE  1
+
+typedef struct tag_dsp_download_space
+{
+  __u16 type;  /* see definitions above to differ union elements */
+  union
+  {
+    struct
+    {
+      __u32               r3addr;
+      __u16               ioADDR;
+      __u16               ioADDRH;
+      __u16               ioDATA;
+      __u16               BadData;  /* in case of verify error */
+      __u16               GoodData;
+    } io;     /* for io based adapters */
+    struct
+    {
+      __u32               r3addr;
+      eicon_pci_boot     *boot;
+      __u32               BadData;  /* in case of verify error */
+      __u32               GoodData;
+      __u16               timeout;
+    } mem;    /* for memory based adapters */
+  } dat;
+} t_dsp_download_space;
+
+
+/* Shared memory */
+typedef union {
+       eicon_pci_boot boot;
+} eicon_pci_shmem;
+
+/*
+ * card's description
+ */
+typedef struct {
+       int               ramsize;
+       int               irq;      /* IRQ                        */
+       unsigned int      PCIram;
+       unsigned int      PCIreg;
+       unsigned int      PCIcfg;
+       long int          serial;   /* Serial No.                 */
+       int               channels; /* No. of supported channels  */
+        void*             card;
+        eicon_pci_shmem*  shmem;    /* Shared-memory area         */
+        unsigned char*    intack;   /* Int-Acknowledge            */
+        unsigned char*    stopcpu;  /* Writing here stops CPU     */
+        unsigned char*    startcpu; /* Writing here starts CPU    */
+        unsigned char     type;     /* card type                  */
+        unsigned char     irqprobe; /* Flag: IRQ-probing          */
+        unsigned char     mvalid;   /* Flag: Memory is valid      */
+        unsigned char     ivalid;   /* Flag: IRQ is valid         */
+        unsigned char     master;   /* Flag: Card is Quadro 1/4   */
+        void*             generic;  /* Ptr to generic card struct */
+} eicon_pci_card;
+
+
+
+extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb);
+extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb);
+extern void eicon_pci_release(eicon_pci_card *card);
+extern void eicon_pci_printpar(eicon_pci_card *card);
+extern int eicon_pci_find_card(char *ID);
+
+#endif  /* __KERNEL__ */
+
+#endif /* eicon_pci_h */
index da07e7b8c20f76c77f2553462eca43a29f3ed0aa..9e7cb777373ffb980a6d27cdcbe4bd2edcb38d17 100644 (file)
@@ -8,7 +8,7 @@ L_TARGET :=
 O_TARGET :=
 
 O_OBJS := isdnl1.o tei.o isdnl2.o isdnl3.o \
-          lmgr.o q931.o callc.o fsm.o
+          lmgr.o q931.o callc.o fsm.o cert.o
 
 # EXTRA_CFLAGS += -S
 
@@ -27,6 +27,7 @@ endif
 ISAC_OBJ :=
 ARCOFI_OBJ :=
 HSCX_OBJ :=
+ISAR_OBJ :=
 HFC_OBJ :=
 HFC_2BDS0 :=
 RAWHDLC_OBJ :=
@@ -43,12 +44,36 @@ ifeq ($(CONFIG_HISAX_16_3),y)
         HSCX_OBJ := hscx.o
 endif
 
+ifeq ($(CONFIG_HISAX_TELESPCI),y)
+        O_OBJS += telespci.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+
+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_AVM_A1_PCMCIA),y)
+        O_OBJS += avm_a1p.o
+        ISAC_OBJ := isac.o
+        HSCX_OBJ := hscx.o
+endif
+ifeq ($(CONFIG_HISAX_FRITZPCI),y)
+        O_OBJS += avm_pci.o
+        ISAC_OBJ := isac.o
+endif
+
+
 ifeq ($(CONFIG_HISAX_ELSA),y)
         O_OBJS += elsa.o
         ISAC_OBJ := isac.o
@@ -84,6 +109,7 @@ ifeq ($(CONFIG_HISAX_SEDLBAUER),y)
         O_OBJS += sedlbauer.o
         ISAC_OBJ := isac.o
         HSCX_OBJ := hscx.o
+        ISAR_OBJ := isar.o
 endif
 
 ifeq ($(CONFIG_HISAX_SPORTSTER),y)
@@ -101,6 +127,7 @@ endif
 ifeq ($(CONFIG_HISAX_NETJET),y)
         O_OBJS += netjet.o
         ISAC_OBJ := isac.o
+#       RAWHDLC_OBJ := rawhdlc.o
 endif
 
 ifeq ($(CONFIG_HISAX_TELES3C),y)
@@ -108,10 +135,8 @@ ifeq ($(CONFIG_HISAX_TELES3C),y)
         HFC_2BDS0 := hfc_2bds0.o
 endif
 ifeq ($(CONFIG_HISAX_AMD7930),y)
-        RAWHDLC_OBJ := foreign.o rawhdlc.o
-endif
-ifeq ($(CONFIG_HISAX_DBRI),y)
-        RAWHDLC_OBJ := foreign.o rawhdlc.o
+        O_OBJS += amd7930.o
+        RAWHDLC_OBJ := rawhdlc.o
 endif
 
 ifeq ($(CONFIG_HISAX_NICCY),y)
@@ -120,7 +145,8 @@ ifeq ($(CONFIG_HISAX_NICCY),y)
         HSCX_OBJ := hscx.o
 endif
 
-O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(HFC_OBJ) $(ARCOFI_OBJ) $(HFC_2BDS0) $(RAWHDLC_OBJ)
+O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(ARCOFI_OBJ) 
+O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(RAWHDLC_OBJ) 
 OX_OBJS += config.o
 
 O_TARGET :=
@@ -134,4 +160,14 @@ else
   endif
 endif
 
+
 include $(TOPDIR)/Rules.make
+
+MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \
+           tei.c callc.c cert.c l3dss1.c l3_1tr6.c elsa.c
+
+CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
+
+cert.o:        $(MD5FILES) md5sums.asc
+       $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c
+
index 1717b3a278ec6115b209e2e9bc95fa6ccb0e849b..a7c09132138fa41c75fadbd81e8878674a9cbb63 100644 (file)
@@ -1,12 +1,28 @@
-/* $Id: arcofi.c,v 1.1 1997/10/29 18:51:20 keil Exp $
+/* $Id: arcofi.c,v 1.6 1998/09/30 22:21:56 keil Exp $
 
- * arcofi.h   Ansteuerung ARCOFI 2165
+ * arcofi.c   Ansteuerung ARCOFI 2165
  *
  * Author     Karsten Keil (keil@temic-ech.spacenet.de)
  *
  *
  *
  * $Log: arcofi.c,v $
+ * Revision 1.6  1998/09/30 22:21:56  keil
+ * cosmetics
+ *
+ * Revision 1.5  1998/09/27 12:52:57  keil
+ * cosmetics
+ *
+ * Revision 1.4  1998/08/20 13:50:24  keil
+ * More support for hybrid modem (not working yet)
+ *
+ * Revision 1.3  1998/05/25 12:57:38  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 1.2  1998/04/15 16:47:16  keil
+ * new interface
+ *
  * Revision 1.1  1997/10/29 18:51:20  keil
  * New files
  *
 #include "isac.h"
 
 int
-send_arcofi(struct IsdnCardState *cs, const u_char *msg) {
+send_arcofi(struct IsdnCardState *cs, const u_char *msg, int bc, int receive) {
        u_char val;
-       char tmp[32];
        long flags;
-       int cnt=2;
+       int cnt=30;
        
        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++]);
@@ -39,12 +62,18 @@ send_arcofi(struct IsdnCardState *cs, const u_char *msg) {
        sti();
        while (cnt && !test_bit(HW_MON1_TX_END, &cs->HW_Flags)) {
                cnt--;
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+               udelay(500);
+       }
+       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);
+       if (cnt <= 0) {
+               printk(KERN_WARNING"HiSax arcofi monitor timed out\n");
+               debugl1(cs, "HiSax arcofi monitor timed out");
+       }
        return(cnt);    
 }
-
index 5e1bb9e993e59ac80c8dc6f7a620aa7ad542728a..be1097d15bfd0ba19e1af08a14e8bab17a9bd0c4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: arcofi.h,v 1.1 1997/10/29 18:51:20 keil Exp $
+/* $Id: arcofi.h,v 1.3 1998/05/25 12:57:39 keil Exp $
 
  * arcofi.h   Ansteuerung ARCOFI 2165
  *
@@ -7,6 +7,13 @@
  *
  *
  * $Log: arcofi.h,v $
+ * Revision 1.3  1998/05/25 12:57:39  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 1.2  1998/04/15 16:47:17  keil
+ * new interface
+ *
  * Revision 1.1  1997/10/29 18:51:20  keil
  * New files
  *
@@ -14,4 +21,4 @@
  
 #define ARCOFI_USE     1
 
-extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg);
+extern int send_arcofi(struct IsdnCardState *cs, const u_char *msg, int bc, int receive);
index 6980a2888685c9d4fa5ef812dcae9a5026498e02..4990f9eb82e0de2c298e7c2942dade65e5c727d1 100644 (file)
@@ -1,13 +1,22 @@
-/* $Id: asuscom.c,v 1.2 1998/02/02 13:27:06 keil Exp $
+/* $Id: asuscom.c,v 1.5 1998/11/15 23:54:19 keil Exp $
 
  * asuscom.c     low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
  *
- * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * Thanks to  ASUSCOM NETWORK INC. Taiwan and  Dynalink NL for informations
  *
  *
  * $Log: asuscom.c,v $
+ * Revision 1.5  1998/11/15 23:54:19  keil
+ * changes from 2.0
+ *
+ * Revision 1.4  1998/06/18 23:18:20  keil
+ * Support for new IPAC card
+ *
+ * Revision 1.3  1998/04/15 16:46:53  keil
+ * new init code
+ *
  * Revision 1.2  1998/02/02 13:27:06  keil
  * New
  *
 #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.2 $";
+const char *Asuscom_revision = "$Revision: 1.5 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -33,6 +43,12 @@ const char *Asuscom_revision = "$Revision: 1.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 */
 
@@ -106,6 +122,30 @@ 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)
 {
@@ -183,6 +223,52 @@ asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        }
 }
 
+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;
+
+       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)
+               debugl1(cs, "IPAC ISTA %02X", ista);
+       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)
 {
@@ -197,14 +283,27 @@ reset_asuscom(struct IsdnCardState *cs)
 {
        long flags;
 
-       byteout(cs->hw.asus.adr, ASUS_RESET);   /* Reset On */
+       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;
        schedule_timeout(1);
-       byteout(cs->hw.asus.adr, 0);    /* Reset Off */
+       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;
        schedule_timeout(1);
+       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);
 }
 
@@ -219,13 +318,15 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        release_io_asuscom(cs);
                        return(0);
                case CARD_SETIRQ:
-                       return(request_irq(cs->irq, &asuscom_interrupt,
+                       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:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       cs->debug |= L1_DEB_IPAC;
+                       inithscxisac(cs, 3);
                        return(0);
                case CARD_TEST:
                        return(0);
@@ -238,6 +339,7 @@ setup_asuscom(struct IsdnCard *card))
 {
        int bytecnt;
        struct IsdnCardState *cs = card->cs;
+       u_char val;
        char tmp[64];
 
        strcpy(tmp, Asuscom_revision);
@@ -248,12 +350,6 @@ setup_asuscom(struct IsdnCard *card))
        bytecnt = 8;
        cs->hw.asus.cfg_reg = card->para[1];
        cs->irq = card->para[0];
-       cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
-       cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
-       cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
-       cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
-       cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
-
        if (check_region((cs->hw.asus.cfg_reg), bytecnt)) {
                printk(KERN_WARNING
                       "HiSax: %s config port %x-%x already in use\n",
@@ -264,27 +360,45 @@ setup_asuscom(struct IsdnCard *card))
        } else {
                request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn");
        }
-
-       printk(KERN_INFO
-              "ISDNLink: defined at 0x%x IRQ %d\n",
-              cs->hw.asus.cfg_reg,
-              cs->irq);
-       printk(KERN_INFO "ISDNLink: resetting card\n");
-       reset_asuscom(cs);
-       cs->readisac = &ReadISAC;
-       cs->writeisac = &WriteISAC;
-       cs->readisacfifo = &ReadISACfifo;
-       cs->writeisacfifo = &WriteISACfifo;
+       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;
-       ISACVersion(cs, "ISDNLink:");
-       if (HscxVersion(cs, "ISDNLink:")) {
-               printk(KERN_WARNING
-                    "ISDNLink: wrong HSCX versions check IO address\n");
-               release_io_asuscom(cs);
-               return (0);
+       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 464bc33fd4dc1502dc41377da5dcaf2ee80b1d42..5c5f944d44c23162bd692dae407d1c76c3724820 100644 (file)
@@ -1,11 +1,20 @@
-/* $Id: avm_a1.c,v 2.7 1998/02/02 13:29:37 keil Exp $
+/* $Id: avm_a1.c,v 2.10 1998/11/15 23:54:21 keil Exp $
 
  * avm_a1.c     low level stuff for AVM A1 (Fritz) isdn cards
  *
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *
  *
  * $Log: avm_a1.c,v $
+ * Revision 2.10  1998/11/15 23:54:21  keil
+ * changes from 2.0
+ *
+ * Revision 2.9  1998/08/13 23:36:12  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.8  1998/04/15 16:44:27  keil
+ * new init code
+ *
  * Revision 2.7  1998/02/02 13:29:37  keil
  * fast io
  *
@@ -57,7 +66,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *avm_revision = "$Revision: 2.7 $";
+static const char *avm_revision = "$Revision: 2.10 $";
 
 #define         AVM_A1_STAT_ISAC       0x01
 #define         AVM_A1_STAT_HSCX       0x02
@@ -145,7 +154,6 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
        struct IsdnCardState *cs = dev_id;
        u_char val, sval, stat = 0;
-       char tmp[32];
 
        if (!cs) {
                printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
@@ -155,10 +163,8 @@ avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                if (!(sval & AVM_A1_STAT_TIMER)) {
                        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(cs, tmp);
-               }
+               } else if (cs->debug & L1_DEB_INTSTAT)
+                       debugl1(cs, "avm IntStatus %x", sval);
                if (!(sval & AVM_A1_STAT_HSCX)) {
                        val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
                        if (val) {
@@ -217,10 +223,10 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        return(request_irq(cs->irq, &avm_a1_interrupt,
                                        I4L_IRQ_FLAG, "HiSax", cs));
                case CARD_INIT:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       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);
@@ -348,7 +354,6 @@ setup_avm_a1(struct IsdnCard *card))
        val = bytein(cs->hw.avm.cfg_reg + 2);
        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
               cs->hw.avm.cfg_reg + 2, val);
-       byteout(cs->hw.avm.cfg_reg, 0x1E);
        val = bytein(cs->hw.avm.cfg_reg);
        printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
               cs->hw.avm.cfg_reg, val);
diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c
new file mode 100644 (file)
index 0000000..c11ac41
--- /dev/null
@@ -0,0 +1,334 @@
+/* $Id: avm_a1p.c,v 2.3 1998/11/15 23:54:22 keil Exp $
+ *
+ * avm_a1p.c    low level stuff for the following AVM cards:
+ *              A1 PCMCIA
+ *             FRITZ!Card PCMCIA
+ *             FRITZ!Card PCMCIA 2.0
+ *
+ * Author       Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: avm_a1p.c,v $
+ * Revision 2.3  1998/11/15 23:54:22  keil
+ * changes from 2.0
+ *
+ * Revision 2.2  1998/08/13 23:36:13  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.1  1998/07/15 15:01:23  calle
+ * Support for AVM passive PCMCIA cards:
+ *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
+ *
+ * Revision 1.1.2.1  1998/07/15 14:43:26  calle
+ * Support for AVM passive PCMCIA cards:
+ *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+
+/* register offsets */
+#define ADDRREG_OFFSET         0x02
+#define DATAREG_OFFSET         0x03
+#define ASL0_OFFSET            0x04
+#define ASL1_OFFSET            0x05
+#define MODREG_OFFSET          0x06
+#define VERREG_OFFSET          0x07
+
+/* address offsets */
+#define ISAC_FIFO_OFFSET       0x00
+#define ISAC_REG_OFFSET                0x20
+#define HSCX_CH_DIFF           0x40
+#define HSCX_FIFO_OFFSET       0x80
+#define HSCX_REG_OFFSET                0xa0
+
+/* read bits ASL0 */
+#define         ASL0_R_TIMER           0x10 /* active low */
+#define         ASL0_R_ISAC            0x20 /* active low */
+#define         ASL0_R_HSCX            0x40 /* active low */
+#define         ASL0_R_TESTBIT         0x80
+#define  ASL0_R_IRQPENDING     (ASL0_R_ISAC|ASL0_R_HSCX|ASL0_R_TIMER)
+
+/* write bits ASL0 */
+#define         ASL0_W_RESET           0x01
+#define         ASL0_W_TDISABLE        0x02
+#define         ASL0_W_TRESET          0x04
+#define         ASL0_W_IRQENABLE       0x08
+#define         ASL0_W_TESTBIT         0x80
+
+/* write bits ASL1 */
+#define         ASL1_W_LED0            0x10
+#define         ASL1_W_LED1            0x20
+#define         ASL1_W_ENABLE_S0       0xC0
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+static const char *avm_revision = "$Revision: 2.3 $";
+
+static inline u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       long flags;
+        u_char ret;
+
+        offset -= 0x20;
+       save_flags(flags);
+       cli();
+        byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
+       ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
+       restore_flags(flags);
+       return ret;
+}
+
+static inline void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       long flags;
+
+        offset -= 0x20;
+
+       save_flags(flags);
+       cli();
+        byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
+       byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
+       restore_flags(flags);
+}
+
+static inline void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
+       insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
+       restore_flags(flags);
+}
+
+static inline void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
+       outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
+       restore_flags(flags);
+}
+
+static inline u_char
+ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+       u_char ret;
+       long flags;
+
+        offset -= 0x20;
+
+       save_flags(flags);
+       cli();
+       byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
+                       HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
+       ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
+       restore_flags(flags);
+       return ret;
+}
+
+static inline void
+WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+       long flags;
+
+        offset -= 0x20;
+
+       save_flags(flags);
+       cli();
+       byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
+                       HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
+       byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
+       restore_flags(flags);
+}
+
+static inline void
+ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
+                       HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
+       insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
+       restore_flags(flags);
+}
+
+static inline void
+WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
+{
+       long flags;
+
+       save_flags(flags);
+       cli();
+       byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
+                       HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
+       outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
+       restore_flags(flags);
+}
+
+/*
+ * fast interrupt HSCX stuff goes here
+ */
+
+#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
+#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
+#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) 
+#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
+
+#include "hscx_irq.c"
+
+static void
+avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, sval, stat = 0;
+
+       if (!cs) {
+               printk(KERN_WARNING "AVM A1 PCMCIA: Spurious interrupt!\n");
+               return;
+       }
+       while ((sval = (~bytein(cs->hw.avm.cfg_reg+ASL0_OFFSET) & ASL0_R_IRQPENDING))) {
+               if (cs->debug & L1_DEB_INTSTAT)
+                       debugl1(cs, "avm IntStatus %x", sval);
+               if (sval & ASL0_R_HSCX) {
+                        val = ReadHSCX(cs, 1, HSCX_ISTA);
+                       if (val) {
+                               hscx_int_main(cs, val);
+                               stat |= 1;
+                       }
+               }
+               if (sval & ASL0_R_ISAC) {
+                       val = ReadISAC(cs, ISAC_ISTA);
+                       if (val) {
+                               isac_interrupt(cs, val);
+                               stat |= 2;
+                       }
+               }
+       }
+       if (stat & 1) {
+               WriteHSCX(cs, 0, HSCX_MASK, 0xff);
+               WriteHSCX(cs, 1, HSCX_MASK, 0xff);
+               WriteHSCX(cs, 0, HSCX_MASK, 0x00);
+               WriteHSCX(cs, 1, HSCX_MASK, 0x00);
+       }
+       if (stat & 2) {
+               WriteISAC(cs, ISAC_MASK, 0xff);
+               WriteISAC(cs, ISAC_MASK, 0x00);
+       }
+}
+
+static int
+AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       int ret;
+       switch (mt) {
+               case CARD_RESET:
+                       byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
+                       HZDELAY(HZ / 5 + 1);
+                       byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
+                       HZDELAY(HZ / 5 + 1);
+                       byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
+                       return 0;
+
+               case CARD_RELEASE:
+                       /* free_irq is done in HiSax_closecard(). */
+                       /* free_irq(cs->irq, cs); */
+                       return 0;
+
+               case CARD_SETIRQ:
+                       ret = request_irq(cs->irq, &avm_a1p_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs);
+                       if (ret)
+                               return ret;
+                       byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,
+                               ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE);
+                        return 0;
+
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       clear_pending_hscx_ints(cs);
+                       inithscxisac(cs, 1);
+                       inithscxisac(cs, 2);
+                       return 0;
+
+               case CARD_TEST:
+                       /* we really don't need it for the PCMCIA Version */
+                       return 0;
+
+               default:
+                       /* all card drivers ignore others, so we do the same */
+                       return 0;
+       }
+       return 0;
+}
+
+__initfunc(int
+setup_avm_a1_pcmcia(struct IsdnCard *card))
+{
+       u_char model, vers;
+       struct IsdnCardState *cs = card->cs;
+       long flags;
+       char tmp[64];
+
+
+       strcpy(tmp, avm_revision);
+       printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
+                                                HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_A1_PCMCIA)
+               return (0);
+
+       cs->hw.avm.cfg_reg = card->para[1];
+       cs->irq = card->para[0];
+
+
+       save_flags(flags);
+       outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0);
+        sti();
+
+       byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
+       HZDELAY(HZ / 5 + 1);
+       byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
+       HZDELAY(HZ / 5 + 1);
+       byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
+
+       byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET, ASL0_W_TDISABLE|ASL0_W_TRESET);
+
+       restore_flags(flags);
+
+       model = bytein(cs->hw.avm.cfg_reg+MODREG_OFFSET);
+       vers = bytein(cs->hw.avm.cfg_reg+VERREG_OFFSET);
+
+       printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
+                               cs->hw.avm.cfg_reg, cs->irq, model, vers);
+
+       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 PCMCIA:");
+       if (HscxVersion(cs, "AVM A1 PCMCIA:")) {
+               printk(KERN_WARNING
+                      "AVM A1 PCMCIA: wrong HSCX versions check IO address\n");
+               return (0);
+       }
+       return (1);
+}
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
new file mode 100644 (file)
index 0000000..c0f04f9
--- /dev/null
@@ -0,0 +1,865 @@
+/* $Id: avm_pci.c,v 1.7 1999/02/22 18:26:30 keil Exp $
+
+ * avm_pci.c    low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
+ *              Thanks to AVM, Berlin for informations
+ *
+ * Author       Karsten Keil (keil@isdn4linux.de)
+ *
+ *
+ * $Log: avm_pci.c,v $
+ * Revision 1.7  1999/02/22 18:26:30  keil
+ * Argh ! ISAC address was only set with PCI
+ *
+ * Revision 1.6  1998/11/27 19:59:28  keil
+ * set subtype for Fritz!PCI
+ *
+ * Revision 1.5  1998/11/27 12:56:45  keil
+ * forgot to update setup function name
+ *
+ * Revision 1.4  1998/11/15 23:53:19  keil
+ * Fritz!PnP; changes from 2.0
+ *
+ * Revision 1.3  1998/09/27 23:53:39  keil
+ * Fix error handling
+ *
+ * Revision 1.2  1998/09/27 12:54:55  keil
+ * bcs assign was lost in setstack, very bad results
+ *
+ * Revision 1.1  1998/08/20 13:47:30  keil
+ * first version
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+extern const char *CardType[];
+static const char *avm_pci_rev = "$Revision: 1.7 $";
+
+#define  AVM_FRITZ_PCI         1
+#define  AVM_FRITZ_PNP         2
+
+#define  PCI_VENDOR_AVM                0x1244
+#define  PCI_FRITZPCI_ID       0xa00
+
+#define  HDLC_FIFO             0x0
+#define  HDLC_STATUS           0x4
+
+#define         AVM_HDLC_1             0x00
+#define         AVM_HDLC_2             0x01
+#define         AVM_ISAC_FIFO          0x02
+#define         AVM_ISAC_REG_LOW       0x04
+#define         AVM_ISAC_REG_HIGH      0x06
+
+#define  AVM_STATUS0_IRQ_ISAC  0x01
+#define  AVM_STATUS0_IRQ_HDLC  0x02
+#define  AVM_STATUS0_IRQ_TIMER 0x04
+#define  AVM_STATUS0_IRQ_MASK  0x07
+
+#define  AVM_STATUS0_RESET     0x01
+#define  AVM_STATUS0_DIS_TIMER 0x02
+#define  AVM_STATUS0_RES_TIMER 0x04
+#define  AVM_STATUS0_ENA_IRQ   0x08
+#define  AVM_STATUS0_TESTBIT   0x10
+
+#define  AVM_STATUS1_INT_SEL   0x0f
+#define  AVM_STATUS1_ENA_IOM   0x80
+
+#define  HDLC_MODE_ITF_FLG     0x01
+#define  HDLC_MODE_TRANS       0x02
+#define  HDLC_MODE_CCR_7       0x04
+#define  HDLC_MODE_CCR_16      0x08
+#define  HDLC_MODE_TESTLOOP    0x80
+
+#define  HDLC_INT_XPR          0x80
+#define  HDLC_INT_XDU          0x40
+#define  HDLC_INT_RPR          0x20
+#define  HDLC_INT_MASK         0xE0
+
+#define  HDLC_STAT_RME         0x01
+#define  HDLC_STAT_RDO         0x10
+#define  HDLC_STAT_CRCVFRRAB   0x0E
+#define  HDLC_STAT_CRCVFR      0x06
+#define  HDLC_STAT_RML_MASK    0x3f00
+
+#define  HDLC_CMD_XRS          0x80
+#define  HDLC_CMD_XME          0x01
+#define  HDLC_CMD_RRS          0x20
+#define  HDLC_CMD_XML_MASK     0x3f00
+
+
+/* Interface functions */
+
+static u_char
+ReadISAC(struct IsdnCardState *cs, u_char offset)
+{
+       register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+       register u_char val;
+       register long flags;
+
+       save_flags(flags);
+       cli();
+       outb(idx, cs->hw.avm.cfg_reg + 4);
+       val = inb(cs->hw.avm.isac + (offset & 0xf));
+       restore_flags(flags);
+       return (val);
+}
+
+static void
+WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+       register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+       register long flags;
+
+       save_flags(flags);
+       cli();
+       outb(idx, cs->hw.avm.cfg_reg + 4);
+       outb(value, cs->hw.avm.isac + (offset & 0xf));
+       restore_flags(flags);
+}
+
+static void
+ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
+       insb(cs->hw.avm.isac, data, size);
+}
+
+static void
+WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+{
+       outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
+       outsb(cs->hw.avm.isac, data, size);
+}
+
+static inline u_int
+ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset)
+{
+       register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
+       register u_int val;
+       register long flags;
+
+       save_flags(flags);
+       cli();
+       outl(idx, cs->hw.avm.cfg_reg + 4);
+       val = inl(cs->hw.avm.isac + offset);
+       restore_flags(flags);
+       return (val);
+}
+
+static inline void
+WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value)
+{
+       register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
+       register long flags;
+
+       save_flags(flags);
+       cli();
+       outl(idx, cs->hw.avm.cfg_reg + 4);
+       outl(value, cs->hw.avm.isac + offset);
+       restore_flags(flags);
+}
+
+static inline u_char
+ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset)
+{
+       register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
+       register u_char val;
+       register long flags;
+
+       save_flags(flags);
+       cli();
+       outb(idx, cs->hw.avm.cfg_reg + 4);
+       val = inb(cs->hw.avm.isac + offset);
+       restore_flags(flags);
+       return (val);
+}
+
+static inline void
+WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
+{
+       register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
+       register long flags;
+
+       save_flags(flags);
+       cli();
+       outb(idx, cs->hw.avm.cfg_reg + 4);
+       outb(value, cs->hw.avm.isac + offset);
+       restore_flags(flags);
+}
+
+static u_char
+ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset)
+{
+       return(0xff & ReadHDLCPCI(cs, chan, offset));
+}
+
+static void
+WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
+{
+       WriteHDLCPCI(cs, chan, offset, value);
+}
+
+static inline
+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 inline
+hdlc_sched_event(struct BCState *bcs, int event)
+{
+       bcs->event |= 1 << event;
+       queue_task(&bcs->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+void
+write_ctrl(struct BCState *bcs, int which) {
+
+       if (bcs->cs->debug & L1_DEB_HSCX)
+               debugl1(bcs->cs, "hdlc %c wr%x ctrl %x",
+                       'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl);
+       if (bcs->cs->subtyp == AVM_FRITZ_PCI) {
+               WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl);
+       } else {
+               if (which & 4)
+                       WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2,
+                               bcs->hw.hdlc.ctrl.sr.mode);
+               if (which & 2)
+                       WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1,
+                               bcs->hw.hdlc.ctrl.sr.xml);
+               if (which & 1)
+                       WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS,
+                               bcs->hw.hdlc.ctrl.sr.cmd);
+       }
+}
+
+void
+modehdlc(struct BCState *bcs, int mode, int bc)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       int hdlc = bcs->channel;
+
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "hdlc %c mode %d ichan %d",
+                       'A' + hdlc, mode, bc);
+       bcs->mode = mode;
+       bcs->channel = bc;
+       bcs->hw.hdlc.ctrl.ctrl = 0;
+       switch (mode) {
+               case (L1_MODE_NULL):
+                       bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
+                       bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
+                       write_ctrl(bcs, 5);
+                       break;
+               case (L1_MODE_TRANS):
+                       bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
+                       bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
+                       write_ctrl(bcs, 5);
+                       bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
+                       write_ctrl(bcs, 1);
+                       bcs->hw.hdlc.ctrl.sr.cmd = 0;
+                       hdlc_sched_event(bcs, B_XMTBUFREADY);
+                       break;
+               case (L1_MODE_HDLC):
+                       bcs->hw.hdlc.ctrl.sr.cmd  = HDLC_CMD_XRS | HDLC_CMD_RRS;
+                       bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+                       write_ctrl(bcs, 5);
+                       bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
+                       write_ctrl(bcs, 1);
+                       bcs->hw.hdlc.ctrl.sr.cmd = 0;
+                       hdlc_sched_event(bcs, B_XMTBUFREADY);
+                       break;
+       }
+}
+
+static inline void
+hdlc_empty_fifo(struct BCState *bcs, int count)
+{
+       register u_int *ptr;
+       u_char *p;
+       u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1;
+       int cnt=0;
+       struct IsdnCardState *cs = bcs->cs;
+
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "hdlc_empty_fifo %d", count);
+       if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) {
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "hdlc_empty_fifo: incoming packet too large");
+               return;
+       }
+       ptr = (u_int *) p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
+       bcs->hw.hdlc.rcvidx += count;
+       if (cs->subtyp == AVM_FRITZ_PCI) {
+               outl(idx, cs->hw.avm.cfg_reg + 4);
+               while (cnt < count) {
+                       *ptr++ = inl(cs->hw.avm.isac);
+                       cnt += 4;
+               }
+       } else {
+               outb(idx, cs->hw.avm.cfg_reg + 4);
+               while (cnt < count) {
+                       *p++ = inb(cs->hw.avm.isac);
+                       cnt++;
+               }
+       }
+       if (cs->debug & L1_DEB_HSCX_FIFO) {
+               char *t = bcs->blog;
+
+               if (cs->subtyp == AVM_FRITZ_PNP)
+                       p = (u_char *) ptr;
+               t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
+                            bcs->channel ? 'B' : 'A', count);
+               QuickHex(t, p, count);
+               debugl1(cs, bcs->blog);
+       }
+}
+
+static inline void
+hdlc_fill_fifo(struct BCState *bcs)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       int count, cnt =0;
+       int fifo_size = 32;
+       u_char *p;
+       u_int *ptr;
+
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "hdlc_fill_fifo");
+       if (!bcs->tx_skb)
+               return;
+       if (bcs->tx_skb->len <= 0)
+               return;
+
+       bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME;
+       if (bcs->tx_skb->len > fifo_size) {
+               count = fifo_size;
+       } else {
+               count = bcs->tx_skb->len;
+               if (bcs->mode != L1_MODE_TRANS)
+                       bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
+       }
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len);
+       ptr = (u_int *) p = bcs->tx_skb->data;
+       skb_pull(bcs->tx_skb, count);
+       bcs->tx_cnt -= count;
+       bcs->hw.hdlc.count += count;
+       bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
+       write_ctrl(bcs, 3);  /* sets the correct index too */
+       if (cs->subtyp == AVM_FRITZ_PCI) {
+               while (cnt<count) {
+                       outl(*ptr++, cs->hw.avm.isac);
+                       cnt += 4;
+               }
+       } else {
+               while (cnt<count) {
+                       outb(*p++, cs->hw.avm.isac);
+                       cnt++;
+               }
+       }
+       if (cs->debug & L1_DEB_HSCX_FIFO) {
+               char *t = bcs->blog;
+
+               if (cs->subtyp == AVM_FRITZ_PNP)
+                       p = (u_char *) ptr;
+               t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
+                            bcs->channel ? 'B' : 'A', count);
+               QuickHex(t, p, count);
+               debugl1(cs, bcs->blog);
+       }
+}
+
+static void
+fill_hdlc(struct BCState *bcs)
+{
+       long flags;
+       save_flags(flags);
+       cli();
+       hdlc_fill_fifo(bcs);
+       restore_flags(flags);
+}
+
+static inline void
+HDLC_irq(struct BCState *bcs, u_int stat) {
+       int len;
+       struct sk_buff *skb;
+
+       if (bcs->cs->debug & L1_DEB_HSCX)
+               debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
+       if (stat & HDLC_INT_RPR) {
+               if (stat & HDLC_STAT_RDO) {
+                       if (bcs->cs->debug & L1_DEB_HSCX)
+                               debugl1(bcs->cs, "RDO");
+                       else
+                               debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
+                       bcs->hw.hdlc.ctrl.sr.xml = 0;
+                       bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS;
+                       write_ctrl(bcs, 1);
+                       bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS;
+                       write_ctrl(bcs, 1);
+                       bcs->hw.hdlc.rcvidx = 0;
+               } else {
+                       if (!(len = (stat & HDLC_STAT_RML_MASK)>>8))
+                               len = 32;
+                       hdlc_empty_fifo(bcs, len);
+                       if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
+                               if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) ||
+                                       (bcs->mode == L1_MODE_TRANS)) {
+                                       if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx)))
+                                               printk(KERN_WARNING "HDLC: receive out of memory\n");
+                                       else {
+                                               memcpy(skb_put(skb, bcs->hw.hdlc.rcvidx),
+                                                       bcs->hw.hdlc.rcvbuf, bcs->hw.hdlc.rcvidx);
+                                               skb_queue_tail(&bcs->rqueue, skb);
+                                       }
+                                       bcs->hw.hdlc.rcvidx = 0;
+                                       hdlc_sched_event(bcs, B_RCVBUFREADY);
+                               } else {
+                                       if (bcs->cs->debug & L1_DEB_HSCX)
+                                               debugl1(bcs->cs, "invalid frame");
+                                       else
+                                               debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat);
+                                       bcs->hw.hdlc.rcvidx = 0;
+                               }
+                       }
+               }
+       }
+       if (stat & HDLC_INT_XDU) {
+               /* Here we lost an TX interrupt, so
+                * restart transmitting the whole frame.
+                */
+               if (bcs->tx_skb) {
+                       skb_push(bcs->tx_skb, bcs->hw.hdlc.count);
+                       bcs->tx_cnt += bcs->hw.hdlc.count;
+                       bcs->hw.hdlc.count = 0;
+//                     hdlc_sched_event(bcs, B_XMTBUFREADY);
+                       if (bcs->cs->debug & L1_DEB_WARN)
+                               debugl1(bcs->cs, "ch%d XDU", bcs->channel);
+               } else if (bcs->cs->debug & L1_DEB_WARN)
+                       debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel);
+               bcs->hw.hdlc.ctrl.sr.xml = 0;
+               bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
+               write_ctrl(bcs, 1);
+               bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS;
+               write_ctrl(bcs, 1);
+               hdlc_fill_fifo(bcs);
+       } else if (stat & HDLC_INT_XPR) {
+               if (bcs->tx_skb) {
+                       if (bcs->tx_skb->len) {
+                               hdlc_fill_fifo(bcs);
+                               return;
+                       } else {
+                               if (bcs->st->lli.l1writewakeup &&
+                                       (PACKET_NOACK != bcs->tx_skb->pkt_type))
+                                       bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count);
+                               dev_kfree_skb(bcs->tx_skb);
+                               bcs->hw.hdlc.count = 0;
+                               bcs->tx_skb = NULL;
+                       }
+               }
+               if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+                       bcs->hw.hdlc.count = 0;
+                       test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+                       hdlc_fill_fifo(bcs);
+               } else {
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+                       hdlc_sched_event(bcs, B_XMTBUFREADY);
+               }
+       }
+}
+
+inline void
+HDLC_irq_main(struct IsdnCardState *cs)
+{
+       u_int stat;
+       long  flags;
+       struct BCState *bcs;
+
+       save_flags(flags);
+       cli();
+       if (cs->subtyp == AVM_FRITZ_PCI) {
+               stat = ReadHDLCPCI(cs, 0, HDLC_STATUS);
+       } else {
+               stat = ReadHDLCPnP(cs, 0, HDLC_STATUS);
+               if (stat & HDLC_INT_RPR)
+                       stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS+1))<<8;
+       }
+       if (stat & HDLC_INT_MASK) {
+               if (!(bcs = Sel_BCS(cs, 0))) {
+                       if (cs->debug)
+                               debugl1(cs, "hdlc spurious channel 0 IRQ");
+               } else
+                       HDLC_irq(bcs, stat);
+       }
+       if (cs->subtyp == AVM_FRITZ_PCI) {
+               stat = ReadHDLCPCI(cs, 1, HDLC_STATUS);
+       } else {
+               stat = ReadHDLCPnP(cs, 1, HDLC_STATUS);
+               if (stat & HDLC_INT_RPR)
+                       stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS+1))<<8;
+       }
+       if (stat & HDLC_INT_MASK) {
+               if (!(bcs = Sel_BCS(cs, 1))) {
+                       if (cs->debug)
+                               debugl1(cs, "hdlc spurious channel 1 IRQ");
+               } else
+                       HDLC_irq(bcs, stat);
+       }
+       restore_flags(flags);
+}
+
+void
+hdlc_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       switch (pr) {
+               case (PH_DATA | REQUEST):
+                       save_flags(flags);
+                       cli();
+                       if (st->l1.bcs->tx_skb) {
+                               skb_queue_tail(&st->l1.bcs->squeue, skb);
+                               restore_flags(flags);
+                       } else {
+                               st->l1.bcs->tx_skb = skb;
+                               test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                               st->l1.bcs->hw.hdlc.count = 0;
+                               restore_flags(flags);
+                               st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       }
+                       break;
+               case (PH_PULL | INDICATION):
+                       if (st->l1.bcs->tx_skb) {
+                               printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n");
+                               break;
+                       }
+                       test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       st->l1.bcs->tx_skb = skb;
+                       st->l1.bcs->hw.hdlc.count = 0;
+                       st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       break;
+               case (PH_PULL | REQUEST):
+                       if (!st->l1.bcs->tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+               case (PH_ACTIVATE | REQUEST):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       modehdlc(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);
+                       modehdlc(st->l1.bcs, 0, st->l1.bc);
+                       st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+                       break;
+       }
+}
+
+void
+close_hdlcstate(struct BCState *bcs)
+{
+       modehdlc(bcs, 0, 0);
+       if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+               if (bcs->hw.hdlc.rcvbuf) {
+                       kfree(bcs->hw.hdlc.rcvbuf);
+                       bcs->hw.hdlc.rcvbuf = NULL;
+               }
+               if (bcs->blog) {
+                       kfree(bcs->blog);
+                       bcs->blog = NULL;
+               }
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->tx_skb) {
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               }
+       }
+}
+
+int
+open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
+{
+       if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+               if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+                       printk(KERN_WARNING
+                              "HiSax: No memory for hdlc.rcvbuf\n");
+                       return (1);
+               }
+               if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+                       printk(KERN_WARNING
+                               "HiSax: No memory for bcs->blog\n");
+                       test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+                       kfree(bcs->hw.hdlc.rcvbuf);
+                       bcs->hw.hdlc.rcvbuf = NULL;
+                       return (2);
+               }
+               skb_queue_head_init(&bcs->rqueue);
+               skb_queue_head_init(&bcs->squeue);
+       }
+       bcs->tx_skb = NULL;
+       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+       bcs->event = 0;
+       bcs->hw.hdlc.rcvidx = 0;
+       bcs->tx_cnt = 0;
+       return (0);
+}
+
+int
+setstack_hdlc(struct PStack *st, struct BCState *bcs)
+{
+       bcs->channel = st->l1.bc;
+       if (open_hdlcstate(st->l1.hardware, bcs))
+               return (-1);
+       st->l1.bcs = bcs;
+       st->l2.l2l1 = hdlc_l2l1;
+       setstack_manager(st);
+       bcs->st = st;
+       setstack_l1_B(st);
+       return (0);
+}
+
+HISAX_INITFUNC(void
+clear_pending_hdlc_ints(struct IsdnCardState *cs))
+{
+       u_int val;
+
+       if (cs->subtyp == AVM_FRITZ_PCI) {
+               val = ReadHDLCPCI(cs, 0, HDLC_STATUS);
+               debugl1(cs, "HDLC 1 STA %x", val);
+               val = ReadHDLCPCI(cs, 1, HDLC_STATUS);
+               debugl1(cs, "HDLC 2 STA %x", val);
+       } else {
+               val = ReadHDLCPnP(cs, 0, HDLC_STATUS);
+               debugl1(cs, "HDLC 1 STA %x", val);
+               val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1);
+               debugl1(cs, "HDLC 1 RML %x", val);
+               val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2);
+               debugl1(cs, "HDLC 1 MODE %x", val);
+               val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3);
+               debugl1(cs, "HDLC 1 VIN %x", val);
+               val = ReadHDLCPnP(cs, 1, HDLC_STATUS);
+               debugl1(cs, "HDLC 2 STA %x", val);
+               val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1);
+               debugl1(cs, "HDLC 2 RML %x", val);
+               val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2);
+               debugl1(cs, "HDLC 2 MODE %x", val);
+               val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3);
+               debugl1(cs, "HDLC 2 VIN %x", val);
+       }
+}
+
+HISAX_INITFUNC(void
+inithdlc(struct IsdnCardState *cs))
+{
+       cs->bcs[0].BC_SetStack = setstack_hdlc;
+       cs->bcs[1].BC_SetStack = setstack_hdlc;
+       cs->bcs[0].BC_Close = close_hdlcstate;
+       cs->bcs[1].BC_Close = close_hdlcstate;
+       modehdlc(cs->bcs, 0, 0);
+       modehdlc(cs->bcs + 1, 0, 0);
+}
+
+static void
+avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val, stat = 0;
+       u_char sval;
+
+       if (!cs) {
+               printk(KERN_WARNING "AVM PCI: Spurious interrupt!\n");
+               return;
+       }
+       sval = inb(cs->hw.avm.cfg_reg + 2);
+       if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK)
+               /* possible a shared  IRQ reqest */
+               return;
+       if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
+               val = ReadISAC(cs, ISAC_ISTA);
+               isac_interrupt(cs, val);
+               stat |= 2;
+       }
+       if (!(sval & AVM_STATUS0_IRQ_HDLC)) {
+               HDLC_irq_main(cs);
+       }
+       if (stat & 2) {
+               WriteISAC(cs, ISAC_MASK, 0xFF);
+               WriteISAC(cs, ISAC_MASK, 0x0);
+       }
+}
+
+static void
+reset_avmpcipnp(struct IsdnCardState *cs)
+{
+       long flags;
+
+       printk(KERN_INFO "AVM PCI/PnP: reset\n");
+       save_flags(flags);
+       sti();
+       outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+       outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
+       outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+       printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
+}
+
+static int
+AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+       u_int irq_flag;
+
+       switch (mt) {
+               case CARD_RESET:
+                       reset_avmpcipnp(cs);
+                       return(0);
+               case CARD_RELEASE:
+                       outb(0, cs->hw.avm.cfg_reg + 2);
+                       release_region(cs->hw.avm.cfg_reg, 32);
+                       return(0);
+               case CARD_SETIRQ:
+                       if (cs->subtyp == AVM_FRITZ_PCI)
+                               irq_flag = I4L_IRQ_FLAG | SA_SHIRQ;
+                       else
+                               irq_flag = I4L_IRQ_FLAG;
+                       return(request_irq(cs->irq, &avm_pcipnp_interrupt,
+                                       irq_flag, "HiSax", cs));
+               case CARD_INIT:
+                       clear_pending_isac_ints(cs);
+                       initisac(cs);
+                       clear_pending_hdlc_ints(cs);
+                       inithdlc(cs);
+                       outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER,
+                               cs->hw.avm.cfg_reg + 2);
+                       WriteISAC(cs, ISAC_MASK, 0);
+                       outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
+                               AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
+                       /* RESET Receiver and Transmitter */
+                       WriteISAC(cs, ISAC_CMDR, 0x41);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+static         struct pci_dev *dev_avm __initdata = NULL;
+
+__initfunc(int
+setup_avm_pcipnp(struct IsdnCard *card))
+{
+       u_int val, ver;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, avm_pci_rev);
+       printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_FRITZPCI)
+               return (0);
+       if (card->para[1]) {
+               cs->hw.avm.cfg_reg = card->para[1];
+               cs->irq = card->para[0];
+               cs->subtyp = AVM_FRITZ_PNP;
+       } else {
+#if CONFIG_PCI
+               if (!pci_present()) {
+                       printk(KERN_ERR "FritzPCI: no PCI bus present\n");
+                       return(0);
+               }
+               if ((dev_avm = pci_find_device(PCI_VENDOR_AVM,
+                       PCI_FRITZPCI_ID,  dev_avm))) {
+                       cs->irq = dev_avm->irq;
+                       if (!cs->irq) {
+                               printk(KERN_WARNING "FritzPCI: No IRQ for PCI card found\n");
+                               return(0);
+                       }
+                       cs->hw.avm.cfg_reg = dev_avm->base_address[1] &
+                               PCI_BASE_ADDRESS_IO_MASK; 
+                       if (!cs->hw.avm.cfg_reg) {
+                               printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n");
+                               return(0);
+                       }
+                       cs->subtyp = AVM_FRITZ_PCI;
+               } else {
+                       printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+                       return(0);
+               }
+#else
+               printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
+               return (0);
+#endif /* CONFIG_PCI */
+       }
+       cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
+       if (check_region((cs->hw.avm.cfg_reg), 32)) {
+               printk(KERN_WARNING
+                      "HiSax: %s config port %x-%x already in use\n",
+                      CardType[card->typ],
+                      cs->hw.avm.cfg_reg,
+                      cs->hw.avm.cfg_reg + 31);
+               return (0);
+       } else {
+               request_region(cs->hw.avm.cfg_reg, 32,
+                       (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP");
+       }
+       switch (cs->subtyp) {
+         case AVM_FRITZ_PCI:
+               val = inl(cs->hw.avm.cfg_reg);
+               printk(KERN_INFO "AVM PCI: stat %#x\n", val);
+               printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
+                       val & 0xff, (val>>8) & 0xff);
+               cs->BC_Read_Reg = &ReadHDLC_s;
+               cs->BC_Write_Reg = &WriteHDLC_s;
+               break;
+         case AVM_FRITZ_PNP:
+               val = inb(cs->hw.avm.cfg_reg);
+               ver = inb(cs->hw.avm.cfg_reg + 1);
+               printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
+               reset_avmpcipnp(cs);
+               cs->BC_Read_Reg = &ReadHDLCPnP;
+               cs->BC_Write_Reg = &WriteHDLCPnP;
+               break;
+         default:
+               printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp);
+               outb(0, cs->hw.avm.cfg_reg + 2);
+               release_region(cs->hw.avm.cfg_reg, 32);
+               return(0);
+       }
+       printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n",
+               (cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP",
+               cs->irq, cs->hw.avm.cfg_reg);
+
+       cs->readisac = &ReadISAC;
+       cs->writeisac = &WriteISAC;
+       cs->readisacfifo = &ReadISACfifo;
+       cs->writeisacfifo = &WriteISACfifo;
+       cs->BC_Send_Data = &fill_hdlc;
+       cs->cardmsg = &AVM_card_msg;
+       ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
+       return (1);
+}
index bcd305058ca99521a5902da9098b72c85f7dbab5..bf09acd20b50e881dc62a4f1f771b4395c0135d2 100644 (file)
@@ -1,12 +1,61 @@
-/* $Id: callc.c,v 2.13 1998/02/12 23:07:16 keil Exp $
+/* $Id: callc.c,v 2.25 1999/01/02 11:17:20 keil Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
+ *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: callc.c,v $
+ * Revision 2.25  1999/01/02 11:17:20  keil
+ * Changes for 2.2
+ *
+ * Revision 2.24  1998/11/15 23:54:24  keil
+ * changes from 2.0
+ *
+ * Revision 2.23  1998/09/30 22:21:57  keil
+ * cosmetics
+ *
+ * Revision 2.22  1998/08/20 13:50:29  keil
+ * More support for hybrid modem (not working yet)
+ *
+ * Revision 2.21  1998/08/13 23:36:15  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.20  1998/06/26 15:13:05  fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 2.19  1998/05/25 14:08:06  keil
+ * HiSax 3.0
+ * fixed X.75 and leased line to work again
+ * Point2Point and fixed TEI are runtime options now:
+ *    hisaxctrl <id> 7 1  set PTP
+ *    hisaxctrl <id> 8 <TEIVALUE *2 >
+ *    set fixed TEI to TEIVALUE (0-63)
+ *
+ * Revision 2.18  1998/05/25 12:57:40  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.17  1998/04/15 16:46:06  keil
+ * RESUME support
+ *
+ * Revision 2.16  1998/04/10 10:35:17  paul
+ * fixed (silly?) warnings from egcs on Alpha.
+ *
+ * Revision 2.15  1998/03/19 13:18:37  keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
+ * Revision 2.14  1998/03/07 22:56:54  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 2.13  1998/02/12 23:07:16  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
 
 #define __NO_VERSION__
 #include "hisax.h"
+#include "../avmb1/capicmd.h"  /* this should be moved in a common place */
 
 #ifdef MODULE
 #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
 #endif                         /* MODULE */
 
-const char *lli_revision = "$Revision: 2.13 $";
+const char *lli_revision = "$Revision: 2.25 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
@@ -77,20 +127,18 @@ static void release_b_st(struct Channel *chanp);
 
 static struct Fsm callcfsm =
 {NULL, 0, 0, NULL, NULL};
-static struct Fsm lcfsm =
-{NULL, 0, 0, NULL, NULL};
 
 static int chancount = 0;
 
-/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ 
-#define ALERT_REJECT 1
+/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */
+#define ALERT_REJECT 0
 
 /* 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 
+ * You can adjust this value on runtime with
  * hisaxctrl <id> 2 <value>
  * value is in milliseconds
  */
@@ -114,11 +162,12 @@ static int chancount = 0;
 #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 10000
+#define        DREL_TIMER_VALUE 40000
 
 /*
  * Find card with given driverId
@@ -136,15 +185,30 @@ hisax_findcard(int driverid)
        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);
+               ret++;
+       }
+       return(ret);
+}
+
 static void
-link_debug(struct Channel *chanp, char *s, int direction)
+link_debug(struct Channel *chanp, int direction, char *fmt, ...)
 {
-       char tmp[100], tm[32];
+       va_list args;
+       char tmp[16];
 
-       jiftime(tm, jiffies);
-       sprintf(tmp, "%s Channel %d %s %s\n", tm, chanp->chan,
-               direction ? "LL->HL" : "HL->LL", s);
-       HiSax_putstatus(chanp->cs, tmp);
+       va_start(args, fmt);
+       sprintf(tmp, "Ch%d %s ", chanp->chan,
+               direction ? "LL->HL" : "HL->LL");
+       VHiSax_putstatus(chanp->cs, tmp, fmt, args);
+       va_end(args);
 }
 
 
@@ -244,72 +308,21 @@ 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_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_RELEASE_WAIT",
-};
-
-enum {
-       EV_LC_ESTABLISH,
-       EV_LC_PH_ACTIVATE,
-       EV_LC_PH_DEACTIVATE,
-       EV_LC_DL_ESTABLISH,
-       EV_LC_TIMER,
-       EV_LC_DL_RELEASE,
-       EV_LC_RELEASE,
-};
-
-#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
-
-static char *strLcEvent[] =
-{
-       "EV_LC_ESTABLISH",
-       "EV_LC_PH_ACTIVATE",
-       "EV_LC_PH_DEACTIVATE",
-       "EV_LC_DL_ESTABLISH",
-       "EV_LC_TIMER",
-       "EV_LC_DL_RELEASE",
-       "EV_LC_RELEASE",
-};
-
-#define LC_D  0
-#define LC_B  1
-
 static inline void
-lli_deliver_cause(struct Channel *chanp)
+lli_deliver_cause(struct Channel *chanp, isdn_ctrl *ic)
 {
-       isdn_ctrl ic;
-
        if (chanp->proc->para.cause < 0)
                return;
-       ic.driver = chanp->cs->myid;
-       ic.command = ISDN_STAT_CAUSE;
-       ic.arg = chanp->chan;
+       ic->driver = chanp->cs->myid;
+       ic->command = ISDN_STAT_CAUSE;
+       ic->arg = chanp->chan;
        if (chanp->cs->protocol == ISDN_PTYPE_EURO)
-               sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f,
+               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->proc->para.loc & 0x7f,
+               sprintf(ic->parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f,
                        chanp->proc->para.cause & 0x7f);
-       chanp->cs->iif.statcallb(&ic);
+       chanp->cs->iif.statcallb(ic);
 }
 
 static void
@@ -321,13 +334,12 @@ lli_d_established(struct FsmInst *fi, int event, void *arg)
        if (chanp->leased) {
                isdn_ctrl ic;
                int ret;
-               char txt[32];
 
-               chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan);
+               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);
+                       link_debug(chanp, 0, "STAT_ICALL_LEASED");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_ICALL;
                ic.arg = chanp->chan;
@@ -335,15 +347,13 @@ lli_d_established(struct FsmInst *fi, int event, void *arg)
                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.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 (chanp->debug & 1)
+                       link_debug(chanp, 1, "statcallb ret=%d", ret);
                if (!ret) {
-                       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+                       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
                        FsmChangeState(fi, ST_NULL);
                }
        } else if (fi->state == ST_WAIT_DSHUTDOWN)
@@ -371,28 +381,14 @@ lli_prep_dialout(struct FsmInst *fi, int event, void *arg)
        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 "lli_prep_dialout unknown protocol\n");
-                       break;
-       }
        if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
                FsmEvent(fi, EV_DLEST, NULL);
        } else {
                chanp->Flags = 0;
+               if (EV_RESUME == event)
+                       test_and_set_bit(FLG_RESUME, &chanp->Flags);
                test_and_set_bit(FLG_START_D, &chanp->Flags);
-               if (chanp->leased) {
-                       chanp->lc_d->l2_establish = 0;
-               }
-               FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+               chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
        }
 }
 
@@ -400,14 +396,19 @@ static void
 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 *) chanp->chan);
+       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) {
                FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
        } else {
                test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
-               chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_REQ, chanp);
+               chanp->d_st->lli.l4l3(chanp->d_st, ev, chanp);
                test_and_set_bit(FLG_CALL_SEND, &chanp->Flags);
        }
 }
@@ -421,14 +422,14 @@ lli_init_bchan_out(struct FsmInst *fi, int event, void *arg)
        FsmChangeState(fi, ST_WAIT_BCONN);
        test_and_set_bit(FLG_LL_DCONN, &chanp->Flags);
        if (chanp->debug & 1)
-               link_debug(chanp, "STAT_DCONN", 0);
+               link_debug(chanp, 0, "STAT_DCONN");
        ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_DCONN;
        ic.arg = chanp->chan;
        chanp->cs->iif.statcallb(&ic);
        init_b_st(chanp, 0);
        test_and_set_bit(FLG_START_B, &chanp->Flags);
-       FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL);
+       chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -441,15 +442,19 @@ lli_go_active(struct FsmInst *fi, int event, void *arg)
        chanp->data_open = !0;
        test_and_set_bit(FLG_CONNECT_B, &chanp->Flags);
        if (chanp->debug & 1)
-               link_debug(chanp, "STAT_BCONN", 0);
+               link_debug(chanp, 0, "STAT_BCONN");
        test_and_set_bit(FLG_LL_BCONN, &chanp->Flags);
        ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_BCONN;
        ic.arg = chanp->chan;
        chanp->cs->iif.statcallb(&ic);
-       chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) chanp->chan);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan);
 }
 
+/*
+ * RESUME
+ */
+
 /* incomming call */
 
 static void
@@ -463,14 +468,14 @@ lli_start_dchan(struct FsmInst *fi, int event, void *arg)
                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            
+#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 if (!test_and_set_bit(FLG_START_D, &chanp->Flags))
-               FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+               chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -479,9 +484,8 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
        struct Channel *chanp = fi->userdata;
        isdn_ctrl ic;
        int ret;
-       char txt[32];
 
-       chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) chanp->chan);
+       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
@@ -491,7 +495,7 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
                FsmChangeState(fi, ST_IN_WAIT_LL);
                test_and_set_bit(FLG_CALL_REC, &chanp->Flags);
                if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_ICALL", 0);
+                       link_debug(chanp, 0, "STAT_ICALL");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_ICALL;
                ic.arg = chanp->chan;
@@ -501,22 +505,21 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
                 */
                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 (chanp->debug & 1)
+                       link_debug(chanp, 1, "statcallb ret=%d", ret);
                switch (ret) {
                        case 1: /* OK, anybody likes this call */
                                FsmDelTimer(&chanp->drel_timer, 61);
                                if (test_bit(FLG_ESTAB_D, &chanp->Flags)) {
                                        FsmChangeState(fi, ST_IN_ALERT_SEND);
                                        test_and_set_bit(FLG_CALL_ALERT, &chanp->Flags);
-                                       chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING_REQ, chanp->proc);
+                                       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);
-                                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+                                       chanp->d_st->lli.l4l3(chanp->d_st,
+                                               DL_ESTABLISH | REQUEST, NULL);
                                }
                                break;
                        case 2: /* Rejecting Call */
@@ -524,38 +527,36 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg)
                                break;
                        case 0: /* OK, nobody likes this call */
                        default:        /* statcallb problems */
-                               chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc);
-                               chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+                               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);
-#ifndef LAYER2_WATCHING
-                               if (test_bit(FLG_ESTAB_D, &chanp->Flags))
+                               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);
-#endif
                                break;
                }
        } else {
-               chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE, chanp->proc);
-               chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+               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);
-#ifndef LAYER2_WATCHING
-               if (test_bit(FLG_ESTAB_D, &chanp->Flags))
+               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);
-#endif
        }
 }
 
 static void
 lli_establish_d(struct FsmInst *fi, int event, void *arg)
 {
-       /* This establish the D-channel for pending L3 messages 
-        * without blocking th channel
+       /* 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);
-       FsmEvent(&chanp->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+       chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL);
 }
 
 static void
@@ -573,27 +574,18 @@ lli_do_action(struct FsmInst *fi, int event, void *arg)
                !test_bit(FLG_DO_HANGUP, &chanp->Flags)) {
                FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
                test_and_clear_bit(FLG_DO_ALERT, &chanp->Flags);
-               chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc);
+               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_REQ, chanp->proc);
+               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_REQ, chanp->proc);
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
                test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
-       } else if (test_and_clear_bit(FLG_DO_ESTAB, &chanp->Flags)) {
-               FsmChangeState(fi, ST_NULL);
-               chanp->Flags = 0;
-               test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
-               chanp->d_st->lli.l4l3(chanp->d_st, CC_ESTABLISH, chanp->proc);
-               chanp->proc = NULL;
-#ifndef LAYER2_WATCHING
-               FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
-#endif
        }
 }
 
@@ -603,7 +595,7 @@ lli_send_dconnect(struct FsmInst *fi, int event, void *arg)
        struct Channel *chanp = fi->userdata;
 
        FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
-       chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP_RSP, chanp->proc);
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc);
 }
 
 static void
@@ -615,29 +607,26 @@ lli_init_bchan_in(struct FsmInst *fi, int event, void *arg)
        FsmChangeState(fi, ST_WAIT_BCONN);
        test_and_set_bit(FLG_LL_DCONN, &chanp->Flags);
        if (chanp->debug & 1)
-               link_debug(chanp, "STAT_DCONN", 0);
+               link_debug(chanp, 0, "STAT_DCONN");
        ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_DCONN;
        ic.arg = chanp->chan;
        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 "bchannel unknown protocol\n");
-                       break;
-       }
        init_b_st(chanp, !0);
        test_and_set_bit(FLG_START_B, &chanp->Flags);
-       FsmEvent(&chanp->lc_b->lcfi, EV_LC_ESTABLISH, NULL);
+       chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL);
+}
+
+/* Call suspend */
+
+static void
+lli_suspend(struct FsmInst *fi, int event, void *arg)
+{
+       struct Channel *chanp = fi->userdata;
+
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc);
 }
 
 /* Call clearing */
@@ -651,7 +640,7 @@ lli_cancel_call(struct FsmInst *fi, int event, void *arg)
        FsmChangeState(fi, ST_WAIT_DRELEASE);
        if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_BHUP", 0);
+                       link_debug(chanp, 0, "STAT_BHUP");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
@@ -660,7 +649,7 @@ lli_cancel_call(struct FsmInst *fi, int event, void *arg)
        if (test_and_clear_bit(FLG_START_B, &chanp->Flags))
                release_b_st(chanp);
        chanp->proc->para.cause = 0x10;         /* Normal Call Clearing */
-       chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT_REQ, chanp->proc);
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
        test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
 }
 
@@ -670,22 +659,22 @@ lli_shutdown_d(struct FsmInst *fi, int event, void *arg)
        struct Channel *chanp = fi->userdata;
 
        FsmDelTimer(&chanp->drel_timer, 62);
-#ifdef LAYER2_WATCHING
-       FsmChangeState(fi, ST_NULL);
-#else
-       if (!test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) {
-               if (chanp->chan) {
-                       if (chanp->cs->channel[0].fi.state != ST_NULL)
-                               return;
-               } else {
-                       if (chanp->cs->channel[1].fi.state != ST_NULL)
-                               return;
+       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);
        }
-       FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
-       test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags);
-       FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
-#endif
 }
 
 static void
@@ -694,22 +683,20 @@ lli_timeout_d(struct FsmInst *fi, int event, void *arg)
        struct Channel *chanp = fi->userdata;
        isdn_ctrl ic;
 
-       if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
-               if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_DHUP", 0);
-               lli_deliver_cause(chanp);
-               ic.driver = chanp->cs->myid;
-               ic.command = ISDN_STAT_DHUP;
-               ic.arg = chanp->chan;
-               chanp->cs->iif.statcallb(&ic);
-       }
+       test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+       if (chanp->debug & 1)
+               link_debug(chanp, 0, "STAT_DHUP");
+       lli_deliver_cause(chanp, &ic);
+       ic.driver = chanp->cs->myid;
+       ic.command = ISDN_STAT_DHUP;
+       ic.arg = chanp->chan;
+       chanp->cs->iif.statcallb(&ic);
        FsmChangeState(fi, ST_NULL);
        chanp->Flags = 0;
        test_and_set_bit(FLG_ESTAB_D, &chanp->Flags);
-#ifndef LAYER2_WATCHING
-       FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
-#endif
-       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+       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
@@ -720,7 +707,7 @@ lli_go_null(struct FsmInst *fi, int event, void *arg)
        FsmChangeState(fi, ST_NULL);
        chanp->Flags = 0;
        FsmDelTimer(&chanp->drel_timer, 63);
-       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 }
 
 static void
@@ -731,7 +718,7 @@ lli_disconn_bchan(struct FsmInst *fi, int event, void *arg)
        chanp->data_open = 0;
        FsmChangeState(fi, ST_WAIT_BRELEASE);
        test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags);
-       FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
+       chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 }
 
 static void
@@ -746,7 +733,7 @@ lli_send_d_disc(struct FsmInst *fi, int event, void *arg)
        FsmChangeState(fi, ST_WAIT_DRELEASE);
        if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_BHUP", 0);
+                       link_debug(chanp, 0, "STAT_BHUP");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
@@ -760,20 +747,20 @@ lli_send_d_disc(struct FsmInst *fi, int event, void *arg)
                sprintf(ic.parm.num, "L0010");
                chanp->cs->iif.statcallb(&ic);
                if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_DHUP", 0);
+                       link_debug(chanp, 0, "STAT_DHUP");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_DHUP;
                ic.arg = chanp->chan;
                chanp->cs->iif.statcallb(&ic);
                FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
                test_and_clear_bit(FLG_ESTAB_D, &chanp->Flags);
-               FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
+               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_REQ, chanp->proc);
+               chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, chanp->proc);
                test_and_set_bit(FLG_DISC_SEND, &chanp->Flags);
        }
 }
@@ -788,7 +775,7 @@ lli_released_bchan(struct FsmInst *fi, int event, void *arg)
        chanp->data_open = 0;
        if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_BHUP", 0);
+                       link_debug(chanp, 0, "STAT_BHUP");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
@@ -808,7 +795,7 @@ lli_release_bchan(struct FsmInst *fi, int event, void *arg)
        test_and_set_bit(FLG_DISC_REC, &chanp->Flags);
        FsmChangeState(fi, ST_WAIT_BREL_DISC);
        test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags);
-       FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
+       chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
 }
 
 static void
@@ -821,12 +808,11 @@ lli_received_d_rel(struct FsmInst *fi, int event, void *arg)
        FsmChangeState(fi, ST_NULL);
        test_and_set_bit(FLG_REL_REC, &chanp->Flags);
        if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
-               chanp->lc_b->l2_establish = 0;  /* direct reset in lc_b->lcfi */
-               FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
+               chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
        }
        if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_BHUP", 0);
+                       link_debug(chanp, 0, "STAT_BHUP");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
@@ -834,17 +820,13 @@ lli_received_d_rel(struct FsmInst *fi, int event, void *arg)
        }
        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);
-               lli_deliver_cause(chanp);
-               ic.driver = chanp->cs->myid;
-               ic.command = ISDN_STAT_DHUP;
-               ic.arg = chanp->chan;
-               chanp->cs->iif.statcallb(&ic);
-       }
+       if (chanp->debug & 1)
+               link_debug(chanp, 0, "STAT_DHUP");
+       lli_deliver_cause(chanp, &ic);
+       ic.driver = chanp->cs->myid;
+       ic.command = ISDN_STAT_DHUP;
+       ic.arg = chanp->chan;
+       chanp->cs->iif.statcallb(&ic);
        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);
@@ -862,12 +844,11 @@ lli_received_d_relcnf(struct FsmInst *fi, int event, void *arg)
        chanp->data_open = 0;
        FsmChangeState(fi, ST_NULL);
        if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
-               chanp->lc_b->l2_establish = 0;  /* direct reset in lc_b->lcfi */
-               FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
+               chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
        }
        if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_BHUP", 0);
+                       link_debug(chanp, 0, "STAT_BHUP");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
@@ -875,17 +856,13 @@ lli_received_d_relcnf(struct FsmInst *fi, int event, void *arg)
        }
        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);
-               lli_deliver_cause(chanp);
-               ic.driver = chanp->cs->myid;
-               ic.command = ISDN_STAT_DHUP;
-               ic.arg = chanp->chan;
-               chanp->cs->iif.statcallb(&ic);
-       }
+       if (chanp->debug & 1)
+               link_debug(chanp, 0, "STAT_DHUP");
+       lli_deliver_cause(chanp, &ic);
+       ic.driver = chanp->cs->myid;
+       ic.command = ISDN_STAT_DHUP;
+       ic.arg = chanp->chan;
+       chanp->cs->iif.statcallb(&ic);
        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);
@@ -905,7 +882,7 @@ lli_received_d_disc(struct FsmInst *fi, int event, void *arg)
        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);
+                       link_debug(chanp, 0, "STAT_BHUP");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
@@ -913,21 +890,17 @@ lli_received_d_disc(struct FsmInst *fi, int event, void *arg)
        }
        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);
-               lli_deliver_cause(chanp);
-               ic.driver = chanp->cs->myid;
-               ic.command = ISDN_STAT_DHUP;
-               ic.arg = chanp->chan;
-               chanp->cs->iif.statcallb(&ic);
-       }
+       if (chanp->debug & 1)
+               link_debug(chanp, 0, "STAT_DHUP");
+       lli_deliver_cause(chanp, &ic);
+       ic.driver = chanp->cs->myid;
+       ic.command = ISDN_STAT_DHUP;
+       ic.arg = chanp->chan;
+       chanp->cs->iif.statcallb(&ic);
        test_and_clear_bit(FLG_CALL_ALERT, &chanp->Flags);
        test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
        test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
-       chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE_REQ, chanp->proc);
+       chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, chanp->proc);
 }
 
 /* processing charge info */
@@ -953,14 +926,14 @@ lli_no_dchan(struct FsmInst *fi, int event, void *arg)
        isdn_ctrl ic;
 
        if (chanp->debug & 1)
-               link_debug(chanp, "STAT_NODCH", 0);
+               link_debug(chanp, 0, "STAT_NODCH");
        ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_NODCH;
        ic.arg = chanp->chan;
        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
@@ -970,7 +943,7 @@ lli_no_dchan_ready(struct FsmInst *fi, int event, void *arg)
        isdn_ctrl ic;
 
        if (chanp->debug & 1)
-               link_debug(chanp, "STAT_DHUP", 0);
+               link_debug(chanp, 0, "STAT_DHUP");
        ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_DHUP;
        ic.arg = chanp->chan;
@@ -984,15 +957,15 @@ lli_no_dchan_in(struct FsmInst *fi, int event, void *arg)
        isdn_ctrl ic;
 
        if (chanp->debug & 1)
-               link_debug(chanp, "STAT_DHUP", 0);
+               link_debug(chanp, 0, "STAT_DHUP");
        ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_DHUP;
        ic.arg = chanp->chan;
        chanp->cs->iif.statcallb(&ic);
-       chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc);
+       chanp->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
@@ -1004,7 +977,7 @@ lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
        FsmChangeState(fi, ST_NULL);
        test_and_clear_bit(FLG_CALL_SEND, &chanp->Flags);
        if (chanp->debug & 1)
-               link_debug(chanp, "STAT_DHUP", 0);
+               link_debug(chanp, 0, "STAT_DHUP");
        ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_DHUP;
        ic.arg = chanp->chan;
@@ -1019,15 +992,14 @@ lli_setup_err(struct FsmInst *fi, int event, void *arg)
        isdn_ctrl ic;
 
        FsmChangeState(fi, ST_WAIT_DRELEASE);
-       if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
-               if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_DHUP", 0);
-               lli_deliver_cause(chanp);
-               ic.driver = chanp->cs->myid;
-               ic.command = ISDN_STAT_DHUP;
-               ic.arg = chanp->chan;
-               chanp->cs->iif.statcallb(&ic);
-       }
+       test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+       if (chanp->debug & 1)
+               link_debug(chanp, 0, "STAT_DHUP");
+       lli_deliver_cause(chanp, &ic);
+       ic.driver = chanp->cs->myid;
+       ic.command = ISDN_STAT_DHUP;
+       ic.arg = chanp->chan;
+       chanp->cs->iif.statcallb(&ic);
        test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */
 }
 
@@ -1038,15 +1010,14 @@ lli_connect_err(struct FsmInst *fi, int event, void *arg)
        isdn_ctrl ic;
 
        FsmChangeState(fi, ST_WAIT_DRELEASE);
-       if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
-               if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_DHUP", 0);
-               lli_deliver_cause(chanp);
-               ic.driver = chanp->cs->myid;
-               ic.command = ISDN_STAT_DHUP;
-               ic.arg = chanp->chan;
-               chanp->cs->iif.statcallb(&ic);
-       }
+       test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+       if (chanp->debug & 1)
+               link_debug(chanp, 0, "STAT_DHUP");
+       lli_deliver_cause(chanp, &ic);
+       ic.driver = chanp->cs->myid;
+       ic.command = ISDN_STAT_DHUP;
+       ic.arg = chanp->chan;
+       chanp->cs->iif.statcallb(&ic);
        test_and_set_bit(FLG_DISC_SEND, &chanp->Flags); /* DISCONN was sent from L3 */
 }
 
@@ -1059,12 +1030,11 @@ lli_got_dlrl(struct FsmInst *fi, int event, void *arg)
        chanp->data_open = 0;
        FsmChangeState(fi, ST_NULL);
        if (test_and_clear_bit(FLG_CONNECT_B, &chanp->Flags)) {
-               chanp->lc_b->l2_establish = 0;  /* direct reset in lc_b->lcfi */
-               FsmEvent(&chanp->lc_b->lcfi, EV_LC_RELEASE, NULL);
+               chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL);
        }
        if (test_and_clear_bit(FLG_LL_BCONN, &chanp->Flags)) {
                if (chanp->debug & 1)
-                       link_debug(chanp, "STAT_BHUP", 0);
+                       link_debug(chanp, 0, "STAT_BHUP");
                ic.driver = chanp->cs->myid;
                ic.command = ISDN_STAT_BHUP;
                ic.arg = chanp->chan;
@@ -1084,33 +1054,33 @@ lli_got_dlrl(struct FsmInst *fi, int event, void *arg)
                chanp->cs->iif.statcallb(&ic);
                chanp->Flags = 0;
        } else {
-               if (test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags)) {
-                       if (chanp->debug & 1)
-                               link_debug(chanp, "STAT_DHUP", 0);
-                       if (chanp->cs->protocol == ISDN_PTYPE_EURO) {
-                               chanp->proc->para.cause = 0x2f;
-                               chanp->proc->para.loc = 0;
-                       } else {
-                               chanp->proc->para.cause = 0x70;
-                               chanp->proc->para.loc = 0;
-                       }
-                       lli_deliver_cause(chanp);
-                       ic.driver = chanp->cs->myid;
-                       ic.command = ISDN_STAT_DHUP;
-                       ic.arg = chanp->chan;
-                       chanp->cs->iif.statcallb(&ic);
+               test_and_clear_bit(FLG_LL_DCONN, &chanp->Flags);
+               if (chanp->debug & 1)
+                       link_debug(chanp, 0, "STAT_DHUP");
+               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;
                }
-               chanp->d_st->lli.l4l3(chanp->d_st, CC_DLRL, chanp->proc);
+               lli_deliver_cause(chanp, &ic);
+               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;
-               FsmEvent(&chanp->lc_d->lcfi, EV_LC_RELEASE, NULL);
+               chanp->d_st->lli.l4l3(chanp->d_st, DL_RELEASE | REQUEST, NULL);
        }
-       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) chanp->chan);
+       chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan);
 }
 
 /* *INDENT-OFF* */
 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},
@@ -1162,6 +1132,7 @@ static struct FsmNode fnlist[] HISAX_INITDATA =
        {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},
@@ -1195,6 +1166,7 @@ static struct FsmNode fnlist[] HISAX_INITDATA =
        {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* */
@@ -1202,153 +1174,6 @@ static struct FsmNode fnlist[] HISAX_INITDATA =
 
 #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
 
-static void
-lc_activate_l1(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmDelTimer(&lf->act_timer, 50);
-       FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
-       /* This timeout is to avoid a hang if no L1 activation is possible */
-       FsmAddTimer(&lf->act_timer, 30000, EV_LC_TIMER, NULL, 50);
-       lf->st->ma.manl1(lf->st, PH_ACTIVATE_REQ, NULL);
-}
-
-static void
-lc_activated_from_l1(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       if (lf->l2_establish)
-               FsmChangeState(fi, ST_LC_DELAY);
-       else {
-               FsmChangeState(fi, ST_LC_CONNECTED);
-               lf->lccall(lf, LC_ESTABLISH, NULL);
-       }
-}
-
-static void
-lc_l1_activated(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmDelTimer(&lf->act_timer, 50);
-       FsmChangeState(fi, ST_LC_DELAY);
-       /* This timer is needed for delay the first paket on a channel
-          to be shure that the other side is ready too */
-       if (lf->delay)
-               FsmAddTimer(&lf->act_timer, lf->delay, EV_LC_TIMER, NULL, 51);
-       else
-               FsmEvent(fi, EV_LC_TIMER, NULL);
-}
-
-static void
-lc_start_l2(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-/*     if (!lf->st->l1.act_state)
-               lf->st->l1.act_state = 2;
-*/     if (lf->l2_establish) {
-               FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
-               if (lf->l2_start)
-                       lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
-       } else {
-               FsmChangeState(fi, ST_LC_CONNECTED);
-               lf->lccall(lf, LC_ESTABLISH, NULL);
-       }
-}
-
-static void
-lc_connected(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmDelTimer(&lf->act_timer, 50);
-       FsmChangeState(fi, ST_LC_CONNECTED);
-       lf->lccall(lf, LC_ESTABLISH, NULL);
-}
-
-static void
-lc_release_l2(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       if (lf->l2_establish) {
-               FsmChangeState(fi, ST_LC_RELEASE_WAIT);
-               lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
-       } else {
-               FsmChangeState(fi, ST_LC_NULL);
-               lf->st->ma.manl1(lf->st, PH_DEACTIVATE_REQ, NULL);
-               lf->lccall(lf, LC_RELEASE, NULL);
-       }
-}
-
-static void
-lc_l2_released(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmChangeState(fi, ST_LC_RELEASE_WAIT);
-       FsmDelTimer(&lf->act_timer, 51);
-       /* This delay is needed for send out the UA frame before
-        * PH_DEACTIVATE the interface
-        */
-       FsmAddTimer(&lf->act_timer, 20, EV_LC_TIMER, NULL, 54);
-}
-
-static void
-lc_release_l1(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_REQ, NULL);
-       lf->lccall(lf, LC_RELEASE, NULL);
-}
-
-static void
-lc_l1_deactivated(struct FsmInst *fi, int event, void *arg)
-{
-       struct LcFsm *lf = fi->userdata;
-
-       FsmDelTimer(&lf->act_timer, 54);
-       FsmChangeState(fi, ST_LC_NULL);
-       lf->lccall(lf, LC_RELEASE, NULL);
-}
-/* *INDENT-OFF* */
-static struct FsmNode LcFnList[] HISAX_INITDATA =
-{
-       {ST_LC_NULL,            EV_LC_ESTABLISH,        lc_activate_l1},
-       {ST_LC_NULL,            EV_LC_PH_ACTIVATE,      lc_activated_from_l1},
-       {ST_LC_NULL,            EV_LC_DL_ESTABLISH,     lc_connected},
-       {ST_LC_ACTIVATE_WAIT,   EV_LC_PH_ACTIVATE,      lc_l1_activated},
-       {ST_LC_ACTIVATE_WAIT,   EV_LC_TIMER,            lc_release_l1},
-       {ST_LC_ACTIVATE_WAIT,   EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
-       {ST_LC_DELAY,           EV_LC_ESTABLISH,        lc_start_l2},
-       {ST_LC_DELAY,           EV_LC_TIMER,            lc_start_l2},
-       {ST_LC_DELAY,           EV_LC_DL_ESTABLISH,     lc_connected},
-       {ST_LC_DELAY,           EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
-       {ST_LC_ESTABLISH_WAIT,  EV_LC_DL_ESTABLISH,     lc_connected},
-       {ST_LC_ESTABLISH_WAIT,  EV_LC_RELEASE,          lc_release_l1},
-       {ST_LC_ESTABLISH_WAIT,  EV_LC_DL_RELEASE,       lc_release_l1},
-       {ST_LC_ESTABLISH_WAIT,  EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
-       {ST_LC_CONNECTED,       EV_LC_ESTABLISH,        lc_connected},
-       {ST_LC_CONNECTED,       EV_LC_RELEASE,          lc_release_l2},
-       {ST_LC_CONNECTED,       EV_LC_DL_RELEASE,       lc_l2_released},
-       {ST_LC_CONNECTED,       EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
-       {ST_LC_FLUSH_WAIT,      EV_LC_TIMER,            lc_release_l2},
-       {ST_LC_FLUSH_WAIT,      EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
-       {ST_LC_RELEASE_WAIT,    EV_LC_DL_RELEASE,       lc_release_l1},
-       {ST_LC_RELEASE_WAIT,    EV_LC_TIMER,            lc_release_l1},
-       {ST_LC_FLUSH_WAIT,      EV_LC_PH_DEACTIVATE,    lc_l1_deactivated},
-};
-/* *INDENT-ON* */
-
-
-#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
-
 HISAX_INITFUNC(void
 CallcNew(void))
 {
@@ -1357,18 +1182,11 @@ CallcNew(void))
        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);
 }
 
@@ -1384,75 +1202,10 @@ release_b_st(struct Channel *chanp)
                        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
-dc_l1man(struct PStack *st, int pr, void *arg)
-{
-       struct Channel *chanp;
-
-       chanp = (struct Channel *) st->lli.userdata;
-       switch (pr) {
-               case (PH_ACTIVATE_CNF):
-               case (PH_ACTIVATE_IND):
-                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_ACTIVATE, NULL);
-                       break;
-               case (PH_DEACTIVATE_IND):
-                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_PH_DEACTIVATE, NULL);
-                       break;
-       }
-}
-
-static void
-dc_l2man(struct PStack *st, int pr, void *arg)
-{
-       struct Channel *chanp = (struct Channel *) st->lli.userdata;
-
-       switch (pr) {
-               case (DL_ESTABLISH):
-                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_ESTABLISH, NULL);
-                       break;
-               case (DL_RELEASE):
-                       FsmEvent(&chanp->lc_d->lcfi, EV_LC_DL_RELEASE, NULL);
-                       break;
-       }
-}
-
-static void
-bc_l1man(struct PStack *st, int pr, void *arg)
-{
-       struct Channel *chanp = (struct Channel *) st->lli.userdata;
-
-       switch (pr) {
-               case (PH_ACTIVATE_IND):
-               case (PH_ACTIVATE_CNF):
-                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_ACTIVATE, NULL);
-                       break;
-               case (PH_DEACTIVATE_IND):
-                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_PH_DEACTIVATE, NULL);
-                       break;
-       }
-}
-
-static void
-bc_l2man(struct PStack *st, int pr, void *arg)
-{
-       struct Channel *chanp = (struct Channel *) st->lli.userdata;
-
-       switch (pr) {
-               case (DL_ESTABLISH):
-                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL);
-                       break;
-               case (DL_RELEASE):
-                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_RELEASE, NULL);
-                       break;
-       }
 }
 
 struct Channel
@@ -1471,7 +1224,7 @@ struct Channel
                        return (chanp);
                chanp++;
                i++;
-       }               
+       }
        return (NULL);
 }
 
@@ -1491,62 +1244,85 @@ is_activ(struct PStack *st)
                        return (1);
                chanp++;
                i++;
-       }               
+       }
        return (0);
 }
 
 static void
-ll_handler(struct l3_process *pc, int pr, void *arg)
+dchan_l3l4(struct PStack *st, int pr, void *arg)
 {
+       struct l3_process *pc = arg;
+       struct IsdnCardState *cs = st->l1.hardware;
        struct Channel *chanp;
-       char tmp[64], tm[32];
+       int event;
+
+       switch (pr) {
+               case (DL_ESTABLISH | INDICATION):
+                       event = EV_DLEST;
+                       break;
+               case (DL_RELEASE | INDICATION):
+                       event = EV_DLRL;
+                       break;
+               default:
+                       event = -1;
+                       break;
+       }
+       if (event >= 0) {
+               int i;
 
-       if (pr == CC_SETUP_IND) {
+               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, pc);
-                       return;
+                       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;
                }
-       } else if (pr == CC_ESTABLISH) {
-               if (is_activ(pc->st)) {
-                       pc->st->lli.l4l3(pc->st, CC_ESTABLISH, pc);
-                       return;
-               } else if (!(chanp = selectfreechannel(pc->st))) {
-                       pc->st->lli.l4l3(pc->st, CC_DLRL, pc);
-                       return;
-               } else {
-                       chanp->proc = pc;
-                       FsmEvent(&chanp->fi, EV_ESTABLISH, NULL);
-                       return;
-               }
-
-                       
+               return;
        }
-       chanp = pc->chan;
+       if (!(chanp = pc->chan))
+               return;
+
        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_SUSPEND | CONFIRM):
                        FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
                        break;
-               case (CC_RELEASE_IND):
+               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 | 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):
@@ -1558,15 +1334,14 @@ ll_handler(struct l3_process *pc, int pr, void *arg)
                case (CC_RELEASE_ERR):
                        FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL);
                        break;
-               case (CC_PROCEEDING_IND):
-               case (CC_ALERTING_IND):
+               case (CC_PROCEEDING | INDICATION):
+               case (CC_ALERTING | INDICATION):
                        break;
                default:
                        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->cs, tmp);
+                               HiSax_putstatus(chanp->cs, "Ch",
+                                       "%d L3->L4 unknown primitiv %x",
+                                       chanp->chan, pr);
                        }
        }
 }
@@ -1576,7 +1351,7 @@ init_d_st(struct Channel *chanp)
 {
        struct PStack *st = chanp->d_st;
        struct IsdnCardState *cs = chanp->cs;
-       char tmp[128];
+       char tmp[16];
 
        HiSax_addlist(cs, st);
        setstack_HiSax(st, cs);
@@ -1590,95 +1365,50 @@ init_d_st(struct Channel *chanp)
        st->l2.window = 1;
        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 */
+       st->l2.T203 = 10000;    /* 10000 milliseconds */
+       if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags))
+               sprintf(tmp, "DCh%d Q.921 ", chanp->chan);
        else
-               st->l2.T203 = 10000;    /* 5000 milliseconds  */
-       
-       sprintf(tmp, "Channel %d q.921", chanp->chan);
+               sprintf(tmp, "DCh Q.921 ");
        setstack_isdnl2(st, tmp);
-       setstack_isdnl3(st, chanp);
+       setstack_l3dc(st, chanp);
        st->lli.userdata = chanp;
        st->lli.l2writewakeup = NULL;
-       st->l3.l3l4 = ll_handler;
-       st->l1.l1man = dc_l1man;
-       st->l2.l2man = dc_l2man;
+       st->l3.l3l4 = dchan_l3l4;
 }
 
 static void
-callc_debug(struct FsmInst *fi, char *s)
+callc_debug(struct FsmInst *fi, char *fmt, ...)
 {
-       char str[80], tm[32];
+       va_list args;
        struct Channel *chanp = fi->userdata;
+       char tmp[16];
 
-       jiftime(tm, jiffies);
-       sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
-       HiSax_putstatus(chanp->cs, 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 dc %s\n", tm, lf->ch->chan, s);
-       HiSax_putstatus(lf->ch->cs, 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 bc %s\n", tm, lf->ch->chan, s);
-       HiSax_putstatus(lf->ch->cs, str);
+       va_start(args, fmt);
+       sprintf(tmp, "Ch%d callc ", chanp->chan);
+       VHiSax_putstatus(chanp->cs, tmp, fmt, args);
+       va_end(args);
 }
 
 static void
-lccall_d(struct LcFsm *lf, int pr, void *arg)
-{
-       struct IsdnCardState *cs = lf->st->l1.hardware;
-       struct Channel *chanp;
-       int i;
-
-       if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) {
-               chanp = lf->ch;
-               i = 1;
-       } else {
-               chanp = cs->channel;
-               i = 0;
-       }
-       while (i < 2) {
-               switch (pr) {
-                       case (LC_ESTABLISH):
-                               FsmEvent(&chanp->fi, EV_DLEST, NULL);
-                               break;
-                       case (LC_RELEASE):
-                               FsmEvent(&chanp->fi, EV_DLRL, NULL);
-                               break;
-               }
-               chanp++;
-               i++;
-       }
+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
@@ -1693,9 +1423,8 @@ init_chan(int chan, struct IsdnCardState *csta)
        chanp->debug = 0;
        chanp->Flags = 0;
        chanp->leased = 0;
-       chanp->b_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
-       chanp->b_st->next = NULL;
-
+       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;
@@ -1704,41 +1433,14 @@ init_chan(int chan, struct IsdnCardState *csta)
        FsmInitTimer(&chanp->fi, &chanp->dial_timer);
        FsmInitTimer(&chanp->fi, &chanp->drel_timer);
        if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
-               chanp->d_st = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+               init_PStack(&chanp->d_st);
+               if (chan)
+                       csta->channel->d_st->next = chanp->d_st;
                chanp->d_st->next = NULL;
                init_d_st(chanp);
-               chanp->lc_d = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC);
-               chanp->lc_d->lcfi.fsm = &lcfsm;
-               chanp->lc_d->lcfi.state = ST_LC_NULL;
-               chanp->lc_d->lcfi.debug = 0;
-               chanp->lc_d->lcfi.userdata = chanp->lc_d;
-               chanp->lc_d->lcfi.printdebug = lc_debug;
-               chanp->lc_d->type = LC_D;
-               chanp->lc_d->delay = 0;
-               chanp->lc_d->ch = chanp;
-               chanp->lc_d->st = chanp->d_st;
-               chanp->lc_d->l2_establish = !0;
-               chanp->lc_d->l2_start = !0;
-               chanp->lc_d->lccall = lccall_d;
-               FsmInitTimer(&chanp->lc_d->lcfi, &chanp->lc_d->act_timer);
        } else {
                chanp->d_st = csta->channel->d_st;
-               chanp->lc_d = csta->channel->lc_d;
        }
-       chanp->lc_b = kmalloc(sizeof(struct LcFsm), GFP_ATOMIC);
-       chanp->lc_b->lcfi.fsm = &lcfsm;
-       chanp->lc_b->lcfi.state = ST_LC_NULL;
-       chanp->lc_b->lcfi.debug = 0;
-       chanp->lc_b->lcfi.userdata = chanp->lc_b;
-       chanp->lc_b->lcfi.printdebug = dlc_debug;
-       chanp->lc_b->type = LC_B;
-       chanp->lc_b->delay = DEFAULT_B_DELAY;
-       chanp->lc_b->ch = chanp;
-       chanp->lc_b->st = chanp->b_st;
-       chanp->lc_b->l2_establish = !0;
-       chanp->lc_b->l2_start = !0;
-       chanp->lc_b->lccall = lccall_b;
-       FsmInitTimer(&chanp->lc_b->lcfi, &chanp->lc_b->act_timer);
        chanp->data_open = 0;
 }
 
@@ -1749,11 +1451,12 @@ CallcNewChan(struct IsdnCardState *csta)
        init_chan(0, csta);
        init_chan(1, csta);
        printk(KERN_INFO "HiSax: 2 channels added\n");
-#ifdef LAYER2_WATCHING
-       printk(KERN_INFO "LAYER2 ESTABLISH\n");
-       test_and_set_bit(FLG_START_D, &csta->channel->Flags);
-       FsmEvent(&csta->channel->lc_d->lcfi, EV_LC_ESTABLISH, NULL);
-#endif
+       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);
 }
 
@@ -1779,8 +1482,6 @@ 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_d->act_timer, 77);
-               FsmDelTimer(&csta->channel[i].lc_b->act_timer, 76);
                if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags))
                        release_d_st(csta->channel + i);
                if (csta->channel[i].b_st) {
@@ -1790,18 +1491,8 @@ CallcFreeChan(struct IsdnCardState *csta)
                        csta->channel[i].b_st = NULL;
                } else
                        printk(KERN_WARNING "CallcFreeChan b_st ch%d allready freed\n", i);
-               if (csta->channel[i].lc_b) {
-                       kfree(csta->channel[i].lc_b);
-                       csta->channel[i].b_st = NULL;
-               }
                if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
                        release_d_st(csta->channel + i);
-                       FsmDelTimer(&csta->channel[i].lc_d->act_timer, 77);
-                       if (csta->channel[i].lc_d) {
-                               kfree(csta->channel[i].lc_d);
-                               csta->channel[i].d_st = NULL;
-                       } else
-                               printk(KERN_WARNING "CallcFreeChan lc_d ch%d allready freed\n", i);
                } else
                        csta->channel[i].d_st = NULL;
        }
@@ -1814,15 +1505,23 @@ lldata_handler(struct PStack *st, int pr, void *arg)
        struct sk_buff *skb = arg;
 
        switch (pr) {
-               case (DL_DATA):
+               case (DL_DATA  | INDICATION):
                        if (chanp->data_open)
                                chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
                        else {
                                dev_kfree_skb(skb);
                        }
                        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",
+                       printk(KERN_WARNING "lldata_handler unknown primitive %x\n",
                               pr);
                        break;
        }
@@ -1835,22 +1534,24 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
        struct sk_buff *skb = arg;
 
        switch (pr) {
-               case (PH_DATA_IND):
+               case (PH_DATA | INDICATION):
                        if (chanp->data_open)
                                chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
                        else {
-                               if (chanp->lc_b->lcfi.state == ST_LC_DELAY)
-                                       FsmEvent(&chanp->lc_b->lcfi, EV_LC_DL_ESTABLISH, NULL);
-                               if (chanp->data_open) {
-                                       link_debug(chanp, "channel now open", 0);
-                                       chanp->cs->iif.rcvcallb_skb(chanp->cs->myid,
-                                               chanp->chan, skb);
-                               } else
-                                       dev_kfree_skb(skb);
+                               link_debug(chanp, 0, "channel not open");
+                               dev_kfree_skb(skb);
                        }
                        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",
+                       printk(KERN_WARNING "lltrans_handler unknown primitive %x\n",
                               pr);
                        break;
        }
@@ -1865,7 +1566,7 @@ ll_writewakeup(struct PStack *st, int len)
        ic.driver = chanp->cs->myid;
        ic.command = ISDN_STAT_BSENT;
        ic.arg = chanp->chan;
-       ic.parm.length = len;
+//     ic.parm.length = len;
        chanp->cs->iif.statcallb(&ic);
 }
 
@@ -1874,10 +1575,27 @@ init_b_st(struct Channel *chanp, int incoming)
 {
        struct PStack *st = chanp->b_st;
        struct IsdnCardState *cs = chanp->cs;
-       char tmp[128];
+       char tmp[16];
 
        st->l1.hardware = cs;
-       chanp->bcs->mode = 2;
+       if (chanp->leased)
+               st->l1.bc = chanp->chan & 1;
+       else
+               st->l1.bc = chanp->proc->para.bchannel - 1;
+       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.flag = 0;
@@ -1892,49 +1610,86 @@ init_b_st(struct Channel *chanp, int incoming)
        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 = bc_l1man;
-                       st->l2.l2man = bc_l2man;
                        st->lli.userdata = chanp;
                        st->lli.l1writewakeup = NULL;
                        st->lli.l2writewakeup = ll_writewakeup;
                        st->l2.l2m.debug = chanp->debug & 16;
                        st->l2.debug = chanp->debug & 64;
-                       st->ma.manl2(st, MDL_NOTEIPROC, NULL);
-                       st->l1.mode = L1_MODE_HDLC;
-                       if (chanp->leased)
-                               st->l1.bc = chanp->chan & 1;
-                       else
-                               st->l1.bc = chanp->proc->para.bchannel - 1;
                        break;
                case (ISDN_PROTO_L2_HDLC):
-                       st->l1.l1l2 = lltrans_handler;
-                       st->l1.l1man = bc_l1man;
-                       st->lli.userdata = chanp;
-                       st->lli.l1writewakeup = ll_writewakeup;
-                       st->l1.mode = L1_MODE_HDLC;
-                       if (chanp->leased)
-                               st->l1.bc = chanp->chan & 1;
-                       else
-                               st->l1.bc = chanp->proc->para.bchannel - 1;
-                       break;
                case (ISDN_PROTO_L2_TRANS):
+//             case (ISDN_PROTO_L2_MODEM):
                        st->l1.l1l2 = lltrans_handler;
-                       st->l1.l1man = bc_l1man;
                        st->lli.userdata = chanp;
                        st->lli.l1writewakeup = ll_writewakeup;
-                       st->l1.mode = L1_MODE_TRANS;
-                       if (chanp->leased)
-                               st->l1.bc = chanp->chan & 1;
-                       else
-                               st->l1.bc = chanp->proc->para.bchannel - 1;
+                       setstack_transl2(st);
+                       setstack_l3bc(st, chanp);
                        break;
        }
        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, 0, "leased line d-channel DATA");
+                       dev_kfree_skb(skb);
+                       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 %x\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, 0, "leased line d-channel DATA");
+                       dev_kfree_skb(skb);
+                       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 %x\n", pr);
+                       break;
+       }
+}
+
 static void
 channel_report(struct Channel *chanp)
 {
@@ -1953,13 +1708,70 @@ distr_debug(struct IsdnCardState *csta, int debugflags)
                chanp[i].b_st->l2.l2m.debug = debugflags & 0x10;
                chanp[i].d_st->l2.debug = debugflags & 0x20;
                chanp[i].b_st->l2.debug = debugflags & 0x40;
-               chanp[i].lc_d->lcfi.debug = debugflags & 0x80;
-               chanp[i].lc_b->lcfi.debug = debugflags & 0x100;
+               chanp[i].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;
+               chanp[i].b_st->l1.l1m.debug = debugflags & 0x2000;
+       }
+       if (debugflags & 4)
+               csta->debug |= DEB_DLOG_HEX;
+       else
+               csta->debug &= ~DEB_DLOG_HEX;
+}
+
+static char tmpbuf[256];
+
+static void
+capi_debug(struct Channel *chanp, capi_msg *cm)
+{
+       char *t = tmpbuf;
+
+       t += sprintf(tmpbuf, "%d CAPIMSG", chanp->chan);
+       t += QuickHex(t, (u_char *)cm, (cm->Length>50)? 50: cm->Length);
+       t--;
+       *t= 0;
+       HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf);
+}
+
+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);
+               }
        }
-       csta->dlogflag = debugflags & 4;
 }
 
 int
@@ -1967,9 +1779,9 @@ HiSax_command(isdn_ctrl * ic)
 {
        struct IsdnCardState *csta = hisax_findcard(ic->driver);
        struct Channel *chanp;
-       char tmp[128];
        int i;
-       unsigned int num;
+       u_int num;
+       u_long adr;
 
        if (!csta) {
                printk(KERN_ERR
@@ -1977,32 +1789,32 @@ 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) {
-                               sprintf(tmp, "SETEAZ card %d %s", csta->cardnr + 1,
-                                       ic->parm.num);
-                               link_debug(chanp, tmp, 1);
-                       }
                        break;
+
                case (ISDN_CMD_SETL2):
                        chanp = csta->channel + (ic->arg & 0xff);
-                       if (chanp->debug & 1) {
-                               sprintf(tmp, "SETL2 card %d %ld", csta->cardnr + 1,
-                                       ic->arg >> 8);
-                               link_debug(chanp, tmp, 1);
-                       }
+                       if (chanp->debug & 1)
+                               link_debug(chanp, 1, "SETL2 card %d %ld",
+                                       csta->cardnr + 1, ic->arg >> 8);
                        chanp->l2_protocol = ic->arg >> 8;
                        break;
+               case (ISDN_CMD_SETL3):
+                       chanp = csta->channel + (ic->arg & 0xff);
+                       if (chanp->debug & 1)
+                               link_debug(chanp, 1, "SETL3 card %d %ld",
+                                       csta->cardnr + 1, ic->arg >> 8);
+                       chanp->l3_protocol = ic->arg >> 8;
+                       break;
                case (ISDN_CMD_DIAL):
                        chanp = csta->channel + (ic->arg & 0xff);
-                       if (chanp->debug & 1) {
-                               sprintf(tmp, "DIAL %s -> %s (%d,%d)",
+                       if (chanp->debug & 1)
+                               link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)",
                                        ic->parm.setup.eazmsn, ic->parm.setup.phone,
-                                ic->parm.setup.si1, ic->parm.setup.si2);
-                               link_debug(chanp, tmp, 1);
-                       }
+                                       ic->parm.setup.si1, ic->parm.setup.si2);
                        chanp->setup = ic->parm.setup;
                        if (!strcmp(chanp->setup.eazmsn, "0"))
                                chanp->setup.eazmsn[0] = '\0';
@@ -2018,57 +1830,54 @@ HiSax_command(isdn_ctrl * ic)
                case (ISDN_CMD_ACCEPTB):
                        chanp = csta->channel + ic->arg;
                        if (chanp->debug & 1)
-                               link_debug(chanp, "ACCEPTB", 1);
+                               link_debug(chanp, 1, "ACCEPTB");
                        FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
                        break;
                case (ISDN_CMD_ACCEPTD):
                        chanp = csta->channel + ic->arg;
                        if (chanp->debug & 1)
-                               link_debug(chanp, "ACCEPTD", 1);
+                               link_debug(chanp, 1, "ACCEPTD");
                        FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
                        break;
                case (ISDN_CMD_HANGUP):
                        chanp = csta->channel + ic->arg;
                        if (chanp->debug & 1)
-                               link_debug(chanp, "HANGUP", 1);
+                               link_debug(chanp, 1, "HANGUP");
                        FsmEvent(&chanp->fi, EV_HANGUP, NULL);
                        break;
-               case (ISDN_CMD_SUSPEND):
-                       chanp = csta->channel + ic->arg;
-                       if (chanp->debug & 1) {
-                               sprintf(tmp, "SUSPEND %s", ic->parm.num);
-                               link_debug(chanp, tmp, 1);
-                       }
-                       FsmEvent(&chanp->fi, EV_SUSPEND, ic);
-                       break;
-               case (ISDN_CMD_RESUME):
+               case (CAPI_PUT_MESSAGE):
                        chanp = csta->channel + ic->arg;
-                       if (chanp->debug & 1) {
-                               sprintf(tmp, "RESUME %s", ic->parm.num);
-                               link_debug(chanp, tmp, 1);
+                       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;
                        }
-                       FsmEvent(&chanp->fi, EV_RESUME, ic);
                        break;
                case (ISDN_CMD_LOCK):
                        HiSax_mod_inc_use_count();
 #ifdef MODULE
-                       if (csta->channel[0].debug & 0x400) {
-                               jiftime(tmp, jiffies);
-                               i = strlen(tmp);
-                               sprintf(tmp + i, "   LOCK modcnt %d\n", MOD_USE_COUNT);
-                               HiSax_putstatus(csta, tmp);
-                       }
+                       if (csta->channel[0].debug & 0x400)
+                               HiSax_putstatus(csta, "   LOCK ", "modcnt %x",
+                                       MOD_USE_COUNT);
 #endif                         /* MODULE */
                        break;
                case (ISDN_CMD_UNLOCK):
                        HiSax_mod_dec_use_count();
 #ifdef MODULE
-                       if (csta->channel[0].debug & 0x400) {
-                               jiftime(tmp, jiffies);
-                               i = strlen(tmp);
-                               sprintf(tmp + i, " UNLOCK modcnt %d\n", MOD_USE_COUNT);
-                               HiSax_putstatus(csta, tmp);
-                       }
+                       if (csta->channel[0].debug & 0x400)
+                               HiSax_putstatus(csta, " UNLOCK ", "modcnt %x",
+                                       MOD_USE_COUNT);
 #endif                         /* MODULE */
                        break;
                case (ISDN_CMD_IOCTL):
@@ -2081,19 +1890,19 @@ HiSax_command(isdn_ctrl * ic)
                                case (1):
                                        num = *(unsigned int *) ic->parm.num;
                                        distr_debug(csta, num);
-                                       sprintf(tmp, "debugging flags card %d set to %x\n",
+                                       printk(KERN_DEBUG "HiSax: debugging flags card %d set to %x\n",
                                                csta->cardnr + 1, num);
-                                       HiSax_putstatus(csta, tmp);
-                                       printk(KERN_DEBUG "HiSax: %s", tmp);
+                                       HiSax_putstatus(csta, "debugging flags ",
+                                               "card %d set to %x", csta->cardnr + 1, num);
                                        break;
                                case (2):
-                                       num = *(unsigned int *) ic->parm.num; 
-                                       csta->channel[0].lc_b->delay = num;
-                                       csta->channel[1].lc_b->delay = num;
-                                       sprintf(tmp, "delay card %d set to %d ms\n",
+                                       num = *(unsigned int *) ic->parm.num;
+                                       csta->channel[0].b_st->l1.delay = num;
+                                       csta->channel[1].b_st->l1.delay = num;
+                                       HiSax_putstatus(csta, "delay ", "card %d set to %d ms",
+                                               csta->cardnr + 1, num);
+                                       printk(KERN_DEBUG "HiSax: 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++)
@@ -2106,47 +1915,91 @@ HiSax_command(isdn_ctrl * ic)
                                case (5):       /* set card in leased mode */
                                        num = *(unsigned int *) ic->parm.num;
                                        if ((num <1) || (num > 2)) {
-                                               sprintf(tmp, "Set LEASED wrong channel %d\n",
+                                               HiSax_putstatus(csta, "Set LEASED ",
+                                                       "wrong channel %d", num);
+                                               printk(KERN_WARNING "HiSax: Set LEASED wrong channel %d\n",
                                                        num);
-                                               HiSax_putstatus(csta, tmp);
-                                               printk(KERN_WARNING "HiSax: %s", tmp);
                                        } else {
                                                num--;
-                                               csta->channel[num].leased = 1;
-                                               csta->channel[num].lc_d->l2_establish = 0;
-                                               sprintf(tmp, "card %d channel %d set leased mode\n",
+                                               chanp = csta->channel +num;
+                                               chanp->leased = 1;
+                                               HiSax_putstatus(csta, "Card",
+                                                       "%d channel %d set leased mode\n",
                                                        csta->cardnr + 1, num + 1);
-                                               HiSax_putstatus(csta, tmp);
-                                               FsmEvent(&csta->channel[num].lc_d->lcfi, EV_LC_ESTABLISH, NULL);
+                                               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->ma.manl1(csta->stlist,
-                                                       PH_TESTLOOP_REQ, (void *) num);
+                                               csta->stlist->l2.l2l1(csta->stlist,
+                                                       PH_TESTLOOP | REQUEST, (void *) (long)num);
+                                       break;
+                               case (7):       /* set card in PTP mode */
+                                       num = *(unsigned int *) ic->parm.num;
+                                       if (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+                                               printk(KERN_ERR "HiSax PTP mode only with one TEI possible\n");
+                                       } else if (num) {
+                                               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;
+                                               HiSax_putstatus(csta, "set card ", "in PTP mode");
+                                               printk(KERN_DEBUG "HiSax: set card in PTP mode\n");
+                                               printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
+                                               test_and_set_bit(FLG_START_D, &csta->channel[0].Flags);
+                                               test_and_set_bit(FLG_START_D, &csta->channel[1].Flags);
+                                               csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st,
+                                                       DL_ESTABLISH | REQUEST, NULL);
+                                       } else {
+                                               test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag);
+                                               test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag);
+                                               HiSax_putstatus(csta, "set card ", "in PTMP mode");
+                                               printk(KERN_DEBUG "HiSax: set card in PTMP mode\n");
+                                       }
+                                       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;
+                                       HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num);
+                                       printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n",
+                                               num);
+                                       break;
+                               case (9): /* load firmware */
+                                       memcpy(&adr, ic->parm.num, sizeof(ulong));
+                                       csta->cardmsg(csta, CARD_LOAD_FIRM,
+                                               (void *) adr);
                                        break;
 #ifdef MODULE
                                case (55):
                                        while ( MOD_USE_COUNT > 0)
-                                           MOD_DEC_USE_COUNT;
+                                               MOD_DEC_USE_COUNT;
                                        HiSax_mod_inc_use_count();
                                        break;
 #endif                         /* MODULE */
                                case (11):
+                                       num = csta->debug & DEB_DLOG_HEX;
                                        csta->debug = *(unsigned int *) ic->parm.num;
-                                       sprintf(tmp, "l1 debugging flags card %d set to %x\n",
+                                       csta->debug |= num;
+                                       HiSax_putstatus(cards[0].cs, "l1 debugging ",
+                                               "flags card %d set to %x",
+                                               csta->cardnr + 1, csta->debug);
+                                       printk(KERN_DEBUG "HiSax: l1 debugging flags card %d set to %x\n",
                                                csta->cardnr + 1, csta->debug);
-                                       HiSax_putstatus(cards[0].cs, tmp);
-                                       printk(KERN_DEBUG "HiSax: %s", tmp);
                                        break;
                                case (13):
                                        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",
+                                       HiSax_putstatus(cards[0].cs, "l3 debugging ",
+                                               "flags card %d set to %x\n", csta->cardnr + 1,
+                                               *(unsigned int *) ic->parm.num);
+                                       printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n",
                                                csta->cardnr + 1, *(unsigned int *) ic->parm.num);
-                                       HiSax_putstatus(cards[0].cs, tmp);
-                                       printk(KERN_DEBUG "HiSax: %s", tmp);
                                        break;
                                default:
                                        printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
@@ -2170,7 +2023,6 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
        int len = skb->len;
        unsigned long flags;
        struct sk_buff *nskb;
-       char tmp[64];
 
        if (!csta) {
                printk(KERN_ERR
@@ -2180,13 +2032,13 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
        chanp = csta->channel + chan;
        st = chanp->b_st;
        if (!chanp->data_open) {
-               link_debug(chanp, "writebuf: channel not open", 1);
+               link_debug(chanp, 1, "writebuf: channel not open");
                return -EIO;
        }
        if (len > MAX_DATA_SIZE) {
-               sprintf(tmp, "writebuf: packet too large (%d bytes)", len);
-               printk(KERN_WARNING "HiSax_%s !\n", tmp);
-               link_debug(chanp, tmp, 1);
+               link_debug(chanp, 1, "writebuf: packet too large (%d bytes)", len);
+               printk(KERN_WARNING "HiSax_writebuf: packet too large (%d bytes) !\n",
+                       len);
                return -EINVAL;
        }
        if (len) {
@@ -2194,10 +2046,8 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
                        /* Must return 0 here, since this is not an error
                         * but a temporary lack of resources.
                         */
-                       if (chanp->debug & 0x800) {
-                               sprintf(tmp, "writebuf: no buffers for %d bytes", len);
-                               link_debug(chanp, tmp, 1);
-                       }
+                       if (chanp->debug & 0x800)
+                               link_debug(chanp, 1, "writebuf: no buffers for %d bytes", len);
                        return 0;
                }
                save_flags(flags);
@@ -2206,11 +2056,11 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
                if (nskb) {
                        if (!ack)
                                nskb->pkt_type = PACKET_NOACK;
-                       if (chanp->lc_b->l2_establish)
-                               st->l3.l3l2(st, DL_DATA, nskb);
+                       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_REQ, nskb);
+                               st->l2.l2l1(st, PH_DATA | REQUEST, nskb);
                        }
                        dev_kfree_skb(skb);
                } else
diff --git a/drivers/isdn/hisax/cert.c b/drivers/isdn/hisax/cert.c
new file mode 100644 (file)
index 0000000..a76736b
--- /dev/null
@@ -0,0 +1,55 @@
+/* $Id: cert.c,v 2.1 1998/11/15 23:51:15 keil Exp $
+
+ * Author       Karsten Keil (keil@isdn4linux.de)
+ *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
+ *
+ * $Log: cert.c,v $
+ * Revision 2.1  1998/11/15 23:51:15  keil
+ * certification stuff
+ *
+ * Revision 1.2.2.1  1998/11/03 21:46:37  keil
+ * first version
+ *
+ *
+ */
+#include <linux/kernel.h>
+
+int
+certification_check(int output) {
+
+#ifdef CERTIFICATION
+#if CERTIFICATION == 0
+       if (output) {
+               printk(KERN_INFO "HiSax: Approval certification valid\n");
+               printk(KERN_INFO "HiSax: Approved with ELSA Quickstep series cards\n");
+               printk(KERN_INFO "HiSax: Approval registration numbers:\n");
+               printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n");
+               printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n");
+       }
+       return(0);
+#endif
+#if CERTIFICATION == 1
+       if (output) {
+               printk(KERN_INFO "HiSax: Approval certification failed because of\n");
+               printk(KERN_INFO "HiSax: unauthorized source code changes\n");
+       }
+       return(1);
+#endif
+#if CERTIFICATION == 127
+       if (output) {
+               printk(KERN_INFO "HiSax: Approval certification not possible\n");
+               printk(KERN_INFO "HiSax: because \"md5sum\" is not available\n");
+       }
+       return(2);
+#endif
+#else
+       if (output) {
+               printk(KERN_INFO "HiSax: Certification not verified\n");
+       }
+       return(3);
+#endif
+}
index 3b98a3a306d75a77c082d71b197d0c2121f0f184..7ca2de9e4051a70c86a9026581ac1de179522c87 100644 (file)
@@ -1,10 +1,50 @@
-/* $Id: config.c,v 2.12 1998/02/11 17:28:02 keil Exp $
+/* $Id: config.c,v 2.23 1999/02/17 10:53:02 cpetig Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
  *
  * $Log: config.c,v $
+ * Revision 2.23  1999/02/17 10:53:02  cpetig
+ * Added Hisax_closecard to exported symbols.
+ * As indicated by Oliver Schoett <os@sdm.de>.
+ *
+ * If anyone is annoyed by exporting symbols deep inside the code, please
+ * contact me.
+ *
+ * Revision 2.22  1999/02/04 21:41:53  keil
+ * Fix printk msg
+ *
+ * Revision 2.21  1999/02/04 10:48:52  keil
+ * Fix readstat bug
+ *
+ * Revision 2.20  1998/11/15 23:54:28  keil
+ * changes from 2.0
+ *
+ * Revision 2.19  1998/08/13 23:36:18  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.18  1998/07/30 21:01:37  niemann
+ * Fixed Sedlbauer Speed Fax PCMCIA missing isdnl3new
+ *
+ * Revision 2.17  1998/07/15 15:01:26  calle
+ * Support for AVM passive PCMCIA cards:
+ *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
+ *
+ * Revision 2.16  1998/05/25 14:10:03  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.15  1998/05/25 12:57:43  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.14  1998/04/15 16:38:25  keil
+ * Add S0Box and Teles PCI support
+ *
+ * Revision 2.13  1998/03/09 23:19:23  keil
+ * Changes for PCMCIA
+ *
  * Revision 2.12  1998/02/11 17:28:02  keil
  * Niccy PnP/PCI support
  *
 #include <linux/timer.h>
 #include <linux/config.h>
 #include "hisax.h"
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#define HISAX_STATUS_BUFSIZE 4096
+#define INCLUDE_INLINE_FUNCS
 
 /*
  * This structure array contains one entry per card. An entry looks
  *   13 Teleint          p0=irq p1=iobase
  *   14 Teles 16.3c      p0=irq p1=iobase
  *   15 Sedlbauer speed  p0=irq p1=iobase
+ *   15 Sedlbauer PC/104       p0=irq p1=iobase
+ *   15 Sedlbauer speed pci    no parameter
  *   16 USR Sportster internal  p0=irq  p1=iobase
  *   17 MIC card                p0=irq  p1=iobase
  *   18 ELSA Quickstep 1000PCI  no parameter
  *   19 Compaq ISDN S0 ISA card p0=irq  p1=IO0 (HSCX)  p2=IO1 (ISAC) p3=IO2
  *   20 Travers Technologies NETjet PCI card
- *   21 reserved TELES PCI
+ *   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)
+ *   26 AVM A1 PCMCIA (Fritz)   p0=irq p1=iobase
+ *   27 AVM PnP/PCI            p0=irq p1=iobase (PCI no parameter)
+ *   28 Sedlbauer Speed Fax+   p0=irq p1=iobase (from isapnp setup)
  *
  * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
  *
  *
  */
 
+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", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
+ "Sedlbauer Speed Fax +"
+};
+
 #ifdef CONFIG_HISAX_ELSA
 #define DEFAULT_CARD ISDN_CTYPE_ELSA
 #define DEFAULT_CFG {0,0,0,0}
-#ifdef MODULE
 int elsa_init_pcmcia(void*, int, int*, int);
 EXPORT_SYMBOL(elsa_init_pcmcia);
 #endif
-#endif
 #ifdef CONFIG_HISAX_AVM_A1
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_A1
 #define DEFAULT_CFG {10,0x340,0,0}
 #endif
+
+#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA
+#define DEFAULT_CFG {11,0x170,0,0}
+int avm_a1_init_pcmcia(void*, int, int*, int);
+EXPORT_SYMBOL(avm_a1_init_pcmcia);
+#endif
+
+#ifdef CONFIG_HISAX_FRITZPCI
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_FRITZPCI
+#define DEFAULT_CFG {0,0,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,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
@@ -121,6 +203,13 @@ EXPORT_SYMBOL(elsa_init_pcmcia);
 #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
@@ -193,13 +282,6 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
 #define DEFAULT_CFG {12,0x3e0,0,0}
 #endif
 
-#ifdef CONFIG_HISAX_DBRI
-#undef DEFAULT_CARD
-#undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_DBRI
-#define DEFAULT_CFG {0,0x0,0,0}
-#endif
-
 #ifdef CONFIG_HISAX_NICCY
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
@@ -232,10 +314,10 @@ EXPORT_SYMBOL(sedl_init_pcmcia);
 #endif
 
 #define FIRST_CARD { \
-  DEFAULT_CARD, \
-  DEFAULT_PROTO, \
-  DEFAULT_CFG, \
-  NULL, \
+       DEFAULT_CARD, \
+       DEFAULT_PROTO, \
+       DEFAULT_CFG, \
+       NULL, \
 }
 
 #define EMPTY_CARD     {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
@@ -250,29 +332,20 @@ 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] 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" \
+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";
 char *HiSax_id HISAX_INITDATA = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
 static int type[] 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};
 static int protocol[] 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};
 static int io[] 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};
 #undef IO0_IO1
 #ifdef CONFIG_HISAX_16_3
 #define IO0_IO1
@@ -283,29 +356,29 @@ static int io[] HISAX_INITDATA =
 #endif
 #ifdef IO0_IO1
 static int io0[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+{0, 0, 0, 0, 0, 0, 0, 0};
 static int io1[] 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};
 #endif
 static int irq[] 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};
 static int mem[] 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};
 static char *id HISAX_INITDATA = HiSaxID;
 
 MODULE_AUTHOR("Karsten Keil");
-MODULE_PARM(type, "1-3i");
-MODULE_PARM(protocol, "1-2i");
+MODULE_PARM(type, "1-8i");
+MODULE_PARM(protocol, "1-8i");
 MODULE_PARM(io, "1-8i");
-MODULE_PARM(irq, "1-2i");
-MODULE_PARM(mem, "1-12i");
+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-8i");
 MODULE_PARM(io1, "1-8i");
-#endif
+#endif /* CONFIG_HISAX_16_3 */
 
-#endif
+#endif /* MODULE */
 
 int nrcards;
 
@@ -333,23 +406,25 @@ HiSax_getrev(const char *revision))
 HISAX_INITFUNC(void
 HiSaxVersion(void))
 {
-       char tmp[64], rev[64];
-       char *r = rev;
+       char tmp[64];
 
+       printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
+#ifdef MODULE
+       printk(KERN_INFO "HiSax: Version 3.1a (module)\n");
+#else
+       printk(KERN_INFO "HiSax: Version 3.1a (kernel)\n");
+#endif
        strcpy(tmp, l1_revision);
-       r += sprintf(r, "%s/", HiSax_getrev(tmp));
+       printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
        strcpy(tmp, l2_revision);
-       r += sprintf(r, "%s/", HiSax_getrev(tmp));
+       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);
-       r += sprintf(r, "%s/", HiSax_getrev(tmp));
+       printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp));
        strcpy(tmp, lli_revision);
-       r += sprintf(r, "%s/", HiSax_getrev(tmp));
-       strcpy(tmp, tei_revision);
-       r += sprintf(r, "%s", HiSax_getrev(tmp));
-
-       printk(KERN_INFO "HiSax: Driver for Siemens chip set ISDN cards\n");
-       printk(KERN_INFO "HiSax: Version 2.8\n");
-       printk(KERN_INFO "HiSax: Revisions %s\n", rev);
+       printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", HiSax_getrev(tmp));
+       certification_check(1);
 }
 
 void
@@ -375,7 +450,7 @@ HiSax_setup(char *str, int *ints))
        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++;
@@ -413,11 +488,759 @@ HiSax_setup(char *str, int *ints))
 }
 #endif
 
+#if CARD_TELES0
+extern int setup_teles0(struct IsdnCard *card);
+#endif
+
+#if CARD_TELES3
+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
+extern int setup_avm_a1(struct IsdnCard *card);
+#endif
+
+#if CARD_AVM_A1_PCMCIA
+extern int setup_avm_a1_pcmcia(struct IsdnCard *card);
+#endif
+
+#if CARD_FRITZPCI
+extern int setup_avm_pcipnp(struct IsdnCard *card);
+#endif
+
+#if CARD_ELSA
+extern int setup_elsa(struct IsdnCard *card);
+#endif
+
+#if CARD_IX1MICROR2
+extern int setup_ix1micro(struct IsdnCard *card);
+#endif
+
+#if CARD_DIEHLDIVA
+extern int  setup_diva(struct IsdnCard *card);
+#endif
+
+#if CARD_ASUSCOM
+extern int setup_asuscom(struct IsdnCard *card);
+#endif
+
+#if CARD_TELEINT
+extern int setup_TeleInt(struct IsdnCard *card);
+#endif
+
+#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
+
+#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
+
+/*
+ * Find card with given driverId
+ */
+static inline struct IsdnCardState
+*hisax_findcard(int driverid)
+{
+       int i;
+
+       for (i = 0; i < nrcards; i++)
+               if (cards[i].cs)
+                       if (cards[i].cs->myid == driverid)
+                               return (cards[i].cs);
+       return (NULL);
+}
+
+int
+HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+       int count,cnt;
+       u_char *p = buf;
+       struct IsdnCardState *cs = hisax_findcard(id);
+
+       if (cs) {
+               if (len > HISAX_STATUS_BUFSIZE) {
+                       printk(KERN_WARNING "HiSax: status overflow readstat %d/%d\n",
+                               len, HISAX_STATUS_BUFSIZE);
+               }
+               count = cs->status_end - cs->status_read +1;
+               if (count >= len)
+                       count = len;
+               if (user)
+                       copy_to_user(p, cs->status_read, count);
+               else
+                       memcpy(p, cs->status_read, count);
+               cs->status_read += count;
+               if (cs->status_read > cs->status_end)
+                       cs->status_read = cs->status_buf;
+               p += count;
+               count = len - count;
+               while (count) {
+                       if (count > HISAX_STATUS_BUFSIZE)
+                               cnt = HISAX_STATUS_BUFSIZE;
+                       else
+                               cnt = count;
+                       if (user)
+                               copy_to_user(p, cs->status_read, cnt);
+                       else
+                               memcpy(p, cs->status_read, cnt);
+                       p += cnt;
+                       cs->status_read += cnt % HISAX_STATUS_BUFSIZE;
+                       count -= cnt;
+               }
+               return len;
+       } else {
+               printk(KERN_ERR
+                "HiSax: if_readstatus called with invalid driverId!\n");
+               return -ENODEV;
+       }
+}
+
+inline int
+jiftime(char *s, long mark)
+{
+       s += 8;
+
+       *s-- = '\0';
+       *s-- = mark % 10 + '0';
+       mark /= 10;
+       *s-- = mark % 10 + '0';
+       mark /= 10;
+       *s-- = '.';
+       *s-- = mark % 10 + '0';
+       mark /= 10;
+       *s-- = mark % 6 + '0';
+       mark /= 6;
+       *s-- = ':';
+       *s-- = mark % 10 + '0';
+       mark /= 10;
+       *s-- = mark % 10 + '0';
+       return(8);
+}
+
+static u_char tmpbuf[HISAX_STATUS_BUFSIZE];
+
+void
+VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args)
+{
+/* if head == NULL the fmt contains the full info */
+
+       long flags;
+       int count, i;
+       u_char *p;
+       isdn_ctrl ic;
+       int len;
+
+       save_flags(flags);
+       cli();
+       p = tmpbuf;
+       if (head) {
+               p += jiftime(p, jiffies);
+               p += sprintf(p, " %s", head);
+               p += vsprintf(p, fmt, args);
+               *p++ = '\n';
+               *p = 0;
+               len = p - tmpbuf;
+               p = tmpbuf;
+       } else {
+               p = fmt;
+               len = strlen(fmt);
+       }
+       if (!cs) {
+               printk(KERN_WARNING "HiSax: No CardStatus for message %s", p);
+               restore_flags(flags);
+               return;
+       }
+       if (len > HISAX_STATUS_BUFSIZE) {
+               printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
+                       len, HISAX_STATUS_BUFSIZE);
+               restore_flags(flags);
+               return;
+       }
+       count = len;
+       i = cs->status_end - cs->status_write +1;
+       if (i >= len)
+               i = len;
+       len -= i;
+       memcpy(cs->status_write, p, i);
+       cs->status_write += i;
+       if (cs->status_write > cs->status_end)
+               cs->status_write = cs->status_buf;
+       p += i;
+       if (len) {
+               memcpy(cs->status_write, p, len);
+               cs->status_write += len;
+       }
+#ifdef KERNELSTACK_DEBUG
+       i = (ulong)&len - current->kernel_stack_page;
+       sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm,
+               current->kernel_stack_page, i);
+       len = strlen(tmpbuf);
+       for (p = tmpbuf, i = len; i > 0; i--, p++) {
+               *cs->status_write++ = *p;
+               if (cs->status_write > cs->status_end)
+                       cs->status_write = cs->status_buf;
+               count++;
+       }
+#endif
+       restore_flags(flags);
+       if (count) {
+               ic.command = ISDN_STAT_STAVAIL;
+               ic.driver = cs->myid;
+               ic.arg = count;
+               cs->iif.statcallb(&ic);
+       }
+}
+
+void
+HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       VHiSax_putstatus(cs, head, fmt, args);
+       va_end(args);
+}
+
+int
+ll_run(struct IsdnCardState *cs)
+{
+       long flags;
+       isdn_ctrl ic;
+
+       save_flags(flags);
+       cli();
+       ic.driver = cs->myid;
+       ic.command = ISDN_STAT_RUN;
+       cs->iif.statcallb(&ic);
+       restore_flags(flags);
+       return 0;
+}
+
+void
+ll_stop(struct IsdnCardState *cs)
+{
+       isdn_ctrl ic;
+
+       ic.command = ISDN_STAT_STOP;
+       ic.driver = cs->myid;
+       cs->iif.statcallb(&ic);
+       CallcFreeChan(cs);
+}
+
+static void
+ll_unload(struct IsdnCardState *cs)
+{
+       isdn_ctrl ic;
+
+       ic.command = ISDN_STAT_UNLOAD;
+       ic.driver = cs->myid;
+       cs->iif.statcallb(&ic);
+       if (cs->status_buf)
+               kfree(cs->status_buf);
+       cs->status_read = NULL;
+       cs->status_write = NULL;
+       cs->status_end = NULL;
+       kfree(cs->dlog);
+}
+
+static void
+closecard(int cardnr)
+{
+       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);
+       }
+
+       if (csta->rcvbuf) {
+               kfree(csta->rcvbuf);
+               csta->rcvbuf = NULL;
+       }
+       discard_queue(&csta->rq);
+       discard_queue(&csta->sq);
+       if (csta->tx_skb) {
+               dev_kfree_skb(csta->tx_skb);
+               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);
+       if (csta->dbusytimer.function != NULL)
+               del_timer(&csta->dbusytimer);
+       ll_unload(csta);
+}
+
+HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
+{
+       int irq_cnt, cnt = 3;
+       long flags;
+
+       save_flags(flags);
+       cli();
+       irq_cnt = kstat_irqs(cs->irq);
+       printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq,
+               irq_cnt);
+       if (cs->cardmsg(cs, CARD_SETIRQ, NULL)) {
+               printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
+                       cs->irq);
+               restore_flags(flags);
+               return(1);
+       }
+       while (cnt) {
+               cs->cardmsg(cs, CARD_INIT, NULL);
+               sti();
+               current->state = TASK_INTERRUPTIBLE;
+               /* Timeout 10ms */
+               schedule_timeout((10 * HZ) / 1000);
+               restore_flags(flags);
+               printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
+                       cs->irq, kstat_irqs(cs->irq));
+               if (kstat_irqs(cs->irq) == irq_cnt) {
+                       printk(KERN_WARNING
+                              "%s: IRQ(%d) getting no interrupts during init %d\n",
+                              CardType[cs->typ], cs->irq, 4 - cnt);
+                       if (cnt == 1) {
+                               free_irq(cs->irq, cs);
+                               return (2);
+                       } else {
+                               cs->cardmsg(cs, CARD_RESET, NULL);
+                               cnt--;
+                       }
+               } else {
+                       cs->cardmsg(cs, CARD_TEST, NULL);
+                       return(0);
+               }
+       }
+       restore_flags(flags);
+       return(3);
+}
+
+HISAX_INITFUNC(static int
+checkcard(int cardnr, char *id, int *busy_flag))
+{
+       long flags;
+       int ret = 0;
+       struct IsdnCard *card = cards + cardnr;
+       struct IsdnCardState *cs;
+
+       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);
+       }
+       memset(cs, 0, sizeof(struct IsdnCardState));
+       card->cs = cs;
+       cs->cardnr = cardnr;
+       cs->debug = L1_DEB_WARN;
+       cs->HW_Flags = 0;
+       cs->busy_flag = busy_flag;
+#if TEI_PER_CARD
+#else
+       test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#endif
+       cs->protocol = card->protocol;
+
+       if ((card->typ > 0) && (card->typ < 31)) {
+               if (!((1 << card->typ) & SUPORTED_CARDS)) {
+                       printk(KERN_WARNING
+                            "HiSax: Support for %s Card not selected\n",
+                              CardType[card->typ]);
+                       restore_flags(flags);
+                       return (0);
+               }
+       } else {
+               printk(KERN_WARNING
+                      "HiSax: Card Type %d out of range\n",
+                      card->typ);
+               restore_flags(flags);
+               return (0);
+       }
+       if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
+               printk(KERN_WARNING
+                      "HiSax: No memory for dlog(card %d)\n",
+                      cardnr + 1);
+               restore_flags(flags);
+               return (0);
+       }
+       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(cs->dlog);
+               restore_flags(flags);
+               return (0);
+       }
+       cs->stlist = NULL;
+       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
+           ISDN_FEATURE_P_1TR6 |
+#endif
+#ifdef CONFIG_HISAX_EURO
+           ISDN_FEATURE_P_EURO |
+#endif
+#ifdef        CONFIG_HISAX_NI1
+           ISDN_FEATURE_P_NI1 |
+#endif
+           0;
+
+       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", cs->iif.id, cs->myid);
+       switch (card->typ) {
+#if CARD_TELES0
+               case ISDN_CTYPE_16_0:
+               case ISDN_CTYPE_8_0:
+                       ret = setup_teles0(card);
+                       break;
+#endif
+#if CARD_TELES3
+               case ISDN_CTYPE_16_3:
+               case ISDN_CTYPE_PNP:
+               case ISDN_CTYPE_TELESPCMCIA:
+               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);
+                       break;
+#endif
+#if CARD_AVM_A1_PCMCIA
+               case ISDN_CTYPE_A1_PCMCIA:
+                       ret = setup_avm_a1_pcmcia(card);
+                       break;
+#endif
+#if CARD_FRITZPCI
+               case ISDN_CTYPE_FRITZPCI:
+                       ret = setup_avm_pcipnp(card);
+                       break;
+#endif
+#if CARD_ELSA
+               case ISDN_CTYPE_ELSA:
+               case ISDN_CTYPE_ELSA_PNP:
+               case ISDN_CTYPE_ELSA_PCMCIA:
+               case ISDN_CTYPE_ELSA_PCI:
+                       ret = setup_elsa(card);
+                       break;
+#endif
+#if CARD_IX1MICROR2
+               case ISDN_CTYPE_IX1MICROR2:
+                       ret = setup_ix1micro(card);
+                       break;
+#endif
+#if CARD_DIEHLDIVA
+               case ISDN_CTYPE_DIEHLDIVA:
+                       ret = setup_diva(card);
+                       break;
+#endif
+#if CARD_ASUSCOM
+               case ISDN_CTYPE_ASUSCOM:
+                       ret = setup_asuscom(card);
+                       break;
+#endif
+#if CARD_TELEINT
+               case ISDN_CTYPE_TELEINT:
+                       ret = setup_TeleInt(card);
+                       break;
+#endif
+#if CARD_SEDLBAUER
+               case ISDN_CTYPE_SEDLBAUER:
+               case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+               case ISDN_CTYPE_SEDLBAUER_FAX:
+                       ret = setup_sedlbauer(card);
+                       break;
+#endif
+#if CARD_SPORTSTER
+               case ISDN_CTYPE_SPORTSTER:
+                       ret = setup_sportster(card);
+                       break;
+#endif
+#if CARD_MIC
+               case ISDN_CTYPE_MIC:
+                       ret = setup_mic(card);
+                       break;
+#endif
+#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_L1, 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(cs, cs->protocol);
+       CallcNewChan(cs);
+       /* ISAR needs firmware download first */
+       if (!test_bit(HW_ISAR, &cs->HW_Flags))
+               ll_run(cs);
+       restore_flags(flags);
+       return (1);
+}
+
+HISAX_INITFUNC(void
+HiSax_shiftcards(int idx))
+{
+       int i;
+
+       for (i = idx; i < (HISAX_MAX_CARDS - 1); i++)
+               memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
+}
+
+HISAX_INITFUNC(int
+HiSax_inithardware(int *busy_flag))
+{
+       int foundcards = 0;
+       int i = 0;
+       int t = ',';
+       int flg = 0;
+       char *id;
+       char *next_id = HiSax_id;
+       char ids[20];
+
+       if (strchr(HiSax_id, ','))
+               t = ',';
+       else if (strchr(HiSax_id, '%'))
+               t = '%';
+
+       while (i < nrcards) {
+               if (cards[i].typ < 1)
+                       break;
+               id = next_id;
+               if ((next_id = strchr(id, t))) {
+                       *next_id++ = 0;
+                       strcpy(ids, id);
+                       flg = i + 1;
+               } else {
+                       next_id = id;
+                       if (flg >= i)
+                               strcpy(ids, id);
+                       else
+                               sprintf(ids, "%s%d", id, i);
+               }
+               if (checkcard(i, ids, busy_flag)) {
+                       foundcards++;
+                       i++;
+               } else {
+                       printk(KERN_WARNING "HiSax: Card %s not installed !\n",
+                              CardType[cards[i].typ]);
+                       if (cards[i].cs)
+                               kfree((void *) cards[i].cs);
+                       cards[i].cs = NULL;
+                       HiSax_shiftcards(i);
+               }
+       }
+       return foundcards;
+}
+
+void
+HiSax_closecard(int cardnr)
+{
+       int     i,last=nrcards - 1;
+
+       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;
+       }
+       i = cardnr;
+       while (i!=last) {
+               cards[i] = cards[i+1];
+               i++;
+       }
+       nrcards--;
+}
+
+EXPORT_SYMBOL(HiSax_closecard);
+
+void
+HiSax_reportcard(int cardnr)
+{
+       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[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: HW_Flags %x bc0 flg %x bc0 flg %x\n",
+               cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
+       printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
+               cs->bcs[0].mode, cs->bcs[0].channel);
+       printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n",
+               cs->bcs[1].mode, cs->bcs[1].channel);
+       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++;
+               }
+       }
+}
+
+
 __initfunc(int
 HiSax_init(void))
 {
        int i;
-       
+
 #ifdef MODULE
        int nzproto = 0;
 #ifdef CONFIG_HISAX_ELSA
@@ -432,13 +1255,19 @@ HiSax_init(void))
                return 0;
        }
 #endif
+#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
+       if (type[0] == ISDN_CTYPE_A1_PCMCIA) {
+               /* we have to export  and return in this case */
+               return 0;
+       }
+#endif
 #endif
-       HiSaxVersion();
        nrcards = 0;
+       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];
@@ -476,6 +1305,7 @@ HiSax_init(void))
                        case ISDN_CTYPE_16_3:
                        case ISDN_CTYPE_TELESPCMCIA:
                        case ISDN_CTYPE_A1:
+                       case ISDN_CTYPE_A1_PCMCIA:
                        case ISDN_CTYPE_ELSA_PNP:
                        case ISDN_CTYPE_ELSA_PCMCIA:
                        case ISDN_CTYPE_IX1MICROR2:
@@ -484,16 +1314,19 @@ HiSax_init(void))
                        case ISDN_CTYPE_TELEINT:
                        case ISDN_CTYPE_SEDLBAUER:
                        case ISDN_CTYPE_SEDLBAUER_PCMCIA:
+                       case ISDN_CTYPE_SEDLBAUER_FAX:
                        case ISDN_CTYPE_SPORTSTER:
                        case ISDN_CTYPE_MIC:
                        case ISDN_CTYPE_TELES3C:
+                       case ISDN_CTYPE_S0BOX:
+                       case ISDN_CTYPE_FRITZPCI:
                                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_DBRI:
+                       case ISDN_CTYPE_TELESPCI:
                                break;
                }
        }
@@ -507,13 +1340,14 @@ 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();
        TeiNew();
        Isdnl1New();
@@ -522,7 +1356,6 @@ HiSax_init(void))
                /* No symbols to export, hide all symbols */
 
 #ifdef MODULE
-               EXPORT_NO_SYMBOLS;
                printk(KERN_INFO "HiSax: module installed\n");
 #endif
                return (0);
@@ -530,6 +1363,7 @@ HiSax_init(void))
                Isdnl1Free();
                TeiFree();
                Isdnl2Free();
+               Isdnl3Free();
                CallcFree();
                return -EIO;
        }
@@ -539,13 +1373,27 @@ HiSax_init(void))
 void
 cleanup_module(void)
 {
-       HiSax_closehardware();
+       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");
 }
+#endif
 
 #ifdef CONFIG_HISAX_ELSA
 int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 {
+#ifdef MODULE
        int i;
        int nzproto = 0;
 
@@ -553,10 +1401,10 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        HiSaxVersion();
        if (id)                 /* If id= string used */
                HiSax_id = id;
-       /* Initialize all 16 structs, even though we only accept
+       /* Initialize all 8 structs, even though we only accept
           two pcmcia cards
           */
-       for (i = 0; i < 16; i++) {
+       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];
@@ -575,7 +1423,7 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
                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",
@@ -583,16 +1431,71 @@ int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 
        Isdnl1New();
        CallcNew();
+       Isdnl3New();
        Isdnl2New();
        TeiNew();
        HiSax_inithardware(busy_flag);
        printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
        return (0);
 }
 #endif
+
 #ifdef CONFIG_HISAX_SEDLBAUER
 int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 {
+#ifdef MODULE
+       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" : "");
+
+       CallcNew();
+       Isdnl3New();
+       Isdnl2New();
+       Isdnl1New();
+       TeiNew();
+       HiSax_inithardware(busy_flag);
+       printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
+       return (0);
+}
+#endif
+
+#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
+int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
+{
+#ifdef MODULE
        int i;
        int nzproto = 0;
 
@@ -615,14 +1518,14 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
        cards[0].para[0] = pcm_irq;
        cards[0].para[1] = (int)pcm_iob;
        cards[0].protocol = prot;
-       cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
+       cards[0].typ = ISDN_CTYPE_A1_PCMCIA;
        nzproto = 1;
 
        if (!HiSax_id)
                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",
@@ -630,11 +1533,12 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 
        Isdnl1New();
        CallcNew();
+       Isdnl3New();
        Isdnl2New();
        TeiNew();
        HiSax_inithardware(busy_flag);
        printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
        return (0);
 }
 #endif
-#endif 
index a533272c86d4703dbd54ccd6ec01ea5f5249ee0c..4baf740b1dcbfa7bea1a35c2d5810c0bfaeec8cc 100644 (file)
@@ -1,13 +1,30 @@
-/* $Id: diva.c,v 1.5 1998/02/02 13:29:38 keil Exp $
+/* $Id: diva.c,v 1.10 1998/11/15 23:54:31 keil Exp $
 
  * diva.c     low level stuff for Eicon.Diehl Diva Family ISDN cards
  *
- * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * Thanks to Eicon Technology Diehl GmbH & Co. oHG for documents and informations
  *
  *
  * $Log: diva.c,v $
+ * Revision 1.10  1998/11/15 23:54:31  keil
+ * changes from 2.0
+ *
+ * Revision 1.9  1998/06/27 22:52:03  keil
+ * support for Diva 2.01
+ *
+ * Revision 1.8  1998/05/25 12:57:46  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 1.7  1998/04/15 16:42:36  keil
+ * new init code
+ * new PCI init (2.1.94)
+ *
+ * Revision 1.6  1998/03/07 22:56:57  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 1.5  1998/02/02 13:29:38  keil
  * fast io
  *
 #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.5 $";
+const char *Diva_revision = "$Revision: 1.10 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -47,6 +64,8 @@ const char *Diva_revision = "$Revision: 1.5 $";
 #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
@@ -55,6 +74,7 @@ const char *Diva_revision = "$Revision: 1.5 $";
 /* SUB Types */
 #define DIVA_ISA       1
 #define DIVA_PCI       2
+#define DIVA_IPAC_ISA  3
 
 /* PCI stuff */
 #define PCI_VENDOR_EICON_DIEHL 0x1133
@@ -140,12 +160,36 @@ ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
        readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size);
 }
 
-static void 
+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)
 {
@@ -168,13 +212,13 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
                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
@@ -215,18 +259,69 @@ diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        }
 }
 
+static void
+diva_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char ista,val;
+       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)
+               debugl1(cs, "IPAC ISTA %02X", ista);
+       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;
-       
-       del_timer(&cs->hw.diva.tl);
-       if (cs->subtyp == DIVA_ISA)
+
+       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) {
-               byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */
                release_region(cs->hw.diva.cfg_reg, bytecnt);
        }
 }
@@ -238,19 +333,30 @@ reset_diva(struct IsdnCardState *cs)
 
        save_flags(flags);
        sti();
-       cs->hw.diva.ctrl_reg = 0;        /* Reset On */
-       byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
-       cs->hw.diva.ctrl_reg |= DIVA_RESET;  /* Reset Off */
-       byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
-       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);
+       if (cs->subtyp == DIVA_IPAC_ISA) {
+               writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+               writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+               writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
+       } else {
+               cs->hw.diva.ctrl_reg = 0;        /* Reset On */
+               byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+               cs->hw.diva.ctrl_reg |= DIVA_RESET;  /* Reset Off */
+               byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
+               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
@@ -260,6 +366,8 @@ 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) ?
@@ -272,14 +380,14 @@ diva_led_handler(struct IsdnCardState *cs)
        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) { 
+       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);
@@ -291,6 +399,8 @@ diva_led_handler(struct IsdnCardState *cs)
 static int
 Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
+       u_int irq_flag = I4L_IRQ_FLAG;
+
        switch (mt) {
                case CARD_RESET:
                        reset_diva(cs);
@@ -299,36 +409,40 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        release_io_diva(cs);
                        return(0);
                case CARD_SETIRQ:
-                       return(request_irq(cs->irq, &diva_interrupt,
-                                       I4L_IRQ_FLAG, "HiSax", cs));
+                       if (cs->subtyp == DIVA_PCI)
+                               irq_flag |= SA_SHIRQ;
+                       if (cs->subtyp == DIVA_IPAC_ISA) {
+                               return(request_irq(cs->irq, &diva_interrupt_ipac,
+                                               irq_flag, "HiSax", cs));
+                       } else {
+                               return(request_irq(cs->irq, &diva_interrupt,
+                                               irq_flag, "HiSax", cs));
+                       }
                case CARD_INIT:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       inithscxisac(cs, 3);
                        return(0);
                case CARD_TEST:
                        return(0);
-               case MDL_REMOVE_REQ:
+               case (MDL_REMOVE | REQUEST):
                        cs->hw.diva.status = 0;
                        break;
-               case MDL_ASSIGN_REQ:
+               case (MDL_ASSIGN | REQUEST):
                        cs->hw.diva.status |= DIVA_ASSIGN;
                        break;
                case MDL_INFO_SETUP:
-                       if ((int)arg) 
+                       if ((long)arg)
                                cs->hw.diva.status |=  0x0200;
                        else
                                cs->hw.diva.status |=  0x0100;
                        break;
                case MDL_INFO_CONN:
-                       if ((int)arg) 
+                       if ((long)arg)
                                cs->hw.diva.status |=  0x2000;
                        else
                                cs->hw.diva.status |=  0x1000;
                        break;
                case MDL_INFO_REL:
-                       if ((int)arg) {
+                       if ((long)arg) {
                                cs->hw.diva.status &=  ~0x2000;
                                cs->hw.diva.status &=  ~0x0200;
                        } else {
@@ -337,18 +451,19 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        }
                        break;
        }
-       diva_led_handler(cs);
+       if (cs->subtyp != DIVA_IPAC_ISA)
+               diva_led_handler(cs);
        return(0);
 }
 
-
-
-static         int pci_index __initdata = 0;
+static         struct pci_dev *dev_diva __initdata = NULL;
+static         struct pci_dev *dev_diva_u __initdata = NULL;
 
 __initfunc(int
 setup_diva(struct IsdnCard *card))
 {
        int bytecnt;
+       u_char val;
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
 
@@ -358,64 +473,72 @@ setup_diva(struct IsdnCard *card))
                return(0);
        cs->hw.diva.status = 0;
        if (card->para[1]) {
-               cs->subtyp = DIVA_ISA;
                cs->hw.diva.ctrl_reg = 0;
                cs->hw.diva.cfg_reg = card->para[1];
-               cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
-               cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
-               cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
-               cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
-               cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+               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;
+               if (!pci_present()) {
+                       printk(KERN_ERR "Diva: no PCI bus present\n");
+                       return(0);
+               }
 
                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)
+               if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL,
+                       PCI_DIVA20_ID, dev_diva))) {
                                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)
+                       /* get IRQ */
+                       cs->irq = dev_diva->irq;
+                       /* get IO address */
+                       cs->hw.diva.cfg_reg = dev_diva->base_address[2]
+                               & PCI_BASE_ADDRESS_IO_MASK;
+               } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL,
+                       PCI_DIVA20_U_ID, dev_diva_u))) {
                                cs->subtyp = DIVA_PCI;
-                       else
-                               break;
                        /* get IRQ */
-                       pcibios_read_config_byte(pci_bus, pci_device_fn,
-                               PCI_INTERRUPT_LINE, &pci_irq);
-
+                       cs->irq = dev_diva_u->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) {
+                       cs->hw.diva.cfg_reg = dev_diva_u->base_address[2]
+                               & PCI_BASE_ADDRESS_IO_MASK;
+               } else {
                        printk(KERN_WARNING "Diva: No PCI card found\n");
                        return(0);
                }
-               if (!pci_irq) {
+
+               if (!cs->irq) {
                        printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
                        return(0);
                }
 
-               if (!pci_ioaddr) {
+               if (!cs->hw.diva.cfg_reg) {
                        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;
+               cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+               cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+               cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+               cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+               cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
                bytecnt = 32;
 #else
                printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
@@ -426,7 +549,8 @@ setup_diva(struct IsdnCard *card))
 
        printk(KERN_INFO
                "Diva: %s card configured at 0x%x IRQ %d\n",
-               (cs->subtyp == DIVA_ISA) ? "ISA" : "PCI",
+               (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
@@ -440,24 +564,32 @@ setup_diva(struct IsdnCard *card))
        }
 
        reset_diva(cs);
-       cs->hw.diva.tl.function = (void *) diva_led_handler;
-       cs->hw.diva.tl.data = (long) cs;
-       init_timer(&cs->hw.diva.tl);
-       cs->readisac  = &ReadISAC;
-       cs->writeisac = &WriteISAC;
-       cs->readisacfifo  = &ReadISACfifo;
-       cs->writeisacfifo = &WriteISACfifo;
        cs->BC_Read_Reg  = &ReadHSCX;
        cs->BC_Write_Reg = &WriteHSCX;
        cs->BC_Send_Data = &hscx_fill_fifo;
        cs->cardmsg = &Diva_card_msg;
-
-       ISACVersion(cs, "Diva:");
-       if (HscxVersion(cs, "Diva:")) {
-               printk(KERN_WARNING
+       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);
+                       release_io_diva(cs);
+                       return (0);
+               }
        }
        return (1);
 }
index 00817806590dff90d1cdc7ed3ea5e828027e14a0..50f9df9c081b9bf76981c84e6f041b8822d2ce57 100644 (file)
@@ -1,13 +1,41 @@
-/* $Id: elsa.c,v 2.6 1998/02/02 13:29:40 keil Exp $
+/* $Id: elsa.c,v 2.12 1998/11/15 23:54:35 keil Exp $
 
  * elsa.c     low level stuff for Elsa isdn cards
  *
- * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author     Karsten Keil (keil@isdn4linux.de)
+ *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
  *
  * Thanks to    Elsa GmbH for documents and informations
  *
+ *              Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE)
+ *              for ELSA PCMCIA support
+ *
  *
  * $Log: elsa.c,v $
+ * Revision 2.12  1998/11/15 23:54:35  keil
+ * changes from 2.0
+ *
+ * Revision 2.11  1998/08/20 13:50:34  keil
+ * More support for hybrid modem (not working yet)
+ *
+ * Revision 2.10  1998/08/13 23:36:22  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.9  1998/05/25 12:57:48  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.8  1998/04/15 16:41:42  keil
+ * QS3000 PCI support
+ * new init code
+ * new PCI init (2.1.94)
+ *
+ * Revision 2.7  1998/03/07 22:56:58  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 2.6  1998/02/02 13:29:40  keil
  * fast io
  *
  * Revision 2.0  1997/06/26 11:02:40  keil
  * New Layer and card interface
  *
- * Revision 1.14  1997/04/13 19:53:25  keil
- * Fixed QS1000 init, change in IRQ check delay for SMP
- *
- * Revision 1.13  1997/04/07 22:58:07  keil
- * need include config.h
- *
- * Revision 1.12  1997/04/06 22:54:14  keil
- * Using SKB's
- *
  * old changes removed KKe
  *
  */
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
-#include <linux/bios32.h>
+
+//#define KDEBUG_DEF
+//#include "../kdebug.h"
 
 extern const char *CardType[];
 
-const char *Elsa_revision = "$Revision: 2.6 $";
+static const char *Elsa_revision = "$Revision: 2.12 $";
 const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
- "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI"};
+ "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI"};
 
 const char *ITACVer[] =
 {"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
@@ -87,11 +108,13 @@ const char *ITACVer[] =
 #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
@@ -128,6 +151,30 @@ const char *ITACVer[] =
 #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
 readreg(unsigned int ale, unsigned int adr, u_char off)
 {
@@ -302,6 +349,21 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
                return;
        }
+       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;
+       }
+#if ARCOFI_USE
+       if (cs->hw.elsa.MFlag) {
+               val = serial_inp(cs, UART_IIR);
+               if (!(val & UART_IIR_NO_INT)) {
+                       debugl1(cs,"IIR %02x", val);
+                       rs_interrupt_elsa(intno, cs);
+               }
+       }
+#endif
        val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
       Start_HSCX:
        if (val) {
@@ -338,6 +400,14 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                        cs->hw.elsa.counter++;
                }
        }
+       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);
@@ -350,25 +420,28 @@ elsa_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 "Elsa: Spurious interrupt!\n");
                return;
        }
-       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;
+       val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */
+       if (!(val & ELSA_PCI_IRQ_MASK))
+               return;
+#if ARCOFI_USE
+       if (cs->hw.elsa.MFlag) {
+               val = serial_inp(cs, UART_IIR);
+               if (!(val & UART_IIR_NO_INT)) {
+                       debugl1(cs,"IIR %02x", val);
+                       rs_interrupt_elsa(intno, cs);
+               }
        }
+#endif
        ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA);
 Start_IPAC:
-       if (cs->debug & L1_DEB_IPAC) {
-               sprintf(tmp, "IPAC ISTA %02X", ista);
-               debugl1(cs, tmp);
-       }
+       if (cs->debug & L1_DEB_IPAC)
+               debugl1(cs, "IPAC ISTA %02X", ista);
        if (ista & 0x0f) {
                val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40);
                if (ista & 0x01)
@@ -409,15 +482,24 @@ release_io_elsa(struct IsdnCardState *cs)
        del_timer(&cs->hw.elsa.tl);
        if (cs->hw.elsa.ctrl)
                byteout(cs->hw.elsa.ctrl, 0);   /* LEDs Out */
-       if ((cs->subtyp == ELSA_PCFPRO) || 
-               (cs->subtyp == ELSA_QS3000) ||
-               (cs->subtyp == ELSA_PCF))
-               bytecnt = 16;
        if (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);
        }
+       if (cs->subtyp == ELSA_QS3000PCI) {
+               byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable 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);
+       }
        if (cs->hw.elsa.base)
                release_region(cs->hw.elsa.base, bytecnt);
 }
@@ -445,7 +527,7 @@ reset_elsa(struct IsdnCardState *cs)
                if (cs->hw.elsa.trig)
                        byteout(cs->hw.elsa.trig, 0xff);
        }
-       if (cs->subtyp == ELSA_QS1000PCI) {
+       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);
@@ -455,35 +537,55 @@ reset_elsa(struct IsdnCardState *cs)
                current->state = TASK_INTERRUPTIBLE;
                schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
                writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
-               schedule();
                restore_flags(flags);
-               byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */
+               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 */
        }
 }
 
-const u_char ARCOFI_VERSION[] = {2,0xa0,0};
-const u_char ARCOFI_COP_5[] = {4,0xa1,0x25,0xbb,0x4a}; /* GTX */
-const u_char ARCOFI_COP_6[] = {6,0xa1,0x26,0,0,0x82,0x7c}; /* GRL GRH */
-const u_char ARCOFI_COP_7[] = {4,0xa1,0x27,0x80,0x80}; /* GZ */
-const u_char ARCOFI_COP_8[] = {10,0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}; /* TX */
-const u_char ARCOFI_COP_9[] = {10,0xa1,0x29,0x80,0xcb,0x9e,0x88,0x00,0xc8,0xd8,0x80}; /* RX */
-const u_char ARCOFI_XOP_0[] = {2,0xa1,0x30}; /* PWR Down */
-const u_char ARCOFI_XOP_1[] = {2,0xa1,0x31}; /* PWR Down */
-const u_char ARCOFI_XOP_F[] = {2,0xa1,0x3f}; /* PWR Down */
-const u_char ARCOFI_SOP_F[] = {10,0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12};
 static void
 init_arcofi(struct IsdnCardState *cs) {
-       send_arcofi(cs, ARCOFI_COP_5);
-       send_arcofi(cs, ARCOFI_COP_6);
-       send_arcofi(cs, ARCOFI_COP_7);
-       send_arcofi(cs, ARCOFI_COP_8);
-       send_arcofi(cs, ARCOFI_COP_9);
-       send_arcofi(cs, ARCOFI_SOP_F);
-       send_arcofi(cs, ARCOFI_XOP_F);
+       send_arcofi(cs, ARCOFI_XOP_0, 1, 0);
+/*     send_arcofi(cs, ARCOFI_XOP_F, 1);
+*/
 }
 
+#define ARCDEL 500
+
 static void
+set_arcofi(struct IsdnCardState *cs, int bc) {
+       long flags;
+
+       debugl1(cs,"set_arcofi bc=%d", bc);
+       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);
+       debugl1(cs,"end set_arcofi bc=%d", bc);
+}
+
+static int
 check_arcofi(struct IsdnCardState *cs)
 {
 #if ARCOFI_USE
@@ -496,13 +598,12 @@ check_arcofi(struct IsdnCardState *cs)
                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;
+                       return(0);
                }
-       send_arcofi(cs, ARCOFI_VERSION);
+       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);
+                       debugl1(cs, "Arcofi response received %d bytes", cs->mon_rxp);
                        p = cs->mon_rx;
                        t = tmp;
                        t += sprintf(tmp, "Arcofi data");
@@ -531,8 +632,7 @@ check_arcofi(struct IsdnCardState *cs)
                        cs->mon_rxp = 0;
                }
        } else if (cs->mon_tx) {
-               sprintf(tmp, "Arcofi not detected");
-               debugl1(cs, tmp);
+               debugl1(cs, "Arcofi not detected");
        }
        if (arcofi_present) {
                if (cs->subtyp==ELSA_QS1000) {
@@ -573,8 +673,10 @@ check_arcofi(struct IsdnCardState *cs)
                                Elsa_Types[cs->subtyp],
                                cs->hw.elsa.base+8);
                init_arcofi(cs);
+               return(1);
        }
 #endif
+       return(0);
 }
 
 static void
@@ -582,8 +684,7 @@ elsa_led_handler(struct IsdnCardState *cs)
 {
        int blink = 0;
 
-       if ((cs->subtyp == ELSA_PCMCIA) &&
-               (cs->subtyp == ELSA_QS1000PCI))
+       if (cs->subtyp == ELSA_PCMCIA)
                return;
        del_timer(&cs->hw.elsa.tl);
        if (cs->hw.elsa.status & ELSA_ASSIGN)
@@ -602,7 +703,16 @@ elsa_led_handler(struct IsdnCardState *cs)
        } else
                cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED;
 
-       byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
+       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);
@@ -613,8 +723,9 @@ elsa_led_handler(struct IsdnCardState *cs)
 static int
 Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
-       int pwr, ret = 0;
-       long flags;     
+       int len, ret = 0;
+       u_char *msg;
+       long flags;
 
        switch (mt) {
                case CARD_RESET:
@@ -624,28 +735,33 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        release_io_elsa(cs);
                        return(0);
                case CARD_SETIRQ:
-                       if (cs->subtyp == ELSA_QS1000PCI)
+                       if ((cs->subtyp == ELSA_QS1000PCI) ||
+                               (cs->subtyp == ELSA_QS3000PCI))
                                ret = request_irq(cs->irq, &elsa_interrupt_ipac,
-                                       I4L_IRQ_FLAG, "HiSax", cs);
+                                       I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs);
                        else
                                ret = request_irq(cs->irq, &elsa_interrupt,
                                        I4L_IRQ_FLAG, "HiSax", cs);
                        return(ret);
                case CARD_INIT:
-                       if (cs->hw.elsa.trig)
-                               byteout(cs->hw.elsa.trig, 0xff);
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
-                       if (cs->subtyp == ELSA_QS1000) {
+                       cs->debug |= L1_DEB_IPAC;
+                       inithscxisac(cs, 1);
+                       if ((cs->subtyp == ELSA_QS1000) ||
+                           (cs->subtyp == ELSA_QS3000))
+                       {
                                byteout(cs->hw.elsa.timer, 0);
-                               byteout(cs->hw.elsa.trig, 0xff);
                        }
+                       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)) {
+                       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();
@@ -653,48 +769,52 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                                cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
                                byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
                                byteout(cs->hw.elsa.timer, 0);
-                       } else
-                               return(0);
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout((110*HZ)/1000);                /* Timeout 110ms */
-                       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;
+                               current->state = TASK_INTERRUPTIBLE;
+                               /* Timeout 110ms */
+                               schedule_timeout((110*HZ)/1000);
+                               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;
+                               }
                        }
-                       check_arcofi(cs);
+#if ARCOFI_USE
+                       if (check_arcofi(cs)) {
+                               init_modem(cs);
+                       }
+#endif
                        elsa_led_handler(cs);
                        return(ret);
-               case MDL_REMOVE_REQ:
+               case (MDL_REMOVE | REQUEST):
                        cs->hw.elsa.status &= 0;
                        break;
-               case MDL_ASSIGN_REQ:
+               case (MDL_ASSIGN | REQUEST):
                        cs->hw.elsa.status |= ELSA_ASSIGN;
                        break;
                case MDL_INFO_SETUP:
-                       if ((int) arg)
+                       if ((long) arg)
                                cs->hw.elsa.status |= 0x0200;
                        else
                                cs->hw.elsa.status |= 0x0100;
                        break;
                case MDL_INFO_CONN:
-                       if ((int) arg)
+                       if ((long) arg)
                                cs->hw.elsa.status |= 0x2000;
                        else
                                cs->hw.elsa.status |= 0x1000;
                        break;
                case MDL_INFO_REL:
-                       if ((int) arg) {
+                       if ((long) arg) {
                                cs->hw.elsa.status &= ~0x2000;
                                cs->hw.elsa.status &= ~0x0200;
                        } else {
@@ -703,13 +823,23 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        }
                        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;
        }
-       pwr = bytein(cs->hw.elsa.ale);
-       if (pwr & 0x08)
-               cs->hw.elsa.status |= ELSA_BAD_PWR;
-       else
-               cs->hw.elsa.status &= ~ELSA_BAD_PWR;
+       if (cs->typ == ISDN_CTYPE_ELSA) {
+               int 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);
 }
@@ -778,7 +908,8 @@ probe_elsa(struct IsdnCardState *cs)
        return (CARD_portlist[i]);
 }
 
-static         int pci_index __initdata = 0;
+static         struct pci_dev *dev_qs1000 __initdata = NULL;
+static         struct pci_dev *dev_qs3000 __initdata = NULL;
 
 int
 setup_elsa(struct IsdnCard *card)
@@ -793,6 +924,7 @@ setup_elsa(struct IsdnCard *card)
        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");
@@ -886,59 +1018,62 @@ setup_elsa(struct IsdnCard *card)
                       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;
-
+               if (!pci_present()) {
+                       printk(KERN_ERR "Elsa: no PCI bus present\n");
+                       return(0);
+               }
                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)
+               if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID,
+                        dev_qs1000))) {
                                cs->subtyp = ELSA_QS1000PCI;
-                       else
-                               break;
-                       /* get IRQ */
-                       pcibios_read_config_byte(pci_bus, pci_device_fn,
-                               PCI_INTERRUPT_LINE, &pci_irq);
-
-                       /* get IO address */
-                       pcibios_read_config_dword(pci_bus, pci_device_fn,
-                               PCI_BASE_ADDRESS_1, &pci_ioaddr);
-                       pci_ioaddr &= ~3; /* remove io/mem flag */
-                       cs->hw.elsa.cfg = pci_ioaddr;
-                       pcibios_read_config_dword(pci_bus, pci_device_fn,
-                               PCI_BASE_ADDRESS_3, &pci_ioaddr);
-                       if (cs->subtyp)
-                               break;
-               }
-               if (!cs->subtyp) {
+                       cs->irq = dev_qs1000->irq;
+                       cs->hw.elsa.cfg = dev_qs1000->base_address[1] & 
+                               PCI_BASE_ADDRESS_IO_MASK;
+                       cs->hw.elsa.base = dev_qs1000->base_address[3] & 
+                               PCI_BASE_ADDRESS_IO_MASK;
+               } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA,
+                       PCI_QS3000_ID, dev_qs3000))) {
+                       cs->subtyp = ELSA_QS3000PCI;
+                       cs->irq = dev_qs3000->irq;
+                       cs->hw.elsa.cfg = dev_qs3000->base_address[1] & 
+                               PCI_BASE_ADDRESS_IO_MASK;
+                       cs->hw.elsa.base = dev_qs3000->base_address[3] & 
+                               PCI_BASE_ADDRESS_IO_MASK;
+               } else {
                        printk(KERN_WARNING "Elsa: No PCI card found\n");
                        return(0);
                }
-               if (!pci_irq) {
+               if (!cs->irq) {
                        printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
                        return(0);
                }
 
-               if (!pci_ioaddr) {
+               if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
                        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;
+               cs->hw.elsa.ale  = cs->hw.elsa.base;
+               cs->hw.elsa.isac = cs->hw.elsa.base +1;
+               cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
                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);
+                       "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);
+               if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+                       printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+                       printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+                       printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
+                       printk(KERN_WARNING "Elsa: Waiting 5 sec to sync discs\n");
+                       save_flags(flags);
+                       sti();
+                       HZDELAY(500);   /* wait 500*10 ms */
+                       restore_flags(flags);
+               }
 #else
                printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
                printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
@@ -957,6 +1092,7 @@ setup_elsa(struct IsdnCard *card)
                        break;
                case ELSA_PCFPRO:
                case ELSA_PCF:
+               case ELSA_QS3000PCI:
                        bytecnt = 16;
                        break;
                case ELSA_QS1000PCI:
@@ -980,7 +1116,7 @@ setup_elsa(struct IsdnCard *card)
        } else {
                request_region(cs->hw.elsa.base, bytecnt, "elsa isdn");
        }
-       if (cs->subtyp == ELSA_QS1000PCI) {
+       if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
                if (check_region(cs->hw.elsa.cfg, 0x80)) {
                        printk(KERN_WARNING
                               "HiSax: %s pci port %x-%x already in use\n",
@@ -1020,12 +1156,12 @@ setup_elsa(struct IsdnCard *card)
                }
                printk(KERN_INFO "Elsa: timer OK; resetting card\n");
        }
-       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) {
+       reset_elsa(cs);
+       if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
                cs->readisac = &ReadISAC_IPAC;
                cs->writeisac = &WriteISAC_IPAC;
                cs->readisacfifo = &ReadISACfifo_IPAC;
@@ -1056,4 +1192,3 @@ setup_elsa(struct IsdnCard *card)
        }
        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..b63511e
--- /dev/null
@@ -0,0 +1,748 @@
+#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_OPEN
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_REG
+//#define SERIAL_DEBUG_REG 1
+
+#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&C1E0&D2\r\0";
+static char *MInit_2 = "ATL2M1S64=13\r\0";
+static char *MInit_3 = "AT+FCLASS=0\r\0";
+static char *MInit_4 = "ATV1S2=128X1\r\0";
+static char *MInit_5 = "AT\\V8\\N3\r\0";
+static char *MInit_6 = "ATL0M0&G0%E1\r\0";
+static char *MInit_7 = "AT%L1%M0%C3\r\0";
+
+static char *MInit_speed28800 = "AT%G0%B28800\r\0";
+
+static char *MInit_dialout = "ATs7=60 x1 d\r\0";
+static char *MInit_dialin = "ATs7=60 x1 a\r\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);
+       debugl1(cs,"in   %s %02x",ModemIn[offset], val);
+       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);
+       debugl1(cs,"inp  %s %02x",ModemIn[offset], val);
+#else
+       u_int val = inb_p(cs->hw.elsa.base + 8 + offset);
+       debugl1(cs,"inP  %s %02x",ModemIn[offset], val);
+#endif
+       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
+       debugl1(cs,"out  %s %02x",ModemOut[offset], value);
+#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
+       debugl1(cs,"outp %s %02x",ModemOut[offset], value);
+#else
+       debugl1(cs,"outP %s %02x",ModemOut[offset], value);
+#endif
+#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;
+       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);
+
+       debugl1(cs,"modem quot=0x%x", quot);
+       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 */
+       serial_inp(cs, UART_RX);
+       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, BASE_BAUD);
+       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(KERN_DEBUG"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);
+#ifdef SERIAL_DEBUG_OPEN
+       printk(" done\n");
+#endif
+}
+
+inline int
+write_modem(struct BCState *bcs) {
+       int ret=0;
+       struct IsdnCardState *cs = bcs->cs;
+       int count, len, fp, buflen;
+       long flags;
+       
+       if (!bcs->tx_skb)
+               return 0;
+       if (bcs->tx_skb->len <= 0)
+               return 0;
+       save_flags(flags);
+       cli();
+       buflen = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
+       len = MIN(buflen, bcs->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, bcs->tx_skb->data, count);
+               skb_pull(bcs->tx_skb, count);
+               cs->hw.elsa.transcnt += count;
+               ret = count;
+               count = len - count;
+               fp = 0;
+       }
+       memcpy((cs->hw.elsa.transbuf + fp), bcs->tx_skb->data, count);
+       skb_pull(bcs->tx_skb, 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->tx_skb) {
+               if (bcs->tx_skb->len) {
+                       write_modem(bcs);
+                       return;
+               } else {
+                       if (bcs->st->lli.l1writewakeup &&
+                               (PACKET_NOACK != bcs->tx_skb->pkt_type))
+                                       bcs->st->lli.l1writewakeup(bcs->st,
+                                               bcs->hw.hscx.count);
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->tx_skb = NULL;
+               }
+       }
+       if ((bcs->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;
+       
+       debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp, 
+               cs->hw.elsa.transcnt);
+       
+       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;
+       
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt_single(%d)...", irq);
+#endif
+
+       do {
+               status = serial_inp(cs, UART_LSR);
+               debugl1(cs,"rs LSR %02x", status);
+#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);
+               debugl1(cs,"rs IIR %02x", iir);
+               if ((iir & 0xf) == 0) {
+                       msr = serial_inp(cs, UART_MSR);
+                       debugl1(cs,"rs MSR %02x", msr);
+               }
+       } while (!(iir & UART_IIR_NO_INT));
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+
+extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs);
+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, bcs->channel);
+       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);
+               }
+               while ((skb = skb_dequeue(&bcs->squeue))) {
+                       dev_kfree_skb(skb);
+               }
+               if (bcs->tx_skb) {
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               }
+       }
+}
+
+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;
+
+#define RCV_DELAY 20000        
+       save_flags(flags);
+       sti();
+       modem_write_cmd(cs, MInit_1, strlen(MInit_1));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY);
+       modem_write_cmd(cs, MInit_2, strlen(MInit_2));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY);
+       modem_write_cmd(cs, MInit_3, strlen(MInit_3));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY);
+       modem_write_cmd(cs, MInit_4, strlen(MInit_4));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY );
+       modem_write_cmd(cs, MInit_5, strlen(MInit_5));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY);
+       modem_write_cmd(cs, MInit_6, strlen(MInit_6));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY);
+       modem_write_cmd(cs, MInit_7, strlen(MInit_7));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY);
+       restore_flags(flags);
+}
+
+void
+modem_set_dial(struct IsdnCardState *cs, int outgoing) {
+       long flags;
+       int timeout;
+#define RCV_DELAY 20000        
+
+       save_flags(flags);
+       sti();
+       modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY);
+       if (outgoing)
+               modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout));
+       else
+               modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin));
+       timeout = 1000;
+       while(timeout-- && cs->hw.elsa.transcnt)
+               udelay(1000);
+       debugl1(cs, "msi tout=%d", timeout);
+       udelay(RCV_DELAY);
+       restore_flags(flags);
+}
+
+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->tx_skb) {
+                       skb_queue_tail(&st->l1.bcs->squeue, skb);
+                       restore_flags(flags);
+               } else {
+                       st->l1.bcs->tx_skb = skb;
+                       test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       st->l1.bcs->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);
+               mstartup(st->l1.bcs->cs);
+               modem_set_dial(st->l1.bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
+               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);
+       }
+}
+
+int
+setstack_elsa(struct PStack *st, struct BCState *bcs)
+{
+
+       bcs->channel = st->l1.bc;
+       switch (st->l1.mode) {
+               case L1_MODE_HDLC:
+               case L1_MODE_TRANS:
+                       if (open_hscxstate(st->l1.hardware, bcs))
+                               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->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 ae0662f3f561ccc573a31dbcdb606cefb35cd2c7..aa0ff4adbd14bfb655e84b3b2c3c7763805e0043 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fsm.c,v 1.7 1997/11/06 17:09:13 keil Exp $
+/* $Id: fsm.c,v 1.10 1998/11/15 23:54:39 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,6 +7,18 @@
  *              Fritz Elfert
  *
  * $Log: fsm.c,v $
+ * Revision 1.10  1998/11/15 23:54:39  keil
+ * changes from 2.0
+ *
+ * Revision 1.9  1998/03/26 07:10:02  paul
+ * The jumpmatrix table in struct Fsm was an array of "int". This is not
+ * large enough for pointers to functions on Linux/Alpha (instant crash
+ * on "insmod hisax). Now there is a typedef for the pointer to function.
+ * This also prevents warnings about "incompatible pointer types".
+ *
+ * Revision 1.8  1998/03/07 22:56:59  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 1.7  1997/11/06 17:09:13  keil
  * New 2.1 init code
  *
@@ -41,18 +53,18 @@ FsmNew(struct Fsm *fsm,
 {
        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);
+       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(%d/%d) ev(%d/%d)\n",
-                               i,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] = (int) fnlist[i].routine;
+                               fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
 }
 
 void
@@ -64,31 +76,26 @@ FsmFree(struct Fsm *fsm)
 int
 FsmEvent(struct FsmInst *fi, int event, void *arg)
 {
-       void (*r) (struct FsmInst *, int, void *);
-       char str[80];
+       FSMFNPTR r;
 
        if ((fi->state>=fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
-               printk(KERN_ERR "FsmEvent Error st(%d/%d) ev(%d/%d)\n",
-                       fi->state,fi->fsm->state_count,event,fi->fsm->event_count);
+               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 = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
+       r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
        if (r) {
-               if (fi->debug) {
-                       sprintf(str, "State %s Event %s",
+               if (fi->debug)
+                       fi->printdebug(fi, "State %s Event %s",
                                fi->fsm->strState[fi->state],
                                fi->fsm->strEvent[event]);
-                       fi->printdebug(fi, str);
-               }
                r(fi, event, arg);
                return (0);
        } else {
-               if (fi->debug) {
-                       sprintf(str, "State %s Event %s no routine",
+               if (fi->debug)
+                       fi->printdebug(fi, "State %s Event %s no routine",
                                fi->fsm->strState[fi->state],
                                fi->fsm->strEvent[event]);
-                       fi->printdebug(fi, str);
-               }
                return (!0);
        }
 }
@@ -96,25 +103,18 @@ FsmEvent(struct FsmInst *fi, int event, void *arg)
 void
 FsmChangeState(struct FsmInst *fi, int newstate)
 {
-       char str[80];
-
        fi->state = newstate;
-       if (fi->debug) {
-               sprintf(str, "ChangeState %s",
+       if (fi->debug)
+               fi->printdebug(fi, "ChangeState %s",
                        fi->fsm->strState[newstate]);
-               fi->printdebug(fi, str);
-       }
 }
 
 static void
 FsmExpireTimer(struct FsmTimer *ft)
 {
 #if FSM_TIMER_DEBUG
-       if (ft->fi->debug) {
-               char str[40];
-               sprintf(str, "FsmExpireTimer %lx", (long) ft);
-               ft->fi->printdebug(ft->fi, str);
-       }
+       if (ft->fi->debug)
+               ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
 #endif
        FsmEvent(ft->fi, ft->event, ft->arg);
 }
@@ -126,11 +126,8 @@ FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
        ft->tl.function = (void *) FsmExpireTimer;
        ft->tl.data = (long) ft;
 #if FSM_TIMER_DEBUG
-       if (ft->fi->debug) {
-               char str[40];
-               sprintf(str, "FsmInitTimer %lx", (long) ft);
-               ft->fi->printdebug(ft->fi, str);
-       }
+       if (ft->fi->debug)
+               ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
 #endif
        init_timer(&ft->tl);
 }
@@ -139,11 +136,8 @@ void
 FsmDelTimer(struct FsmTimer *ft, int where)
 {
 #if FSM_TIMER_DEBUG
-       if (ft->fi->debug) {
-               char str[40];
-               sprintf(str, "FsmDelTimer %lx %d", (long) ft, where);
-               ft->fi->printdebug(ft->fi, str);
-       }
+       if (ft->fi->debug)
+               ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
 #endif
        del_timer(&ft->tl);
 }
@@ -154,11 +148,9 @@ FsmAddTimer(struct FsmTimer *ft,
 {
 
 #if FSM_TIMER_DEBUG
-       if (ft->fi->debug) {
-               char str[40];
-               sprintf(str, "FsmAddTimer %lx %d %d", (long) ft, millisec, where);
-               ft->fi->printdebug(ft->fi, str);
-       }
+       if (ft->fi->debug)
+               ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
+                       (long) ft, millisec, where);
 #endif
 
        if (ft->tl.next || ft->tl.prev) {
@@ -180,11 +172,9 @@ FsmRestartTimer(struct FsmTimer *ft,
 {
 
 #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);
-       }
+       if (ft->fi->debug)
+               ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
+                       (long) ft, millisec, where);
 #endif
 
        if (ft->tl.next || ft->tl.prev)
@@ -195,24 +185,3 @@ FsmRestartTimer(struct FsmTimer *ft,
        ft->tl.expires = jiffies + (millisec * HZ) / 1000;
        add_timer(&ft->tl);
 }
-
-void
-jiftime(char *s, long mark)
-{
-       s += 8;
-
-       *s-- = '\0';
-       *s-- = mark % 10 + '0';
-       mark /= 10;
-       *s-- = mark % 10 + '0';
-       mark /= 10;
-       *s-- = '.';
-       *s-- = mark % 10 + '0';
-       mark /= 10;
-       *s-- = mark % 6 + '0';
-       mark /= 6;
-       *s-- = ':';
-       *s-- = mark % 10 + '0';
-       mark /= 10;
-       *s-- = mark % 10 + '0';
-}
index c42a2bb56d2426616dd0758ca2b3e92d9613f394..b649c55f43c31a5a40aceb0f0d27656258681338 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.c,v 1.3 1998/02/12 23:07:22 keil Exp $
+/* $Id: hfc_2bds0.c,v 1.8 1998/11/15 23:54:40 keil Exp $
  *
  *  specific routines for CCD's HFC 2BDS0
  *
@@ -6,6 +6,22 @@
  *
  *
  * $Log: hfc_2bds0.c,v $
+ * Revision 1.8  1998/11/15 23:54:40  keil
+ * changes from 2.0
+ *
+ * Revision 1.7  1998/09/30 22:24:45  keil
+ * Fix missing line in setstack*
+ *
+ * Revision 1.6  1998/08/13 23:36:26  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 1.5  1998/06/27 22:52:58  keil
+ * make 16.3c working with 3.0
+ *
+ * Revision 1.4  1998/05/25 12:57:52  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
  * Revision 1.3  1998/02/12 23:07:22  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -46,11 +62,8 @@ ReadReg(struct IsdnCardState *cs, int data, u_char 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);
-               }
+               if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
+                       debugl1(cs, "t3c RD %02x %02x", reg, ret);
 #endif
        } else
                ret = bytein(cs->hw.hfcD.addr | 1);
@@ -67,11 +80,8 @@ WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value)
        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);
-       }
+       if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB))
+               debugl1(cs, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value);
 #endif
 }
 
@@ -227,7 +237,6 @@ static struct sk_buff
        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");
@@ -283,11 +292,9 @@ static struct sk_buff
                        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",
+                       if (cs->debug & L1_DEB_HSCX)
+                               debugl1(cs, "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);
@@ -315,14 +322,11 @@ hfc_fill_fifo(struct BCState *bcs)
        int idx, fcnt;
        int count;
        u_char cip;
-       char tmp[64];
-       
 
-       if (!bcs->hw.hfc.tx_skb)
+       if (!bcs->tx_skb)
                return;
-       if (bcs->hw.hfc.tx_skb->len <= 0)
+       if (bcs->tx_skb->len <= 0)
                return;
-
        save_flags(flags);
        cli();
        SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel)); 
@@ -335,12 +339,10 @@ hfc_fill_fifo(struct BCState *bcs)
        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)",
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "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;
@@ -351,13 +353,11 @@ hfc_fill_fifo(struct BCState *bcs)
                return;
        }
        count = GetFreeFifoBytes_B(bcs);
-       if (cs->debug & L1_DEB_HSCX) {
-               sprintf(tmp, "hfc_fill_fifo %d count(%d/%d),%lx",
-                       bcs->channel, bcs->hw.hfc.tx_skb->len,
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "hfc_fill_fifo %d count(%ld/%d),%lx",
+                       bcs->channel, bcs->tx_skb->len,
                        count, current->state);
-               debugl1(cs, tmp);
-       }
-       if (count < bcs->hw.hfc.tx_skb->len) {
+       if (count < bcs->tx_skb->len) {
                if (cs->debug & L1_DEB_HSCX)
                        debugl1(cs, "hfc_fill_fifo no fifo mem");
                restore_flags(flags);
@@ -368,26 +368,26 @@ hfc_fill_fifo(struct BCState *bcs)
        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) {
+       WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
+       while (idx < bcs->tx_skb->len) {
                cli();
                if (!WaitNoBusy(cs))
                        break;
-               WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->hw.hfc.tx_skb->data[idx]);
+               WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]);
                sti();
                idx++;
        }
-       if (idx != bcs->hw.hfc.tx_skb->len) {
+       if (idx != bcs->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;
+               bcs->tx_cnt -= bcs->tx_skb->len;
                if (bcs->st->lli.l1writewakeup &&
-                       (PACKET_NOACK != bcs->hw.hfc.tx_skb->pkt_type))
-                       bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hfc.tx_skb->len);
-               dev_kfree_skb(bcs->hw.hfc.tx_skb);
-               bcs->hw.hfc.tx_skb = NULL;
+                       (PACKET_NOACK != bcs->tx_skb->pkt_type))
+                       bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
+               dev_kfree_skb(bcs->tx_skb);
+               bcs->tx_skb = NULL;
        }
        WaitForBusy(cs);
        cli();
@@ -404,15 +404,12 @@ 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);
-       }
+       } else
+               debugl1(cs,"send_data %d blocked", bcs->channel);
 }
 
 void
@@ -424,15 +421,13 @@ main_rec_2bds0(struct BCState *bcs)
        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);
+               debugl1(cs,"rec_data %d blocked", bcs->channel);
                restore_flags(flags);
                return;
        }
@@ -445,11 +440,9 @@ main_rec_2bds0(struct BCState *bcs)
        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)",
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "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));
@@ -458,11 +451,9 @@ main_rec_2bds0(struct BCState *bcs)
                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)",
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "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);
@@ -490,12 +481,9 @@ 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",
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "HFCD bchannel mode %d bchan %d/%d",
                        mode, bc, bcs->channel);
-               debugl1(cs, tmp);
-       }
        bcs->mode = mode;
        bcs->channel = bc;
        switch (mode) {
@@ -543,121 +531,98 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
        long flags;
 
        switch (pr) {
-               case (PH_DATA_REQ):
+               case (PH_DATA | REQUEST):
                        save_flags(flags);
                        cli();
-                       if (st->l1.bcs->hw.hfc.tx_skb) {
+                       if (st->l1.bcs->tx_skb) {
                                skb_queue_tail(&st->l1.bcs->squeue, skb);
                                restore_flags(flags);
                        } else {
-                               st->l1.bcs->hw.hfc.tx_skb = skb;
+                               st->l1.bcs->tx_skb = skb;
 /*                             test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 */                             st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
                                restore_flags(flags);
                        }
                        break;
-               case (PH_PULL_IND):
-                       if (st->l1.bcs->hw.hfc.tx_skb) {
+               case (PH_PULL | INDICATION):
+                       if (st->l1.bcs->tx_skb) {
                                printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
                                break;
                        }
                        save_flags(flags);
                        cli();
 /*                     test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-*/                     st->l1.bcs->hw.hfc.tx_skb = skb;
+*/                     st->l1.bcs->tx_skb = skb;
                        st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
                        restore_flags(flags);
                        break;
-               case (PH_PULL_REQ):
-                       if (!st->l1.bcs->hw.hfc.tx_skb) {
+               case (PH_PULL | REQUEST):
+                       if (!st->l1.bcs->tx_skb) {
                                test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                               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);
+                       l1_msg_b(st, pr, arg);
+                       break;
+               case (PH_DEACTIVATE | REQUEST):
+                       l1_msg_b(st, pr, arg);
+                       break;
+               case (PH_DEACTIVATE | CONFIRM):
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       mode_2bs0(st->l1.bcs, 0, st->l1.bc);
+                       st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+                       break;
        }
 }
 
 void
 close_2bs0(struct BCState *bcs)
 {
-       struct sk_buff *skb;
-
-       mode_2bs0(bcs, 0, 0);
+       mode_2bs0(bcs, 0, bcs->channel);
        if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
-               while ((skb = skb_dequeue(&bcs->rqueue))) {
-                       dev_kfree_skb(skb);
-               }
-               while ((skb = skb_dequeue(&bcs->squeue))) {
-                       dev_kfree_skb(skb);
-               }
-               if (bcs->hw.hfc.tx_skb) {
-                       dev_kfree_skb(bcs->hw.hfc.tx_skb);
-                       bcs->hw.hfc.tx_skb = NULL;
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->tx_skb) {
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->tx_skb = NULL;
                        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
                }
        }
 }
 
 static int
-open_hfcstate(struct IsdnCardState *cs,
-             int bc)
+open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
 {
-       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;
+       bcs->tx_skb = NULL;
        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
        bcs->event = 0;
        bcs->tx_cnt = 0;
        return (0);
 }
 
-static void
-hfc_manl1(struct PStack *st, int pr,
-         void *arg)
-{
-       switch (pr) {
-               case (PH_ACTIVATE_REQ):
-                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-                       mode_2bs0(st->l1.bcs, st->l1.mode, st->l1.bc);
-                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
-                       break;
-               case (PH_DEACTIVATE_REQ):
-                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
-                               mode_2bs0(st->l1.bcs, 0, 0);
-                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-                       break;
-       }
-}
-
 int
 setstack_2b(struct PStack *st, struct BCState *bcs)
 {
-       if (open_hfcstate(st->l1.hardware, bcs->channel))
+       bcs->channel = st->l1.bc;
+       if (open_hfcstate(st->l1.hardware, bcs))
                return (-1);
        st->l1.bcs = bcs;
        st->l2.l2l1 = hfc_l2l1;
-       st->ma.manl1 = hfc_manl1;
        setstack_manager(st);
        bcs->st = st;
+       setstack_l1_B(st);
        return (0);
 }
 
-static void
-manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
-       struct PStack *st;
-
-       st = cs->stlist;
-       while (st) {
-               st->ma.manl1(st, msg, arg);
-               st = st->next;
-       }
-}
-
 static void
 hfcd_bh(struct IsdnCardState *cs)
 {
@@ -671,7 +636,7 @@ hfcd_bh(struct IsdnCardState *cs)
                        debugl1(cs, "D-Channel Busy cleared");
                stptr = cs->stlist;
                while (stptr != NULL) {
-                       stptr->l1.l1l2(stptr, PH_PAUSE_CNF, NULL);
+                       stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
                        stptr = stptr->next;
                }
        }
@@ -679,19 +644,19 @@ hfcd_bh(struct IsdnCardState *cs)
        if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
                switch (cs->ph_state) {
                        case (0):
-                               manl1_msg(cs, PH_RESET_IND, NULL);
+                               l1_msg(cs, HW_RESET | INDICATION, NULL);
                                break;
                        case (3):
-                               manl1_msg(cs, PH_DEACT_IND, NULL);
+                               l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
                                break;
                        case (8):
-                               manl1_msg(cs, PH_RSYNC_IND, NULL);
+                               l1_msg(cs, HW_RSYNC | INDICATION, NULL);
                                break;
                        case (6):
-                               manl1_msg(cs, PH_INFO2_IND, NULL);
+                               l1_msg(cs, HW_INFO2 | INDICATION, NULL);
                                break;
                        case (7):
-                               manl1_msg(cs, PH_I4_P8_IND, NULL);
+                               l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
                                break;
                        default:
                                break;
@@ -722,7 +687,6 @@ int receive_dmsg(struct IsdnCardState *cs)
        int chksum;
        int count=5;
        u_char *ptr;
-       char tmp[64];
 
        save_flags(flags);
        cli();
@@ -745,11 +709,9 @@ int receive_dmsg(struct IsdnCardState *cs)
                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)",
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "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;
@@ -796,11 +758,9 @@ int receive_dmsg(struct IsdnCardState *cs)
                                WaitNoBusy(cs);
                                stat = ReadReg(cs, HFCD_DATA, cip);
                                sti();
-                               if (cs->debug & L1_DEB_ISAC) {
-                                       sprintf(tmp, "empty_dfifo chksum %x stat %x",
+                               if (cs->debug & L1_DEB_ISAC)
+                                       debugl1(cs, "empty_dfifo chksum %x stat %x",
                                                chksum, stat);
-                                       debugl1(cs, tmp);
-                               }
                                if (stat) {
                                        debugl1(cs, "FIFO CRC error");
                                        dev_kfree_skb(skb);
@@ -837,7 +797,6 @@ hfc_fill_dfifo(struct IsdnCardState *cs)
        int idx, fcnt;
        int count;
        u_char cip;
-       char tmp[64];
 
        if (!cs->tx_skb)
                return;
@@ -855,12 +814,10 @@ hfc_fill_dfifo(struct IsdnCardState *cs)
        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)",
+       if (cs->debug & L1_DEB_ISAC)
+               debugl1(cs, "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;
@@ -871,11 +828,9 @@ hfc_fill_dfifo(struct IsdnCardState *cs)
                return;
        }
        count = GetFreeFifoBytes_D(cs);
-       if (cs->debug & L1_DEB_ISAC) {
-               sprintf(tmp, "hfc_fill_Dfifo count(%d/%d)",
+       if (cs->debug & L1_DEB_ISAC)
+               debugl1(cs, "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");
@@ -929,24 +884,19 @@ 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,
+       if (cs->debug & L1_DEB_ISAC)
+               debugl1(cs, "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,
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ph_state chg %d->%d", cs->ph_state,
                                exval);
-                       debugl1(cs, tmp);
-               }
                cs->ph_state = exval;
                sched_event_D(cs, D_L1STATECHANGE);
                val &= ~0x40;
@@ -983,23 +933,19 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
                                if (cs->debug)
                                        debugl1(cs, "hfcd spurious 0x01 IRQ");
                        } else {
-                               if (bcs->hw.hfc.tx_skb) {
+                               if (bcs->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
+                                               debugl1(cs,"fill_data %d blocked", bcs->channel);
                                } else {
-                                       if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) {
+                                       if ((bcs->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
+                                                       debugl1(cs,"fill_data %d blocked", bcs->channel);
                                        } else {
                                                hfc_sched_event(bcs, B_XMTBUFREADY);
                                        }
@@ -1011,23 +957,19 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
                                if (cs->debug)
                                        debugl1(cs, "hfcd spurious 0x02 IRQ");
                        } else {
-                               if (bcs->hw.hfc.tx_skb) {
+                               if (bcs->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
+                                               debugl1(cs,"fill_data %d blocked", bcs->channel);
                                } else {
-                                       if ((bcs->hw.hfc.tx_skb = skb_dequeue(&bcs->squeue))) {
+                                       if ((bcs->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
+                                                       debugl1(cs,"fill_data %d blocked", bcs->channel);
                                        } else {
                                                hfc_sched_event(bcs, B_XMTBUFREADY);
                                        }
@@ -1042,7 +984,7 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
                                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)
                                if (cs->tx_skb->len) {
                                        if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
                                                hfc_fill_dfifo(cs);
@@ -1056,7 +998,6 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
                                        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)) {
@@ -1072,10 +1013,8 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
                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);
-                       }
+                       if (cs->debug & L1_DEB_ISAC)
+                               debugl1(cs, "HFCD irq %x loop %d", val, 15-count);
                } else
                        val = 0;
                restore_flags(flags);
@@ -1083,13 +1022,17 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
 }
 
 static void
-HFCD_l2l1(struct PStack *st, int pr, void *arg)
+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_REQ):
+               case (PH_DATA | REQUEST):
+                       if (cs->debug & DEB_DLOG_HEX)
+                               LogFrame(cs, skb->data, skb->len);
+                       if (cs->debug & DEB_DLOG_VERBOSE)
+                               dlogframe(cs, skb, 0);
                        if (cs->tx_skb) {
                                skb_queue_tail(&cs->sq, skb);
 #ifdef L2FRAME_DEBUG           /* psa */
@@ -1097,12 +1040,6 @@ HFCD_l2l1(struct PStack *st, int pr, void *arg)
                                        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 */
@@ -1117,19 +1054,17 @@ HFCD_l2l1(struct PStack *st, int pr, void *arg)
 
                        }
                        break;
-               case (PH_PULL_IND):
+               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 */
+                       if (cs->debug & DEB_DLOG_HEX)
                                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);
-                       }
+                       if (cs->debug & DEB_DLOG_VERBOSE)
+                               dlogframe(cs, skb, 0);
                        cs->tx_skb = skb;
                        cs->tx_cnt = 0;
 #ifdef L2FRAME_DEBUG           /* psa */
@@ -1142,47 +1077,39 @@ HFCD_l2l1(struct PStack *st, int pr, void *arg)
                        } else
                                debugl1(cs, "hfc_fill_dfifo blocked");
                        break;
-               case (PH_PULL_REQ):
+               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_CNF, NULL);
+                               st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
                        } else
                                test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
                        break;
-       }
-}
-
-void
-hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
-{
-       char tmp[32];
-       switch(msg) {
-               case PH_RESET_REQ:
+               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);
-                       manl1_msg(cs, PH_POWERUP_CNF, NULL);
+                       l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
                        break;
-               case PH_ENABLE_REQ:
+               case (HW_ENABLE | REQUEST):
                        cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION);
                        break;
-               case PH_DEACT_ACK:
+               case (HW_DEACTIVATE | REQUEST):
                        cs->hw.hfcD.mst_m &= ~HFCD_MASTER;
                        cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
                        break;
-               case PH_INFO3_REQ:
+               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 PH_TESTLOOP_REQ:
+               case (HW_TESTLOOP | REQUEST):
                        u_char val = 0;
                        if (1 & (int) arg)
                                val |= 0x0c;
@@ -1208,10 +1135,8 @@ hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
                        break;
 #endif
                default:
-                       if (cs->debug & L1_DEB_WARN) {
-                               sprintf(tmp, "hfcd_l1cmd unknown %4x", msg);
-                               debugl1(cs, tmp);
-                       }
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "hfcd_l1hw unknown pr %4x", pr);
                        break;
        }
 }
@@ -1219,7 +1144,7 @@ hfcd_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
 void
 setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
 {
-       st->l2.l2l1 = HFCD_l2l1;
+       st->l1.l1hw = HFCD_l1hw;
 }
 
 static void
@@ -1234,7 +1159,7 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
                stptr = cs->stlist;
                
                while (stptr != NULL) {
-                       stptr->l1.l1l2(stptr, PH_PAUSE_IND, NULL);
+                       stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
                        stptr = stptr->next;
                }
        }
@@ -1260,7 +1185,6 @@ __initfunc(void
 init2bds0(struct IsdnCardState *cs))
 {
        cs->setstack_d = setstack_hfcd;
-       cs->l1cmd = hfcd_l1cmd;
        cs->dbusytimer.function = (void *) hfc_dbusy_timer;
        cs->dbusytimer.data = (long) cs;
        init_timer(&cs->dbusytimer);
index 2d9ce5bd52ea131b43b7605ecaa4c2c2b68efc0d..26d47b936b41d73565bf72411278fd04710d58c6 100644 (file)
@@ -1,11 +1,24 @@
-/* $Id: hfc_2bs0.c,v 1.4 1998/02/12 23:07:29 keil Exp $
+/* $Id: hfc_2bs0.c,v 1.8 1998/11/15 23:54:43 keil Exp $
 
  *  specific routines for CCD's HFC 2BS0
  *
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *
  *
  * $Log: hfc_2bs0.c,v $
+ * Revision 1.8  1998/11/15 23:54:43  keil
+ * changes from 2.0
+ *
+ * Revision 1.7  1998/09/30 22:24:46  keil
+ * Fix missing line in setstack*
+ *
+ * Revision 1.6  1998/08/13 23:36:28  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 1.5  1998/05/25 12:57:54  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
  * Revision 1.4  1998/02/12 23:07:29  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -109,7 +122,6 @@ hfc_clear_fifo(struct BCState *bcs)
        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");
@@ -129,21 +141,17 @@ hfc_clear_fifo(struct BCState *bcs)
        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)",
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "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)",
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "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)) {
@@ -180,7 +188,6 @@ hfc_empty_fifo(struct BCState *bcs, int count)
        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");
@@ -235,11 +242,9 @@ hfc_empty_fifo(struct BCState *bcs, int count)
                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",
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "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);
@@ -261,11 +266,10 @@ hfc_fill_fifo(struct BCState *bcs)
        int idx, fcnt;
        int count;
        u_char cip;
-       char tmp[64];
 
-       if (!bcs->hw.hfc.tx_skb)
+       if (!bcs->tx_skb)
                return;
-       if (bcs->hw.hfc.tx_skb->len <= 0)
+       if (bcs->tx_skb->len <= 0)
                return;
 
        save_flags(flags);
@@ -281,12 +285,10 @@ hfc_fill_fifo(struct BCState *bcs)
        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)",
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "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;
@@ -297,13 +299,11 @@ hfc_fill_fifo(struct BCState *bcs)
                return;
        }
        count = GetFreeFifoBytes(bcs);
-       if (cs->debug & L1_DEB_HSCX) {
-               sprintf(tmp, "hfc_fill_fifo %d count(%d/%d)",
-                       bcs->channel, bcs->hw.hfc.tx_skb->len,
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)",
+                       bcs->channel, bcs->tx_skb->len,
                        count);
-               debugl1(cs, tmp);
-       }
-       if (count < bcs->hw.hfc.tx_skb->len) {
+       if (count < bcs->tx_skb->len) {
                if (cs->debug & L1_DEB_HSCX)
                        debugl1(cs, "hfc_fill_fifo no fifo mem");
                restore_flags(flags);
@@ -311,18 +311,18 @@ hfc_fill_fifo(struct BCState *bcs)
        }
        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) {
+       while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs))
+               cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
+       if (idx != bcs->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;
+               count =  bcs->tx_skb->len;
                bcs->tx_cnt -= count;
-               if (PACKET_NOACK == bcs->hw.hfc.tx_skb->pkt_type)
+               if (PACKET_NOACK == bcs->tx_skb->pkt_type)
                        count = -1;
-               dev_kfree_skb(bcs->hw.hfc.tx_skb);
-               bcs->hw.hfc.tx_skb = NULL;
+               dev_kfree_skb(bcs->tx_skb);
+               bcs->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));
@@ -343,7 +343,6 @@ main_irq_hfc(struct BCState *bcs)
        u_char f1, f2, cip;
        int receive, transmit, count = 5;
        struct sk_buff *skb;
-       char tmp[64];
 
        save_flags(flags);
       Begin:
@@ -360,11 +359,9 @@ main_irq_hfc(struct BCState *bcs)
        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)",
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "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));
@@ -372,11 +369,9 @@ main_irq_hfc(struct BCState *bcs)
                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)",
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "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);
@@ -388,14 +383,14 @@ main_irq_hfc(struct BCState *bcs)
        restore_flags(flags);
        udelay(1);
        cli();
-       if (bcs->hw.hfc.tx_skb) {
+       if (bcs->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))) {
+               if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
                        transmit = 1;
                        test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
                        hfc_fill_fifo(bcs);
@@ -417,13 +412,11 @@ 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",
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "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):
@@ -468,57 +461,66 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
        long flags;
 
        switch (pr) {
-               case (PH_DATA_REQ):
+               case (PH_DATA | REQUEST):
                        save_flags(flags);
                        cli();
-                       if (st->l1.bcs->hw.hfc.tx_skb) {
+                       if (st->l1.bcs->tx_skb) {
                                skb_queue_tail(&st->l1.bcs->squeue, skb);
                                restore_flags(flags);
                        } else {
-                               st->l1.bcs->hw.hfc.tx_skb = skb;
+                               st->l1.bcs->tx_skb = skb;
                                test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
                                st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
                                restore_flags(flags);
                        }
                        break;
-               case (PH_PULL_IND):
-                       if (st->l1.bcs->hw.hfc.tx_skb) {
+               case (PH_PULL | INDICATION):
+                       if (st->l1.bcs->tx_skb) {
                                printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
                                break;
                        }
                        save_flags(flags);
                        cli();
                        test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-                       st->l1.bcs->hw.hfc.tx_skb = skb;
+                       st->l1.bcs->tx_skb = skb;
                        st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
                        restore_flags(flags);
                        break;
-               case (PH_PULL_REQ):
-                       if (!st->l1.bcs->hw.hfc.tx_skb) {
+               case (PH_PULL | REQUEST):
+                       if (!st->l1.bcs->tx_skb) {
                                test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                               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);
+                       l1_msg_b(st, pr, arg);
+                       break;
+               case (PH_DEACTIVATE | REQUEST):
+                       l1_msg_b(st, pr, arg);
+                       break;
+               case (PH_DEACTIVATE | CONFIRM):
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       mode_hfc(st->l1.bcs, 0, st->l1.bc);
+                       st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+                       break;
        }
 }
 
+
 void
 close_hfcstate(struct BCState *bcs)
 {
-       struct sk_buff *skb;
-
-       mode_hfc(bcs, 0, 0);
+       mode_hfc(bcs, 0, bcs->channel);
        if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
-               while ((skb = skb_dequeue(&bcs->rqueue))) {
-                       dev_kfree_skb(skb);
-               }
-               while ((skb = skb_dequeue(&bcs->squeue))) {
-                       dev_kfree_skb(skb);
-               }
-               if (bcs->hw.hfc.tx_skb) {
-                       dev_kfree_skb(bcs->hw.hfc.tx_skb);
-                       bcs->hw.hfc.tx_skb = NULL;
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->tx_skb) {
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->tx_skb = NULL;
                        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
                }
        }
@@ -526,50 +528,30 @@ close_hfcstate(struct BCState *bcs)
 }
 
 static int
-open_hfcstate(struct IsdnCardState *cs,
-             int bc)
+open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
 {
-       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;
+       bcs->tx_skb = NULL;
        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
        bcs->event = 0;
        bcs->tx_cnt = 0;
        return (0);
 }
 
-static void
-hfc_manl1(struct PStack *st, int pr,
-         void *arg)
-{
-       switch (pr) {
-               case (PH_ACTIVATE_REQ):
-                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-                       mode_hfc(st->l1.bcs, st->l1.mode, st->l1.bc);
-                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
-                       break;
-               case (PH_DEACTIVATE_REQ):
-                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
-                               mode_hfc(st->l1.bcs, 0, 0);
-                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-                       break;
-       }
-}
-
 int
 setstack_hfc(struct PStack *st, struct BCState *bcs)
 {
-       if (open_hfcstate(st->l1.hardware, bcs->channel))
+       bcs->channel = st->l1.bc;
+       if (open_hfcstate(st->l1.hardware, bcs))
                return (-1);
        st->l1.bcs = bcs;
        st->l2.l2l1 = hfc_l2l1;
-       st->ma.manl1 = hfc_manl1;
        setstack_manager(st);
        bcs->st = st;
+       setstack_l1_B(st);
        return (0);
 }
 
index 4795ada084091aadf980bdbe6fee16bfce4bca4e..36cd82ee12d3e4105ad4e24e83a6f27805a80724 100644 (file)
@@ -1,8 +1,48 @@
-/* $Id: hisax.h,v 2.14 1998/02/11 17:28:04 keil Exp $
+/* $Id: hisax.h,v 2.26 1998/11/15 23:54:45 keil Exp $
 
  *   Basic declarations, defines and prototypes
  *
  * $Log: hisax.h,v $
+ * Revision 2.26  1998/11/15 23:54:45  keil
+ * changes from 2.0
+ *
+ * Revision 2.25  1998/09/30 22:28:42  keil
+ * More work for ISAR support
+ *
+ * Revision 2.24  1998/08/20 13:50:39  keil
+ * More support for hybrid modem (not working yet)
+ *
+ * Revision 2.23  1998/08/13 23:36:31  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.22  1998/07/15 15:01:28  calle
+ * Support for AVM passive PCMCIA cards:
+ *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
+ *
+ * Revision 2.21  1998/05/25 14:10:05  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.20  1998/05/25 12:57:57  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.19  1998/04/15 16:39:15  keil
+ * Add S0Box and Teles PCI support
+ *
+ * Revision 2.18  1998/03/26 07:10:04  paul
+ * The jumpmatrix table in struct Fsm was an array of "int". This is not
+ * large enough for pointers to functions on Linux/Alpha (instant crash
+ * on "insmod hisax). Now there is a typedef for the pointer to function.
+ * This also prevents warnings about "incompatible pointer types".
+ *
+ * Revision 2.17  1998/03/19 13:18:43  keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
+ * Revision 2.16  1998/03/09 23:19:25  keil
+ * Changes for PCMCIA
+ *
  * Revision 2.14  1998/02/11 17:28:04  keil
  * Niccy PnP/PCI support
  *
 #include <linux/isdnif.h>
 #include <linux/tty.h>
 #include <linux/init.h>
+#include <linux/serialP.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 CARD_LOAD_FIRM 0x00F6
+
+#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_REQ        0x0010
-#define PH_ACTIVATE_CNF        0x0011
-#define PH_ACTIVATE_IND        0x0012
-#define PH_DEACTIVATE_REQ 0x0020
-#define PH_DEACTIVATE_CNF 0x0021
-#define PH_DEACTIVATE_IND 0x0022
-#define PH_DEACT_REQ   0x0024
-#define PH_DEACT_CNF   0x0025
-#define PH_DEACT_IND   0x0026
-#define PH_DEACT_ACK   0x0027
-#define PH_TESTLOOP_REQ        0x0030
-#define PH_PAUSE_CNF   0x0035
-#define PH_PAUSE_IND   0x0036
-#define PH_PULL_REQ    0x0038
-#define PH_PULL_CNF    0x0039
-#define        PH_PULL_IND     0x003A
-#define PH_DATA_REQ    0x0040
-#define PH_DATA_IND    0x0042
-
-#define PH_INFO3_REQ   0x0008
-#define PH_INFO2_IND   0x000A
-#define PH_ENABLE_REQ  0x0004
-#define PH_RSYNC_IND   0x0006
-#define PH_RESET_REQ   0x0000
-#define PH_RESET_IND   0x0002
-#define PH_POWERUP_CNF 0x0003
-#define PH_ACTIV_REQ   0x000C
-#define PH_I4_P8_IND   0x000D
-#define PH_I4_P10_IND  0x000F
-
-#define MDL_ASSIGN_REQ 0x0050
-#define MDL_ASSIGN_IND 0x0052
-#define MDL_REMOVE_REQ 0x0054
-#define MDL_ERROR_REQ  0x0058
-#define MDL_ERROR_IND  0x005A
-#define CARD_AUX_IND   0x005E
-
-#define DL_UNIT_DATA   6
-#define CC_ESTABLISH   7
-#define DL_ESTABLISH   8
-#define DL_DATA                9
-
-#define CC_CONNECT     15
-#define DL_RELEASE     20
-#define DL_FLUSH       21
-
-#define CC_REJECT      23
-
-#define CC_SETUP_REQ   24
-#define CC_SETUP_CNF   25
-#define CC_SETUP_IND   26
-#define CC_SETUP_RSP   27
-#define CC_SETUP_COMPLETE_IND  28
-
-#define CC_DISCONNECT_REQ      29
-#define CC_DISCONNECT_IND      30
-
-#define CC_RELEASE_CNF 31
-#define CC_RELEASE_IND 32
-#define CC_RELEASE_REQ 33
-
-#define CC_REJECT_REQ  34
-
-#define CC_PROCEEDING_IND      35
-
-#define CC_DLRL                36
-#define CC_DLEST       37
-
-#define CC_ALERTING_REQ        38
-#define CC_ALERTING_IND        39
-
-#define DL_STOP                40
-#define DL_START       41
-
-#define MDL_INFO_SETUP 42
-#define MDL_INFO_CONN  43
-#define MDL_INFO_REL   44
-#define MDL_NOTEIPROC  46
-
-#define LC_ESTABLISH   47
-#define LC_RELEASE     48
-
-#define CC_INFO_CHARGE 52
-
-#define CC_MORE_INFO   53
-#define CC_IGNORE      54
-#define CC_RESTART     55
-
-
-#define CC_T303                60
-#define CC_T304                61
-#define CC_T305                62
-#define CC_T308_1      64
-#define CC_T308_2      65
-#define CC_T310                66
-#define CC_T313                67
-#define CC_T318                68
-#define CC_T319                69
-
-#define CC_NOSETUP_RSP_ERR     70
-#define CC_SETUP_ERR           71
-#define CC_CONNECT_ERR         72
-#define CC_RELEASE_ERR         73
-
-#define CARD_RESET     0x1001
-#define CARD_SETIRQ    0x1002
-#define CARD_INIT      0x1003
-#define CARD_RELEASE   0x1004
-#define CARD_TEST      0x1005
 
 #ifdef __KERNEL__
 
 #define MAX_DFRAME_LEN 260
+#define MAX_DFRAME_LEN_L1      300
 #define HSCX_BUFMAX    4096
 #define MAX_DATA_SIZE  (HSCX_BUFMAX - 4)
 #define MAX_DATA_MEM   (HSCX_BUFMAX + 64)
 #define MAX_HEADER_LEN 4
 #define MAX_WINDOW     8
 #define MAX_MON_FRAME  32
+#define MAX_DLOG_SPACE 2048
+#define MAX_BLOG_SPACE 256
 
 /* #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;
 };
@@ -213,7 +229,7 @@ struct FsmInst {
        int debug;
        void *userdata;
        int userint;
-       void (*printdebug) (struct FsmInst *, char *);
+       void (*printdebug) (struct FsmInst *, char *, ...);
 };
 
 struct FsmNode {
@@ -249,9 +265,10 @@ struct Layer1 {
        struct FsmInst l1m;
        struct FsmTimer timer;
        void (*l1l2) (struct PStack *, int, void *);
-       void (*l1man) (struct PStack *, int, void *);
+       void (*l1hw) (struct PStack *, int, void *);
        void (*l1tei) (struct PStack *, int, void *);
        int mode, bc;
+       int delay;
 };
 
 #define GROUP_TEI      127
@@ -266,17 +283,20 @@ struct Layer1 {
 #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_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 tei;
-       int tei_wanted;
        int sap;
        int maxlen;
        unsigned int flag;
@@ -288,23 +308,25 @@ struct Layer2 {
        struct sk_buff_head i_queue;
        struct sk_buff_head ui_queue;
        void (*l2l1) (struct PStack *, int, void *);
-       void (*l2man) (struct PStack *, int, void *);
        void (*l2l3) (struct PStack *, int, void *);
        void (*l2tei) (struct PStack *, int, void *);
        struct FsmInst l2m;
        struct FsmTimer t200, t203;
        int T200, N200, T203;
        int debug;
-       char debug_id[32];
+       char debug_id[16];
 };
 
 struct Layer3 {
-       void (*l3l4) (struct l3_process *, int, void *);
+       void (*l3l4) (struct PStack *, int, void *);
        void (*l3l2) (struct PStack *, int, void *);
+       struct FsmInst l3m;
+       struct sk_buff_head squeue;
        struct l3_process *proc;
        struct l3_process *global;
        int N303;
        int debug;
+       char debug_id[8];
 };
 
 struct LLInterface {
@@ -321,8 +343,6 @@ struct Management {
        struct FsmTimer t202;
        int T202, N202, debug;
        void (*layer) (struct PStack *, int, void *);
-       void (*manl1) (struct PStack *, int, void *);
-       void (*manl2) (struct PStack *, int, void *);
 };
 
 
@@ -343,7 +363,7 @@ struct PStack {
        struct Layer1 l1;
        struct Layer2 l2;
        struct Layer3 l3;
-       struct LLInterface lli; 
+       struct LLInterface lli;
        struct Management ma;
        int protocol;           /* EDSS1 or 1TR6 */
 };
@@ -361,21 +381,55 @@ struct l3_process {
 };
 
 struct hscx_hw {
+       int hscx;
+       int rcvidx;
+       int count;              /* Current skb sent count */
+       u_char *rcvbuf;         /* B-Channel receive Buffer */
+};
+
+struct isar_reg {
+       unsigned int Flags;
+       volatile u_char bstat;
+       volatile u_char iis;
+       volatile u_char cmsb;
+       volatile u_char clsb;
+       volatile u_char par[8];
+};
+
+struct isar_hw {
+       int dpath;
+       int rcvidx;
+       int txcnt;
+       int mml;
+       u_char *rcvbuf;         /* B-Channel receive Buffer */
+       struct isar_reg *reg;
+};
+
+struct hdlc_stat_reg {
+       u_char cmd  __attribute__((packed));
+       u_char xml  __attribute__((packed));
+       u_char mode __attribute__((packed));
+       u_char fill __attribute__((packed));
+};
+
+struct hdlc_hw {
+       union {
+               u_int ctrl;
+               struct hdlc_stat_reg sr;
+       } ctrl;
+       u_int stat;
        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;
@@ -397,8 +451,7 @@ struct tiger_hw {
        u_char s_state;
 };
 
-struct foreign_hw {
-       int doHDLCprocessing;
+struct amd7930_hw {
        u_char *tx_buff;
        u_char *rv_buff;
        int rv_buff_in;
@@ -407,9 +460,9 @@ struct foreign_hw {
        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
@@ -420,6 +473,7 @@ struct foreign_hw {
 #define L1_MODE_NULL   0
 #define L1_MODE_TRANS  1
 #define L1_MODE_HDLC   2
+#define L1_MODE_MODEM  7
 
 struct BCState {
        int channel;
@@ -427,34 +481,26 @@ struct BCState {
        int Flag;
        struct IsdnCardState *cs;
        int tx_cnt;             /* B-Channel transmit counter */
+       struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
        struct sk_buff_head rqueue;     /* B-Channel receive Queue */
        struct sk_buff_head squeue;     /* B-Channel send Queue */
        struct PStack *st;
+       u_char *blog;
+       struct timer_list transbusy;
        struct tq_struct tqueue;
        int event;
        int  (*BC_SetStack) (struct PStack *, struct BCState *);
        void (*BC_Close) (struct BCState *);
        union {
                struct hscx_hw hscx;
+               struct hdlc_hw hdlc;
+               struct isar_hw isar;
                struct hfcB_hw hfc;
                struct tiger_hw tiger;
-               struct foreign_hw foreign;
+               struct amd7930_hw  amd7930;
        } hw;
 };
 
-struct LcFsm {
-       int type;
-       int delay;
-       struct FsmInst lcfi;
-       struct Channel *ch;
-       void (*lccall) (struct LcFsm *, int, void *);
-       struct PStack *st;
-       int l2_establish;
-       int l2_start;
-       struct FsmTimer act_timer;
-       char debug_id[32];
-};
-
 struct Channel {
        struct PStack *b_st, *d_st;
        struct IsdnCardState *cs;
@@ -462,11 +508,10 @@ struct Channel {
        int chan;
        int incoming;
        struct FsmInst fi;
-       struct LcFsm *lc_d;
-       struct LcFsm *lc_b;
        struct FsmTimer drel_timer, dial_timer;
        int debug;
        int l2_protocol, l2_active_protocol;
+       int l3_protocol;
        int data_open;
        struct l3_process *proc;
        setup_parm setup;       /* from isdnif.h numbers and Serviceindicator */
@@ -487,21 +532,33 @@ struct elsa_hw {
        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;
-       unsigned int isac;
-       unsigned int hscx[2];
-       unsigned int isacfifo;
-       unsigned int hscxfifo[2];
-};     
+       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;
@@ -510,7 +567,7 @@ struct avm_hw {
        unsigned int isacfifo;
        unsigned int hscxfifo[2];
        unsigned int counter;
-};     
+};
 
 struct ix1_hw {
        unsigned int cfg_reg;
@@ -530,7 +587,7 @@ struct diva_hw {
        unsigned int status;
        struct timer_list tl;
        u_char ctrl_reg;
-};     
+};
 
 struct asus_hw {
        unsigned int cfg_reg;
@@ -559,6 +616,9 @@ struct sedl_hw {
        unsigned int hscx;
        unsigned int reset_on;
        unsigned int reset_off;
+       struct isar_reg isar;
+       unsigned int chip;
+       unsigned int bus;
 };
 
 struct spt_hw {
@@ -566,7 +626,7 @@ struct spt_hw {
        unsigned int isac;
        unsigned int hscx[2];
        unsigned char res_irq;
-};     
+};
 
 struct mic_hw {
        unsigned int cfg_reg;
@@ -610,6 +670,7 @@ struct hfcD_hw {
 
 #define HW_IOM1                0
 #define HW_IPAC                1
+#define HW_ISAR                2
 #define FLG_TWO_DCHAN  4
 #define FLG_L1_DBUSY   5
 #define FLG_DBUSY_TIMER 6
@@ -624,7 +685,7 @@ struct IsdnCardState {
        unsigned char subtyp;
        int protocol;
        unsigned int irq;
-       int HW_Flags; 
+       int HW_Flags;
        int *busy_flag;
        union {
                struct elsa_hw elsa;
@@ -641,7 +702,6 @@ struct IsdnCardState {
                struct njet_hw njet;
                struct hfcD_hw hfcD;
                struct ix1_hw niccy;
-                struct foreign_interface *foreign;
        } hw;
        int myid;
        isdn_if iif;
@@ -657,7 +717,6 @@ struct IsdnCardState {
        void   (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char);
        void   (*BC_Send_Data) (struct BCState *);
        int    (*cardmsg) (struct IsdnCardState *, int, void *);
-       void   (*l1cmd) (struct IsdnCardState *, int, void *);
        struct Channel channel[2];
        struct BCState bcs[2];
        struct PStack *stlist;
@@ -671,8 +730,7 @@ struct IsdnCardState {
        struct sk_buff_head rq, sq; /* D-channel queues */
        int ph_state;
        int cardnr;
-       int dlogflag;
-       char *dlogspace;
+       char *dlog;
        int debug;
        u_char *mon_tx;
        u_char *mon_rx;
@@ -688,6 +746,8 @@ 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
@@ -712,9 +772,12 @@ struct IsdnCardState {
 #define  ISDN_CTYPE_SEDLBAUER_PCMCIA   22
 #define  ISDN_CTYPE_AMD7930    23
 #define  ISDN_CTYPE_NICCY      24
-#define  ISDN_CTYPE_DBRI       25
+#define  ISDN_CTYPE_S0BOX      25
+#define  ISDN_CTYPE_A1_PCMCIA  26
+#define  ISDN_CTYPE_FRITZPCI   27
+#define  ISDN_CTYPE_SEDLBAUER_FAX     28
 
-#define  ISDN_CTYPE_COUNT      25
+#define  ISDN_CTYPE_COUNT      28
 
 #ifdef ISDN_CHIP_ISAC
 #undef ISDN_CHIP_ISAC
@@ -742,15 +805,42 @@ struct IsdnCardState {
 #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 
+#ifndef ISDN_CHIP_ISAC
 #define ISDN_CHIP_ISAC 1
 #endif
 #else
 #define  CARD_AVM_A1  0
 #endif
 
+#ifdef CONFIG_HISAX_AVM_A1_PCMCIA
+#define  CARD_AVM_A1_PCMCIA (1<< ISDN_CTYPE_A1_PCMCIA)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_AVM_A1_PCMCIA  0
+#endif
+
+#ifdef CONFIG_HISAX_FRITZPCI
+#define  CARD_FRITZPCI (1<< ISDN_CTYPE_FRITZPCI)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
+#else
+#define  CARD_FRITZPCI  0
+#endif
+
 #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)
@@ -803,7 +893,7 @@ struct IsdnCardState {
 #endif
 
 #ifdef  CONFIG_HISAX_SEDLBAUER
-#define CARD_SEDLBAUER (1 << ISDN_CTYPE_SEDLBAUER) | (1 << ISDN_CTYPE_SEDLBAUER_PCMCIA)
+#define CARD_SEDLBAUER (1 << ISDN_CTYPE_SEDLBAUER) | (1 << ISDN_CTYPE_SEDLBAUER_PCMCIA) | ( 1 << ISDN_CTYPE_SEDLBAUER_FAX)
 #ifndef ISDN_CHIP_ISAC
 #define ISDN_CHIP_ISAC 1
 #endif
@@ -859,18 +949,21 @@ struct IsdnCardState {
 #define CARD_NICCY 0
 #endif
 
-#ifdef  CONFIG_HISAX_DBRI
-#define CARD_DBRI (1 << ISDN_CTYPE_DBRI)
+#ifdef CONFIG_HISAX_S0BOX
+#define        CARD_S0BOX (1 << ISDN_CTYPE_S0BOX)
+#ifndef ISDN_CHIP_ISAC
+#define ISDN_CHIP_ISAC 1
+#endif
 #else
-#define CARD_DBRI 0
+#define CARD_S0BOX 0
 #endif
 
-
 #define  SUPORTED_CARDS  (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \
                         | CARD_IX1MICROR2 | CARD_DIEHLDIVA | CARD_ASUSCOM \
                         | CARD_TELEINT | CARD_SEDLBAUER | CARD_SPORTSTER \
                         | CARD_MIC | CARD_NETJET | CARD_TELES3C | CARD_AMD7930 \
-                        | CARD_NICCY | CARD_DBRI)
+                        | CARD_AVM_A1_PCMCIA | CARD_FRITZPCI\
+                        | CARD_NICCY | CARD_S0BOX | CARD_TELESPCI)
 
 #define TEI_PER_CARD 0
 
@@ -883,25 +976,38 @@ struct IsdnCardState {
 #undef TEI_PER_CARD
 #define TEI_PER_CARD 1
 #define HISAX_EURO_SENDCOMPLETE 1
-#ifdef CONFIG_HISAX_ML
+#define EXT_BEARER_CAPS 1
+#define HISAX_SEND_STD_LLC_IE 1
+#ifdef CONFIG_HISAX_NO_SENDCOMPLETE
 #undef HISAX_EURO_SENDCOMPLETE
 #endif
+#ifdef CONFIG_HISAX_NO_LLC
+#undef HISAX_SEND_STD_LLC_IE
+#endif
 #undef HISAX_DE_AOC
 #ifdef CONFIG_DE_AOC
 #define HISAX_DE_AOC 1
 #endif
 #endif
 
-#if TEI_PER_CARD
-#undef TEI_FIXED
-#endif
-
-#undef PTP_DATA_LINK
-
-#ifdef PTP_DATA_LINK
-#undef TEI_FIXED
-#define TEI_FIXED 0
-#define LAYER2_WATCHING
+/* L1 Debug */
+#define        L1_DEB_WARN             0x01
+#define        L1_DEB_INTSTAT          0x02
+#define        L1_DEB_ISAC             0x04
+#define        L1_DEB_ISAC_FIFO        0x08
+#define        L1_DEB_HSCX             0x10
+#define        L1_DEB_HSCX_FIFO        0x20
+#define        L1_DEB_LAPD             0x40
+#define        L1_DEB_IPAC             0x80
+#define        L1_DEB_RECEIVE_FRAME    0x100
+#define L1_DEB_MONITOR         0x200
+#define DEB_DLOG_HEX           0x400
+#define DEB_DLOG_VERBOSE       0x800
+
+#define L2FRAME_DEBUG
+
+#ifdef L2FRAME_DEBUG
+extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir);
 #endif
 
 struct IsdnCard {
@@ -911,17 +1017,26 @@ struct IsdnCard {
        struct IsdnCardState *cs;
 };
 
-void setstack_isdnl2(struct PStack *st, char *debug_id);
-int HiSax_inithardware(int *);
-void HiSax_closehardware(void);
+void init_bcstate(struct IsdnCardState *cs, int bc);
 
 void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs);
 unsigned int random_ri(void);
-void setstack_isdnl3(struct PStack *st, struct Channel *chanp);
 void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
+void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
+
+void setstack_l1_B(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);
 
 u_char *findie(u_char * p, int size, u_char ie, int wanted_set);
 int getcallref(u_char * p);
@@ -937,20 +1052,18 @@ int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
 void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
        void *arg, int where);
 void FsmDelTimer(struct FsmTimer *ft, int where);
-void jiftime(char *s, long mark);
+int jiftime(char *s, long mark);
 
 int HiSax_command(isdn_ctrl * ic);
 int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
-void HiSax_putstatus(struct IsdnCardState *csta, char *buf);
+void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
+void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
 void HiSax_reportcard(int cardnr);
 int QuickHex(char *txt, u_char * p, int cnt);
-void LogFrame(struct IsdnCardState *sp, u_char * p, int size);
-void dlogframe(struct IsdnCardState *sp, u_char * p, int size, char *comment);
+void LogFrame(struct IsdnCardState *cs, u_char * p, int size);
+void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
 void iecpy(u_char * dest, u_char * iestart, int ieoffset);
-void setstack_transl2(struct PStack *st);
-void releasestack_transl2(struct PStack *st);
-void setstack_tei(struct PStack *st);
-void setstack_manager(struct PStack *st);
+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 */
@@ -958,18 +1071,21 @@ void setstack_isac(struct PStack *st, struct IsdnCardState *cs);
 
 #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
 
-int ll_run(struct IsdnCardState *csta);
-void ll_stop(struct IsdnCardState *csta);
+int ll_run(struct IsdnCardState *cs);
+void ll_stop(struct IsdnCardState *cs);
 void CallcNew(void);
 void CallcFree(void);
-int CallcNewChan(struct IsdnCardState *csta);
-void CallcFreeChan(struct IsdnCardState *csta);
+int CallcNewChan(struct IsdnCardState *cs);
+void CallcFreeChan(struct IsdnCardState *cs);
 void Isdnl1New(void);
 void Isdnl1Free(void);
 void Isdnl2New(void);
 void Isdnl2Free(void);
-void init_tei(struct IsdnCardState *sp, int protocol);
-void release_tei(struct IsdnCardState *sp);
+void Isdnl3New(void);
+void Isdnl3Free(void);
+void init_tei(struct IsdnCardState *cs, int protocol);
+void release_tei(struct IsdnCardState *cs);
 char *HiSax_getrev(const char *revision);
 void TeiNew(void);
 void TeiFree(void);
+int certification_check(int output);
index c44cc54dfbf6fa9191e6260b4620f1ba08e6446a..980dc76e8a663f4833b1e1be3d4999a92fde1f6e 100644 (file)
@@ -1,11 +1,40 @@
-/* $Id: hscx.c,v 1.7 1998/02/12 23:07:36 keil Exp $
+/* $Id: hscx.c,v 1.16 1998/11/15 23:54:48 keil Exp $
 
  * hscx.c   HSCX specific routines
  *
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *
  *
  * $Log: hscx.c,v $
+ * Revision 1.16  1998/11/15 23:54:48  keil
+ * changes from 2.0
+ *
+ * Revision 1.15  1998/08/20 13:50:42  keil
+ * More support for hybrid modem (not working yet)
+ *
+ * Revision 1.14  1998/08/13 23:36:33  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 1.13  1998/06/26 22:03:28  keil
+ * send flags between hdlc frames
+ *
+ * Revision 1.12  1998/06/09 18:26:01  keil
+ * PH_DEACTIVATE B-channel every time signaled to higher layer
+ *
+ * Revision 1.11  1998/05/25 14:10:07  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 1.10  1998/05/25 12:57:59  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 1.9  1998/04/15 16:45:33  keil
+ * new init code
+ *
+ * Revision 1.8  1998/03/19 13:16:24  keil
+ * fix the correct release of the hscx
+ *
  * Revision 1.7  1998/02/12 23:07:36  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -30,6 +59,7 @@
 #define __NO_VERSION__
 #include "hisax.h"
 #include "hscx.h"
+#include "isac.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
 
@@ -56,21 +86,20 @@ void
 modehscx(struct BCState *bcs, int mode, int bc)
 {
        struct IsdnCardState *cs = bcs->cs;
-       int hscx = bcs->channel;
+       int hscx = bcs->hw.hscx.hscx;
 
-       if (cs->debug & L1_DEB_HSCX) {
-               char tmp[40];
-               sprintf(tmp, "hscx %c mode %d ichan %d",
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "hscx %c mode %d ichan %d",
                        'A' + hscx, mode, bc);
-               debugl1(cs, tmp);
-       }
        bcs->mode = mode;
-       cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, 0x85);
+       bcs->channel = bc;
        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_CCR1,
+               test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85);
        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);
@@ -90,14 +119,16 @@ modehscx(struct BCState *bcs, int mode, int bc)
        }
        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_TSAX, 0x1f);
+                       cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f);
                        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;
        }
@@ -114,89 +145,106 @@ hscx_sched_event(struct BCState *bcs, int event)
        mark_bh(IMMEDIATE_BH);
 }
 
-static void
+void
 hscx_l2l1(struct PStack *st, int pr, void *arg)
 {
        struct sk_buff *skb = arg;
        long flags;
 
        switch (pr) {
-               case (PH_DATA_REQ):
+               case (PH_DATA | REQUEST):
                        save_flags(flags);
                        cli();
-                       if (st->l1.bcs->hw.hscx.tx_skb) {
+                       if (st->l1.bcs->tx_skb) {
                                skb_queue_tail(&st->l1.bcs->squeue, skb);
                                restore_flags(flags);
                        } else {
-                               st->l1.bcs->hw.hscx.tx_skb = skb;
+                               st->l1.bcs->tx_skb = skb;
                                test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
                                st->l1.bcs->hw.hscx.count = 0;
                                restore_flags(flags);
                                st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
                        }
                        break;
-               case (PH_PULL_IND):
-                       if (st->l1.bcs->hw.hscx.tx_skb) {
+               case (PH_PULL | INDICATION):
+                       if (st->l1.bcs->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->tx_skb = skb;
                        st->l1.bcs->hw.hscx.count = 0;
                        st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
                        break;
-               case (PH_PULL_REQ):
-                       if (!st->l1.bcs->hw.hscx.tx_skb) {
+               case (PH_PULL | REQUEST):
+                       if (!st->l1.bcs->tx_skb) {
                                test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                               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)
 {
-       struct sk_buff *skb;
-
-       modehscx(bcs, 0, 0);
+       modehscx(bcs, 0, bcs->channel);
        if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
                if (bcs->hw.hscx.rcvbuf) {
                        kfree(bcs->hw.hscx.rcvbuf);
                        bcs->hw.hscx.rcvbuf = NULL;
                }
-               while ((skb = skb_dequeue(&bcs->rqueue))) {
-                       dev_kfree_skb(skb);
-               }
-               while ((skb = skb_dequeue(&bcs->squeue))) {
-                       dev_kfree_skb(skb);
+               if (bcs->blog) {
+                       kfree(bcs->blog);
+                       bcs->blog = NULL;
                }
-               if (bcs->hw.hscx.tx_skb) {
-                       dev_kfree_skb(bcs->hw.hscx.tx_skb);
-                       bcs->hw.hscx.tx_skb = NULL;
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->tx_skb) {
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->tx_skb = NULL;
                        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
                }
        }
 }
 
-static int
-open_hscxstate(struct IsdnCardState *cs,
-              int bc)
+int
+open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs)
 {
-       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");
+                               "HiSax: No memory for hscx.rcvbuf\n");
+                       test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
                        return (1);
                }
+               if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+                       printk(KERN_WARNING
+                               "HiSax: No memory for bcs->blog\n");
+                       test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
+                       kfree(bcs->hw.hscx.rcvbuf);
+                       bcs->hw.hscx.rcvbuf = NULL;
+                       return (2);
+               }
                skb_queue_head_init(&bcs->rqueue);
                skb_queue_head_init(&bcs->squeue);
        }
-       bcs->hw.hscx.tx_skb = NULL;
+       bcs->tx_skb = NULL;
        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
        bcs->event = 0;
        bcs->hw.hscx.rcvidx = 0;
@@ -204,77 +252,74 @@ open_hscxstate(struct IsdnCardState *cs,
        return (0);
 }
 
-static void
-hscx_manl1(struct PStack *st, int pr,
-          void *arg)
-{
-       switch (pr) {
-               case (PH_ACTIVATE_REQ):
-                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-                       modehscx(st->l1.bcs, st->l1.mode, st->l1.bc);
-                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
-                       break;
-               case (PH_DEACTIVATE_REQ):
-                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
-                               modehscx(st->l1.bcs, 0, 0);
-                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-                       break;
-       }
-}
-
 int
 setstack_hscx(struct PStack *st, struct BCState *bcs)
 {
-       if (open_hscxstate(st->l1.hardware, bcs->channel))
+       bcs->channel = st->l1.bc;
+       if (open_hscxstate(st->l1.hardware, bcs))
                return (-1);
        st->l1.bcs = bcs;
        st->l2.l2l1 = hscx_l2l1;
-       st->ma.manl1 = hscx_manl1;
        setstack_manager(st);
        bcs->st = st;
+       setstack_l1_B(st);
        return (0);
 }
 
 HISAX_INITFUNC(void
 clear_pending_hscx_ints(struct IsdnCardState *cs))
 {
-       int val;
-       char tmp[64];
+       int val, eval;
 
        val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA);
-       sprintf(tmp, "HSCX B ISTA %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "HSCX B ISTA %x", val);
        if (val & 0x01) {
-               val = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
-               sprintf(tmp, "HSCX B EXIR %x", val);
-               debugl1(cs, tmp);
-       } else if (val & 0x02) {
-               val = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
-               sprintf(tmp, "HSCX A EXIR %x", val);
-               debugl1(cs, tmp);
+               eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
+               debugl1(cs, "HSCX B EXIR %x", eval);
+       }
+       if (val & 0x02) {
+               eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
+               debugl1(cs, "HSCX A EXIR %x", eval);
        }
        val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA);
-       sprintf(tmp, "HSCX A ISTA %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "HSCX A ISTA %x", val);
        val = cs->BC_Read_Reg(cs, 1, HSCX_STAR);
-       sprintf(tmp, "HSCX B STAR %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "HSCX B STAR %x", val);
        val = cs->BC_Read_Reg(cs, 0, HSCX_STAR);
-       sprintf(tmp, "HSCX A STAR %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "HSCX A STAR %x", val);
+       /* disable all IRQ */
        cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
        cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
-       cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
-       cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
 }
 
-HISAX_INITFUNC(void 
+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;
+       cs->bcs[0].hw.hscx.hscx = 0;
+       cs->bcs[1].hw.hscx.hscx = 1;
        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);
+       }
+}
index ac2d38086276b60672daaccdfde69829d3800bdb..08801bc736ca5d71703201178520daf6b4d82c14 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: hscx.h,v 1.3 1997/07/27 21:38:35 keil Exp $
+/* $Id: hscx.h,v 1.4 1998/04/15 16:45:34 keil Exp $
 
  * hscx.h   HSCX specific defines
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: hscx.h,v $
+ * Revision 1.4  1998/04/15 16:45:34  keil
+ * new init code
+ *
  * Revision 1.3  1997/07/27 21:38:35  keil
  * new B-channel interface
  *
@@ -44,3 +47,4 @@ 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);
index 992ec813be8d1cb37a8f38233695506db10f0b14..fcd65d32ff2d67ef755d7e843b762ba3181743aa 100644 (file)
@@ -1,12 +1,24 @@
-/* $Id: hscx_irq.c,v 1.7 1998/02/12 23:07:37 keil Exp $
+/* $Id: hscx_irq.c,v 1.11 1998/11/15 23:54:49 keil Exp $
 
  * hscx_irq.c     low level b-channel stuff for Siemens HSCX
  *
- * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * This is an include file for fast inline IRQ stuff
  *
  * $Log: hscx_irq.c,v $
+ * Revision 1.11  1998/11/15 23:54:49  keil
+ * changes from 2.0
+ *
+ * Revision 1.10  1998/08/13 23:36:35  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 1.9  1998/06/24 14:44:51  keil
+ * Fix recovery of TX IRQ loss
+ *
+ * Revision 1.8  1998/04/10 10:35:22  paul
+ * fixed (silly?) warnings from egcs on Alpha.
+ *
  * Revision 1.7  1998/02/12 23:07:37  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -85,7 +97,7 @@ hscx_empty_fifo(struct BCState *bcs, int count)
        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);
+               WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
                bcs->hw.hscx.rcvidx = 0;
                return;
        }
@@ -93,17 +105,16 @@ hscx_empty_fifo(struct BCState *bcs, int count)
        bcs->hw.hscx.rcvidx += count;
        save_flags(flags);
        cli();
-       READHSCXFIFO(cs, bcs->channel, ptr, count);
-       WriteHSCXCMDR(cs, bcs->channel, 0x80);
+       READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
+       WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
        restore_flags(flags);
        if (cs->debug & L1_DEB_HSCX_FIFO) {
-               char tmp[256];
-               char *t = tmp;
+               char *t = bcs->blog;
 
                t += sprintf(t, "hscx_empty_fifo %c cnt %d",
-                            bcs->channel ? 'B' : 'A', count);
+                            bcs->hw.hscx.hscx ? 'B' : 'A', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, tmp);
+               debugl1(cs, bcs->blog);
        }
 }
 
@@ -120,36 +131,35 @@ hscx_fill_fifo(struct BCState *bcs)
        if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
                debugl1(cs, "hscx_fill_fifo");
 
-       if (!bcs->hw.hscx.tx_skb)
+       if (!bcs->tx_skb)
                return;
-       if (bcs->hw.hscx.tx_skb->len <= 0)
+       if (bcs->tx_skb->len <= 0)
                return;
 
        more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
-       if (bcs->hw.hscx.tx_skb->len > fifo_size) {
+       if (bcs->tx_skb->len > fifo_size) {
                more = !0;
                count = fifo_size;
        } else
-               count = bcs->hw.hscx.tx_skb->len;
+               count = bcs->tx_skb->len;
 
-       waitforXFW(cs, bcs->channel);
+       waitforXFW(cs, bcs->hw.hscx.hscx);
        save_flags(flags);
        cli();
-       ptr = bcs->hw.hscx.tx_skb->data;
-       skb_pull(bcs->hw.hscx.tx_skb, count);
+       ptr = bcs->tx_skb->data;
+       skb_pull(bcs->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);
+       WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
+       WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
        restore_flags(flags);
        if (cs->debug & L1_DEB_HSCX_FIFO) {
-               char tmp[256];
-               char *t = tmp;
+               char *t = bcs->blog;
 
                t += sprintf(t, "hscx_fill_fifo %c cnt %d",
-                            bcs->channel ? 'B' : 'A', count);
+                            bcs->hw.hscx.hscx ? 'B' : 'A', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, tmp);
+               debugl1(cs, bcs->blog);
        }
 }
 
@@ -161,7 +171,6 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char 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;
@@ -173,11 +182,9 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
                                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",
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, "HSCX RDO mode=%d",
                                                bcs->mode);
-                                       debugl1(cs, tmp);
-                               }
                        if (!(r & 0x20))
                                if (cs->debug & L1_DEB_WARN)
                                        debugl1(cs, "HSCX CRC error");
@@ -189,10 +196,8 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
                                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 (cs->debug & L1_DEB_HSCX_FIFO)
+                                       debugl1(cs, "HX Frame %d", count);
                                if (!(skb = dev_alloc_skb(count)))
                                        printk(KERN_WARNING "HSCX: receive out of memory\n");
                                else {
@@ -219,20 +224,20 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
                }
        }
        if (val & 0x10) {       /* XPR */
-               if (bcs->hw.hscx.tx_skb) {
-                       if (bcs->hw.hscx.tx_skb->len) {
+               if (bcs->tx_skb) {
+                       if (bcs->tx_skb->len) {
                                hscx_fill_fifo(bcs);
                                return;
                        } else {
                                if (bcs->st->lli.l1writewakeup &&
-                                       (PACKET_NOACK != bcs->hw.hscx.tx_skb->pkt_type))
+                                       (PACKET_NOACK != bcs->tx_skb->pkt_type))
                                        bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
-                               dev_kfree_skb(bcs->hw.hscx.tx_skb);
+                               dev_kfree_skb(bcs->tx_skb);
                                bcs->hw.hscx.count = 0; 
-                               bcs->hw.hscx.tx_skb = NULL;
+                               bcs->tx_skb = NULL;
                        }
                }
-               if ((bcs->hw.hscx.tx_skb = skb_dequeue(&bcs->squeue))) {
+               if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
                        bcs->hw.hscx.count = 0;
                        test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
                        hscx_fill_fifo(bcs);
@@ -249,73 +254,60 @@ 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 (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);
+                               if (bcs->tx_skb) {
+                                       skb_push(bcs->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);
-                               }
+                               WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
                        }
-               } else if (cs->debug & L1_DEB_HSCX) {
-                       sprintf(tmp, "HSCX B EXIR %x", exval);
-                       debugl1(cs, tmp);
-               }
+               } else if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX B EXIR %x", exval);
        }
        if (val & 0xf8) {
-               if (cs->debug & L1_DEB_HSCX) {
-                       sprintf(tmp, "HSCX B interrupt %x", val);
-                       debugl1(cs, tmp);
-               }
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX B interrupt %x", val);
                hscx_interrupt(cs, val, 1);
        }
        if (val & 0x02) {
                bcs = cs->bcs;
                exval = READHSCX(cs, 0, HSCX_EXIR);
-               if (exval == 0x40) {
+               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);
+                               if (bcs->tx_skb) {
+                                       skb_push(bcs->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);
-                               }
+                               WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
+                               if (cs->debug & L1_DEB_WARN)
+                                       debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
                        }
-               } else if (cs->debug & L1_DEB_HSCX) {
-                       sprintf(tmp, "HSCX A EXIR %x", exval);
-                       debugl1(cs, tmp);
-               }
+               } else if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX A EXIR %x", exval);
        }
        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);
-               }
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "HSCX A interrupt %x", exval);
                hscx_interrupt(cs, exval, 0);
        }
 }
index 6d856ec6cec8a156e133a4fe2a17b616e4f03018..82c5fa8f89a3ee0fb251e3a0da1e777be2935fc0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ipac.h,v 1.2 1997/10/29 18:51:21 keil Exp $
+/* $Id: ipac.h,v 1.3 1998/04/15 16:48:09 keil Exp $
 
  * ipac.h   IPAC specific defines
  *
@@ -6,6 +6,9 @@
  *
  *
  * $Log: ipac.h,v $
+ * Revision 1.3  1998/04/15 16:48:09  keil
+ * IPAC_ATX added
+ *
  * Revision 1.2  1997/10/29 18:51:21  keil
  * New files
  *
@@ -26,6 +29,7 @@
 #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
index f8458364caedeb4dced40cf8f984e032c8bffc2e..a239fdfad902b7519c095327691312f9385f0627 100644 (file)
@@ -1,11 +1,33 @@
-/* $Id: isac.c,v 1.12 1998/02/12 23:07:40 keil Exp $
+/* $Id: isac.c,v 1.18 1998/11/15 23:54:51 keil Exp $
 
  * isac.c   ISAC specific routines
  *
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
  *
  * $Log: isac.c,v $
+ * Revision 1.18  1998/11/15 23:54:51  keil
+ * changes from 2.0
+ *
+ * Revision 1.17  1998/08/13 23:36:37  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 1.16  1998/05/25 12:58:01  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 1.15  1998/04/15 16:45:32  keil
+ * new init code
+ *
+ * Revision 1.14  1998/04/10 10:35:26  paul
+ * fixed (silly?) warnings from egcs on Alpha.
+ *
+ * Revision 1.13  1998/03/07 22:57:01  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 1.12  1998/02/12 23:07:40  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -63,30 +85,17 @@ ISACVersion(struct IsdnCardState *cs, char *s)
        int val;
 
        val = cs->readisac(cs, ISAC_RBCH);
-       printk(KERN_INFO "%s ISAC version : %s\n", s, ISACVer[(val >> 5) & 3]);
+       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);
-       }
+       if (cs->debug & L1_DEB_ISAC)
+               debugl1(cs, "ph_command %x", command);
        cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
 }
 
-static void
-manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
-       struct PStack *st;
-
-       st = cs->stlist;
-       while (st) {
-               st->ma.manl1(st, msg, arg);
-               st = st->next;
-       }
-}
 
 static void
 isac_new_ph(struct IsdnCardState *cs)
@@ -95,28 +104,28 @@ isac_new_ph(struct IsdnCardState *cs)
                case (ISAC_IND_RS):
                case (ISAC_IND_EI):
                        ph_command(cs, ISAC_CMD_DUI);
-                       manl1_msg(cs, PH_RESET_IND, NULL);
+                       l1_msg(cs, HW_RESET | INDICATION, NULL);
                        break;
                case (ISAC_IND_DID):
-                       manl1_msg(cs, PH_DEACT_CNF, NULL);
+                       l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
                        break;
                case (ISAC_IND_DR):
-                       manl1_msg(cs, PH_DEACT_IND, NULL);
+                       l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
                        break;
                case (ISAC_IND_PU):
-                       manl1_msg(cs, PH_POWERUP_CNF, NULL);
+                       l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
                        break;
                case (ISAC_IND_RSY):
-                       manl1_msg(cs, PH_RSYNC_IND, NULL);
+                       l1_msg(cs, HW_RSYNC | INDICATION, NULL);
                        break;
                case (ISAC_IND_ARD):
-                       manl1_msg(cs, PH_INFO2_IND, NULL);
+                       l1_msg(cs, HW_INFO2 | INDICATION, NULL);
                        break;
                case (ISAC_IND_AI8):
-                       manl1_msg(cs, PH_I4_P8_IND, NULL);
+                       l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
                        break;
                case (ISAC_IND_AI10):
-                       manl1_msg(cs, PH_I4_P10_IND, NULL);
+                       l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
                        break;
                default:
                        break;
@@ -130,13 +139,12 @@ isac_bh(struct IsdnCardState *cs)
        
        if (!cs)
                return;
-
        if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
                if (cs->debug)
                        debugl1(cs, "D-Channel Busy cleared");
                stptr = cs->stlist;
                while (stptr != NULL) {
-                       stptr->l1.l1l2(stptr, PH_PAUSE_CNF, NULL);
+                       stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
                        stptr = stptr->next;
                }
        }
@@ -147,13 +155,13 @@ isac_bh(struct IsdnCardState *cs)
        if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
                DChannel_proc_xmt(cs);
        if (test_and_clear_bit(D_RX_MON0, &cs->event))
-               test_and_set_bit(HW_MON0_TX_END, &cs->HW_Flags);
+               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_TX_END, &cs->HW_Flags);
+               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_RX_END, &cs->HW_Flags);
+               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_RX_END, &cs->HW_Flags);
+               test_and_set_bit(HW_MON1_TX_END, &cs->HW_Flags);
 }
 
 void
@@ -165,13 +173,10 @@ isac_empty_fifo(struct IsdnCardState *cs, int count)
        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",
+       if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+               if (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "isac_empty_fifo overrun %d",
                                cs->rcvidx + count);
-                       debugl1(cs, tmp);
-               }
                cs->writeisac(cs, ISAC_CMDR, 0x80);
                cs->rcvidx = 0;
                return;
@@ -184,12 +189,11 @@ isac_empty_fifo(struct IsdnCardState *cs, int count)
        cs->writeisac(cs, ISAC_CMDR, 0x80);
        restore_flags(flags);
        if (cs->debug & L1_DEB_ISAC_FIFO) {
-               char tmp[128];
-               char *t = tmp;
+               char *t = cs->dlog;
 
                t += sprintf(t, "isac_empty_fifo cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, tmp);
+               debugl1(cs, cs->dlog);
        }
 }
 
@@ -231,12 +235,11 @@ isac_fill_fifo(struct IsdnCardState *cs)
        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;
+               char *t = cs->dlog;
 
                t += sprintf(t, "isac_fill_fifo cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, tmp);
+               debugl1(cs, cs->dlog);
        }
 }
 
@@ -255,12 +258,9 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
        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 (cs->debug & L1_DEB_ISAC)
+               debugl1(cs, "ISAC interrupt %x", val);
        if (val & 0x80) {       /* RME */
                exval = cs->readisac(cs, ISAC_RSTA);
                if ((exval & 0x70) != 0x20) {
@@ -323,12 +323,20 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
        }
       afterXPR:
        if (val & 0x04) {       /* CISQ */
-               cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf;
-               if (cs->debug & L1_DEB_ISAC) {
-                       sprintf(tmp, "ph_state change %x", cs->ph_state);
-                       debugl1(cs, tmp);
+               exval = cs->readisac(cs, ISAC_CIR0);
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC CIR0 %02X", exval );
+               if (exval & 2) {
+                       cs->ph_state = (exval >> 2) & 0xf;
+                       if (cs->debug & L1_DEB_ISAC)
+                               debugl1(cs, "ph_state change %x", cs->ph_state);
+                       isac_sched_event(cs, D_L1STATECHANGE);
+               }
+               if (exval & 1) {
+                       exval = cs->readisac(cs, ISAC_CIR1);
+                       if (cs->debug & L1_DEB_ISAC)
+                               debugl1(cs, "ISAC CIR1 %02X", exval );
                }
-               isac_sched_event(cs, D_L1STATECHANGE);
        }
        if (val & 0x02) {       /* SIN */
                /* never */
@@ -337,16 +345,12 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
        }
        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 (cs->debug & L1_DEB_WARN)
+                       debugl1(cs, "ISAC EXIR %02x", exval);
                if (exval & 0x04) {
                        v1 = cs->readisac(cs, ISAC_MOSR);
-                       if (cs->debug & L1_DEB_WARN) {
-                               sprintf(tmp, "ISAC MOSR %02x", v1);
-                               debugl1(cs, tmp);
-                       }
+                       if (cs->debug & L1_DEB_MONITOR)
+                               debugl1(cs, "ISAC MOSR %02x", v1);
 #if ARCOFI_USE
                        if (v1 & 0x08) {
                                if (!cs->mon_rx) {
@@ -370,10 +374,8 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
                                        goto afterMONR0;
                                }
                                cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
-                               if (cs->debug & L1_DEB_WARN) {
-                                       sprintf(tmp, "ISAC MOR0 %02x", cs->mon_rx[cs->mon_rxp -1]);
-                                       debugl1(cs, tmp);
-                               }
+                               if (cs->debug & L1_DEB_MONITOR)
+                                       debugl1(cs, "ISAC MOR0 %02x", cs->mon_rx[cs->mon_rxp -1]);
                                if (cs->mon_rxp == 1) {
                                        cs->mocr |= 0x04;
                                        cs->writeisac(cs, ISAC_MOCR, cs->mocr);
@@ -402,66 +404,70 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
                                        goto afterMONR1;
                                }
                                cs->mon_rx[cs->mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
-                               if (cs->debug & L1_DEB_WARN) {
-                                       sprintf(tmp, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]);
-                                       debugl1(cs, tmp);
-                               }
-                               if (cs->mon_rxp == 1) {
-                                       cs->mocr |= 0x40;
-                                       cs->writeisac(cs, ISAC_MOCR, cs->mocr);
-                               }
+                               if (cs->debug & L1_DEB_MONITOR)
+                                       debugl1(cs, "ISAC MOR1 %02x", cs->mon_rx[cs->mon_rxp -1]);
+                               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);
-                               isac_sched_event(cs, D_RX_MON0);
+                               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);
-                               isac_sched_event(cs, D_RX_MON1);
+                               test_and_set_bit(HW_MON1_RX_END, &cs->HW_Flags);
                        }
                        if (v1 & 0x02) {
-                               if (!cs->mon_tx) {
+                               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_txp >= cs->mon_txc) {
-                                       if (cs->mon_txc)
-                                               isac_sched_event(cs, D_TX_MON0);
+                               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_WARN) {
-                                       sprintf(tmp, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]);
-                                       debugl1(cs, tmp);
-                               }
+                               if (cs->debug & L1_DEB_MONITOR)
+                                       debugl1(cs, "ISAC %02x -> MOX0", cs->mon_tx[cs->mon_txp -1]);
                        }
                      AfterMOX0:
                        if (v1 & 0x20) {
-                               if (!cs->mon_tx) {
+                               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_txp >= cs->mon_txc) {
-                                       if (cs->mon_txc)
-                                               isac_sched_event(cs, D_TX_MON1);
+                               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_WARN) {
-                                       sprintf(tmp, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]);
-                                       debugl1(cs, tmp);
-                               }
+                               if (cs->debug & L1_DEB_MONITOR)
+                                       debugl1(cs, "ISAC %02x -> MOX1", cs->mon_tx[cs->mon_txp -1]);
                        }
                      AfterMOX1:
 #endif
@@ -470,14 +476,18 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
 }
 
 static void
-ISAC_l2l1(struct PStack *st, int pr, void *arg)
+ISAC_l1hw(struct PStack *st, int pr, void *arg)
 {
        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
        struct sk_buff *skb = arg;
-       char str[64];
+       int  val;
 
        switch (pr) {
-               case (PH_DATA_REQ):
+               case (PH_DATA |REQUEST):
+                       if (cs->debug & DEB_DLOG_HEX)
+                               LogFrame(cs, skb->data, skb->len);
+                       if (cs->debug & DEB_DLOG_VERBOSE)
+                               dlogframe(cs, skb, 0);
                        if (cs->tx_skb) {
                                skb_queue_tail(&cs->sq, skb);
 #ifdef L2FRAME_DEBUG           /* psa */
@@ -485,12 +495,6 @@ ISAC_l2l1(struct PStack *st, int pr, void *arg)
                                        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 */
@@ -500,19 +504,17 @@ ISAC_l2l1(struct PStack *st, int pr, void *arg)
                                isac_fill_fifo(cs);
                        }
                        break;
-               case (PH_PULL_IND):
+               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 */
+                       if (cs->debug & DEB_DLOG_HEX)
                                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);
-                       }
+                       if (cs->debug & DEB_DLOG_VERBOSE)
+                               dlogframe(cs, skb, 0);
                        cs->tx_skb = skb;
                        cs->tx_cnt = 0;
 #ifdef L2FRAME_DEBUG           /* psa */
@@ -521,28 +523,18 @@ ISAC_l2l1(struct PStack *st, int pr, void *arg)
 #endif
                        isac_fill_fifo(cs);
                        break;
-               case (PH_PULL_REQ):
+               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_CNF, NULL);
+                               st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
                        } else
                                test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
                        break;
-       }
-}
-
-void
-isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
-{
-       u_char val;
-       char tmp[32];
-       
-       switch(msg) {
-               case PH_RESET_REQ:
+               case (HW_RESET | REQUEST):
                        if ((cs->ph_state == ISAC_IND_EI) ||
                                (cs->ph_state == ISAC_IND_DR) ||
                                (cs->ph_state == ISAC_IND_RS))
@@ -550,17 +542,17 @@ isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
                        else
                                ph_command(cs, ISAC_CMD_RS);
                        break;
-               case PH_ENABLE_REQ:
+               case (HW_ENABLE | REQUEST):
                        ph_command(cs, ISAC_CMD_TIM);
                        break;
-               case PH_INFO3_REQ:
+               case (HW_INFO3 | REQUEST):
                        ph_command(cs, ISAC_CMD_AR8);
                        break;
-               case PH_TESTLOOP_REQ:
+               case (HW_TESTLOOP | REQUEST):
                        val = 0;
-                       if (1 & (int) arg)
+                       if (1 & (long) arg)
                                val |= 0x0c;
-                       if (2 & (int) arg)
+                       if (2 & (long) arg)
                                val |= 0x3;
                        if (test_bit(HW_IOM1, &cs->HW_Flags)) {
                                /* IOM 1 Mode */
@@ -580,11 +572,21 @@ isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
                                        cs->writeisac(cs, ISAC_ADF1, 0x0);
                        }
                        break;
-               default:
-                       if (cs->debug & L1_DEB_WARN) {
-                               sprintf(tmp, "isac_l1cmd unknown %4x", msg);
-                               debugl1(cs, tmp);
+               case (HW_DEACTIVATE | RESPONSE):
+                       discard_queue(&cs->rq);
+                       discard_queue(&cs->sq);
+                       if (cs->tx_skb) {
+                               dev_kfree_skb(cs->tx_skb);
+                               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)
+                               debugl1(cs, "isac_l1hw unknown %04x", pr);
                        break;
        }
 }
@@ -592,22 +594,29 @@ isac_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
 void
 setstack_isac(struct PStack *st, struct IsdnCardState *cs)
 {
-       st->l2.l2l1 = ISAC_l2l1;
+       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)
+               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_IND, NULL);
+                       stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
                        stptr = stptr->next;
                }
        }
@@ -617,7 +626,6 @@ HISAX_INITFUNC(void
 initisac(struct IsdnCardState *cs))
 {
        cs->tqueue.routine = (void *) (void *) isac_bh;
-       cs->l1cmd = isac_l1cmd;
        cs->setstack_d = setstack_isac;
        cs->dbusytimer.function = (void *) dbusy_timer_handler;
        cs->dbusytimer.data = (long) cs;
@@ -648,35 +656,24 @@ initisac(struct IsdnCardState *cs))
 HISAX_INITFUNC(void
 clear_pending_isac_ints(struct IsdnCardState *cs))
 {
-       int val;
-       char tmp[64];
+       int val, eval;
 
        val = cs->readisac(cs, ISAC_STAR);
-       sprintf(tmp, "ISAC STAR %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "ISAC STAR %x", val);
        val = cs->readisac(cs, ISAC_MODE);
-       sprintf(tmp, "ISAC MODE %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "ISAC MODE %x", val);
        val = cs->readisac(cs, ISAC_ADF2);
-       sprintf(tmp, "ISAC ADF2 %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "ISAC ADF2 %x", val);
        val = cs->readisac(cs, ISAC_ISTA);
-       sprintf(tmp, "ISAC ISTA %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "ISAC ISTA %x", val);
        if (val & 0x01) {
-               val = cs->readisac(cs, ISAC_EXIR);
-               sprintf(tmp, "ISAC EXIR %x", val);
-               debugl1(cs, tmp);
-       } else if (val & 0x04) {
-               val = cs->readisac(cs, ISAC_CIR0);
-               sprintf(tmp, "ISAC CIR0 %x", val);
-               debugl1(cs, tmp);
-               cs->ph_state = (val >> 2) & 0xf;
-       } else {
-               cs->ph_state = (cs->readisac(cs, ISAC_CIX0) >> 2) & 0xf;
+               eval = cs->readisac(cs, ISAC_EXIR);
+               debugl1(cs, "ISAC EXIR %x", eval);
        }
+       val = cs->readisac(cs, ISAC_CIR0);
+       debugl1(cs, "ISAC CIR0 %x", val);
+       cs->ph_state = (val >> 2) & 0xf;
        isac_sched_event(cs, D_L1STATECHANGE);
+       /* Disable all IRQ */
        cs->writeisac(cs, ISAC_MASK, 0xFF);
-       cs->writeisac(cs, ISAC_MASK, 0);
-       cs->writeisac(cs, ISAC_CMDR, 0x41);
 }
index ac4d556470ff953104a9f1f2642fa50ab6e85616..bed887d4fbcbbdd258c0ca93ac89be2edd28ebca 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isac.h,v 1.4 1997/10/29 19:09:34 keil Exp $
+/* $Id: isac.h,v 1.5 1998/05/25 12:58:03 keil Exp $
 
  * isac.h   ISAC specific defines
  *
@@ -6,6 +6,10 @@
  *
  *
  * $Log: isac.h,v $
+ * Revision 1.5  1998/05/25 12:58:03  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
  * Revision 1.4  1997/10/29 19:09:34  keil
  * new L1
  *
 #define ISAC_STAR 0x21
 #define ISAC_CMDR 0x21
 #define ISAC_EXIR 0x24
-#define ISAC_RBCH 0x2a
 #define ISAC_ADF2 0x39
 #define ISAC_SPCR 0x30
 #define ISAC_ADF1 0x38
 #define ISAC_CIR0 0x31
 #define ISAC_CIX0 0x31
+#define ISAC_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
@@ -45,6 +51,8 @@
 #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
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
new file mode 100644 (file)
index 0000000..ba9247a
--- /dev/null
@@ -0,0 +1,937 @@
+/* $Id: isar.c,v 1.2 1998/11/15 23:54:53 keil Exp $
+
+ * isar.c   ISAR (Siemens PSB 7110) specific routines
+ *
+ * Author       Karsten Keil (keil@isdn4linux.de)
+ *
+ *
+ * $Log: isar.c,v $
+ * Revision 1.2  1998/11/15 23:54:53  keil
+ * changes from 2.0
+ *
+ * Revision 1.1  1998/08/13 23:33:47  keil
+ * First version, only init
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isar.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+#define DBG_LOADFIRM   0
+#define DUMP_MBOXFRAME 2
+
+#define MIN(a,b) ((a<b)?a:b)
+
+void isar_setup(struct IsdnCardState *cs);
+
+static inline int
+waitforHIA(struct IsdnCardState *cs, int timeout)
+{
+
+       while ((cs->BC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) {
+               udelay(1);
+               timeout--;
+       }
+       if (!timeout)
+               printk(KERN_WARNING "HiSax: ISAR waitforHIA timeout\n");
+       return(timeout);
+}
+
+
+int
+sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
+       u_char *msg)
+{
+       long flags;
+       int i;
+       
+       if (!waitforHIA(cs, 4000))
+               return(0);
+#if DUMP_MBOXFRAME
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len);
+#endif
+       save_flags(flags);
+       cli();
+       cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg);
+       cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len);
+       cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0);
+       if (msg && len) {
+               cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]);
+               for (i=1; i<len; i++)
+                       cs->BC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]);
+#if DUMP_MBOXFRAME>1
+               if (cs->debug & L1_DEB_HSCX_FIFO) {
+                       char tmp[256], *t;
+                       
+                       i = len;
+                       while (i>0) {
+                               t = tmp;
+                               t += sprintf(t, "sendmbox cnt %d", len);
+                               QuickHex(t, &msg[len-i], (i>64) ? 64:i);
+                               debugl1(cs, tmp);
+                               i -= 64;
+                       }
+               }
+#endif
+       }
+       cs->BC_Write_Reg(cs, 1, ISAR_HIS, his);
+       restore_flags(flags);
+       waitforHIA(cs, 10000);
+       return(1);
+}
+
+/* Call only with IRQ disabled !!! */
+inline void
+rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
+{
+       int i;
+
+       cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0);
+       if (msg && ireg->clsb) {
+               msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX);
+               for (i=1; i < ireg->clsb; i++)
+                        msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX);
+#if DUMP_MBOXFRAME>1
+               if (cs->debug & L1_DEB_HSCX_FIFO) {
+                       char tmp[256], *t;
+                       
+                       i = ireg->clsb;
+                       while (i>0) {
+                               t = tmp;
+                               t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb);
+                               QuickHex(t, &msg[ireg->clsb-i], (i>64) ? 64:i);
+                               debugl1(cs, tmp);
+                               i -= 64;
+                       }
+               }
+#endif
+       }
+       cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+}
+
+/* Call only with IRQ disabled !!! */
+inline void
+get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg)
+{
+       ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS);
+       ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H);
+       ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L);
+#if DUMP_MBOXFRAME
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
+                       ireg->clsb);
+#endif
+}
+
+int
+waitrecmsg(struct IsdnCardState *cs, u_char *len,
+       u_char *msg, int maxdelay)
+{
+       int timeout = 0;
+       long flags;
+       struct isar_reg *ir = cs->bcs[0].hw.isar.reg;
+       
+       
+       while((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) &&
+               (timeout++ < maxdelay))
+               udelay(1);
+       if (timeout >= maxdelay) {
+               printk(KERN_WARNING"isar recmsg IRQSTA timeout\n");
+               return(0);
+       }
+       save_flags(flags);
+       cli();
+       get_irq_infos(cs, ir);
+       rcv_mbox(cs, ir, msg);
+       *len = ir->clsb;
+       restore_flags(flags);
+       return(1);
+}
+
+int
+ISARVersion(struct IsdnCardState *cs, char *s)
+{
+       int ver;
+       u_char msg[] = ISAR_MSG_HWVER;
+       u_char tmp[64];
+       u_char len;
+       int debug;
+
+       cs->cardmsg(cs, CARD_RESET,  NULL);
+       /* disable ISAR IRQ */
+       cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
+       debug = cs->debug;
+       cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
+       if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg))
+               return(-1);
+       if (!waitrecmsg(cs, &len, tmp, 100000))
+                return(-2);
+       cs->debug = debug;
+       if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) {
+               if (len == 1) {
+                       ver = tmp[0] & 0xf;
+                       printk(KERN_INFO "%s ISAR version %d\n", s, ver);
+                       return(ver);
+               }
+               return(-3);
+       }
+       return(-4);
+}
+
+int
+isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
+{
+       int ret, size, cnt, debug;
+       u_char len, nom, noc;
+       u_short sadr, left, *sp;
+       u_char *p = buf;
+       u_char *msg, *tmpmsg, *mp, tmp[64];
+       long flags;
+       struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
+       
+       struct {u_short sadr;
+               u_short len;
+               u_short d_key;
+       } blk_head;
+               
+#define        BLK_HEAD_SIZE 6
+       if (1 != (ret = ISARVersion(cs, "Testing"))) {
+               printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret);
+               return(1);
+       }
+       debug = cs->debug;
+#if DBG_LOADFIRM<2
+       cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);
+#endif
+       printk(KERN_DEBUG"isar_load_firmware buf %#lx\n", (u_long)buf);
+       if ((ret = verify_area(VERIFY_READ, (void *) p, sizeof(int)))) {
+               printk(KERN_ERR"isar_load_firmware verify_area ret %d\n", ret);
+               return ret;
+       }
+       if ((ret = copy_from_user(&size, p, sizeof(int)))) {
+               printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
+               return ret;
+       }
+       p += sizeof(int);
+       printk(KERN_DEBUG"isar_load_firmware size: %d\n", size);
+       if ((ret = verify_area(VERIFY_READ, (void *) p, size))) {
+               printk(KERN_ERR"isar_load_firmware verify_area ret %d\n", ret);
+               return ret;
+       }
+       cnt = 0;
+       /* disable ISAR IRQ */
+       cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
+       if (!(msg = kmalloc(256, GFP_KERNEL))) {
+               printk(KERN_ERR"isar_load_firmware no buffer\n");
+               return (1);
+       }
+       if (!(tmpmsg = kmalloc(256, GFP_KERNEL))) {
+               printk(KERN_ERR"isar_load_firmware no tmp buffer\n");
+               kfree(msg);
+               return (1);
+       }
+       while (cnt < size) {
+               if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) {
+                       printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
+                       goto reterror;
+               }
+               cnt += BLK_HEAD_SIZE;
+               p += BLK_HEAD_SIZE;
+               printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n",
+                       blk_head.sadr, blk_head.len, blk_head.d_key & 0xff);
+               sadr = blk_head.sadr;
+               left = blk_head.len;
+               if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) {
+                       printk(KERN_ERR"isar sendmsg dkey failed\n");
+                       ret = 1;goto reterror;
+               }
+               if (!waitrecmsg(cs, &len, tmp, 100000)) {
+                       printk(KERN_ERR"isar waitrecmsg dkey failed\n");
+                       ret = 1;goto reterror;
+               }
+               if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) {
+                       printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n",
+                               ireg->iis, ireg->cmsb, len);
+                       ret = 1;goto reterror;
+               }
+               while (left>0) {
+                       noc = MIN(126, left);
+                       nom = 2*noc;
+                       mp  = msg;
+                       *mp++ = sadr / 256;
+                       *mp++ = sadr % 256;
+                       left -= noc;
+                       *mp++ = noc;
+                       if ((ret = copy_from_user(tmpmsg, p, nom))) {
+                               printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
+                               goto reterror;
+                       }
+                       p += nom;
+                       cnt += nom;
+                       nom += 3;
+                       sp = (u_short *)tmpmsg;
+#if DBG_LOADFIRM
+                       printk(KERN_DEBUG"isar: load %3d words at %04x\n",
+                                noc, sadr);
+#endif
+                       sadr += noc;
+                       while(noc) {
+                               *mp++ = *sp / 256;
+                               *mp++ = *sp % 256;
+                               sp++;
+                               noc--;
+                       }
+                       if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) {
+                               printk(KERN_ERR"isar sendmsg prog failed\n");
+                               ret = 1;goto reterror;
+                       }
+                       if (!waitrecmsg(cs, &len, tmp, 100000)) {
+                               printk(KERN_ERR"isar waitrecmsg prog failed\n");
+                               ret = 1;goto reterror;
+                       }
+                       if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) {
+                               printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n",
+                                       ireg->iis, ireg->cmsb, len);
+                               ret = 1;goto reterror;
+                       }
+               }
+               printk(KERN_DEBUG"isar firmware block %5d words loaded\n",
+                       blk_head.len);
+       }
+       msg[0] = 0xff;
+       msg[1] = 0xfe;
+       ireg->bstat = 0;
+       if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) {
+               printk(KERN_ERR"isar sendmsg start dsp failed\n");
+               ret = 1;goto reterror;
+       }
+       if (!waitrecmsg(cs, &len, tmp, 100000)) {
+               printk(KERN_ERR"isar waitrecmsg start dsp failed\n");
+               ret = 1;goto reterror;
+       }
+       if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) {
+               printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n",
+                       ireg->iis, ireg->cmsb, len);
+               ret = 1;goto reterror;
+       } else
+               printk(KERN_DEBUG"isar start dsp success\n");
+       /* NORMAL mode entered */
+       /* Enable IRQs of ISAR */
+       cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA);
+       save_flags(flags);
+       sti();
+       cnt = 1000; /* max 1s */
+       while ((!ireg->bstat) && cnt) {
+               udelay(1000);
+               cnt--;
+       }
+       if (!cnt) {
+               printk(KERN_ERR"isar no general status event received\n");
+               ret = 1;goto reterrflg;
+       } else {
+               printk(KERN_DEBUG"isar general status event %x\n",
+                       ireg->bstat);
+       }
+       ireg->iis = 0;
+       if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
+               printk(KERN_ERR"isar sendmsg self tst failed\n");
+               ret = 1;goto reterrflg;
+       }
+       cnt = 1000; /* max 10 ms */
+       while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
+               udelay(10);
+               cnt--;
+       }
+       if (!cnt) {
+               printk(KERN_ERR"isar no self tst response\n");
+               ret = 1;goto reterrflg;
+       } else if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1)
+               && (ireg->par[0] == 0)) {
+               printk(KERN_DEBUG"isar selftest OK\n");
+       } else {
+               printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n",
+                       ireg->cmsb, ireg->clsb, ireg->par[0]);
+               ret = 1;goto reterror;
+       }
+       ireg->iis = 0;
+       if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
+               printk(KERN_ERR"isar RQST SVN failed\n");
+               ret = 1;goto reterror;
+       }
+       cnt = 10000; /* max 100 ms */
+       while ((ireg->iis != ISAR_IIS_DIAG) && cnt) {
+               udelay(10);
+               cnt--;
+       }
+       if (!cnt) {
+               printk(KERN_ERR"isar no SVN response\n");
+               ret = 1;goto reterrflg;
+       } else {
+               if ((ireg->cmsb == ISAR_CTRL_SWVER) && (ireg->clsb == 1))
+                       printk(KERN_DEBUG"isar software version %#x\n",
+                               ireg->par[0]);
+               else {
+                       printk(KERN_ERR"isar wrong swver response (%x,%x) cnt(%d)\n",
+                               ireg->cmsb, ireg->clsb, cnt);
+                       ret = 1;goto reterrflg;
+               }
+       }
+       cs->debug = debug;
+       isar_setup(cs);
+       ret = 0;
+reterrflg:
+       restore_flags(flags);
+reterror:
+       cs->debug = debug;
+       if (ret)
+               /* disable ISAR IRQ */
+               cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0);
+       kfree(msg);
+       kfree(tmpmsg);
+       return(ret);
+}
+
+void
+isar_sched_event(struct BCState *bcs, int event)
+{
+       bcs->event |= 1 << event;
+       queue_task(&bcs->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+static inline void
+isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs)
+{
+       u_char *ptr;
+       struct sk_buff *skb;
+       struct isar_reg *ireg = bcs->hw.isar.reg;
+       
+       if (!ireg->clsb) {
+               debugl1(cs, "isar zero len frame");
+               cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+               return;
+       }
+       switch (bcs->mode) {
+       case L1_MODE_NULL:
+               debugl1(cs, "isar mode 0 spurious IIS_RDATA %x/%x/%x",
+                       ireg->iis, ireg->cmsb, ireg->clsb);
+               printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n",
+                       ireg->iis, ireg->cmsb, ireg->clsb);
+               cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+               break;
+       case L1_MODE_TRANS:
+               if ((skb = dev_alloc_skb(ireg->clsb))) {
+                       rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb));
+                       skb_queue_tail(&bcs->rqueue, skb);
+                       isar_sched_event(bcs, B_RCVBUFREADY);
+               } else {
+                       printk(KERN_WARNING "HiSax: skb out of memory\n");
+                       cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+               }
+               break;
+       case L1_MODE_HDLC:
+               if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) {
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "isar_rcv_frame: incoming packet too large");
+                       cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+                       bcs->hw.isar.rcvidx = 0;
+               } else if (ireg->cmsb & HDLC_ERROR) {
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "isar frame error %x len %d",
+                                       ireg->cmsb, ireg->clsb);
+                       bcs->hw.isar.rcvidx = 0;
+                       cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+               } else {
+                       if (ireg->cmsb & HDLC_FSD)
+                               bcs->hw.isar.rcvidx = 0;
+                       ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
+                       bcs->hw.isar.rcvidx += ireg->clsb;
+                       rcv_mbox(cs, ireg, ptr);
+                       if (ireg->cmsb & HDLC_FED) {
+                               if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
+                                       printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
+                                               bcs->hw.isar.rcvidx);
+                               } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2)))
+                                       printk(KERN_WARNING "ISAR: receive out of memory\n");
+                               else {
+                                       memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2),
+                                               bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2);
+                                       skb_queue_tail(&bcs->rqueue, skb);
+                                       isar_sched_event(bcs, B_RCVBUFREADY);
+                               }
+                       }
+               }
+               break;
+       default:
+               printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
+               cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+               break;
+       }
+}
+
+void
+isar_fill_fifo(struct BCState *bcs)
+{
+       struct IsdnCardState *cs = bcs->cs;
+       int count;
+       u_char msb;
+       u_char *ptr;
+       long flags;
+
+       if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+               debugl1(cs, "isar_fill_fifo");
+       if (!bcs->tx_skb)
+               return;
+       if (bcs->tx_skb->len <= 0)
+               return;
+       if (!(bcs->hw.isar.reg->bstat & 
+               (bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
+               return;
+       if (bcs->tx_skb->len > bcs->hw.isar.mml) {
+               msb = 0;
+               count = bcs->hw.isar.mml;
+       } else {
+               count = bcs->tx_skb->len;
+               msb = HDLC_FED;
+       }
+       if (!bcs->hw.isar.txcnt)
+               msb |= HDLC_FST;
+       save_flags(flags);
+       cli();
+       ptr = bcs->tx_skb->data;
+       skb_pull(bcs->tx_skb, count);
+       bcs->tx_cnt -= count;
+       bcs->hw.isar.txcnt += count;
+       switch (bcs->mode) {
+       case L1_MODE_NULL:
+               printk(KERN_ERR"isar_fill_fifo wrong mode 0\n");
+               break;
+       case L1_MODE_TRANS:
+               if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+                       0, count, ptr)) {
+                       if (cs->debug)
+                               debugl1(cs, "isar bin data send dp%d failed",
+                                       bcs->hw.isar.dpath);
+               }
+               break;
+       case L1_MODE_HDLC:
+               if (!sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA,
+                       msb, count, ptr)) {
+                       if (cs->debug)
+                               debugl1(cs, "isar hdlc data send dp%d failed",
+                                       bcs->hw.isar.dpath);
+               }
+               break;
+       default:
+               printk(KERN_ERR"isar_fill_fifo mode (%x)error\n", bcs->mode);
+               break;
+       }
+       restore_flags(flags);
+}
+
+inline
+struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath)
+{
+       if ((!dpath) || (dpath == 3))
+               return(NULL);
+       if (cs->bcs[0].hw.isar.dpath == dpath)
+               return(&cs->bcs[0]);
+       if (cs->bcs[1].hw.isar.dpath == dpath)
+               return(&cs->bcs[1]);
+       return(NULL);
+}
+
+inline void
+send_frames(struct BCState *bcs)
+{
+       if (bcs->tx_skb) {
+               if (bcs->tx_skb->len) {
+                       isar_fill_fifo(bcs);
+                       return;
+               } else {
+                       if (bcs->st->lli.l1writewakeup &&
+                               (PACKET_NOACK != bcs->tx_skb->pkt_type))
+                                       bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt);
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->hw.isar.txcnt = 0; 
+                       bcs->tx_skb = NULL;
+               }
+       }
+       if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+               bcs->hw.isar.txcnt = 0;
+               test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
+               isar_fill_fifo(bcs);
+       } else {
+               test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+               isar_sched_event(bcs, B_XMTBUFREADY);
+       }
+}
+
+inline void
+check_send(struct IsdnCardState *cs, u_char rdm)
+{
+       struct BCState *bcs;
+       
+       if (rdm & BSTAT_RDM1) {
+               if ((bcs = sel_bcs_isar(cs, 1))) {
+                       if (bcs->mode) {
+                               send_frames(bcs);
+                       }
+               }
+       }
+       if (rdm & BSTAT_RDM2) {
+               if ((bcs = sel_bcs_isar(cs, 2))) {
+                       if (bcs->mode) {
+                               send_frames(bcs);
+                       }
+               }
+       }
+       
+}
+
+static char debbuf[64];
+
+void
+isar_int_main(struct IsdnCardState *cs)
+{
+       long flags;
+       struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
+       struct BCState *bcs;
+
+       save_flags(flags);
+       cli();
+       get_irq_infos(cs, ireg);
+       switch (ireg->iis & ISAR_IIS_MSCMSD) {
+               case ISAR_IIS_RDATA:
+                       if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) {
+                               isar_rcv_frame(cs, bcs);
+                       } else {
+                               debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x",
+                                       ireg->iis, ireg->cmsb, ireg->clsb);
+                               printk(KERN_WARNING"isar spurious IIS_RDATA %x/%x/%x\n",
+                                       ireg->iis, ireg->cmsb, ireg->clsb);
+                               cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+                       }
+                       break;
+               case ISAR_IIS_GSTEV:
+                       cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+                       ireg->bstat |= ireg->cmsb;
+                       check_send(cs, ireg->cmsb);
+                       break;
+               case ISAR_IIS_BSTEV:
+                       cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "Buffer STEV dpath%d msb(%x)",
+                                       ireg->iis>>6, ireg->cmsb);
+                       break;
+               case ISAR_IIS_DIAG:
+               case ISAR_IIS_PSTRSP:
+               case ISAR_IIS_PSTEV:
+               case ISAR_IIS_BSTRSP:
+               case ISAR_IIS_IOM2RSP:
+                       rcv_mbox(cs, ireg, (u_char *)ireg->par);
+                       if ((cs->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO))
+                               == L1_DEB_HSCX) {
+                               u_char *tp=debbuf;
+
+                               tp += sprintf(debbuf, "msg iis(%x) msb(%x)",
+                                       ireg->iis, ireg->cmsb);
+                               QuickHex(tp, (u_char *)ireg->par, ireg->clsb);
+                               debugl1(cs, debbuf);
+                       }
+                       break;
+               default:
+                       rcv_mbox(cs, ireg, debbuf);
+                       if (cs->debug & L1_DEB_WARN)
+                               debugl1(cs, "unhandled msg iis(%x) ctrl(%x/%x)",
+                                       ireg->iis, ireg->cmsb, ireg->clsb);
+                       break;
+       }
+       restore_flags(flags);
+}
+
+void
+setup_pump(struct BCState *bcs) {
+       struct IsdnCardState *cs = bcs->cs;
+       u_char dps = SET_DPS(bcs->hw.isar.dpath);
+       
+       switch (bcs->mode) {
+               case L1_MODE_NULL:
+               case L1_MODE_TRANS:
+               case L1_MODE_HDLC:
+                       if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL)) {
+                               if (cs->debug)
+                                       debugl1(cs, "isar pump bypass cfg dp%d failed",
+                                               bcs->hw.isar.dpath);
+                       }
+                       break;
+       }
+       if (!sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL)) {
+               if (cs->debug)
+                       debugl1(cs, "isar pump status req dp%d failed",
+                               bcs->hw.isar.dpath);
+       }
+}
+
+void
+setup_sart(struct BCState *bcs) {
+       struct IsdnCardState *cs = bcs->cs;
+       u_char dps = SET_DPS(bcs->hw.isar.dpath);
+       
+       switch (bcs->mode) {
+               case L1_MODE_NULL:
+                       if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, NULL)) {
+                               if (cs->debug)
+                                       debugl1(cs, "isar sart disable dp%d failed",
+                                               bcs->hw.isar.dpath);
+                       }
+                       break;
+               case L1_MODE_TRANS:
+                       if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, "\0\0")) {
+                               if (cs->debug)
+                                       debugl1(cs, "isar sart binary dp%d failed",
+                                               bcs->hw.isar.dpath);
+                       }
+                       break;
+               case L1_MODE_HDLC:
+                       if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, "\0")) {
+                               if (cs->debug)
+                                       debugl1(cs, "isar sart binary dp%d failed",
+                                               bcs->hw.isar.dpath);
+                       }
+                       break;
+       }
+       if (!sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL)) {
+               if (cs->debug)
+                       debugl1(cs, "isar buf stat req dp%d failed",
+                               bcs->hw.isar.dpath);
+       }
+}
+
+void
+setup_iom2(struct BCState *bcs) {
+       struct IsdnCardState *cs = bcs->cs;
+       u_char dps = SET_DPS(bcs->hw.isar.dpath);
+       u_char cmsb = 0, msg[5] = {0x10,0,0,0,0};
+       
+       switch (bcs->mode) {
+               case L1_MODE_NULL:
+                       /* dummy slot */
+                       msg[1] = msg[3] = bcs->hw.isar.dpath + 2;
+                       break;
+               case L1_MODE_TRANS:
+               case L1_MODE_HDLC:
+                       cmsb = 0x80;
+                       if (bcs->channel)
+                               msg[1] = msg[3] = 1;
+                       break;
+       }
+       if (!sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg)) {
+               if (cs->debug)
+                       debugl1(cs, "isar iom2 dp%d failed", bcs->hw.isar.dpath);
+       }
+       if (!sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL)) {
+               if (cs->debug)
+                       debugl1(cs, "isar IOM2 cfg req dp%d failed",
+                               bcs->hw.isar.dpath);
+       }
+}
+
+int
+modeisar(struct BCState *bcs, int mode, int bc)
+{
+       struct IsdnCardState *cs = bcs->cs;
+
+       /* Here we are selecting the best datapath for requested mode */
+       if(bcs->mode == L1_MODE_NULL) { /* New Setup */
+               bcs->channel = bc;
+               switch (mode) {
+                       case L1_MODE_NULL: /* init */
+                               break;
+                       case L1_MODE_TRANS:
+                       case L1_MODE_HDLC:
+                               /* best is datapath 2 */
+                               if (!test_and_set_bit(ISAR_DP2_USE, 
+                                       &bcs->hw.isar.reg->Flags))
+                                       bcs->hw.isar.dpath = 2;
+                               else if (!test_and_set_bit(ISAR_DP1_USE,
+                                       &bcs->hw.isar.reg->Flags))
+                                       bcs->hw.isar.dpath = 1;
+                               else {
+                                       printk(KERN_ERR"isar modeisar both pathes in use\n");
+                                       return(1);
+                               }
+                               break;
+               }
+       }
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "isar dp%d mode %d->%d ichan %d",
+                       bcs->hw.isar.dpath, bcs->mode, mode, bc);
+       bcs->mode = mode;
+       setup_pump(bcs);
+       setup_sart(bcs);
+       setup_iom2(bcs);
+       if (bcs->mode == L1_MODE_NULL) {
+               /* Clear resources */
+               if (bcs->hw.isar.dpath == 1)
+                       test_and_clear_bit(ISAR_DP1_USE, &bcs->hw.isar.reg->Flags);
+               else if (bcs->hw.isar.dpath == 2)
+                       test_and_clear_bit(ISAR_DP2_USE, &bcs->hw.isar.reg->Flags);
+               bcs->hw.isar.dpath = 0;
+       }
+       return(0);
+}
+
+void
+isar_setup(struct IsdnCardState *cs)
+{
+       u_char msg;
+       int i;
+       
+       /* Dpath 1, 2 */
+       msg = 61;
+       for (i=0; i<2; i++) {
+               /* Buffer Config */
+               if (!sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
+                       ISAR_HIS_P12CFG, 4, 1, &msg)) {
+                       if (cs->debug)
+                               debugl1(cs, "isar P%dCFG failed", i+1);
+               }
+               cs->bcs[i].hw.isar.mml = msg;
+               cs->bcs[i].mode = 0;
+               cs->bcs[i].hw.isar.dpath = i + 1;
+               modeisar(&cs->bcs[i], 0, 0);
+       }
+}
+
+void
+isar_l2l1(struct PStack *st, int pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+       long flags;
+
+       switch (pr) {
+               case (PH_DATA | REQUEST):
+                       save_flags(flags);
+                       cli();
+                       if (st->l1.bcs->tx_skb) {
+                               skb_queue_tail(&st->l1.bcs->squeue, skb);
+                               restore_flags(flags);
+                       } else {
+                               st->l1.bcs->tx_skb = skb;
+                               test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                               if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
+                                       debugl1(st->l1.bcs->cs, "DRQ set BC_FLG_BUSY");
+                               st->l1.bcs->hw.isar.txcnt = 0;
+                               restore_flags(flags);
+                               st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       }
+                       break;
+               case (PH_PULL | INDICATION):
+                       if (st->l1.bcs->tx_skb) {
+                               printk(KERN_WARNING "isar_l2l1: this shouldn't happen\n");
+                               break;
+                       }
+                       test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
+                               debugl1(st->l1.bcs->cs, "PUI set BC_FLG_BUSY");
+                       st->l1.bcs->tx_skb = skb;
+                       st->l1.bcs->hw.isar.txcnt = 0;
+                       st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
+                       break;
+               case (PH_PULL | REQUEST):
+                       if (!st->l1.bcs->tx_skb) {
+                               test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                               st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+                       } else
+                               test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+                       break;
+               case (PH_ACTIVATE | REQUEST):
+                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       modeisar(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);
+                       if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
+                               debugl1(st->l1.bcs->cs, "PDAC clear BC_FLG_BUSY");
+                       modeisar(st->l1.bcs, 0, st->l1.bc);
+                       st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+                       break;
+       }
+}
+
+void
+close_isarstate(struct BCState *bcs)
+{
+       modeisar(bcs, 0, bcs->channel);
+       if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+               if (bcs->hw.isar.rcvbuf) {
+                       kfree(bcs->hw.isar.rcvbuf);
+                       bcs->hw.isar.rcvbuf = NULL;
+               }
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->tx_skb) {
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->tx_skb = NULL;
+                       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+                       if (bcs->cs->debug & L1_DEB_HSCX)
+                               debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY");
+               }
+       }
+}
+
+int
+open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
+{
+       if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+               if (!(bcs->hw.isar.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+                       printk(KERN_WARNING
+                              "HiSax: No memory for isar.rcvbuf\n");
+                       return (1);
+               }
+               skb_queue_head_init(&bcs->rqueue);
+               skb_queue_head_init(&bcs->squeue);
+       }
+       bcs->tx_skb = NULL;
+       test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "openisar clear BC_FLG_BUSY");
+       bcs->event = 0;
+       bcs->hw.isar.rcvidx = 0;
+       bcs->tx_cnt = 0;
+       return (0);
+}
+
+int
+setstack_isar(struct PStack *st, struct BCState *bcs)
+{
+       bcs->channel = st->l1.bc;
+       if (open_isarstate(st->l1.hardware, bcs))
+               return (-1);
+       st->l1.bcs = bcs;
+       st->l2.l2l1 = isar_l2l1;
+       setstack_manager(st);
+       bcs->st = st;
+       setstack_l1_B(st);
+       return (0);
+}
+
+HISAX_INITFUNC(void 
+initisar(struct IsdnCardState *cs))
+{
+       cs->bcs[0].BC_SetStack = setstack_isar;
+       cs->bcs[1].BC_SetStack = setstack_isar;
+       cs->bcs[0].BC_Close = close_isarstate;
+       cs->bcs[1].BC_Close = close_isarstate;
+}
diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h
new file mode 100644 (file)
index 0000000..de892f8
--- /dev/null
@@ -0,0 +1,91 @@
+/* $Id: isar.h,v 1.2 1998/11/15 23:54:54 keil Exp $
+ * isar.h   ISAR (Siemens PSB 7110) specific defines
+ *
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ *
+ * $Log: isar.h,v $
+ * Revision 1.2  1998/11/15 23:54:54  keil
+ * changes from 2.0
+ *
+ * Revision 1.1  1998/08/13 23:33:48  keil
+ * First version, only init
+ *
+ *
+ */
+#define ISAR_IRQMSK    0x04
+#define ISAR_IRQSTA    0x04
+#define ISAR_IRQBIT    0x75
+#define ISAR_CTRL_H    0x61
+#define ISAR_CTRL_L    0x60
+#define ISAR_IIS       0x58
+#define ISAR_IIA       0x58
+#define ISAR_HIS       0x50
+#define ISAR_HIA       0x50
+#define ISAR_MBOX      0x4c
+#define ISAR_WADR      0x4a
+#define ISAR_RADR      0x48 
+
+#define ISAR_HIS_VNR   0x14
+#define ISAR_HIS_DKEY  0x02
+#define ISAR_HIS_FIRM  0x1e
+#define ISAR_HIS_STDSP  0x08
+#define ISAR_HIS_DIAG  0x05
+#define ISAR_HIS_P0CFG 0x3c
+#define ISAR_HIS_P12CFG        0x24
+#define ISAR_HIS_SARTCFG       0x25    
+#define ISAR_HIS_PUMPCFG       0x26    
+#define ISAR_HIS_IOM2CFG       0x27
+#define ISAR_HIS_IOM2REQ       0x07
+#define ISAR_HIS_BSTREQ        0x0c
+#define ISAR_HIS_PSTREQ        0x0e
+#define ISAR_HIS_SDATA 0x20
+#define ISAR_HIS_DPS1  0x40
+#define ISAR_HIS_DPS2  0x80
+#define SET_DPS(x)     ((x<<6) & 0xc0)
+
+#define ISAR_IIS_MSCMSD 0x3f
+#define ISAR_IIS_VNR   0x15
+#define ISAR_IIS_DKEY  0x03
+#define ISAR_IIS_FIRM  0x1f
+#define ISAR_IIS_STDSP  0x09
+#define ISAR_IIS_DIAG  0x25
+#define ISAR_IIS_GSTEV 0x0
+#define ISAR_IIS_BSTEV 0x28
+#define ISAR_IIS_BSTRSP        0x2c
+#define ISAR_IIS_PSTRSP        0x2e
+#define ISAR_IIS_PSTEV 0x2a
+#define ISAR_IIS_IOM2RSP       0x27
+
+#define ISAR_IIS_RDATA 0x20
+#define ISAR_CTRL_SWVER        0x10
+#define ISAR_CTRL_STST 0x40
+
+#define ISAR_MSG_HWVER {0x20, 0, 1}
+
+#define ISAR_DP1_USE   1
+#define ISAR_DP2_USE   2
+
+#define PMOD_BYPASS    7
+
+#define SMODE_DISABLE  0
+#define SMODE_HDLC     3
+#define SMODE_BINARY   4
+
+#define HDLC_FED       0x40
+#define HDLC_FSD       0x20
+#define HDLC_FST       0x20
+#define HDLC_ERROR     0x1c
+
+#define BSTAT_RDM0     0x1
+#define BSTAT_RDM1     0x2
+#define BSTAT_RDM2     0x4
+#define BSTAT_RDM3     0x8
+
+
+extern int ISARVersion(struct IsdnCardState *cs, char *s);
+extern int isar_load_firmware(struct IsdnCardState *cs, u_char *buf);
+extern void isar_int_main(struct IsdnCardState *cs);
+extern void initisar(struct IsdnCardState *cs);
+extern void isar_fill_fifo(struct BCState *bcs);
index b249b2c479c2d8afdb98935e4dff0205b9debfc4..5433d35919075a76234a9629e94ab6af47d8832a 100644 (file)
@@ -1,9 +1,13 @@
-/* $Id: isdnl1.c,v 2.18 1998/02/12 23:07:42 keil Exp $
+/* $Id: isdnl1.c,v 2.31 1998/11/15 23:54:56 keil Exp $
 
  * isdnl1.c     common low level stuff for Siemens Chipsetbased isdn cards
  *              based on the teles driver from Jan den Ouden
  *
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
+ *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
  *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
  *
  * $Log: isdnl1.c,v $
+ * Revision 2.31  1998/11/15 23:54:56  keil
+ * changes from 2.0
+ *
+ * Revision 2.30  1998/09/30 22:27:00  keil
+ * Add init of l1.Flags
+ *
+ * Revision 2.29  1998/09/27 23:54:43  keil
+ * cosmetics
+ *
+ * Revision 2.28  1998/09/27 12:52:23  keil
+ * Fix against segfault, if the driver cannot allocate an IRQ channel
+ *
+ * Revision 2.27  1998/08/13 23:36:39  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.26  1998/07/15 15:01:31  calle
+ * Support for AVM passive PCMCIA cards:
+ *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
+ *
+ * Revision 2.25  1998/05/25 14:10:09  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.24  1998/05/25 12:58:04  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.22  1998/04/15 16:40:13  keil
+ * Add S0Box and Teles PCI support
+ * Fix cardnr overwrite bug
+ *
+ * Revision 2.21  1998/04/10 10:35:28  paul
+ * fixed (silly?) warnings from egcs on Alpha.
+ *
+ * Revision 2.20  1998/03/09 23:19:27  keil
+ * Changes for PCMCIA
+ *
  * Revision 2.18  1998/02/12 23:07:42  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
  *
  */
 
-const char *l1_revision = "$Revision: 2.18 $";
+const char *l1_revision = "$Revision: 2.31 $";
 
 #define __NO_VERSION__
 #include <linux/config.h>
 #include "hisax.h"
 #include "isdnl1.h"
-#include <linux/kernel_stat.h>
-#if (LINUX_VERSION_CODE < 0x020150) /* 2.1.80 */
-#define kstat_irqs( PAR ) kstat.interrupts( (PAR) )
-#endif
-
-
-
-#if CARD_TELES0
-extern int setup_teles0(struct IsdnCard *card);
-#endif
-
-#if CARD_TELES3
-extern int setup_teles3(struct IsdnCard *card);
-#endif
-
-#if CARD_AVM_A1
-extern int setup_avm_a1(struct IsdnCard *card);
-#endif
-
-#if CARD_ELSA
-extern int setup_elsa(struct IsdnCard *card);
-#endif
-
-#if CARD_IX1MICROR2
-extern int setup_ix1micro(struct IsdnCard *card);
-#endif
-
-#if CARD_DIEHLDIVA
-extern int  setup_diva(struct IsdnCard *card);
-#endif
-
-#if CARD_ASUSCOM
-extern int setup_asuscom(struct IsdnCard *card);
-#endif
-
-#if CARD_TELEINT
-extern int setup_TeleInt(struct IsdnCard *card);
-#endif
-
-#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
-
-#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 || CARD_DBRI
-extern int setup_foreign(struct IsdnCard *card);
-#endif
-
-#if CARD_NICCY
-extern int setup_niccy(struct IsdnCard *card);
-#endif
-
-#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", "DBRI"
-};
+#define TIMER3_VALUE 7000
 
-extern struct IsdnCard cards[];
-extern int nrcards;
-extern char *HiSax_id;
-extern struct IsdnBuffers *tracebuf;
-
-#define TIMER3_VALUE 7
+static
+struct Fsm l1fsm_b =
+{NULL, 0, 0, NULL, NULL};
 
 static
-struct Fsm l1fsm =
+struct Fsm l1fsm_d =
 {NULL, 0, 0, NULL, NULL};
 
 enum {
@@ -187,9 +147,9 @@ enum {
        ST_L1_F8,
 };
 
-#define L1_STATE_COUNT (ST_L1_F8+1)
+#define L1D_STATE_COUNT (ST_L1_F8+1)
 
-static char *strL1State[] =
+static char *strL1DState[] =
 {
        "ST_L1_F2",
        "ST_L1_F3",
@@ -200,8 +160,26 @@ static char *strL1State[] =
        "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,
@@ -219,6 +197,7 @@ enum {
 static char *strL1Event[] =
 {
        "EV_PH_ACTIVATE",
+       "EV_PH_DEACTIVATE",
        "EV_RESET_IND",
        "EV_DEACT_CNF",
        "EV_DEACT_IND",
@@ -231,154 +210,30 @@ static char *strL1Event[] =
        "EV_TIMER3",
 };
 
-/*
- * Find card with given driverId
- */
-static inline struct IsdnCardState
-*hisax_findcard(int driverid)
-{
-       int i;
-
-       for (i = 0; i < nrcards; i++)
-               if (cards[i].cs)
-                       if (cards[i].cs->myid == driverid)
-                               return (cards[i].cs);
-       return (NULL);
-}
-
-int
-HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
-{
-       int count;
-       u_char *p;
-       struct IsdnCardState *csta = hisax_findcard(id);
-
-       if (csta) {
-               for (p = buf, count = 0; count < len; p++, count++) {
-                       if (user)
-                               put_user(*csta->status_read++, p);
-                       else
-                               *p++ = *csta->status_read++;
-                       if (csta->status_read > csta->status_end)
-                               csta->status_read = csta->status_buf;
-               }
-               return count;
-       } else {
-               printk(KERN_ERR
-                "HiSax: if_readstatus called with invalid driverId!\n");
-               return -ENODEV;
-       }
-}
-
-#if ISDN_CTRL_DEBUG
-void
-HiSax_putstatus(struct IsdnCardState *csta, char *buf)
-{
-       long flags;
-       int len, count, i;
-       u_char *p;
-       isdn_ctrl ic;
-
-       save_flags(flags);
-       cli();
-       count = 0;
-       len = strlen(buf);
-
-       if (!csta) {
-               printk(KERN_WARNING "HiSax: No CardStatus for message %s", buf);
-               restore_flags(flags);
-               return;
-       }
-       for (p = buf, i = len; i > 0; i--, p++) {
-               *csta->status_write++ = *p;
-               if (csta->status_write > csta->status_end)
-                       csta->status_write = csta->status_buf;
-               count++;
-       }
-       restore_flags(flags);
-       if (count) {
-               ic.command = ISDN_STAT_STAVAIL;
-               ic.driver = csta->myid;
-               ic.arg = count;
-               csta->iif.statcallb(&ic);
-       }
-}
-#else
-#define KDEBUG_DEF
-#include "../kdebug.h"
-
-static int DbgLineNr=0,DbgSequenzNr=1;
-
 void
-HiSax_putstatus(struct IsdnCardState *csta, char *buf)
+debugl1(struct IsdnCardState *cs, char *fmt, ...)
 {
-       char tmp[512];
+       va_list args;
+       char tmp[8];
        
-       if (DbgLineNr==23)
-               DbgLineNr=0;
-       sprintf(tmp, "%5d %s",DbgSequenzNr++,buf);
-       gput_str(tmp,0,DbgLineNr++);
-}      
-#endif
-
-int
-ll_run(struct IsdnCardState *csta)
-{
-       long flags;
-       isdn_ctrl ic;
-
-       save_flags(flags);
-       cli();
-       ic.driver = csta->myid;
-       ic.command = ISDN_STAT_RUN;
-       csta->iif.statcallb(&ic);
-       restore_flags(flags);
-       return 0;
-}
-
-void
-ll_stop(struct IsdnCardState *csta)
-{
-       isdn_ctrl ic;
-
-       ic.command = ISDN_STAT_STOP;
-       ic.driver = csta->myid;
-       csta->iif.statcallb(&ic);
-       CallcFreeChan(csta);
+       va_start(args, fmt);
+       sprintf(tmp, "Card%d ", cs->cardnr + 1);
+       VHiSax_putstatus(cs, tmp, fmt, args);
+       va_end(args);
 }
 
 static void
-ll_unload(struct IsdnCardState *csta)
-{
-       isdn_ctrl ic;
-
-       ic.command = ISDN_STAT_UNLOAD;
-       ic.driver = csta->myid;
-       csta->iif.statcallb(&ic);
-       if (csta->status_buf)
-               kfree(csta->status_buf);
-       csta->status_read = NULL;
-       csta->status_write = NULL;
-       csta->status_end = NULL;
-       kfree(csta->dlogspace);
-}
-
-void
-debugl1(struct IsdnCardState *cs, char *msg)
-{
-       char tmp[1024], tm[32];
-
-       jiftime(tm, jiffies);
-       sprintf(tmp, "%s Card %d %s\n", tm, cs->cardnr + 1, msg);
-       HiSax_putstatus(cs, tmp);
-}
-
-static void
-l1m_debug(struct FsmInst *fi, char *s)
+l1m_debug(struct FsmInst *fi, char *fmt, ...)
 {
+       va_list args;
        struct PStack *st = fi->userdata;
+       struct IsdnCardState *cs = st->l1.hardware;
+       char tmp[8];
        
-       debugl1(st->l1.hardware, s);
+       va_start(args, fmt);
+       sprintf(tmp, "Card%d ", cs->cardnr + 1);
+       VHiSax_putstatus(cs, tmp, fmt, args);
+       va_end(args);
 }
 
 void
@@ -389,9 +244,9 @@ L1activated(struct IsdnCardState *cs)
        st = cs->stlist;
        while (st) {
                if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
-                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+                       st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
                else
-                       st->l1.l1man(st, PH_ACTIVATE_IND, NULL);
+                       st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL);
                st = st->next;
        }
 }
@@ -404,8 +259,8 @@ L1deactivated(struct IsdnCardState *cs)
        st = cs->stlist;
        while (st) {
                if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
-                       st->l1.l1l2(st, PH_PAUSE_CNF, NULL);
-               st->l1.l1man(st, PH_DEACTIVATE_IND, NULL);
+                       st->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);
@@ -422,7 +277,7 @@ DChannel_proc_xmt(struct IsdnCardState *cs)
        stptr = cs->stlist;
        while (stptr != NULL)
                if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
-                       stptr->l1.l1l2(stptr, PH_PULL_CNF, NULL);
+                       stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL);
                        break;
                } else
                        stptr = stptr->next;
@@ -434,7 +289,6 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
        struct sk_buff *skb, *nskb;
        struct PStack *stptr = cs->stlist;
        int found, tei, sapi;
-       char tmp[64];
 
        if (stptr)
                if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags))
@@ -448,16 +302,15 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
                sapi = skb->data[0] >> 2;
                tei = skb->data[1] >> 1;
 
+               if (cs->debug & DEB_DLOG_HEX)
+                       LogFrame(cs, skb->data, skb->len);
+               if (cs->debug & DEB_DLOG_VERBOSE)
+                       dlogframe(cs, skb, 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");
-                               }
+                       if (sapi == CTRL_SAPI) { /* sapi 0 */
                                while (stptr != NULL) {
                                        if ((nskb = skb_clone(skb, GFP_ATOMIC)))
-                                               stptr->l1.l1l2(stptr, PH_DATA_IND, nskb);
+                                               stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb);
                                        else
                                                printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
                                        stptr = stptr->next;
@@ -465,37 +318,24 @@ DChannel_proc_rcv(struct IsdnCardState *cs)
                        } else if (sapi == TEI_SAPI) {
                                while (stptr != NULL) {
                                        if ((nskb = skb_clone(skb, GFP_ATOMIC)))
-                                               stptr->l1.l1tei(stptr, PH_DATA_IND, nskb);
+                                               stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb);
                                        else
                                                printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n");
                                        stptr = stptr->next;
                                }
                        }
                        dev_kfree_skb(skb);
-               } else if (sapi == CTRL_SAPI) {
+               } else if (sapi == CTRL_SAPI) { /* sapi 0 */
                        found = 0;
                        while (stptr != NULL)
                                if (tei == stptr->l2.tei) {
-                                       stptr->l1.l1l2(stptr, PH_DATA_IND, skb);
+                                       stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb);
                                        found = !0;
                                        break;
                                } else
                                        stptr = stptr->next;
-                       if (!found) {
-                               /* BD 10.10.95
-                                * Print out D-Channel msg not processed
-                                * by isdn4linux
-                                */
-
-                               if ((!(skb->data[0] >> 2)) && (!(skb->data[2] & 0x01))) {
-                                       sprintf(tmp,
-                                               "Q.931 frame network->user with tei %d (not for us)",
-                                               skb->data[1] >> 1);
-                                       LogFrame(cs, skb->data, skb->len);
-                                       dlogframe(cs, skb->data + 4, skb->len - 4, tmp);
-                               }
+                       if (!found)
                                dev_kfree_skb(skb);
-                       }
                }
        }
 }
@@ -505,14 +345,18 @@ BChannel_proc_xmt(struct BCState *bcs)
 {
        struct PStack *st = bcs->st;
 
-       if (test_bit(BC_FLG_BUSY, &bcs->Flag))
+       if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
+               debugl1(bcs->cs, "BC_BUSY Error");
                return;
+       }
 
        if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
-               st->l1.l1l2(st, PH_PULL_CNF, NULL);
-       if (!test_bit(BC_FLG_ACTIV, &bcs->Flag))
-               if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue)))
-                       st->ma.manl1(st, PH_DEACTIVATE_CNF, 0);
+               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);
+               }
+       }
 }
 
 static void
@@ -520,8 +364,12 @@ BChannel_proc_rcv(struct BCState *bcs)
 {
        struct sk_buff *skb;
 
+       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);
+       }
        while ((skb = skb_dequeue(&bcs->rqueue))) {
-               bcs->st->l1.l1l2(bcs->st, PH_DATA_IND, skb);
+               bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb);
        }
 }
 
@@ -581,443 +429,6 @@ init_bcstate(struct IsdnCardState *cs,
        bcs->Flag = 0;
 }
 
-static void
-closecard(int cardnr)
-{
-       struct IsdnCardState *csta = cards[cardnr].cs;
-       struct sk_buff *skb;
-       
-       if (csta->bcs->BC_Close != NULL) { 
-               csta->bcs->BC_Close(csta->bcs + 1);
-               csta->bcs->BC_Close(csta->bcs);
-       }
-
-       if (csta->rcvbuf) {
-               kfree(csta->rcvbuf);
-               csta->rcvbuf = NULL;
-       }
-       while ((skb = skb_dequeue(&csta->rq))) {
-               dev_kfree_skb(skb);
-       }
-       while ((skb = skb_dequeue(&csta->sq))) {
-               dev_kfree_skb(skb);
-       }
-       if (csta->tx_skb) {
-               dev_kfree_skb(csta->tx_skb);
-               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);
-}
-
-HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
-{
-       int irq_cnt, cnt = 3;
-       long flags;
-
-       save_flags(flags);
-       cli();
-       irq_cnt = kstat_irqs(cs->irq);
-       printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq,
-               irq_cnt);
-       if (cs->cardmsg(cs, CARD_SETIRQ, NULL)) {
-               printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
-                       cs->irq);
-               return(1);
-       }
-       while (cnt) {
-               cs->cardmsg(cs, CARD_INIT, NULL);
-               sti();
-               current->state = TASK_INTERRUPTIBLE;
-               /* Timeout 10ms */
-               schedule_timeout((10 * HZ) / 1000);
-               restore_flags(flags);
-               printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
-                       cs->irq, kstat_irqs(cs->irq));
-               if (kstat_irqs(cs->irq) == irq_cnt) {
-                       printk(KERN_WARNING
-                              "%s: IRQ(%d) getting no interrupts during init %d\n",
-                              CardType[cs->typ], cs->irq, 4 - cnt);
-                       if (cnt == 1) {
-                               free_irq(cs->irq, cs);
-                               return (2);
-                       } else {
-                               cs->cardmsg(cs, CARD_RESET, NULL);
-                               cnt--;
-                       }
-               } else {
-                       cs->cardmsg(cs, CARD_TEST, NULL);
-                       return(0);
-               }
-       }
-       restore_flags(flags);
-       return(3);
-}
-
-HISAX_INITFUNC(static int
-checkcard(int cardnr, char *id, int *busy_flag))
-{
-       long flags;
-       int ret = 0;
-       struct IsdnCard *card = cards + cardnr;
-       struct IsdnCardState *cs;
-
-       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);
-       }
-       card->cs = cs;
-       cs->cardnr = cardnr;
-       cs->debug = L1_DEB_WARN;
-       cs->HW_Flags = 0;
-       cs->busy_flag = busy_flag;
-#if TEI_PER_CARD
-#else
-       test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#endif
-       cs->protocol = card->protocol;
-
-       if ((card->typ > 0) && (card->typ < 31)) {
-               if (!((1 << card->typ) & SUPORTED_CARDS)) {
-                       printk(KERN_WARNING
-                            "HiSax: Support for %s Card not selected\n",
-                              CardType[card->typ]);
-                       restore_flags(flags);
-                       return (0);
-               }
-       } else {
-               printk(KERN_WARNING
-                      "HiSax: Card Type %d out of range\n",
-                      card->typ);
-               restore_flags(flags);
-               return (0);
-       }
-       if (!(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 (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
-               printk(KERN_WARNING
-                      "HiSax: No memory for status_buf(card %d)\n",
-                      cardnr + 1);
-               kfree(cs->dlogspace);
-               restore_flags(flags);
-               return (0);
-       }
-       cs->stlist = NULL;
-       cs->dlogflag = 0;
-       cs->mon_tx = NULL;
-       cs->mon_rx = NULL;
-       cs->status_read = cs->status_buf;
-       cs->status_write = cs->status_buf;
-       cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
-       cs->typ = card->typ;
-       strcpy(cs->iif.id, id);
-       cs->iif.channels = 2;
-       cs->iif.maxbufsize = MAX_DATA_SIZE;
-       cs->iif.hl_hdrlen = MAX_HEADER_LEN;
-       cs->iif.features =
-           ISDN_FEATURE_L2_X75I |
-           ISDN_FEATURE_L2_HDLC |
-           ISDN_FEATURE_L2_TRANS |
-           ISDN_FEATURE_L3_TRANS |
-#ifdef CONFIG_HISAX_1TR6
-           ISDN_FEATURE_P_1TR6 |
-#endif
-#ifdef CONFIG_HISAX_EURO
-           ISDN_FEATURE_P_EURO |
-#endif
-#ifdef        CONFIG_HISAX_NI1
-           ISDN_FEATURE_P_NI1 |
-#endif
-           0;
-
-       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", cs->iif.id, cs->myid);
-       switch (card->typ) {
-#if CARD_TELES0
-               case ISDN_CTYPE_16_0:
-               case ISDN_CTYPE_8_0:
-                       ret = setup_teles0(card);
-                       break;
-#endif
-#if CARD_TELES3
-               case ISDN_CTYPE_16_3:
-               case ISDN_CTYPE_PNP:
-               case ISDN_CTYPE_TELESPCMCIA:
-               case ISDN_CTYPE_COMPAQ_ISA:
-                       ret = setup_teles3(card);
-                       break;
-#endif
-#if CARD_AVM_A1
-               case ISDN_CTYPE_A1:
-                       ret = setup_avm_a1(card);
-                       break;
-#endif
-#if CARD_ELSA
-               case ISDN_CTYPE_ELSA:
-               case ISDN_CTYPE_ELSA_PNP:
-               case ISDN_CTYPE_ELSA_PCMCIA:
-               case ISDN_CTYPE_ELSA_PCI:
-                       ret = setup_elsa(card);
-                       break;
-#endif
-#if CARD_IX1MICROR2
-               case ISDN_CTYPE_IX1MICROR2:
-                       ret = setup_ix1micro(card);
-                       break;
-#endif
-#if CARD_DIEHLDIVA
-               case ISDN_CTYPE_DIEHLDIVA:
-                       ret = setup_diva(card);
-                       break;
-#endif
-#if CARD_ASUSCOM
-               case ISDN_CTYPE_ASUSCOM:
-                       ret = setup_asuscom(card);
-                       break;
-#endif
-#if CARD_TELEINT
-               case ISDN_CTYPE_TELEINT:
-                       ret = setup_TeleInt(card);
-                       break;
-#endif
-#if CARD_SEDLBAUER
-               case ISDN_CTYPE_SEDLBAUER:
-               case ISDN_CTYPE_SEDLBAUER_PCMCIA:
-                       ret = setup_sedlbauer(card);
-                       break;
-#endif
-#if CARD_SPORTSTER
-               case ISDN_CTYPE_SPORTSTER:
-                       ret = setup_sportster(card);
-                       break;
-#endif
-#if CARD_MIC
-               case ISDN_CTYPE_MIC:
-                       ret = setup_mic(card);
-                       break;
-#endif
-#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 || CARD_DBRI
-               case ISDN_CTYPE_AMD7930:
-               case ISDN_CTYPE_DBRI:
-                       ret = setup_foreign(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(cs, cs->protocol);
-       CallcNewChan(cs);
-       ll_run(cs);
-       cs->l1cmd(cs, PH_RESET_REQ, NULL);
-       restore_flags(flags);
-       return (1);
-}
-
-HISAX_INITFUNC(void
-HiSax_shiftcards(int idx))
-{
-       int i;
-
-       for (i = idx; i < 15; i++)
-               memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
-}
-
-HISAX_INITFUNC(int
-HiSax_inithardware(int *busy_flag))
-{
-       int foundcards = 0;
-       int i = 0;
-       int t = ',';
-       int flg = 0;
-       char *id;
-       char *next_id = HiSax_id;
-       char ids[20];
-
-       if (strchr(HiSax_id, ','))
-               t = ',';
-       else if (strchr(HiSax_id, '%'))
-               t = '%';
-
-       while (i < nrcards) {
-               if (cards[i].typ < 1)
-                       break;
-               id = next_id;
-               if ((next_id = strchr(id, t))) {
-                       *next_id++ = 0;
-                       strcpy(ids, id);
-                       flg = i + 1;
-               } else {
-                       next_id = id;
-                       if (flg >= i)
-                               strcpy(ids, id);
-                       else
-                               sprintf(ids, "%s%d", id, i);
-               }
-               if (checkcard(i, ids, busy_flag)) {
-                       foundcards++;
-                       i++;
-               } else {
-                       printk(KERN_WARNING "HiSax: Card %s not installed !\n",
-                              CardType[cards[i].typ]);
-                       if (cards[i].cs)
-                               kfree((void *) cards[i].cs);
-                       cards[i].cs = NULL;
-                       HiSax_shiftcards(i);
-               }
-       }
-       return foundcards;
-}
-
-void
-HiSax_closehardware(void)
-{
-       int i;
-       long flags;
-
-       save_flags(flags);
-       cli();
-       for (i = 0; i < nrcards; i++)
-               if (cards[i].cs) {
-                       ll_stop(cards[i].cs);
-                       release_tei(cards[i].cs);
-                       closecard(i);
-                       free_irq(cards[i].cs->irq, cards[i].cs);
-                       kfree((void *) cards[i].cs);
-                       cards[i].cs = NULL;
-               }
-       Isdnl1Free();
-       TeiFree();
-       Isdnl2Free();
-       CallcFree();
-       restore_flags(flags);
-}
-
-void
-HiSax_reportcard(int cardnr)
-{
-       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[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 */
 
 char *
@@ -1052,7 +463,7 @@ l2cmd(u_char cmd)
        }
 }
 
-static char tmp[20];
+static char tmpdeb[32];
 
 char *
 l2frames(u_char * ptr)
@@ -1061,7 +472,7 @@ l2frames(u_char * ptr)
                case 1:
                case 5:
                case 9:
-                       sprintf(tmp, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1);
+                       sprintf(tmpdeb, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1);
                        break;
                case 0x6f:
                case 0x0f:
@@ -1070,36 +481,33 @@ l2frames(u_char * ptr)
                case 0x63:
                case 0x87:
                case 0xaf:
-                       sprintf(tmp, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4);
+                       sprintf(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4);
                        break;
                default:
                        if (!(ptr[2] & 1)) {
-                               sprintf(tmp, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1);
+                               sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1);
                                break;
                        } else
                                return "invalid command";
        }
 
 
-       return tmp;
+       return tmpdeb;
 }
 
 void
 Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir)
 {
-       char tmp[132];
        u_char *ptr;
 
        ptr = skb->data;
 
        if (ptr[0] & 1 || !(ptr[1] & 1))
-               debugl1(cs, "Addres not LAPD");
-       else {
-               sprintf(tmp, "%s %s: %s%c (sapi %d, tei %d)",
+               debugl1(cs, "Address not LAPD");
+       else
+               debugl1(cs, "%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(cs, tmp);
-       }
 }
 #endif
 
@@ -1113,11 +521,10 @@ static void
 l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct IsdnCardState *cs = st->l1.hardware;
 
        FsmChangeState(fi, ST_L1_F3);
        if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
-               cs->l1cmd(cs, PH_ENABLE_REQ, NULL);
+               st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
 }
 
 static void
@@ -1126,24 +533,23 @@ 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)) {
+//     if (!test_bit(FLG_L1_T3RUN, &st->l1.Flags)) {
                FsmDelTimer(&st->l1.timer, 1);
                FsmAddTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
                test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
-       }
+//     }
 }
 
 static void
 l1_power_up(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct IsdnCardState *cs = st->l1.hardware;
 
        if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
                FsmChangeState(fi, ST_L1_F4);
-               cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+               st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
                FsmDelTimer(&st->l1.timer, 1);
-               FsmAddTimer(&st->l1.timer, TIMER3_VALUE * HZ, EV_TIMER3, NULL, 2);
+               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);
@@ -1165,20 +571,18 @@ static void
 l1_info2_ind(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct IsdnCardState *cs = st->l1.hardware;
 
        FsmChangeState(fi, ST_L1_F6);
-       cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+       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;
-       struct IsdnCardState *cs = st->l1.hardware;
 
        FsmChangeState(fi, ST_L1_F7);
-       cs->l1cmd(cs, PH_INFO3_REQ, NULL);
+       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)) {
@@ -1193,50 +597,61 @@ static void
 l1_timer3(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct IsdnCardState *cs = st->l1.hardware;
-       
+
        test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);        
-        if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
-               L1deactivated(cs);
-        if (st->l1.l1m.state != ST_L1_F6)
-               FsmChangeState(fi, ST_L1_F3);
+       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;
-       struct IsdnCardState *cs = st->l1.hardware;
        
        test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
        test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
-       L1activated(cs);
+       L1activated(st->l1.hardware);
 }
 
 static void
 l1_timer_deact(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       struct IsdnCardState *cs = st->l1.hardware;
        
        test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
        test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
-       L1deactivated(cs);
-       cs->l1cmd(cs, PH_DEACT_ACK, NULL);
+       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;
-       struct IsdnCardState *cs = st->l1.hardware;
                 
-       cs->l1cmd(cs, PH_RESET_REQ, NULL);
+       st->l1.l1hw(st, HW_RESET | REQUEST, NULL);
 }
 
-static struct FsmNode L1FnList[] HISAX_INITDATA =
+static void
+l1_activate_no(struct FsmInst *fi, int event, void *arg)
+{
+       struct PStack *st = fi->userdata;
+
+       if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) {
+               test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
+               L1deactivated(st->l1.hardware);
+       }
+}
+
+static struct FsmNode L1DFnList[] HISAX_INITDATA =
 {
        {ST_L1_F3, EV_PH_ACTIVATE, l1_activate},
+       {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
+       {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},
        {ST_L1_F3, EV_RESET_IND, l1_reset},
        {ST_L1_F4, EV_RESET_IND, l1_reset},
        {ST_L1_F5, EV_RESET_IND, l1_reset},
@@ -1280,86 +695,159 @@ static struct FsmNode L1FnList[] HISAX_INITDATA =
        {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
 };
 
-#define L1_FN_COUNT (sizeof(L1FnList)/sizeof(struct FsmNode))
+#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.state_count = L1_STATE_COUNT;
-       l1fsm.event_count = L1_EVENT_COUNT;
-       l1fsm.strEvent = strL1Event;
-       l1fsm.strState = strL1State;
-       FsmNew(&l1fsm, L1FnList, L1_FN_COUNT);
+       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);
+       FsmFree(&l1fsm_d);
+       FsmFree(&l1fsm_b);
 }
 
 static void
-dch_manl1(struct PStack *st, int pr,
-          void *arg)
+dch_l2l1(struct PStack *st, int pr, void *arg)
 {
        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
-       char tmp[32];
 
        switch (pr) {
-               case PH_ACTIVATE_REQ:
-                       if (cs->debug) {
-                               sprintf(tmp, "PH_ACTIVATE_REQ %s",
-                                       strL1State[st->l1.l1m.state]);
-                               debugl1(cs, tmp);
-                       }
+               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)
+                               debugl1(cs, "PH_ACTIVATE_REQ %s",
+                                       strL1DState[st->l1.l1m.state]);
                        if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
-                               st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
+                               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_DEACTIVATE_REQ:
-                       if (cs->debug) {
-                               sprintf(tmp, "PH_DEACTIVATE_REQ %s",
-                                       strL1State[st->l1.l1m.state]);
-                               debugl1(cs, tmp);
-                       }
-                       break;
-               case PH_TESTLOOP_REQ:
-                       if (1 & (int) arg)
+               case (PH_TESTLOOP | REQUEST):
+                       if (1 & (long) arg)
                                debugl1(cs, "PH_TEST_LOOP B1");
-                       if (2 & (int) arg)
+                       if (2 & (long) arg)
                                debugl1(cs, "PH_TEST_LOOP B2");
-                       if (!(3 & (int) arg))
+                       if (!(3 & (long) arg))
                                debugl1(cs, "PH_TEST_LOOP DISABLED");
-                       cs->l1cmd(cs, PH_TESTLOOP_REQ, arg);
-                       break;
-               case PH_RESET_IND:
-                       FsmEvent(&st->l1.l1m, EV_RESET_IND, arg);
-                       break;
-               case PH_DEACT_CNF:
-                       FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg);
-                       break;
-               case PH_DEACT_IND:
-                       FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg);
+                       st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
                        break;
-               case PH_POWERUP_CNF:
-                       FsmEvent(&st->l1.l1m, EV_POWER_UP, arg);
-                       break;
-               case PH_RSYNC_IND:
-                       FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg);
-                       break;
-               case PH_INFO2_IND:
-                       FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg);
+               default:
+                       if (cs->debug)
+                               debugl1(cs, "dch_l2l1 msg %04X unhandled", pr);
                        break;
-               case PH_I4_P8_IND:
-               case PH_I4_P10_IND:
-                       FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg);
+       }
+}
+
+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)
+                                       debugl1(cs, "l1msg %04X unhandled", pr);
+                               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;
-               default:
-                       if (cs->debug) {
-                               sprintf(tmp, "dch_manl1 msg %04X unhandled", pr);
-                               debugl1(cs, tmp);
-                       }
+               case (PH_DEACTIVATE | REQUEST):
+                       FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL);
                        break;
        }
 }
@@ -1369,7 +857,7 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
 {
        st->l1.hardware = cs;
        st->protocol = cs->protocol;
-       st->l1.l1m.fsm = &l1fsm;
+       st->l1.l1m.fsm = &l1fsm_d;
        st->l1.l1m.state = ST_L1_F3;
        st->l1.l1m.debug = cs->debug;
        st->l1.l1m.userdata = st;
@@ -1379,7 +867,22 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
        setstack_tei(st);
        setstack_manager(st);
        st->l1.stlistp = &(cs->stlist);
-       st->ma.manl1 = dch_manl1;
+       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;
+       st->l1.Flags = 0;
+       FsmInitTimer(&st->l1.l1m, &st->l1.timer);
+}
index 71f081a07ed9ab2c5276aff8f7fc0c76b99deec3..01a96b7dd1a3e7d7c1ae0ac0747bb2e49dd48ea7 100644 (file)
@@ -1,6 +1,16 @@
-/* $Id: isdnl1.h,v 2.5 1998/02/02 13:36:58 keil Exp $
+/* $Id: isdnl1.h,v 2.8 1998/11/15 23:54:59 keil Exp $
 
  * $Log: isdnl1.h,v $
+ * Revision 2.8  1998/11/15 23:54:59  keil
+ * changes from 2.0
+ *
+ * Revision 2.7  1998/09/30 22:21:55  keil
+ * cosmetics
+ *
+ * Revision 2.6  1998/05/25 12:58:06  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
  * Revision 2.5  1998/02/02 13:36:58  keil
  * more debug
  *
  *
  */
 
-
-#define L2FRAME_DEBUG
-
-/* DEBUG Level */
-
-#define        L1_DEB_WARN             0x01
-#define        L1_DEB_INTSTAT          0x02
-#define        L1_DEB_ISAC             0x04
-#define        L1_DEB_ISAC_FIFO        0x08
-#define        L1_DEB_HSCX             0x10
-#define        L1_DEB_HSCX_FIFO        0x20
-#define        L1_DEB_LAPD             0x40
-#define        L1_DEB_IPAC             0x80
-#define        L1_DEB_RECEIVE_FRAME    0x100
-
 #define D_RCVBUFREADY  0
 #define D_XMTBUFREADY  1
 #define D_L1STATECHANGE        2
 #define B_RCVBUFREADY 0
 #define B_XMTBUFREADY 1
 
-extern void debugl1(struct IsdnCardState *sp, char *msg);
+extern void debugl1(struct IsdnCardState *cs, char *fmt, ...);
 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);
+extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir);
 #endif
index 824ba16c343978282a290f44abd28de785d650be..ccef2682e6aa3b8d858c4d5efa6d6d483a14d308 100644 (file)
@@ -1,12 +1,42 @@
-/* $Id: isdnl2.c,v 2.7 1998/02/12 23:07:47 keil Exp $
+/* $Id: isdnl2.c,v 2.16 1998/11/15 23:55:01 keil Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
+ *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: isdnl2.c,v $
+ * Revision 2.16  1998/11/15 23:55:01  keil
+ * changes from 2.0
+ *
+ * Revision 2.15  1998/08/13 23:36:42  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.14  1998/06/19 15:19:18  keil
+ * fix LAPB tx_cnt for none I-frames
+ *
+ * Revision 2.13  1998/06/18 23:17:20  keil
+ * LAPB bugfix
+ *
+ * Revision 2.12  1998/05/25 14:10:12  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.11  1998/05/25 12:58:08  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.9  1998/04/10 10:35:30  paul
+ * fixed (silly?) warnings from egcs on Alpha.
+ *
+ * Revision 2.8  1998/03/07 22:57:04  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 2.7  1998/02/12 23:07:47  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -25,7 +55,7 @@
  * Old stuff is still in the separate branch.
  *
  * Revision 2.2  1997/07/31 11:49:05  keil
- * Eroor handling for no TEI assign
+ * Error handling for no TEI assign
  *
  * Revision 2.1  1997/07/27 21:34:38  keil
  * cosmetics
@@ -41,9 +71,9 @@
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 2.7 $";
+const char *l2_revision = "$Revision: 2.16 $";
 
-static void l2m_debug(struct FsmInst *fi, char *s);
+static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
 
 static
 struct Fsm l2fsm =
@@ -91,7 +121,6 @@ enum {
        EV_L2_MDL_ASSIGN,
        EV_L2_MDL_REMOVE,
        EV_L2_MDL_ERROR,
-       EV_L2_MDL_NOTEIPROC,
        EV_L1_DEACTIVATE,
        EV_L2_T200,
        EV_L2_T203,
@@ -117,7 +146,6 @@ static char *strL2Event[] =
        "EV_L2_MDL_ASSIGN",
        "EV_L2_MDL_REMOVE",
        "EV_L2_MDL_ERROR",
-       "EV_L2_MDL_NOTEIPROC",
        "EV_L1_DEACTIVATE",
        "EV_L2_T200",
        "EV_L2_T203",
@@ -161,26 +189,6 @@ cansend(struct PStack *st)
        return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
 }
 
-static void
-discard_i_queue(struct PStack *st)
-{
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&st->l2.i_queue))) {
-               dev_kfree_skb(skb);
-       }
-}
-
-static void
-discard_ui_queue(struct PStack *st)
-{
-       struct sk_buff *skb;
-
-       while ((skb = skb_dequeue(&st->l2.ui_queue))) {
-               dev_kfree_skb(skb);
-       }
-}
-
 inline void
 clear_exception(struct Layer2 *l2)
 {
@@ -224,20 +232,17 @@ sethdraddr(struct Layer2 *l2, u_char * header, int rsp)
        }
 }
 
-static void
-enqueue_ui(struct PStack *st,
-          struct sk_buff *skb)
-{
-       st->l2.l2l1(st, PH_DATA_REQ, skb);
-}
-
-static void
+inline static void
 enqueue_super(struct PStack *st,
              struct sk_buff *skb)
 {
-       st->l2.l2l1(st, PH_DATA_REQ, skb);
+       if (test_bit(FLG_LAPB, &st->l2.flag))
+               st->l1.bcs->tx_cnt += skb->len;
+       st->l2.l2l1(st, PH_DATA | REQUEST, skb);
 }
 
+#define enqueue_ui(a, b) enqueue_super(a, b)
+
 inline int
 IsUI(u_char * data, int ext)
 {
@@ -271,6 +276,16 @@ IsRR(u_char * data, int ext)
                return ((data[0] & 0xf) == 1);
 }
 
+inline int
+IsSFrame(u_char * data, int ext)
+{
+       register u_char d = *data;
+       
+       if (!ext)
+               d &= 0xf;
+       return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
+}
+
 inline int
 IsSABMX(u_char * data, int ext)
 {
@@ -393,15 +408,15 @@ l2_mdl_error(struct FsmInst *fi, int event, void *arg)
        switch (event) {
                case EV_L2_UA:
                        if (get_PollFlagFree(st, skb))
-                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'C');
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C');
                        else
-                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'D');
+                               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_IND, (void *) 'B');
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
                        else {
-                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'E');
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
                                establishlink(fi);
                                test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
                        }
@@ -415,9 +430,16 @@ 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_IND, NULL);
+       
+       if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
+               FsmChangeState(fi, ST_L2_4);
+               establishlink(fi);
+               test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
+       } else {
+               FsmChangeState(fi, ST_L2_3);
+               if (state == ST_L2_1)
+                       st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
+       }
 }
 
 static void
@@ -444,7 +466,7 @@ l2_put_ui(struct FsmInst *fi, int event, void *arg)
        skb_queue_tail(&st->l2.ui_queue, skb);
        if (fi->state == ST_L2_1) {
                FsmChangeState(fi, ST_L2_2);
-               st->l2.l2tei(st, MDL_ASSIGN_IND, NULL);
+               st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL);
        }
        if (fi->state > ST_L2_3)
                l2_send_ui(st);
@@ -458,10 +480,10 @@ l2_got_ui(struct FsmInst *fi, int event, void *arg)
 
        skb_pull(skb, l2headersize(&st->l2, 1));
        if (skb->len > st->l2.maxlen) { 
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O');
                FreeSkb(skb);
        } else
-               st->l2.l2l3(st, DL_UNIT_DATA, skb);
+               st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb);
 }
 
 static void
@@ -470,7 +492,7 @@ l2_establish(struct FsmInst *fi, int event, void *arg)
        struct PStack *st = fi->userdata;
 
        if (fi->state != ST_L2_4)
-               discard_i_queue(st);
+               discard_queue(&st->l2.i_queue);
        if (fi->state != ST_L2_5)
                establishlink(fi);
        test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
@@ -482,13 +504,13 @@ l2_dl_release(struct FsmInst *fi, int event, void *arg)
        struct PStack *st = fi->userdata;
 
        if (fi->state == ST_L2_4) {
-               st->l2.l2man(st, DL_RELEASE, NULL);
+               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_i_queue(st);
+       discard_queue(&st->l2.i_queue);
        FsmChangeState(fi, ST_L2_6);
        st->l2.rc = 0;
        send_uframe(st, DISC | 0x10, CMD);
@@ -510,14 +532,14 @@ l2_got_SABMX(struct FsmInst *fi, int event, void *arg)
        if (test_bit(FLG_ORIG, &st->l2.flag))
                rsp = !rsp;
        if (rsp) {
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               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_IND, (void *) 'N');
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
                FreeSkb(skb);
                if ((state == ST_L2_7) || (state == ST_L2_8))
                        establishlink(fi);
@@ -532,9 +554,9 @@ l2_got_SABMX(struct FsmInst *fi, int event, void *arg)
        if (ST_L2_5 == state)
                return;
        if (ST_L2_4 != state) {
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'F');
+               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;
@@ -547,14 +569,14 @@ l2_got_SABMX(struct FsmInst *fi, int event, void *arg)
        FsmChangeState(fi, ST_L2_7);
        if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
                FsmDelTimer(&st->l2.t200, 2);
-       FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3);
+       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_PULL_REQ, NULL);
+                       st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -571,14 +593,14 @@ l2_got_disconn(struct FsmInst *fi, int event, void *arg)
                rsp = !rsp;
 
        if (rsp) {
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               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_IND, (void *) 'N');
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
                FreeSkb(skb);
                if ((state == ST_L2_7) || (state == ST_L2_8))
                        establishlink(fi);
@@ -600,8 +622,11 @@ l2_got_disconn(struct FsmInst *fi, int event, void *arg)
                        FsmDelTimer(&st->l2.t200, 2);
        }
        send_uframe(st, cmd | PollFlag, RSP);
-       if (rel)
-               st->l2.l2man(st, DL_RELEASE, NULL);
+       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);
+       }
 }
 
 
@@ -610,7 +635,8 @@ l2_got_ua(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
-       u_char PollFlag, est = 1;
+       int pr=-1;
+       u_char PollFlag;
        int state,rsp;
 
        state = fi->state;
@@ -619,14 +645,14 @@ l2_got_ua(struct FsmInst *fi, int event, void *arg)
                rsp = !rsp;
 
        if (!rsp) {
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               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_IND, (void *) 'N');
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
                FreeSkb(skb);
                if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
                        establishlink(fi);
@@ -643,30 +669,31 @@ l2_got_ua(struct FsmInst *fi, int event, void *arg)
                FsmDelTimer(&st->l2.t200, 2);
        if (fi->state == ST_L2_5) {
                if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) {
-                       discard_i_queue(st);
+                       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)) {
-                               if (st->l2.vs != st->l2.va)
-                                       discard_i_queue(st);
-                               else
-                                       est = 0;
+                       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);
-                       FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4);
-                       if (est)
-                               st->l2.l2man(st, DL_ESTABLISH, NULL);
+                       if (pr > -1)
+                               st->l2.l2l3(st, pr, NULL);
                }
        } else {                /* ST_L2_6 */
-               st->l2.l2man(st, DL_RELEASE, NULL);
+               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);
        }
 }
@@ -685,14 +712,14 @@ l2_got_dm(struct FsmInst *fi, int event, void *arg)
                rsp = !rsp;
 
        if (!rsp) {
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               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_IND, (void *) 'N');
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
                FreeSkb(skb);
                if ((fi->state == ST_L2_7) || (fi->state == ST_L2_8))
                        establishlink(fi);
@@ -700,15 +727,41 @@ l2_got_dm(struct FsmInst *fi, int event, void *arg)
        }
        PollFlag = get_PollFlagFree(st, skb);
        if (!PollFlag) {
-               establishlink(fi);
-               test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
+               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_7) || (fi->state == ST_L2_8)) {
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E');
+                       establishlink(fi);
+               }
        } else {
-               if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
-                       FsmDelTimer(&st->l2.t200, 2);
-               if (fi->state == ST_L2_5 && !test_bit(FLG_L3_INIT, &st->l2.flag))
-                       discard_i_queue(st);
-               st->l2.l2man(st, DL_RELEASE, NULL);
-               FsmChangeState(fi, ST_L2_4);
+               switch (fi->state) {
+                       case ST_L2_8:
+                                establishlink(fi);
+                       case ST_L2_7:
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B');
+                               break;
+                       case ST_L2_4:
+                               break;
+                       case ST_L2_5:
+                               if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+                                       FsmDelTimer(&st->l2.t200, 2);
+                               discard_queue(&st->l2.i_queue);
+                               if (test_bit(FLG_LAPB, &st->l2.flag))
+                                       st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+                               st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
+                               FsmChangeState(fi, ST_L2_4);
+                               break;
+                       case ST_L2_6:
+                               if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
+                                       FsmDelTimer(&st->l2.t200, 2);
+                               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);
+                               break;
+               }
        }
 }
 
@@ -763,7 +816,7 @@ nrerrorrecovery(struct FsmInst *fi)
 {
        struct PStack *st = fi->userdata;
 
-       st->ma.layer(st, MDL_ERROR_IND, (void *) 'J');
+       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J');
        establishlink(fi);
 }
 
@@ -785,11 +838,13 @@ invoke_retransmission(struct PStack *st, int nr)
                        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_REQ, NULL);
+               st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
        }
 }
 
@@ -818,9 +873,11 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg)
                        PollFlag = (skb->data[1] & 0x1) == 0x1;
                        nr = skb->data[1] >> 1;
                } else {
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       if (skb->len >2) {
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+                               establishlink(fi);
+                       }
                        FreeSkb(skb);
-                       establishlink(fi);
                        return;
                }
        } else {
@@ -828,7 +885,7 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg)
                        PollFlag = (skb->data[0] & 0x10);
                        nr = (skb->data[0] >> 5) & 0x7;
                } else {
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
                        FreeSkb(skb);
                        establishlink(fi);
                        return;
@@ -839,7 +896,7 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg)
        if ((!rsp) && PollFlag)
                enquiry_response(st);
        if (rsp && PollFlag)
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'A');
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A');
        if (legalnr(st, nr)) {
                if (typ == REJ) {
                        setva(st, nr);
@@ -862,13 +919,13 @@ l2_got_st7_super(struct FsmInst *fi, int event, void *arg)
                        test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
                }
                if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
-                       st->l2.l2l1(st, PH_PULL_REQ, NULL);
+                       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);
        }
 }
 
@@ -883,7 +940,7 @@ l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
        if (!((fi->state == ST_L2_5) && test_bit(FLG_L3_INIT, &st->l2.flag)))
                skb_queue_tail(&st->l2.i_queue, skb);
        if (fi->state == ST_L2_7)
-               st->l2.l2l1(st, PH_PULL_REQ, NULL);
+               st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -891,17 +948,15 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
-       struct IsdnCardState *sp = st->l1.hardware;
        struct Layer2 *l2 = &(st->l2);
-       int PollFlag, ns, nr, i, hs, rsp;
-       char str[64];
+       int PollFlag, ns, nr, i, rsp;
 
        rsp = *skb->data & 0x2;
        if (test_bit(FLG_ORIG, &l2->flag))
                rsp = !rsp;
 
        if (rsp) {
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
                FreeSkb(skb);
                establishlink(fi);
                return;
@@ -909,12 +964,10 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
        i = l2addrsize(l2);
        if (test_bit(FLG_MOD128, &l2->flag)) {
                if (skb->len <= (i + 1)) {
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
                        FreeSkb(skb);
-                       establishlink(fi);
                        return;
                } else if ((skb->len - i - 1) > l2->maxlen) { 
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'O');
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O');
                        FreeSkb(skb);
                        establishlink(fi);
                        return;
@@ -924,12 +977,12 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
                nr = (skb->data[i + 1] >> 1) & 0x7f;
        } else {
                if (skb->len <= i) {
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       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_IND, (void *) 'O');
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'O');
                        FreeSkb(skb);
                        establishlink(fi);
                        return;
@@ -944,20 +997,12 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
        } else if (l2->vr == ns) {
                l2->vr = (l2->vr + 1) % (test_bit(FLG_MOD128, &l2->flag) ? 128 : 8);
                test_and_clear_bit(FLG_REJEXC, &l2->flag);
-               if (test_bit(FLG_LAPD, &l2->flag))
-                       if (sp->dlogflag) {
-                               hs = l2headersize(l2, 0);
-                               LogFrame(st->l1.hardware, skb->data, skb->len);
-                               sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
-                               dlogframe(st->l1.hardware, skb->data + hs,
-                                         skb->len - hs, str);
-                       }
                if (PollFlag)
                        enquiry_response(st);
                else
                        test_and_set_bit(FLG_ACK_PEND, &l2->flag);
                skb_pull(skb, l2headersize(l2, 0));
-               st->l2.l2l3(st, DL_DATA, skb);
+               st->l2.l2l3(st, DL_DATA | INDICATION, skb);
        } else {
                /* n(s)!=v(r) */
                FreeSkb(skb);
@@ -990,7 +1035,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
        }
 
        if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
-               st->l2.l2l1(st, PH_PULL_REQ, NULL);
+               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);
 }
@@ -1000,7 +1045,7 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
 
-       st->l2.tei = (int) arg;
+       st->l2.tei = (long) arg;
 
        if (fi->state == ST_L2_3) {
                establishlink(fi);
@@ -1011,12 +1056,6 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg)
                l2_send_ui(st);
 }
 
-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)
 {
@@ -1028,9 +1067,11 @@ l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
        } else if (st->l2.rc == st->l2.N200) {
                FsmChangeState(fi, ST_L2_4);
                test_and_clear_bit(FLG_T200_RUN, &st->l2.flag);
-               discard_i_queue(st);
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'G');
-               st->l2.l2man(st, DL_RELEASE, NULL);
+               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);
@@ -1049,8 +1090,10 @@ l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
                FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9);
        } else if (st->l2.rc == st->l2.N200) {
                FsmChangeState(fi, ST_L2_4);
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'H');
-               st->l2.l2man(st, DL_RELEASE, NULL);
+               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 {
                st->l2.rc++;
                FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200,
@@ -1146,14 +1189,14 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
                memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
                FreeSkb(oskb);
        }
-       st->l2.l2l1(st, PH_PULL_IND, skb);
+       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_PULL_REQ, NULL);
+               st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
 }
 
 static void
@@ -1179,7 +1222,7 @@ l2_got_st8_super(struct FsmInst *fi, int event, void *arg)
                        PollFlag = (skb->data[1] & 0x1) == 0x1;
                        nr = skb->data[1] >> 1;
                } else {
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
                        FreeSkb(skb);
                        establishlink(fi);
                        return;
@@ -1189,7 +1232,7 @@ l2_got_st8_super(struct FsmInst *fi, int event, void *arg)
                        PollFlag = (skb->data[0] & 0x10);
                        nr = (skb->data[0] >> 5) & 0x7;
                } else {
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
                        FreeSkb(skb);
                        establishlink(fi);
                        return;
@@ -1213,10 +1256,10 @@ l2_got_st8_super(struct FsmInst *fi, int event, void *arg)
                        invoke_retransmission(st, nr);
                        FsmChangeState(fi, ST_L2_7);
                        if (skb_queue_len(&l2->i_queue) && cansend(st))
-                               st->l2.l2l1(st, PH_PULL_REQ, 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 {
@@ -1233,30 +1276,25 @@ l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
-       char tmp[64];
 
        skb_pull(skb, l2addrsize(&st->l2) + 1);
        if (test_bit(FLG_MOD128, &st->l2.flag)) {
                if (skb->len < 5)
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
-               else {
-                       sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+               else
+                       l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x",
                                skb->data[0], skb->data[1], skb->data[2],
                                skb->data[3], skb->data[4]);
-                       l2m_debug(&st->l2.l2m, tmp);
-               }
        } else {
                if (skb->len < 3)
-                       st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
-               else {
-                       sprintf(tmp, "FRMR information %2x %2x %2x",
+                       st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'N');
+               else
+                       l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x",
                                skb->data[0], skb->data[1], skb->data[2]);
-                       l2m_debug(&st->l2.l2m, tmp);
-               }
        }
        if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) ||         /* I or S */
            (IsUA(skb->data, 0) && (fi->state == ST_L2_7))) {
-               st->ma.layer(st, MDL_ERROR_IND, (void *) 'K');
+               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K');
                establishlink(fi);
                test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
        }
@@ -1268,14 +1306,14 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
 
-       discard_i_queue(st);
-       discard_ui_queue(st);
+       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.l2man(st, DL_RELEASE, NULL);
+               st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
        FsmChangeState(fi, ST_L2_1);
 }
 
@@ -1283,33 +1321,45 @@ static void
 l2_persistant_da(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
+       int rel = DL_RELEASE | INDICATION;
+       
        
-       discard_i_queue(st);
-       discard_ui_queue(st);
+       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);
-       test_and_clear_bit(FLG_PEND_REL, &st->l2.flag);
        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.l2man(st, DL_RELEASE, NULL);
+                       st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL);
                case ST_L2_2:
                        FsmChangeState(fi, ST_L2_1);
                        break;
-               case ST_L2_5:
                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.l2man(st, DL_RELEASE, NULL);
+                       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[] HISAX_INITDATA =
 {
-       {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2_no_tei},
        {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},
@@ -1359,8 +1409,8 @@ static struct FsmNode L2FnList[] HISAX_INITDATA =
        {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_7, EV_L2_DM, l2_got_dm},
+       {ST_L2_8, EV_L2_DM, l2_got_dm},
        {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},
@@ -1381,6 +1431,7 @@ static struct FsmNode L2FnList[] HISAX_INITDATA =
        {ST_L2_8, EV_L2_T200, l2_st78_tout_200},
        {ST_L2_7, EV_L2_T203, l2_st7_tout_203},
        {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},
@@ -1400,19 +1451,19 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
        int ret = 1, len;
 
        switch (pr) {
-               case (PH_DATA_IND):
+               case (PH_DATA | INDICATION):
                        datap = skb->data;
                        len = l2addrsize(&st->l2);
                        if (skb->len > len)
                                datap += len;
                        else {
-                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'N');
+                               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 ((*datap & 3) == 1)     /* S-Frame */
+                       else if (IsSFrame(datap, test_bit(FLG_MOD128, &st->l2.flag)))
                                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);
@@ -1427,23 +1478,39 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
                        else if (IsFRMR(datap, test_bit(FLG_MOD128, &st->l2.flag)))
                                ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
                        else {
-                               ret = 0;
-                               st->ma.layer(st, MDL_ERROR_IND, (void *) 'L');
-                               FreeSkb(skb);
+                               ret = 1;
+                               if ((st->l2.l2m.state == ST_L2_7) ||
+                                       (st->l2.l2m.state == ST_L2_8))
+                                       establishlink(&st->l2.l2m);
+                               st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'L');
                        }
                        if (ret) {
                                FreeSkb(skb);
                        }
                        break;
-               case (PH_PULL_CNF):
+               case (PH_PULL | CONFIRM):
                        FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
                        break;
-               case (PH_PAUSE_IND):
+               case (PH_PAUSE | INDICATION):
                        test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag);
                        break;
-               case (PH_PAUSE_CNF):
+               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:
+                       l2m_debug(&st->l2.l2m, "l2 unknown pr %04x", pr);
+                       break;
        }
 }
 
@@ -1451,45 +1518,46 @@ 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);
                        }
                        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);
                        }
                        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;
-               case (PH_DEACTIVATE_IND):
-                       FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg);
-                       break;
-               case (MDL_ASSIGN_REQ):
+               case (MDL_ASSIGN | REQUEST):
                        FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
                        break;
-               case (MDL_REMOVE_REQ):
+               case (MDL_REMOVE | REQUEST):
                        FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
                        break;
-               case (MDL_ERROR_REQ):
+               case (MDL_ERROR | RESPONSE):
                        FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg);
                        break;
        }
@@ -1500,20 +1568,20 @@ releasestack_isdnl2(struct PStack *st)
 {
        FsmDelTimer(&st->l2.t200, 15);
        FsmDelTimer(&st->l2.t203, 16);
-       discard_i_queue(st);
-       discard_ui_queue(st);
+       discard_queue(&st->l2.i_queue);
+       discard_queue(&st->l2.ui_queue);
        ReleaseWin(&st->l2);
 }
 
 static void
-l2m_debug(struct FsmInst *fi, char *s)
+l2m_debug(struct FsmInst *fi, char *fmt, ...)
 {
+       va_list args;
        struct PStack *st = fi->userdata;
-       char tm[32], str[256];
 
-       jiftime(tm, jiffies);
-       sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
-       HiSax_putstatus(st->l1.hardware, str);
+       va_start(args, fmt);
+       VHiSax_putstatus(st->l1.hardware, st->l2.debug_id, fmt, args);
+       va_end(args);
 }
 
 void
@@ -1521,7 +1589,6 @@ setstack_isdnl2(struct PStack *st, char *debug_id)
 {
        st->l1.l1l2 = isdnl2_l1l2;
        st->l3.l3l2 = isdnl2_l3l2;
-       st->ma.manl2 = isdnl2_manl2;
 
        skb_queue_head_init(&st->l2.i_queue);
        skb_queue_head_init(&st->l2.ui_queue);
@@ -1529,6 +1596,9 @@ setstack_isdnl2(struct PStack *st, char *debug_id)
        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;
@@ -1540,9 +1610,27 @@ setstack_isdnl2(struct PStack *st, char *debug_id)
        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 | REQUEST, arg);
+                       break;
+               case (DL_ESTABLISH | REQUEST):
+                       st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL);
+                       break;
+               case (DL_RELEASE | REQUEST):
+                       st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL);
+                       break;
+       }
+}
+
 void
 setstack_transl2(struct PStack *st)
 {
+       st->l3.l3l2 = transl2_l3l2;
 }
 
 void
index 026d8eb760f068e7a8bd1a35198d11b27d5cc3c0..4511251e7f0c4a62d328ff5ece96d05feb544499 100644 (file)
@@ -1,12 +1,27 @@
-/* $Id: isdnl3.c,v 2.5 1998/02/12 23:07:52 keil Exp $
+/* $Id: isdnl3.c,v 2.8 1998/11/15 23:55:04 keil Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
+ *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: isdnl3.c,v $
+ * Revision 2.8  1998/11/15 23:55:04  keil
+ * changes from 2.0
+ *
+ * Revision 2.7  1998/05/25 14:10:15  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.6  1998/05/25 12:58:11  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
  * Revision 2.5  1998/02/12 23:07:52  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 2.5 $";
+const char *l3_revision = "$Revision: 2.8 $";
+
+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[] =
+{
+       "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 *fmt, ...)
+{
+       va_list args;
+       struct PStack *st = fi->userdata;
+
+       va_start(args, fmt);
+       VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args);
+       va_end(args);
+}
 
 u_char *
 findie(u_char * p, int size, u_char ie, int wanted_set)
@@ -114,26 +182,12 @@ newcallref(void)
        return (OrigCallRef);
 }
 
-void
-l3_debug(struct PStack *st, char *s)
-{
-       char str[256], tm[32];
-
-       jiftime(tm, jiffies);
-       sprintf(str, "%s l3 %s\n", tm, s);
-       HiSax_putstatus(st->l1.hardware, str);
-}
-
 void
 newl3state(struct l3_process *pc, int state)
 {
-       char tmp[80];
-
-       if (pc->debug & L3_DEB_STATE) {
-               sprintf(tmp, "newstate cr %d %d --> %d", pc->callref,
+       if (pc->debug & L3_DEB_STATE)
+               l3_debug(pc->st, "newstate cr %d %d --> %d", pc->callref,
                        pc->state, state);
-               l3_debug(pc->st, tmp);
-       }
        pc->state = state;
 }
 
@@ -197,7 +251,7 @@ no_l3_proto(struct PStack *st, int pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
-       HiSax_putstatus(st->l1.hardware, "L3 no D protocol\n");
+       HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
        if (skb) {
                dev_kfree_skb(skb);
        }
@@ -277,16 +331,25 @@ release_l3_process(struct l3_process *p)
                pp = np;
                np = np->next;
        }
-       printk(KERN_ERR "HiSax internal L3 error CR not in list\n");
+       printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref);
+       l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
 };
 
 void
-setstack_isdnl3(struct PStack *st, struct Channel *chanp)
+setstack_l3dc(struct PStack *st, struct Channel *chanp)
 {
        char tmp[64];
 
        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) {
@@ -320,6 +383,11 @@ setstack_isdnl3(struct PStack *st, struct Channel *chanp)
        }
 }
 
+void
+isdnl3_trans(struct PStack *st, int pr, void *arg) {
+       st->l3.l3l2(st, pr, arg);
+}
+
 void
 releasestack_isdnl3(struct PStack *st)
 {
@@ -330,4 +398,136 @@ releasestack_isdnl3(struct PStack *st)
                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 2ff582b4a4dc7f2b45b2d2c7beb9447e50e2cd09..a0e518f8cb2c9ac56990e2377adbb393f34f414b 100644 (file)
@@ -1,6 +1,17 @@
-/* $Id: isdnl3.h,v 2.0 1997/07/27 21:15:42 keil Exp $
+/* $Id: isdnl3.h,v 2.3 1998/11/15 23:55:06 keil Exp $
 
  * $Log: isdnl3.h,v $
+ * Revision 2.3  1998/11/15 23:55:06  keil
+ * changes from 2.0
+ *
+ * Revision 2.2  1998/05/25 14:10:17  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.1  1998/05/25 12:58:13  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
  * Revision 2.0  1997/07/27 21:15:42  keil
  * New Callref based layer3
  *
 
 struct stateentry {
        int state;
-       u_char primitive;
+       int primitive;
        void (*rout) (struct l3_process *, u_char, void *);
 };
 
-extern void l3_debug(struct PStack *st, char *s);
+#define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args)
+
 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);
@@ -45,3 +57,4 @@ 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 0c075546b4220cd98c2eacad8cb7a9c4eb81dadd..009783b6d715c63c5a417a63c310fc5de63f9bef 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ix1_micro.c,v 2.6 1998/02/11 17:28:09 keil Exp $
+/* $Id: ix1_micro.c,v 2.7 1998/04/15 16:44:31 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
@@ -11,6 +11,9 @@
  *              Beat Doebeli
  *
  * $Log: ix1_micro.c,v $
+ * Revision 2.7  1998/04/15 16:44:31  keil
+ * new init code
+ *
  * Revision 2.6  1998/02/11 17:28:09  keil
  * Niccy PnP/PCI support
  *
@@ -81,7 +84,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *ix1_revision = "$Revision: 2.6 $";
+const char *ix1_revision = "$Revision: 2.7 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -277,10 +280,7 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        return(request_irq(cs->irq, &ix1micro_interrupt,
                                        I4L_IRQ_FLAG, "HiSax", cs));
                case CARD_INIT:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       inithscxisac(cs, 3);
                        return(0);
                case CARD_TEST:
                        return(0);
index d60a5da66b809eeeeb22d81de15e40443f06c19c..db6ceca7615b9a996efbc1c0d5905da46fd64385 100644 (file)
@@ -1,11 +1,29 @@
-/* $Id: l3_1tr6.c,v 2.4 1998/02/12 23:07:57 keil Exp $
+/* $Id: l3_1tr6.c,v 2.8 1998/11/15 23:55:08 keil Exp $
 
  *  German 1TR6 D-channel protocol
  *
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
+ *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
  *
  *
  * $Log: l3_1tr6.c,v $
+ * Revision 2.8  1998/11/15 23:55:08  keil
+ * changes from 2.0
+ *
+ * Revision 2.7  1998/08/13 23:36:45  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.6  1998/05/25 14:10:18  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.5  1998/05/25 12:58:14  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
  * Revision 2.4  1998/02/12 23:07:57  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -38,7 +56,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.4 $";
+const char *l3_1tr6_revision = "$Revision: 2.8 $";
 
 #define MsgHead(ptr, cref, mty, dis) \
        *ptr++ = dis; \
@@ -56,66 +74,34 @@ l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd)
                return;
        p = skb_put(skb, 4);
        MsgHead(p, pc->callref, mt, pd);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(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_release_req(struct l3_process *pc, u_char pr, void *arg)
+{
+       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_invalid(struct l3_process *pc, u_char pr, void *arg)
+{
+       struct sk_buff *skb = arg;
+
+       dev_kfree_skb(skb);
+       l3_1tr6_release_req(pc, 0, NULL);
+}
+
+static void
+l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
+{
+       dev_kfree_skb(skb);
+       if (pc->st->l3.debug & L3_DEB_WARN)
+               l3_debug(pc->st, msg);
+       l3_1tr6_release_req(pc, 0, NULL);
 }
 
 static void
@@ -204,7 +190,7 @@ l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer);
        L3AddTimer(&pc->timer, T303, CC_T303);
        newl3state(pc, 1);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
 }
 
 static void
@@ -220,17 +206,29 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
        /* Channel Identification */
        p = skb->data;
        if ((p = findie(p, skb->len, WE0_chanID, 0))) {
-               pc->para.bchannel = p[2] & 0x3;
-               bcfound++;
-       } else if (pc->st->l3.debug & L3_DEB_WARN)
-               l3_debug(pc->st, "setup without bchannel");
+               if (p[1] != 1) {
+                       l3_1tr6_error(pc, "setup wrong chanID len", skb);
+                       return;
+               }
+               if ((p[2] & 0xf4) != 0x80) {
+                       l3_1tr6_error(pc, "setup wrong WE0_chanID", skb);
+                       return;
+               }
+               if ((pc->para.bchannel = p[2] & 0x3))
+                               bcfound++;
+       } else {
+               l3_1tr6_error(pc, "missing setup chanID", skb);
+               return;
+       }
 
        p = skb->data;
        if ((p = findie(p, skb->len, WE6_serviceInd, 6))) {
                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");
+       } else {
+               l3_1tr6_error(pc, "missing setup SI", skb);
+               return;
+       }
 
        p = skb->data;
        if ((p = findie(p, skb->len, WE0_destAddr, 0)))
@@ -261,7 +259,7 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
                        l3_debug(pc->st, tmp);
                }
                newl3state(pc, 6);
-               pc->st->l3.l3l4(pc, CC_SETUP_IND, NULL);
+               pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
        } else
                release_l3_process(pc);
 }
@@ -276,12 +274,22 @@ l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
        p = skb->data;
        newl3state(pc, 2);
        if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+               if (p[1] != 1) {
+                       l3_1tr6_error(pc, "setup_ack wrong chanID len", skb);
+                       return;
+               }
+               if ((p[2] & 0xf4) != 0x80) {
+                       l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb);
+                       return;
+               }
                pc->para.bchannel = p[2] & 0x3;
-       } else if (pc->st->l3.debug & L3_DEB_WARN)
-               l3_debug(pc->st, "setup answer without bchannel");
+       } else {
+               l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb);
+               return;
+       }
        dev_kfree_skb(skb);
        L3AddTimer(&pc->timer, T304, CC_T304);
-       pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL);
+       pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 static void
@@ -293,13 +301,27 @@ l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer);
        p = skb->data;
        if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+               if (p[1] != 1) {
+                       l3_1tr6_error(pc, "call sent wrong chanID len", skb);
+                       return;
+               }
+               if ((p[2] & 0xf4) != 0x80) {
+                       l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb);
+                       return;
+               }
+               if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) {
+                       l3_1tr6_error(pc, "call sent wrong chanID value", skb);
+                       return;
+               }
                pc->para.bchannel = p[2] & 0x3;
-       } else if (pc->st->l3.debug & L3_DEB_WARN)
-               l3_debug(pc->st, "setup answer without bchannel");
+       } else {
+               l3_1tr6_error(pc, "missing call sent WE0_chanID", skb);
+               return;
+       }
        dev_kfree_skb(skb);
        L3AddTimer(&pc->timer, T310, CC_T310);
        newl3state(pc, 3);
-       pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 static void
@@ -310,7 +332,7 @@ l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
        dev_kfree_skb(skb);
        L3DelTimer(&pc->timer); /* T304 */
        newl3state(pc, 4);
-       pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
 }
 
 static void
@@ -330,7 +352,7 @@ l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
                }
                if (tmpcharge > pc->para.chargeinfo) {
                        pc->para.chargeinfo = tmpcharge;
-                       pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
+                       pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
                }
                if (pc->st->l3.debug & L3_DEB_CHARGE) {
                        sprintf(tmp, "charging info %d", pc->para.chargeinfo);
@@ -356,10 +378,14 @@ l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
        struct sk_buff *skb = arg;
 
        L3DelTimer(&pc->timer); /* T310 */
+       if (!findie(skb->data, skb->len, WE6_date, 6)) {
+               l3_1tr6_error(pc, "missing connect date", skb);
+               return;
+       }
        newl3state(pc, 10);
        dev_kfree_skb(skb);
        pc->para.chargeinfo = 0;
-       pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 static void
@@ -380,13 +406,16 @@ l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg)
                        pc->para.cause = 0;
                        pc->para.loc = 0;
                }
-       } else
+       } else {
                pc->para.cause = -1;
+               l3_1tr6_error(pc, "missing REL cause", skb);
+               return;
+       }
        dev_kfree_skb(skb);
        StopAllL3Timer(pc);
        newl3state(pc, 0);
        l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
-       pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
        release_l3_process(pc);
 }
 
@@ -399,7 +428,7 @@ l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
        StopAllL3Timer(pc);
        newl3state(pc, 0);
        pc->para.cause = -1;
-       pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL);
+       pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
        release_l3_process(pc);
 }
 
@@ -421,7 +450,7 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
                }
                if (tmpcharge > pc->para.chargeinfo) {
                        pc->para.chargeinfo = tmpcharge;
-                       pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
+                       pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
                }
                if (pc->st->l3.debug & L3_DEB_CHARGE) {
                        sprintf(tmp, "charging info %d", pc->para.chargeinfo);
@@ -448,9 +477,13 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
                        l3_debug(pc->st, "cause not found");
                pc->para.cause = -1;
        }
+       if (!findie(skb->data, skb->len, WE6_date, 6)) {
+               l3_1tr6_error(pc, "missing connack date", skb);
+               return;
+       }
        dev_kfree_skb(skb);
        newl3state(pc, 12);
-       pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
 }
 
 
@@ -459,11 +492,15 @@ l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
 {
        struct sk_buff *skb = arg;
 
+       if (!findie(skb->data, skb->len, WE6_date, 6)) {
+               l3_1tr6_error(pc, "missing connack date", skb);
+               return;
+       }
        dev_kfree_skb(skb);
        newl3state(pc, 10);
        pc->para.chargeinfo = 0;
        L3DelTimer(&pc->timer);
-       pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 static void
@@ -502,7 +539,7 @@ l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg)
        if (!(skb = l3_alloc_skb(l)))
                return;
        memcpy(skb_put(skb, l), tmp, l);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
        L3DelTimer(&pc->timer);
        L3AddTimer(&pc->timer, T313, CC_T313);
 }
@@ -545,19 +582,10 @@ l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
        if (!(skb = l3_alloc_skb(l)))
                return;
        memcpy(skb_put(skb, l), tmp, l);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
        L3AddTimer(&pc->timer, T305, CC_T305);
 }
 
-static void
-l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg)
-{
-       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 l3_process *pc, u_char pr, void *arg)
 {
@@ -567,8 +595,8 @@ l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg)
                l3_1tr6_setup_req(pc, pr, arg);
        } else {
                L3DelTimer(&pc->timer);
-               pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL);
-               release_l3_process(pc);
+               pc->para.cause = 0;
+               l3_1tr6_disconnect_req(pc, 0, NULL);
        }
 }
 
@@ -578,7 +606,7 @@ l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer);
        pc->para.cause = 0xE6;
        l3_1tr6_disconnect_req(pc, pr, NULL);
-       pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -613,7 +641,7 @@ l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg)
        if (!(skb = l3_alloc_skb(l)))
                return;
        memcpy(skb_put(skb, l), tmp, l);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
        L3AddTimer(&pc->timer, T308, CC_T308_1);
 }
 
@@ -623,7 +651,7 @@ l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer);
        pc->para.cause = 0xE6;
        l3_1tr6_disconnect_req(pc, pr, NULL);
-       pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -632,7 +660,7 @@ l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer);
        pc->para.cause = 0xE6;
        l3_1tr6_disconnect_req(pc, pr, NULL);
-       pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL);
+       pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
 }
 
 static void
@@ -648,29 +676,29 @@ static void
 l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
        L3DelTimer(&pc->timer);
-       pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL);
+       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),
@@ -687,11 +715,13 @@ static struct stateentry downstl[] =
         CC_T308_2, l3_1tr6_t308_2},
 };
 
-static int downstl_len = sizeof(downstl) /
-sizeof(struct stateentry);
+#define DOWNSTL_LEN \
+       (sizeof(downstl) / sizeof(struct stateentry))
 
 static struct stateentry datastln1[] =
 {
+       {SBIT(0),
+        MT_N1_INVALID, l3_1tr6_invalid},
        {SBIT(0),
         MT_N1_SETUP, l3_1tr6_setup},
        {SBIT(1),
@@ -711,18 +741,20 @@ static struct stateentry datastln1[] =
        {SBIT(10),
         MT_N1_INFO, l3_1tr6_info},
        {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
-        SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+        SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
         MT_N1_REL, l3_1tr6_rel},
+       {SBIT(19),
+        MT_N1_REL, l3_1tr6_rel_ack},
+       {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
+        SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
+        MT_N1_REL_ACK, l3_1tr6_invalid},
        {SBIT(19),
         MT_N1_REL_ACK, l3_1tr6_rel_ack}
 };
 /* *INDENT-ON* */
 
-
-
-
-static int datastln1_len = sizeof(datastln1) /
-sizeof(struct stateentry);
+#define DATASTLN1_LEN \
+       (sizeof(datastln1) / sizeof(struct stateentry))
 
 static void
 up1tr6(struct PStack *st, int pr, void *arg)
@@ -732,9 +764,21 @@ up1tr6(struct PStack *st, int pr, void *arg)
        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 %d", skb->len);
+                       sprintf(tmp, "up1tr6 len only %ld", skb->len);
                        l3_debug(st, tmp);
                }
                dev_kfree_skb(skb);
@@ -742,8 +786,8 @@ up1tr6(struct PStack *st, int pr, void *arg)
        }
        if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
                if (st->l3.debug & L3_DEB_PROTERR) {
-                       sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
+                       sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %ld",
+                               (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
                                skb->data[0], skb->len);
                        l3_debug(st, tmp);
                }
@@ -764,12 +808,33 @@ up1tr6(struct PStack *st, int pr, void *arg)
                dev_kfree_skb(skb);
                if (st->l3.debug & L3_DEB_STATE) {
                        sprintf(tmp, "up1tr6%s N0 mt %x unhandled",
-                            (pr == DL_DATA) ? " " : "(broadcast) ", mt);
+                            (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 (mt == MT_N1_SETUP) { 
+                               if (cr < 128) {
+                                       if (!(proc = new_l3_process(st, cr))) {
+                                               if (st->l3.debug & L3_DEB_PROTERR) {
+                                                       sprintf(tmp, "up1tr6 no roc mem");
+                                                       l3_debug(st, tmp);
+                                               }
+                                               dev_kfree_skb(skb);
+                                               return;
+                                       }
+                               } else {
+                                       dev_kfree_skb(skb);
+                                       return;
+                               }
+                       } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) ||
+                               (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) ||
+                               (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) ||
+                               (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) ||
+                               (mt == MT_N1_INFO)) {
+                               dev_kfree_skb(skb);
+                               return;
+                       } else {
                                if (!(proc = new_l3_process(st, cr))) {
                                        if (st->l3.debug & L3_DEB_PROTERR) {
                                                sprintf(tmp, "up1tr6 no roc mem");
@@ -778,20 +843,18 @@ up1tr6(struct PStack *st, int pr, void *arg)
                                        dev_kfree_skb(skb);
                                        return;
                                }
-                       } else {
-                               dev_kfree_skb(skb);
-                               return;
+                               mt = MT_N1_INVALID;
                        }
                }
-               for (i = 0; i < datastln1_len; i++)
+               for (i = 0; i < DATASTLN1_LEN; i++)
                        if ((mt == datastln1[i].primitive) &&
                            ((1 << proc->state) & datastln1[i].state))
                                break;
-               if (i == datastln1_len) {
+               if (i == DATASTLN1_LEN) {
                        dev_kfree_skb(skb);
                        if (st->l3.debug & L3_DEB_STATE) {
                                sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
-                                 (pr == DL_DATA) ? " " : "(broadcast) ",
+                                 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
                                        proc->state, mt);
                                l3_debug(st, tmp);
                        }
@@ -799,7 +862,7 @@ up1tr6(struct PStack *st, int pr, void *arg)
                } else {
                        if (st->l3.debug & L3_DEB_STATE) {
                                sprintf(tmp, "up1tr6%sstate %d mt %x",
-                                 (pr == DL_DATA) ? " " : "(broadcast) ",
+                                 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
                                        proc->state, mt);
                                l3_debug(st, tmp);
                        }
@@ -816,7 +879,10 @@ down1tr6(struct PStack *st, int pr, void *arg)
        struct Channel *chan;
        char tmp[80];
 
-       if (CC_SETUP_REQ == pr) {
+       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;
@@ -832,11 +898,11 @@ down1tr6(struct PStack *st, int pr, void *arg)
                proc = arg;
        }
 
-       for (i = 0; i < downstl_len; i++)
+       for (i = 0; i < DOWNSTL_LEN; i++)
                if ((pr == downstl[i].primitive) &&
                    ((1 << proc->state) & downstl[i].state))
                        break;
-       if (i == downstl_len) {
+       if (i == DOWNSTL_LEN) {
                if (st->l3.debug & L3_DEB_STATE) {
                        sprintf(tmp, "down1tr6 state %d prim %d unhandled",
                                proc->state, pr);
index 90d08793e3ddf0e468f735ea80b5110b285567e2..7c0ba56b291c5d41dae1ee26c9e5bc6f0b01f8ec 100644 (file)
@@ -1,8 +1,11 @@
-/* $Id: l3_1tr6.h,v 2.0 1997/07/27 21:15:47 keil Exp $
+/* $Id: l3_1tr6.h,v 2.1 1998/08/13 23:36:48 keil Exp $
  *
  *  German 1TR6 D-channel protocol defines
  *
  * $Log: l3_1tr6.h,v $
+ * Revision 2.1  1998/08/13 23:36:48  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
  * Revision 2.0  1997/07/27 21:15:47  keil
  * New Callref based layer3
  *
@@ -64,6 +67,7 @@
 #define MT_N1_REG_ACK 0x6C
 #define MT_N1_REG_REJ 0x6F
 #define MT_N1_STAT 0x63
+#define MT_N1_INVALID 0
 
 /*
  * W Elemente
index f8b97fd73135b1f834bed1ddd69dba34ffbef48e..0808d32a0b593041aeba1148c8348b3ad664d7c9 100644 (file)
@@ -1,14 +1,36 @@
-/* $Id: l3dss1.c,v 2.7 1998/02/12 23:08:01 keil Exp $
+/* $Id: l3dss1.c,v 2.12 1998/11/15 23:55:10 keil Exp $
 
  * EURO/DSS1 D-channel protocol
  *
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
+ *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: l3dss1.c,v $
+ * Revision 2.12  1998/11/15 23:55:10  keil
+ * changes from 2.0
+ *
+ * Revision 2.11  1998/08/13 23:36:51  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 2.10  1998/05/25 14:10:20  keil
+ * HiSax 3.0
+ * X.75 and leased are working again.
+ *
+ * Revision 2.9  1998/05/25 12:58:17  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.8  1998/03/19 13:18:47  keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
  * Revision 2.7  1998/02/12 23:08:01  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -50,9 +72,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.7 $";
-
-#define EXT_BEARER_CAPS 1
+const char *dss1_revision = "$Revision: 2.12 $";
 
 #define        MsgHead(ptr, cref, mty) \
        *ptr++ = 0x8; \
@@ -61,12 +81,11 @@ const char *dss1_revision = "$Revision: 2.7 $";
        *ptr++ = mty
 
 
-#ifdef HISAX_DE_AOC
+#if HISAX_DE_AOC
 static void
-l3dss1_parse_facility(struct l3_process *pc, u_char *p)
+l3dss1_parse_facility(struct l3_process *pc, u_char * p)
 {
        int qd_len = 0;
-       char tmp[32];
 
        p++;
        qd_len = *p++;
@@ -74,91 +93,99 @@ l3dss1_parse_facility(struct l3_process *pc, u_char *p)
                l3_debug(pc->st, "qd_len == 0");
                return;
        }
-       if((*p & 0x1F) != 0x11) {       /* Service discriminator, supplementary service */
+       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) {
+       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 */
+       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) \
+       switch (*p & 0x1F) {    /* component tag */
+               case 1: /* invoke */
+                       {
+                               unsigned char nlen = 0, 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) { \
@@ -174,72 +201,74 @@ l3dss1_parse_facility(struct l3_process *pc, u_char *p)
                            p += ilen+2;        \
                    }                   \
            }
-                           
-                   switch(ident) {
-                   default:
-                           break;
-                   case 0x22: /* during */
-                           FOO1("1A",0x30,FOO1("1C",0xA1,FOO1("1D",0x30,FOO1("1E",0x02,({
-                                   ident = 0;
-                                   while(ilen > 0) {
-                                           ident = (ident<<8) | *p++;
-                                           ilen--;
-                                   }
-                                   if (ident > pc->para.chargeinfo) {
-                                           pc->para.chargeinfo = ident;
-                                           pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
-                                   }
-                                   if (pc->st->l3.debug & L3_DEB_CHARGE) {
-                                           if (*(p+2) == 0) {
-                                                   sprintf(tmp, "charging info during %d", pc->para.chargeinfo);
-                                                   l3_debug(pc->st, tmp);
-                                           }
-                                           else {
-                                           sprintf(tmp, "charging info final %d", pc->para.chargeinfo);
-                                           l3_debug(pc->st, tmp);
-                                           }
-                                   }
-                           })))))
-                           break;
-                   case 0x24: /* final */
-                           FOO1("2A",0x30,FOO1("2B",0x30,FOO1("2C",0xA1,FOO1("2D",0x30,FOO1("2E",0x02,({
-                                   ident = 0;
-                                   while(ilen > 0) {
-                                           ident = (ident<<8) | *p++;
-                                           ilen--;
-                                   }
-                                   if (ident > pc->para.chargeinfo) {
-                                           pc->para.chargeinfo = ident;
-                                           pc->st->l3.l3l4(pc, CC_INFO_CHARGE, NULL);
-                                   }
-                                   if (pc->st->l3.debug & L3_DEB_CHARGE) {
-                                           sprintf(tmp, "charging info final %d", pc->para.chargeinfo);
-                                           l3_debug(pc->st, tmp);
-                                   }
-                           }))))))
-                   break;
-                   }
-    #undef FOO1
-    
-               }
-           break;
-           case 2: /* return result */
-                   l3_debug(pc->st, "return result break");
-                   break;
-           case 3: /* return error */
-                   l3_debug(pc->st, "return error break");
-                   break;
-           default:
-                   l3_debug(pc->st, "default break");
-                   break;
+
+                               switch (ident) {
+                                       default:
+                                               break;
+                                       case 0x22:      /* during */
+                                               FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( {
+                                                              ident = 0;
+                                                       nlen = (nlen)?nlen:0; /* Make gcc happy */
+                                                       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;
+                                                       nlen = (nlen)?nlen:0; /* Make gcc happy */
+                                                       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 
+#endif
 
-static int 
-l3dss1_check_messagetype_validity(int mt) {
+static int
+l3dss1_check_messagetype_validity(int mt)
+{
 /* verify if a message type exists */
-       switch(mt) {
+       switch (mt) {
                case MT_ALERTING:
                case MT_CALL_PROCEEDING:
                case MT_CONNECT:
@@ -283,7 +312,7 @@ l3dss1_message(struct l3_process *pc, u_char mt)
                return;
        p = skb_put(skb, 4);
        MsgHead(p, pc->callref, mt);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
 }
 
 static void
@@ -314,165 +343,244 @@ l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
        StopAllL3Timer(pc);
        pc->para.cause = cause;
        newl3state(pc, 0);
-       pc->st->l3.l3l4(pc, CC_RELEASE_CNF, NULL);
+       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;
+#if 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)
+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;
+       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
+DecodeASyncParams(u_char si2, u_char * p)
+{
+       u_char info;
+
+       switch (p[5]) {
+               case 66:        // 1200 bit/s
+
+                       break;  // si2 don't change
+
+               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)
+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;
-  }
+       info &= 0x7f;
+       switch (info) {
+               case 40:        // bit/s negotiation failed  ai := 165 not 175!
+
+                       return si2 + 15;
+               case 15:        // 56000 bit/s failed, ai := 0 not 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;
+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
@@ -498,7 +606,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
        /*
         * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
         */
-#ifdef HISAX_EURO_SENDCOMPLETE
+#if HISAX_EURO_SENDCOMPLETE
        *p++ = 0xa1;            /* complete indicator */
 #endif
        switch (pc->para.setup.si1) {
@@ -558,11 +666,11 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
        msn = pc->para.setup.eazmsn;
        sub = NULL;
        sp = msn;
-       while (*sp) { 
+       while (*sp) {
                if ('.' == *sp) {
                        sub = sp;
                        *sp = 0;
-               } else 
+               } else
                        sp++;
        }
        if (*msn) {
@@ -579,20 +687,20 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
        }
        if (sub) {
                *sub++ = '.';
-               *p++ = 0x6d; /* Calling party subaddress */
-               *p++ = strlen(sub) + 2;
+               *p++ = 0x6d;    /* Calling party subaddress */
+               *p++ = strlen(sub) + 2;
                *p++ = 0x80;    /* NSAP coded */
                *p++ = 0x50;    /* local IDI format */
-               while (*sub)
+               while (*sub)
                        *p++ = *sub++ & 0x7f;
        }
        sub = NULL;
        sp = teln;
-       while (*sp) { 
+       while (*sp) {
                if ('.' == *sp) {
                        sub = sp;
                        *sp = 0;
-               } else 
+               } else
                        sp++;
        }
        *p++ = 0x70;
@@ -604,31 +712,47 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
 
        if (sub) {
                *sub++ = '.';
-               *p++ = 0x71; /* Called party subaddress */
-               *p++ = strlen(sub) + 2;
+               *p++ = 0x71;    /* Called party subaddress */
+               *p++ = strlen(sub) + 2;
                *p++ = 0x80;    /* NSAP coded */
                *p++ = 0x50;    /* local IDI format */
-               while (*sub)
+               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);
-        }
+#if 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);
+#if HISAX_SEND_STD_LLC_IE
+       } else {
+               *p++ = 0x7c;
+               *p++ = 0x02;
+               *p++ = 0x88;
+               *p++ = 0x90;
+#endif
+       }
 #endif
        l = p - tmp;
        if (!(skb = l3_alloc_skb(l)))
@@ -637,7 +761,7 @@ l3dss1_setup_req(struct l3_process *pc, u_char pr,
        L3DelTimer(&pc->timer);
        L3AddTimer(&pc->timer, T303, CC_T303);
        newl3state(pc, 1);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
 }
 
 static void
@@ -657,7 +781,7 @@ l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg)
        dev_kfree_skb(skb);
        newl3state(pc, 3);
        L3AddTimer(&pc->timer, T310, CC_T310);
-       pc->st->l3.l3l4(pc, CC_PROCEEDING_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
 }
 
 static void
@@ -677,7 +801,7 @@ l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
        dev_kfree_skb(skb);
        newl3state(pc, 2);
        L3AddTimer(&pc->timer, T304, CC_T304);
-       pc->st->l3.l3l4(pc, CC_MORE_INFO, NULL);
+       pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
 }
 
 static void
@@ -699,7 +823,7 @@ l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg)
        dev_kfree_skb(skb);
        newl3state(pc, 12);
        pc->para.cause = cause;
-       pc->st->l3.l3l4(pc, CC_DISCONNECT_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
 }
 
 static void
@@ -711,7 +835,7 @@ l3dss1_connect(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer); /* T310 */
        newl3state(pc, 10);
        pc->para.chargeinfo = 0;
-       pc->st->l3.l3l4(pc, CC_SETUP_CNF, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
 }
 
 static void
@@ -722,49 +846,48 @@ l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg)
        dev_kfree_skb(skb);
        L3DelTimer(&pc->timer); /* T304 */
        newl3state(pc, 4);
-       pc->st->l3.l3l4(pc, CC_ALERTING_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
 }
 
 static void
 l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
 {
-  /* This routine is called if here was no SETUP made (checks in dss1up and in
-   * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code
-   * It is called after it is veryfied that Layer2 is up.
-   * The cause value is allready in pc->para.cause
-   * MT_STATUS_ENQUIRE in the NULL state is handled too
-   */
+       /* 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;
+       u_char *p = tmp;
        int l;
        struct sk_buff *skb;
 
        switch (pc->para.cause) {
-         case  81: /* 0x51 invalid callreference */
-         case  96: /* 0x60 mandory IE missing */
-         case 101: /* 0x65 incompatible Callstate */
-               MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
-               *p++ = IE_CAUSE;
-               *p++ = 0x2;
-               *p++ = 0x80;
-               *p++ = pc->para.cause | 0x80;
-               break;
-         default:
-               printk(KERN_ERR "HiSax internal error l3dss1_msg_without_setup\n");
-               return;
-       }       
+               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);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       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];
+       u_char *p, *ptmp[8];
        int i;
        int bcfound = 0;
        char tmp[80];
@@ -772,9 +895,9 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *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;
-       for(i = 0; i < 8; i++)
+       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)
@@ -782,18 +905,14 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
            || 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;
+               /* if ie is < 8 and not 0 nor 4, send RELEASE_COMPLETE
+                * cause 0x60
+                */
+               pc->para.cause = 0x60;
                dev_kfree_skb(skb);
-               if (pc->state == 0)
-                       pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL);
-               else
-                       l3dss1_msg_without_setup(pc, pr, NULL);
+               l3dss1_msg_without_setup(pc, pr, NULL);
                return;
        }
-
        /*
         * Channel Identification
         */
@@ -804,9 +923,14 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
                        bcfound++;
                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");
-
+       } else {
+               if (pc->debug & L3_DEB_WARN)
+                       l3_debug(pc->st, "setup without bchannel");
+               pc->para.cause = 0x60;
+               dev_kfree_skb(skb);
+               l3dss1_msg_without_setup(pc, pr, NULL);
+               return;
+       }
        /*
           * Bearer Capabilities
         */
@@ -824,10 +948,10 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
                                /* Unrestricted digital information */
                                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);
+#if 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:
@@ -849,12 +973,9 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
                if (pc->debug & L3_DEB_WARN)
                        l3_debug(pc->st, "setup without bearer capabilities");
                /* ETS 300-104 1.3.3 */
-               pc->para.cause = 0x60;
+               pc->para.cause = 0x60;
                dev_kfree_skb(skb);
-               if (pc->state == 0)
-                       pc->st->l3.l3l4(pc, CC_ESTABLISH, NULL);
-               else
-                       l3dss1_msg_without_setup(pc, pr, NULL);
+               l3dss1_msg_without_setup(pc, pr, NULL);
                return;
        }
 
@@ -867,8 +988,8 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
        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]='.';
+               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)
@@ -892,24 +1013,28 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg)
        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]='.';
+               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");
        }
-
        dev_kfree_skb(skb);
 
        if (bcfound) {
                if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) {
-                       sprintf(tmp, "non-digital call: %s -> %s",
-                               pc->para.setup.phone, pc->para.setup.eazmsn);
-                       l3_debug(pc->st, tmp);
+                       l3_debug(pc->st, "non-digital call: %s -> %s",
+                           pc->para.setup.phone, pc->para.setup.eazmsn);
+               }
+               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, CC_SETUP_IND, NULL);
+               pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
        } else
                release_l3_process(pc);
 }
@@ -938,7 +1063,7 @@ l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
        dev_kfree_skb(skb);
        newl3state(pc, 10);
        L3DelTimer(&pc->timer);
-       pc->st->l3.l3l4(pc, CC_SETUP_COMPLETE_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
 }
 
 static void
@@ -967,7 +1092,7 @@ l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
                return;
        memcpy(skb_put(skb, l), tmp, l);
        newl3state(pc, 11);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
        L3AddTimer(&pc->timer, T305, CC_T305);
 }
 
@@ -994,8 +1119,8 @@ l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg)
        if (!(skb = l3_alloc_skb(l)))
                return;
        memcpy(skb_put(skb, l), tmp, l);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
-       pc->st->l3.l3l4(pc, 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);
 }
@@ -1016,8 +1141,8 @@ l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
        }
        p = skb->data;
        if ((p = findie(p, skb->len, IE_FACILITY, 0))) {
-#ifdef HISAX_DE_AOC
-           l3dss1_parse_facility(pc,p);
+#if HISAX_DE_AOC
+               l3dss1_parse_facility(pc, p);
 #else
                p = NULL;
 #endif
@@ -1026,7 +1151,7 @@ l3dss1_release(struct l3_process *pc, u_char pr, void *arg)
        StopAllL3Timer(pc);
        pc->para.cause = cause;
        l3dss1_message(pc, MT_RELEASE_COMPLETE);
-       pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+       pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
        newl3state(pc, 0);
        release_l3_process(pc);
 }
@@ -1064,15 +1189,15 @@ l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg)
        if (!(skb = l3_alloc_skb(l)))
                return;
        memcpy(skb_put(skb, l), tmp, l);
-       pc->st->l3.l3l2(pc->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];
+       /* 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;
@@ -1084,7 +1209,7 @@ l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg)
        *p++ = IE_CAUSE;
        *p++ = 0x2;
        *p++ = 0x80;
-       *p++ = 0x62 | 0x80;             /* status sending */
+       *p++ = 0x62 | 0x80;     /* status sending */
 
        *p++ = 0x14;            /* CallState */
        *p++ = 0x1;
@@ -1094,7 +1219,7 @@ l3dss1_status_req(struct l3_process *pc, u_char pr, void *arg)
        if (!(skb = l3_alloc_skb(l)))
                return;
        memcpy(skb_put(skb, l), tmp, l);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
 }
 
 static void
@@ -1107,18 +1232,18 @@ l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg)
 
        if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
                p++;
-               if (1== *p++)
+               if (1 == *p++)
                        callState = *p;
        }
-       if(callState == 0) {
+       if (callState == 0) {
                /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
                 * set down layer 3 without sending any message
                 */
-               pc->st->l3.l3l4(pc, CC_RELEASE_IND, NULL);
+               pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
                newl3state(pc, 0);
                release_l3_process(pc);
        } else {
-               pc->st->l3.l3l4(pc, CC_IGNORE, NULL);
+               pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
        }
 }
 
@@ -1131,7 +1256,7 @@ l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
                l3dss1_setup_req(pc, pr, arg);
        } else {
                L3DelTimer(&pc->timer);
-               pc->st->l3.l3l4(pc, CC_NOSETUP_RSP_ERR, NULL);
+               pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
                release_l3_process(pc);
        }
 }
@@ -1142,7 +1267,7 @@ l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer);
        pc->para.cause = 0xE6;
        l3dss1_disconnect_req(pc, pr, NULL);
-       pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 
 }
 
@@ -1171,7 +1296,7 @@ l3dss1_t305(struct l3_process *pc, u_char pr, void *arg)
                return;
        memcpy(skb_put(skb, l), tmp, l);
        newl3state(pc, 19);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
        L3AddTimer(&pc->timer, T308, CC_T308_1);
 }
 
@@ -1181,7 +1306,7 @@ l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer);
        pc->para.cause = 0xE6;
        l3dss1_disconnect_req(pc, pr, NULL);
-       pc->st->l3.l3l4(pc, CC_SETUP_ERR, NULL);
+       pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
 }
 
 static void
@@ -1190,7 +1315,7 @@ l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
        L3DelTimer(&pc->timer);
        pc->para.cause = 0xE6;
        l3dss1_disconnect_req(pc, pr, NULL);
-       pc->st->l3.l3l4(pc, CC_CONNECT_ERR, NULL);
+       pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
 }
 
 static void
@@ -1206,15 +1331,37 @@ static void
 l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg)
 {
        L3DelTimer(&pc->timer);
-       pc->st->l3.l3l4(pc, CC_RELEASE_ERR, NULL);
+       pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
        release_l3_process(pc);
 }
 
+static void
+l3dss1_t318(struct l3_process *pc, u_char pr, void *arg)
+{
+       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_t319(struct l3_process *pc, u_char pr, void *arg)
+{
+       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_restart(struct l3_process *pc, u_char pr, void *arg)
 {
        L3DelTimer(&pc->timer);
-       pc->st->l3.l3l4(pc, CC_DLRL, NULL);
+       pc->st->l3.l3l4(pc->st, CC_DLRL | INDICATION, pc);
        release_l3_process(pc);
 }
 
@@ -1233,31 +1380,30 @@ l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
        if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
                p++;
                l = *p++;
-               t += sprintf(t,"Status CR %x Cause:", pc->callref);
+               t += sprintf(t, "Status CR %x Cause:", pc->callref);
                while (l--) {
-                       cause = *p;
-                       t += sprintf(t," %2x",*p++);
+                       cause = *p;
+                       t += sprintf(t, " %2x", *p++);
                }
        } else
-               sprintf(t,"Status CR %x no Cause", pc->callref);
+               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);
+       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");
+               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");
+               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 
+       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);
@@ -1268,56 +1414,189 @@ l3dss1_status(struct l3_process *pc, u_char pr, void *arg)
 static void
 l3dss1_facility(struct l3_process *pc, u_char pr, void *arg)
 {
-        u_char *p;
+       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);
+#if 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);
+       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);
+       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);
+       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);
+       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, chan=0;
+       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];
-               sprintf(tmp, "Restart %x", ri);
+               ri = p[2];
+               l3_debug(pc->st, "Restart %x", ri);
        } else {
-               sprintf(tmp, "Restart without restart IE");
+               l3_debug(pc->st, "Restart without restart IE");
                ri = 0x86;
        }
-       l3_debug(pc->st, tmp);
        p = skb->data;
        if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
                chan = p[2] & 3;
-               sprintf(tmp, "Restart for channel %d", chan);
-               l3_debug(pc->st, tmp);
+               ch = p[2];
+               if (pc->st->l3.debug)
+                       l3_debug(pc->st, "Restart for channel %d", chan);
        }
        dev_kfree_skb(skb);
        newl3state(pc, 2);
        up = pc->st->l3.proc;
        while (up) {
-               if ((ri & 7)==7)
-                       up->st->lli.l4l3(up->st, CC_RESTART, up);
+               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, up);
+                       up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
                up = up->next;
        }
        p = tmp;
@@ -1325,9 +1604,9 @@ l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
        if (chan) {
                *p++ = IE_CHANNEL_ID;
                *p++ = 1;
-               *p++ = chan | 0x80;
+               *p++ = ch | 0x80;
        }
-       *p++ = 0x79; /* RESTART Ind */
+       *p++ = 0x79;            /* RESTART Ind */
        *p++ = 1;
        *p++ = ri;
        l = p - tmp;
@@ -1335,32 +1614,33 @@ l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg)
                return;
        memcpy(skb_put(skb, l), tmp, l);
        newl3state(pc, 0);
-       pc->st->l3.l3l2(pc->st, DL_DATA, skb);
+       l3_msg(pc->st, DL_DATA | REQUEST, skb);
 }
-
 /* *INDENT-OFF* */
 static struct stateentry downstatelist[] =
 {
        {SBIT(0),
-        CC_ESTABLISH, l3dss1_msg_without_setup},
+        CC_SETUP | REQUEST, l3dss1_setup_req},
        {SBIT(0),
-        CC_SETUP_REQ, l3dss1_setup_req},
+        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, l3dss1_restart},
+        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),
@@ -1371,14 +1651,18 @@ 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),
         CC_T308_2, l3dss1_t308_2},
 };
 
-static int downsllen = sizeof(downstatelist) /
-sizeof(struct stateentry);
+#define DOWNSLLEN \
+       (sizeof(downstatelist) / sizeof(struct stateentry))
 
 static struct stateentry datastatelist[] =
 {
@@ -1408,10 +1692,10 @@ static struct stateentry datastatelist[] =
         SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
         MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
        {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(11) | SBIT(12) | SBIT(15) /* | SBIT(17) | SBIT(19)*/,
         MT_RELEASE, l3dss1_release},
        {SBIT(19),  MT_RELEASE, l3dss1_release_ind},
-       {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
+       {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},
@@ -1423,61 +1707,57 @@ static struct stateentry datastatelist[] =
         MT_CONNECT_ACKNOWLEDGE, l3dss1_status_req},
        {SBIT(8),
         MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack},
-       {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(8) | SBIT(10) | SBIT(11) | SBIT(19),
+       {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},
 };
 
-static int datasllen = sizeof(datastatelist) / sizeof(struct stateentry);
+#define DATASLLEN \
+       (sizeof(datastatelist) / sizeof(struct stateentry))
 
 static struct stateentry globalmes_list[] =
 {
        {ALL_STATES,
-         MT_STATUS, l3dss1_status},
+        MT_STATUS, l3dss1_status},
        {SBIT(0),
         MT_RESTART, l3dss1_global_restart},
 /*     {SBIT(1),
-        MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},                                  
+        MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},
 */
 };
-static int globalm_len = sizeof(globalmes_list) / sizeof(struct stateentry);
-
-#if 0
-static struct stateentry globalcmd_list[] =
-{
-       {ALL_STATES,
-         CC_STATUS, l3dss1_status_req},
-       {SBIT(0),
-        CC_RESTART, l3dss1_restart_req},
-};
-
-static int globalc_len = sizeof(globalcmd_list) / sizeof(struct stateentry);
-#endif
+#define GLOBALM_LEN \
+       (sizeof(globalmes_list) / sizeof(struct stateentry))
 /* *INDENT-ON* */
 
+
 static void
 global_handler(struct PStack *st, int mt, struct sk_buff *skb)
 {
        int i;
-       char tmp[64];
        struct l3_process *proc = st->l3.global;
-       
-       for (i = 0; i < globalm_len; i++)
+
+       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) {
+       if (i == GLOBALM_LEN) {
                dev_kfree_skb(skb);
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1 global state %d mt %x unhandled",
+                       l3_debug(st, "dss1 global state %d mt %x unhandled",
                                proc->state, mt);
-                       l3_debug(st, tmp);
                }
                return;
        } else {
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1 global %d mt %x",
+                       l3_debug(st, "dss1 global %d mt %x",
                                proc->state, mt);
-                       l3_debug(st, tmp);
                }
                globalmes_list[i].rout(proc, mt, skb);
        }
@@ -1490,24 +1770,34 @@ dss1up(struct PStack *st, int pr, void *arg)
        char *ptr;
        struct sk_buff *skb = arg;
        struct l3_process *proc;
-       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->data[0] != PROTO_DIS_EURO) {
                if (st->l3.debug & L3_DEB_PROTERR) {
-                       sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
-                               skb->data[0], skb->len);
-                       l3_debug(st, tmp);
+                       l3_debug(st, "dss1up%sunexpected discriminator %x message len %d",
+                                (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+                                skb->data[0], skb->len);
                }
                dev_kfree_skb(skb);
                return;
        }
        cr = getcallref(skb->data);
        mt = skb->data[skb->data[1] + 2];
-       if (!cr) {                              /* Global CallRef */
+       if (!cr) {              /* Global CallRef */
                global_handler(st, mt, skb);
                return;
-       } else if (cr == -1) {                  /* Dummy Callref */
+       } else if (cr == -1) {  /* Dummy Callref */
                dev_kfree_skb(skb);
                return;
        } else if (!(proc = getl3proc(st, cr))) {
@@ -1515,7 +1805,7 @@ dss1up(struct PStack *st, int pr, void *arg)
                 * this callreference is active
                 */
                if (mt == MT_SETUP) {
-               /* Setup creates a new transaction process */
+                       /* 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
@@ -1526,14 +1816,14 @@ dss1up(struct PStack *st, int pr, void *arg)
                        }
                } 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;
+                       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) {
+                       if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
                                ptr++;
                                if (*ptr++ == 2)
                                        ptr++;
@@ -1549,29 +1839,29 @@ dss1up(struct PStack *st, int pr, void *arg)
                                return;
                        } else {
                                /* ETS 300-104 part 2.4.2
-                                * if setup has not been made and a message type 
+                                * if setup has not been made and a message type
                                 * MT_STATUS is received with call state != 0,
                                 * we must send MT_RELEASE_COMPLETE cause 101
                                 */
                                dev_kfree_skb(skb);
                                if ((proc = new_l3_process(st, cr))) {
-                                       proc->para.cause = 0x65; /* 101 */
-                                       proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL);
+                                       proc->para.cause = 0x65;        /* 101 */
+                                       l3dss1_msg_without_setup(proc, 0, NULL);
                                }
                                return;
                        }
-               } else if (mt == MT_RELEASE_COMPLETE){
+               } else if (mt == MT_RELEASE_COMPLETE) {
                        dev_kfree_skb(skb);
                        return;
                } else {
                        /* ETS 300-104 part 2
-                        * if setup has not been made and a message type 
+                        * if setup has not been made and a message type
                         * (except MT_SETUP and RELEASE_COMPLETE) is received,
                         * we must send MT_RELEASE_COMPLETE cause 81 */
                        dev_kfree_skb(skb);
                        if ((proc = new_l3_process(st, cr))) {
-                               proc->para.cause = 0x51; /* 81 */
-                               proc->st->l3.l3l4(proc, CC_ESTABLISH, NULL);
+                               proc->para.cause = 0x51;        /* 81 */
+                               l3dss1_msg_without_setup(proc, 0, NULL);
                        }
                        return;
                }
@@ -1581,28 +1871,25 @@ dss1up(struct PStack *st, int pr, void *arg)
                 * 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 ;-) */
+               mt = MT_INVALID;        /* sorry, not clean, but do the right thing ;-) */
        }
-
-       for (i = 0; i < datasllen; i++)
+       for (i = 0; i < DATASLLEN; i++)
                if ((mt == datastatelist[i].primitive) &&
                    ((1 << proc->state) & datastatelist[i].state))
                        break;
-       if (i == datasllen) {
+       if (i == DATASLLEN) {
                dev_kfree_skb(skb);
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1up%sstate %d mt %x unhandled",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
+                       l3_debug(st, "dss1up%sstate %d mt %x unhandled",
+                               (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
                                proc->state, mt);
-                       l3_debug(st, tmp);
                }
                return;
        } else {
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1up%sstate %d mt %x",
-                               (pr == DL_DATA) ? " " : "(broadcast) ",
+                       l3_debug(st, "dss1up%sstate %d mt %x",
+                               (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
                                proc->state, mt);
-                       l3_debug(st, tmp);
                }
                datastatelist[i].rout(proc, pr, skb);
        }
@@ -1614,9 +1901,11 @@ dss1down(struct PStack *st, int pr, void *arg)
        int i, cr;
        struct l3_process *proc;
        struct Channel *chan;
-       char tmp[80];
 
-       if (CC_SETUP_REQ == pr) {
+       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;
@@ -1630,24 +1919,22 @@ dss1down(struct PStack *st, int pr, void *arg)
                proc = arg;
        }
        if (!proc) {
-               printk(KERN_ERR "HiSax internal error dss1down without proc\n");
+               printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr);
                return;
        }
-       for (i = 0; i < downsllen; i++)
+       for (i = 0; i < DOWNSLLEN; i++)
                if ((pr == downstatelist[i].primitive) &&
                    ((1 << proc->state) & downstatelist[i].state))
                        break;
-       if (i == downsllen) {
+       if (i == DOWNSLLEN) {
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1down state %d prim %d unhandled",
+                       l3_debug(st, "dss1down state %d prim %d unhandled",
                                proc->state, pr);
-                       l3_debug(st, tmp);
                }
        } else {
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "dss1down state %d prim %d",
+                       l3_debug(st, "dss1down state %d prim %d",
                                proc->state, pr);
-                       l3_debug(st, tmp);
                }
                downstatelist[i].rout(proc, pr, arg);
        }
index 8508c3109820e7e1b2da9d91d722854d5a967655..10e612482975a5ca5f39070cd36cda55902fa4cb 100644 (file)
@@ -1,8 +1,12 @@
-/* $Id: l3dss1.h,v 1.5 1998/02/02 13:34:30 keil Exp $
+/* $Id: l3dss1.h,v 1.6 1998/03/19 13:18:50 keil Exp $
  *
  *  DSS1 (Euro) D-channel protocol defines
  *
  * $Log: l3dss1.h,v $
+ * Revision 1.6  1998/03/19 13:18:50  keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
  * Revision 1.5  1998/02/02 13:34:30  keil
  * Support australian Microlink net and german AOCD
  *
@@ -63,8 +67,9 @@
 
 #define MT_INVALID             0xff
 
-#define IE_CAUSE               0x08
 #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
index b3e9819b221e64537a16fa9cb619cfee46497d33..d6ef0b63013c045d8384c135c788019f93f48826 100644 (file)
@@ -1,11 +1,21 @@
-/* $Id: lmgr.c,v 1.2 1997/10/29 19:09:34 keil Exp $
+/* $Id: lmgr.c,v 1.5 1998/11/15 23:55:12 keil Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *
  *
  *  Layermanagement module
  *
  * $Log: lmgr.c,v $
+ * Revision 1.5  1998/11/15 23:55:12  keil
+ * changes from 2.0
+ *
+ * Revision 1.4  1998/05/25 12:58:19  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 1.3  1998/03/07 22:57:06  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 1.2  1997/10/29 19:09:34  keil
  * new L1
  *
@@ -26,7 +36,7 @@ error_handling_dchan(struct PStack *st, int Error)
                case 'D':
                case 'G':
                case 'H':
-                       st->l2.l2tei(st, MDL_ERROR_REQ, NULL);
+                       st->l2.l2tei(st, MDL_ERROR | REQUEST, NULL);
                        break;
        }
 }
@@ -34,17 +44,15 @@ error_handling_dchan(struct PStack *st, int Error)
 static void
 hisax_manager(struct PStack *st, int pr, void *arg)
 {
-       char tm[32], str[256];
-       int Code;
+       long Code;
 
        switch (pr) {
-               case MDL_ERROR_IND:
-                       Code = (int) arg;
-                       jiftime(tm, jiffies);
-                       sprintf(str, "%s manager: MDL_ERROR %c %s\n", tm,
-                               Code, test_bit(FLG_LAPD, &st->l2.flag) ?
+               case (MDL_ERROR | INDICATION):
+                       Code = (long) arg;
+                       HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR",
+                               "%c %s\n", (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;
diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc
new file mode 100644 (file)
index 0000000..49888c5
--- /dev/null
@@ -0,0 +1,29 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+
+# This are valid md5sums for certificated HiSax driver.
+# The certification is valid only if the md5sums of all files match.
+# The certification is valid only for ELSA QuickStep cards in the moment.
+# Read ../../../Documentation/isdn/HiSax.cert for more informations.
+# 
+a273c532aec063574273ee519975cd9a  isac.c
+27c5c5bfa2ceabf02e2e6d686b03abde  isdnl1.c
+8c89ac659d3188ab997fb575da22b566  isdnl2.c
+d0fa912aa284b8fd19fed86b65999f6f  isdnl3.c
+1bce120740b615006286ad9b2d7fcdcb  tei.c
+8845f88dd17917d9b58badeff1605057  callc.c
+f3ec2a634f06074d16167aaba02b6dc1  cert.c
+71840ec8189f42b0db86fb38e5e5984c  l3dss1.c
+1882de8bea921b9ccd98fbe77267aa04  l3_1tr6.c
+3bd7af3a11693d028300278744d0da09  elsa.c
+# end of md5sums
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.3i
+Charset: noconv
+
+iQCVAwUBNrl5JDpxHvX/mS9tAQHm8wP+Nk64UJ2abdDG/igXZSrwcYhX/Kp7cxt9
+ccYp+aaur+pALA0lxwY3xcLt9u36fCYuTLHAVmQoiC9Vbemj37yzM2rUpz9nkw/7
+D6gLqZs2jxVpAwVVJgp0JwDONKXaRX6Lt2EPD9PTW6vxRWEu0HqGhM5hrtd/o4rV
+mC1W7Wj13XM=
+=LdhT
+-----END PGP SIGNATURE-----
index 8bf4757c9848024fb192baa39f434e3277f4cba4..ccd103feded2a94bcb9acc28ce70f9b489dd9990 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mic.c,v 1.6 1998/02/17 15:39:57 keil Exp $
+/* $Id: mic.c,v 1.7 1998/04/15 16:44:32 keil Exp $
 
  * mic.c  low level stuff for mic cards
  *
@@ -8,6 +8,9 @@
  *
  *
  * $Log: mic.c,v $
+ * Revision 1.7  1998/04/15 16:44:32  keil
+ * new init code
+ *
  * Revision 1.6  1998/02/17 15:39:57  keil
  * fix reset problem
  *
@@ -37,7 +40,7 @@
 
 extern const char *CardType[];
 
-const char *mic_revision = "$Revision: 1.6 $";
+const char *mic_revision = "$Revision: 1.7 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -220,10 +223,7 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                                        I4L_IRQ_FLAG, "HiSax", cs));
                case CARD_INIT:
                        inithscx(cs); /* /RTSA := ISAC RST */
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       inithscxisac(cs, 3);
                        return(0);
                case CARD_TEST:
                        return(0);
index 54f9c14d8fecb530cc90d77e9523b450f62e25ea..746451ba07bf6db91f706fd119818ba3d372daae 100644 (file)
@@ -1,13 +1,30 @@
-/* $Id: netjet.c,v 1.3 1998/02/12 23:08:05 keil Exp $
+/* $Id: netjet.c,v 1.8 1998/11/15 23:55:14 keil Exp $
 
  * netjet.c     low level stuff for Traverse Technologie NETJet ISDN cards
  *
- * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * Thanks to Traverse Technologie Australia for documents and informations
  *
  *
  * $Log: netjet.c,v $
+ * Revision 1.8  1998/11/15 23:55:14  keil
+ * changes from 2.0
+ *
+ * Revision 1.7  1998/09/30 22:24:48  keil
+ * Fix missing line in setstack*
+ *
+ * Revision 1.6  1998/08/13 23:36:54  keil
+ * HiSax 3.1 - don't work stable with current LinkLevel
+ *
+ * Revision 1.5  1998/05/25 12:58:21  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 1.4  1998/04/15 16:42:35  keil
+ * new init code
+ * new PCI init (2.1.94)
+ *
  * Revision 1.3  1998/02/12 23:08:05  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/interrupt.h>
-#define fcstab  ppp_crc16_table
 #include <linux/ppp_defs.h>
-extern __u16 ppp_crc16_table[256]; /* from ppp code */
 
 extern const char *CardType[];
 
-const char *NETjet_revision = "$Revision: 1.3 $";
+const char *NETjet_revision = "$Revision: 1.8 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -62,6 +76,12 @@ const char *NETjet_revision = "$Revision: 1.3 $";
 
 #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
 
@@ -115,6 +135,42 @@ ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
        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)
 {
@@ -146,25 +202,20 @@ 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",
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "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",
+                       if (cs->debug & L1_DEB_HSCX)
+                               debugl1(cs, "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;
@@ -197,16 +248,14 @@ mode_tiger(struct BCState *bcs, int mode, int bc)
                        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",
+       if (cs->debug & L1_DEB_HSCX)
+               debugl1(cs, "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)
@@ -266,7 +315,7 @@ static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s
                        val >>= 1;\
                }
 
-static void make_raw_data(struct BCState *bcs) {
+static int make_raw_data(struct BCState *bcs) {
        register u_int i,s_cnt=0;
        register u_char j;
        register u_char val;
@@ -274,13 +323,15 @@ static void make_raw_data(struct BCState *bcs) {
        register u_char s_val = 0;
        register u_char bitcnt = 0;
        u_int fcs;
-       char tmp[64];
-       
        
+       if (!bcs->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];
+       for (i=0; i<bcs->tx_skb->len; i++) {
+               val = bcs->tx_skb->data[i];
                fcs = PPP_FCS (fcs, val);
                MAKE_RAW_BYTE;
        }
@@ -303,11 +354,9 @@ static void make_raw_data(struct BCState *bcs) {
                }
                val >>= 1;
        }
-       if (bcs->cs->debug & L1_DEB_HSCX) {
-               sprintf(tmp,"tiger make_raw: in %d out %d.%d",
-                       bcs->hw.tiger.tx_skb->len, s_cnt, bitcnt);
-               debugl1(bcs->cs,tmp);
-       }
+       if (bcs->cs->debug & L1_DEB_HSCX)
+               debugl1(bcs->cs,"tiger make_raw: in %ld out %d.%d",
+                       bcs->tx_skb->len, s_cnt, bitcnt);
        if (bitcnt) {
                while (8>bitcnt++) {
                        s_val >>= 1;
@@ -316,8 +365,9 @@ static void make_raw_data(struct BCState *bcs) {
                bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
        }
        bcs->hw.tiger.sendcnt = s_cnt;
-       bcs->tx_cnt -= bcs->hw.tiger.tx_skb->len;
+       bcs->tx_cnt -= bcs->tx_skb->len;
        bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
+       return(0);
 }
 
 static void got_frame(struct BCState *bcs, int count) {
@@ -349,7 +399,6 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
        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);
@@ -370,11 +419,9 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
                                } 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",
+                                       if (bcs->cs->debug & L1_DEB_HSCX)
+                                               debugl1(bcs->cs,"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) {
@@ -387,11 +434,9 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
                                                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",
+                                               if (bcs->cs->debug & L1_DEB_HSCX)
+                                                       debugl1(bcs->cs,"tiger read_raw: flag(%d,%d,%d) %x",
                                                                bcs->hw.tiger.r_tot,i,j,val);
-                                                       debugl1(bcs->cs,tmp);
-                                               }
                                        }
                                        r_one=0;
                                }
@@ -425,12 +470,10 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
                                        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",
+                                       if (bcs->cs->debug & L1_DEB_HSCX)
+                                               debugl1(bcs->cs,"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) {
@@ -453,11 +496,9 @@ static void read_raw(struct BCState *bcs, u_int *buf, int cnt){
                                                        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",
+                                                       if (bcs->cs->debug & L1_DEB_HSCX)
+                                                               debugl1(bcs->cs,"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
@@ -509,7 +550,15 @@ static void read_tiger(struct IsdnCardState *cs) {
        u_int *p;
        int cnt = NETJET_DMA_SIZE/2;
        
-       if (cs->hw.njet.irqstat0 & 4)
+       if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) {
+               debugl1(cs,"tiger warn read double dma %x/%x",
+                       cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
+               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;
@@ -517,32 +566,28 @@ static void read_tiger(struct IsdnCardState *cs) {
                read_raw(cs->bcs, p, cnt);
        if (cs->bcs[1].mode == L1_MODE_HDLC)
                read_raw(cs->bcs + 1, p, cnt);
-       cs->hw.njet.irqstat0 &= 0xf3;
+       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)
+       if (!bcs->tx_skb)
                return;
-       if (bcs->cs->debug & L1_DEB_HSCX) {
-               sprintf(tmp,"tiger fill_dma1: c%d %4x", bcs->channel,
+       if (bcs->cs->debug & L1_DEB_HSCX)
+               debugl1(bcs->cs,"tiger fill_dma1: c%d %4x", bcs->channel,
                        bcs->Flag);
-                       debugl1(bcs->cs,tmp);
-       }
        if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
                return;
-       make_raw_data(bcs);
-       if (bcs->cs->debug & L1_DEB_HSCX) {
-               sprintf(tmp,"tiger fill_dma2: c%d %4x", bcs->channel,
+       if (make_raw_data(bcs))
+               return;         
+       if (bcs->cs->debug & L1_DEB_HSCX)
+               debugl1(bcs->cs,"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)) {
@@ -582,17 +627,14 @@ static void fill_dma(struct BCState *bcs)
                }
                write_raw(bcs, p, cnt);
        }
-       if (bcs->cs->debug & L1_DEB_HSCX) {
-               sprintf(tmp,"tiger fill_dma3: c%d %4x", bcs->channel,
+       if (bcs->cs->debug & L1_DEB_HSCX)
+               debugl1(bcs->cs,"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;
@@ -617,26 +659,23 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
                                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)
+                       debugl1(bcs->cs,"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);
                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);
+                       if (!bcs->tx_skb) {
+                               debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt);
                        } else {
                                if (bcs->st->lli.l1writewakeup &&
-                                       (PACKET_NOACK != bcs->hw.tiger.tx_skb->pkt_type))
-                                       bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.tiger.tx_skb->len);
-                               dev_kfree_skb(bcs->hw.tiger.tx_skb);
-                               bcs->hw.tiger.tx_skb = NULL;
+                                       (PACKET_NOACK != bcs->tx_skb->pkt_type))
+                                       bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
+                               dev_kfree_skb(bcs->tx_skb);
+                               bcs->tx_skb = NULL;
                        }
                        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
                        bcs->hw.tiger.free = cnt - s_cnt;
@@ -646,7 +685,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
                                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))) {
+                       if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
                                fill_dma(bcs);
                        } else {
                                mask ^= 0xffffffff;
@@ -656,11 +695,9 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
                                                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",
+                                       if (bcs->cs->debug & L1_DEB_HSCX)
+                                               debugl1(bcs->cs, "tiger write_raw: fill rest %d",
                                                        cnt - s_cnt);
-                                               debugl1(bcs->cs,tmp);
-                                       }
                                }
                                bcs->event |= 1 << B_XMTBUFREADY;
                                queue_task(&bcs->tqueue, &tq_immediate);
@@ -671,24 +708,28 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
                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);
-               }
+               if (bcs->cs->debug & L1_DEB_HSCX)
+                       debugl1(bcs->cs,"tiger write_raw: fill half");
        } 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);
-               }
+               if (bcs->cs->debug & L1_DEB_HSCX)
+                       debugl1(bcs->cs,"tiger write_raw: fill full");
        }
 }
 
 static void write_tiger(struct IsdnCardState *cs) {
        u_int *p, cnt = NETJET_DMA_SIZE/2;
        
-       if (cs->hw.njet.irqstat0  & 1)
+       if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
+               debugl1(cs,"tiger warn write double dma %x/%x",
+                       cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
+               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;
@@ -696,7 +737,7 @@ static void write_tiger(struct IsdnCardState *cs) {
                write_raw(cs->bcs, p, cnt);
        if (cs->bcs[1].mode == L1_MODE_HDLC)
                write_raw(cs->bcs + 1, p, cnt);
-       cs->hw.njet.irqstat0 &= 0xfc;
+       cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE;
 }
 
 static void
@@ -706,45 +747,58 @@ tiger_l2l1(struct PStack *st, int pr, void *arg)
        long flags;
 
        switch (pr) {
-               case (PH_DATA_REQ):
+               case (PH_DATA | REQUEST):
                        save_flags(flags);
                        cli();
-                       if (st->l1.bcs->hw.tiger.tx_skb) {
+                       if (st->l1.bcs->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->tx_skb = skb;
                                st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
                                restore_flags(flags);
                        }
                        break;
-               case (PH_PULL_IND):
-                       if (st->l1.bcs->hw.tiger.tx_skb) {
+               case (PH_PULL | INDICATION):
+                       if (st->l1.bcs->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->tx_skb = skb;
                        st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
                        restore_flags(flags);
                        break;
-               case (PH_PULL_REQ):
-                       if (!st->l1.bcs->hw.tiger.tx_skb) {
+               case (PH_PULL | REQUEST):
+                       if (!st->l1.bcs->tx_skb) {
                                test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-                               st->l1.l1l2(st, PH_PULL_CNF, NULL);
+                               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);
+                       l1_msg_b(st, pr, arg);
+                       break;
+               case (PH_DEACTIVATE | REQUEST):
+                       l1_msg_b(st, pr, arg);
+                       break;
+               case (PH_DEACTIVATE | CONFIRM):
+                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+                       test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+                       mode_tiger(st->l1.bcs, 0, st->l1.bc);
+                       st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+                       break;
        }
 }
 
+
 void
 close_tigerstate(struct BCState *bcs)
 {
-       struct sk_buff *skb;
-
-       mode_tiger(bcs, 0, 0);
+       mode_tiger(bcs, 0, bcs->channel);
        if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
                if (bcs->hw.tiger.rcvbuf) {
                        kfree(bcs->hw.tiger.rcvbuf);
@@ -754,32 +808,26 @@ close_tigerstate(struct BCState *bcs)
                        kfree(bcs->hw.tiger.sendbuf);
                        bcs->hw.tiger.sendbuf = NULL;
                }
-               while ((skb = skb_dequeue(&bcs->rqueue))) {
-                       dev_kfree_skb(skb);
-               }
-               while ((skb = skb_dequeue(&bcs->squeue))) {
-                       dev_kfree_skb(skb);
-               }
-               if (bcs->hw.tiger.tx_skb) {
-                       dev_kfree_skb(bcs->hw.tiger.tx_skb);
-                       bcs->hw.tiger.tx_skb = NULL;
+               discard_queue(&bcs->rqueue);
+               discard_queue(&bcs->squeue);
+               if (bcs->tx_skb) {
+                       dev_kfree_skb(bcs->tx_skb);
+                       bcs->tx_skb = NULL;
                        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
                }
        }
 }
 
 static int
-open_tigerstate(struct IsdnCardState *cs, int bc)
+open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs)
 {
-       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))) {
+               if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
                        printk(KERN_WARNING
                               "HiSax: No memory for tiger.rcvbuf\n");
                        return (1);
                }
-               if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_KERNEL))) {
+               if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
                        printk(KERN_WARNING
                               "HiSax: No memory for tiger.sendbuf\n");
                        return (1);
@@ -787,7 +835,7 @@ open_tigerstate(struct IsdnCardState *cs, int bc)
                skb_queue_head_init(&bcs->rqueue);
                skb_queue_head_init(&bcs->squeue);
        }
-       bcs->hw.tiger.tx_skb = NULL;
+       bcs->tx_skb = NULL;
        bcs->hw.tiger.sendcnt = 0;
        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
        bcs->event = 0;
@@ -795,34 +843,17 @@ open_tigerstate(struct IsdnCardState *cs, int bc)
        return (0);
 }
 
-static void
-tiger_manl1(struct PStack *st, int pr,
-         void *arg)
-{
-       switch (pr) {
-               case (PH_ACTIVATE_REQ):
-                       test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-                       mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
-                       st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
-                       break;
-               case (PH_DEACTIVATE_REQ):
-                       if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
-                               mode_tiger(st->l1.bcs, 0, 0);
-                       test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-                       break;
-       }
-}
-
 int
 setstack_tiger(struct PStack *st, struct BCState *bcs)
 {
-       if (open_tigerstate(st->l1.hardware, bcs->channel))
+       bcs->channel = st->l1.bc;
+       if (open_tigerstate(st->l1.hardware, bcs))
                return (-1);
        st->l1.bcs = bcs;
        st->l2.l2l1 = tiger_l2l1;
-       st->ma.manl1 = tiger_manl1;
        setstack_manager(st);
        bcs->st = st;
+       setstack_l1_B(st);
        return (0);
 }
 
@@ -830,8 +861,6 @@ setstack_tiger(struct PStack *st, struct BCState *bcs)
 __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
@@ -845,9 +874,8 @@ inittiger(struct IsdnCardState *cs))
        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,
+       debugl1(cs, "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),
@@ -860,9 +888,8 @@ inittiger(struct IsdnCardState *cs))
                       "HiSax: No memory for tiger.rec\n");
                return;
        }
-       sprintf(tmp, "tiger: rec buf %x - %x", (u_int)cs->bcs[0].hw.tiger.rec,
+       debugl1(cs, "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),
@@ -871,11 +898,10 @@ inittiger(struct IsdnCardState *cs))
                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",
+       debugl1(cs, "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;
@@ -906,8 +932,8 @@ static void
 netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 {
        struct IsdnCardState *cs = dev_id;
-       u_char val, sval, stat = 1;
-       char tmp[128];
+       u_char val, sval;
+       long flags;
 
        if (!cs) {
                printk(KERN_WARNING "NETjet: Spurious interrupt!\n");
@@ -916,49 +942,49 @@ netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        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 (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "tiger: i1 %x %x", sval, val);
                if (val) {
                        isac_interrupt(cs, val);
-                       stat |= 2;
+                       WriteISAC(cs, ISAC_MASK, 0xFF);
+                       WriteISAC(cs, ISAC_MASK, 0x0);
                }
        }
-       if ((cs->hw.njet.irqstat0 = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) {
-/*             sprintf(tmp, "tiger: ist0 %x  %x %x  %x/%x  pulse=%d",
+       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);
+/*             debugl1(cs, "tiger: ist0 %x  %x %x  %x/%x  pulse=%d",
                        sval, 
                        bytein(cs->hw.njet.base + NETJET_DMACTRL),
                        bytein(cs->hw.njet.base + NETJET_IRQMASK0),
                        inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
                        inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
                        bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
-               debugl1(cs, tmp);
 */
-               if (cs->hw.njet.last_is0 & cs->hw.njet.irqstat0 & 0xf) {
-                       sprintf(tmp, "tiger: ist0 %x->%x irq lost",
-                               cs->hw.njet.last_is0, cs->hw.njet.irqstat0);
-                       debugl1(cs, tmp);
-               }
-               cs->hw.njet.last_is0 = cs->hw.njet.irqstat0;
 /*             cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30;
 */             byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0);
 /*             byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0);
-*/             if (cs->hw.njet.irqstat0 & 0x0c)
+*/             if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ)
                        read_tiger(cs);
-               if (cs->hw.njet.irqstat0 & 0x03)
+               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);
        }
-*/     if (stat & 2) {
-               WriteISAC(cs, ISAC_MASK, 0xFF);
-               WriteISAC(cs, ISAC_MASK, 0x0);
-       }
+*/
 }
 
 static void
@@ -1006,11 +1032,13 @@ NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        return(0);
                case CARD_SETIRQ:
                        return(request_irq(cs->irq, &netjet_interrupt,
-                                       I4L_IRQ_FLAG, "HiSax", cs));
+                                       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);
@@ -1020,7 +1048,7 @@ NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 
 
 
-static         int pci_index __initdata = 0;
+static         struct pci_dev *dev_netjet __initdata = NULL;
 
 __initfunc(int
 setup_netjet(struct IsdnCard *card))
@@ -1028,52 +1056,37 @@ 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);
+       test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
 #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");
+       if (!pci_present()) {
+               printk(KERN_ERR "Netjet: no PCI bus present\n");
                return(0);
        }
-       if (!pci_irq) {
+       if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH,
+               PCI_NETJET_ID,  dev_netjet))) {
+               cs->irq = dev_netjet->irq;
+               if (!cs->irq) {
                printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n");
                return(0);
        }
-       if (!pci_ioaddr) {
+               cs->hw.njet.base = dev_netjet->base_address[0] &
+                       PCI_BASE_ADDRESS_IO_MASK; 
+               if (!cs->hw.njet.base) {
                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;
+               cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+               cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
        bytecnt = 256;
+       } else {
+               printk(KERN_WARNING "NETjet: No PCI card found\n");
+               return(0);
+       }
 #else
        printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n");
        printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n");
index 59a8a94e34d90c95ab1a013627ed4f8ceb4f5eac..13717f856a6e27058fbfc0fd690336518476635e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: niccy.c,v 1.2 1998/02/11 17:31:04 keil Exp $
+/* $Id: niccy.c,v 1.4 1998/04/16 19:16:48 keil Exp $
 
  * niccy.c  low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
  *          compatible (SAGEM cybermodem)
@@ -8,24 +8,28 @@
  * Thanks to Dr. Neuhaus and SAGEM for informations
  *
  * $Log: niccy.c,v $
- * Revision 1.2  1998/02/11 17:31:04  keil
- * new file
+ * Revision 1.4  1998/04/16 19:16:48  keil
+ * need config.h
  *
+ * Revision 1.3  1998/04/15 16:42:59  keil
+ * new init code
  *
+ * Revision 1.2  1998/02/11 17:31:04  keil
+ * new file
  *
  */
 
-#include <linux/config.h>
+
 #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.2 $";
+const char *niccy_revision = "$Revision: 1.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -44,6 +48,10 @@ const char *niccy_revision = "$Revision: 1.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)
@@ -152,6 +160,13 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                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) {
@@ -191,9 +206,15 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
 void
 release_io_niccy(struct IsdnCardState *cs)
 {
-       if (cs->subtyp == NICCY_PCI)
+       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 {
+       else {
                release_region(cs->hw.niccy.isac, 2);
                release_region(cs->hw.niccy.isac_ale, 2);
        }
@@ -202,12 +223,20 @@ release_io_niccy(struct IsdnCardState *cs)
 static void
 niccy_reset(struct IsdnCardState *cs)
 {
-       // No reset procedure known
+       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);
@@ -216,13 +245,15 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        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,
-                                       I4L_IRQ_FLAG, "HiSax", cs));
+                               imode, "HiSax", cs));
+                       break;
                case CARD_INIT:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       niccy_reset(cs);
                        return(0);
                case CARD_TEST:
                        return(0);
@@ -230,7 +261,7 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-static         int pci_index __initdata = 0;
+static         struct pci_dev *niccy_dev __initdata = NULL;
 
 __initfunc(int
 setup_niccy(struct IsdnCard *card))
@@ -272,49 +303,41 @@ setup_niccy(struct IsdnCard *card))
                        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;
 
+               if (!pci_present()) {
+                       printk(KERN_ERR "Niccy: no PCI bus present\n");
+                       return(0);
+               }
+
                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;
+               if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS,
+                          PCI_NICCY_ID, niccy_dev))) {
                        /* get IRQ */
-                       pcibios_read_config_byte(pci_bus, pci_device_fn,
-                               PCI_INTERRUPT_LINE, &pci_irq);
-
-                       /* get IO address */
-                       /* if it won't work try the other PCI addresses
-                        * PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5
-                        */
-                       pcibios_read_config_dword(pci_bus, pci_device_fn,
-                               PCI_BASE_ADDRESS_2, &pci_ioaddr);
-                       if (cs->subtyp)
-                               break;
-               }
-               if (!cs->subtyp) {
-                       printk(KERN_WARNING "Niccy: No PCI card found\n");
+                       if (!niccy_dev->irq) {
+                               printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
                        return(0);
                }
-               if (!pci_irq) {
-                       printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
+                       cs->irq = niccy_dev->irq;
+                       if (!niccy_dev->base_address[0]) {
+                               printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
                        return(0);
                }
-
-               if (!pci_ioaddr) {
+                       cs->hw.niccy.cfg_reg = niccy_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+                       if (!niccy_dev->base_address[1]) {
                        printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
                        return(0);
                }
-               pci_ioaddr &= ~3; /* remove io/mem flag */
+                       pci_ioaddr = niccy_dev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
                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;
+                       cs->subtyp = NICCY_PCI;
+               } else {
+                       printk(KERN_WARNING "Niccy: No PCI card found\n");
+                       return(0);
+               }
                if (check_region((cs->hw.niccy.isac), 4)) {
                        printk(KERN_WARNING
                                "HiSax: %s data port %x-%x already in use\n",
@@ -324,6 +347,17 @@ setup_niccy(struct IsdnCard *card))
                        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");
@@ -334,7 +368,6 @@ setup_niccy(struct IsdnCard *card))
                "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
                CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
                cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
-       niccy_reset(cs);
        cs->readisac = &ReadISAC;
        cs->writeisac = &WriteISAC;
        cs->readisacfifo = &ReadISACfifo;
index a0ba3645a5cae01c9da20e7bc053cded3486d99d..d3c269a04db1774d51789eac868a4b7994c5cbf6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: q931.c,v 1.6 1997/07/27 21:09:44 keil Exp $
+/* $Id: q931.c,v 1.7 1998/11/15 23:55:17 keil Exp $
 
  * q931.c       code to decode ITU Q.931 call control messages
  *
@@ -14,6 +14,9 @@
  *
  *
  * $Log: q931.c,v $
+ * Revision 1.7  1998/11/15 23:55:17  keil
+ * changes from 2.0
+ *
  * Revision 1.6  1997/07/27 21:09:44  keil
  * move functions to isdnl3.c
  *
@@ -159,7 +162,7 @@ struct MessageType mt_n0[] =
        {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
 };
 
-int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
+#define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType))
 
 static
 struct MessageType mt_n1[] =
@@ -196,7 +199,7 @@ struct MessageType mt_n1[] =
        {MT_N1_STAT, "STATus"}
 };
 
-int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
+#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
 
 static struct MessageType fac_1tr6[] =
 {
@@ -220,9 +223,7 @@ static struct MessageType fac_1tr6[] =
        {FAC_Rueckwechsel, "Rueckwechsel"},
        {FAC_Umleitung, "Umleitung"}
 };
-int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
-
-
+#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType))
 
 static int
 prbits(char *dest, u_char b, int start, int len)
@@ -925,7 +926,7 @@ static struct InformationElement we_0[] =
        {WE0_userInfo, "User Info", general}
 };
 
-static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
+#define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement))
 
 static struct InformationElement we_6[] =
 {
@@ -937,7 +938,7 @@ static struct InformationElement we_6[] =
        {WE6_statusCalled, "Status Called", general},
        {WE6_addTransAttr, "Additional Transmission Attributes", general}
 };
-static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
+#define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement))
 
 int
 QuickHex(char *txt, u_char * p, int cnt)
@@ -964,39 +965,92 @@ QuickHex(char *txt, u_char * p, int cnt)
 }
 
 void
-LogFrame(struct IsdnCardState *sp, u_char * buf, int size)
+LogFrame(struct IsdnCardState *cs, u_char * buf, int size)
 {
        char *dp;
 
        if (size < 1)
                return;
-       dp = sp->dlogspace;
-       if (size < 4096 / 3 - 10) {
-               dp += sprintf(dp, "HEX:");
+       dp = cs->dlog;
+       if (size < MAX_DLOG_SPACE / 3 - 10) {
+               *dp++ = 'H';
+               *dp++ = 'E';
+               *dp++ = 'X';
+               *dp++ = ':';
                dp += QuickHex(dp, buf, size);
                dp--;
                *dp++ = '\n';
                *dp = 0;
+               HiSax_putstatus(cs, NULL, cs->dlog);
        } else
-               sprintf(dp, "LogFrame: warning Frame too big (%d)\n",
-                       size);
-       HiSax_putstatus(sp, sp->dlogspace);
+               HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
 }
 
 void
-dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment)
+dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
 {
-       u_char *bend = buf + size;
+       u_char *bend, *buf;
        char *dp;
        unsigned char pd, cr_l, cr, mt;
-       int i, cs = 0, cs_old = 0, cs_fest = 0;
+       unsigned char sapi, tei, ftyp;
+       int i, cset = 0, cs_old = 0, cs_fest = 0;
+       int size, finish = 0;
 
-       if (size < 1)
+       if (skb->len < 3)
                return;
        /* display header */
-       dp = sp->dlogspace;
-       dp += sprintf(dp, "%s\n", comment);
-
+       dp = cs->dlog;
+       dp += jiftime(dp, jiffies);
+       *dp++ = ' ';
+       sapi = skb->data[0] >> 2;
+       tei  = skb->data[1] >> 1;
+       ftyp = skb->data[2];
+       buf = skb->data;
+       dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network");
+       size = skb->len;
+       
+       if (tei == GROUP_TEI) {
+               if (sapi == CTRL_SAPI) { /* sapi 0 */
+                       if (ftyp == 3) {
+                               dp += sprintf(dp, "broadcast\n");
+                               buf += 3;
+                               size -= 3;
+                       } else {
+                               dp += sprintf(dp, "no UI broadcast\n");
+                               finish = 1;
+                       }
+               } else if (sapi == TEI_SAPI) {
+                       dp += sprintf(dp, "tei managment\n");
+                       finish = 1;
+               } else {
+                       dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
+                       finish = 1;
+               }
+       } else {
+               if (sapi == CTRL_SAPI) {
+                       if (!(ftyp & 1)) { /* IFrame */
+                               dp += sprintf(dp, "with tei %d\n", tei);
+                               buf += 4;
+                               size -= 4;
+                       } else {
+                               dp += sprintf(dp, "SFrame with tei %d\n", tei);
+                               finish = 1;
+                       }
+               } else {
+                       dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei);
+                       finish = 1;
+               }
+       }
+       bend = skb->data + skb->len;
+       if (buf >= bend) {
+               dp += sprintf(dp, "frame too short\n");
+               finish = 1;
+       }
+       if (finish) {
+               *dp = 0;
+               HiSax_putstatus(cs, NULL, cs->dlog);
+               return;
+       }
        if ((0xfe & buf[0]) == PROTO_DIS_N0) {  /* 1TR6 */
                /* locate message type */
                pd = *buf++;
@@ -1007,11 +1061,11 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment)
                        cr = 0;
                mt = *buf++;
                if (pd == PROTO_DIS_N0) {       /* N0 */
-                       for (i = 0; i < mt_n0_len; i++)
+                       for (i = 0; i < MT_N0_LEN; i++)
                                if (mt_n0[i].nr == mt)
                                        break;
                        /* display message type if it exists */
-                       if (i == mt_n0_len)
+                       if (i == MT_N0_LEN)
                                dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
                                              cr & 0x7f, (cr & 0x80) ? "called" : "caller",
                                              size, mt);
@@ -1020,11 +1074,11 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment)
                                              cr & 0x7f, (cr & 0x80) ? "called" : "caller",
                                              size, mt_n0[i].descr);
                } else {        /* N1 */
-                       for (i = 0; i < mt_n1_len; i++)
+                       for (i = 0; i < MT_N1_LEN; i++)
                                if (mt_n1[i].nr == mt)
                                        break;
                        /* display message type if it exists */
-                       if (i == mt_n1_len)
+                       if (i == MT_N1_LEN)
                                dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
                                              cr & 0x7f, (cr & 0x80) ? "called" : "caller",
                                              size, mt);
@@ -1041,8 +1095,8 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment)
                                switch ((*buf >> 4) & 7) {
                                        case 1:
                                                dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
-                                               cs_old = cs;
-                                               cs = *buf & 7;
+                                               cs_old = cset;
+                                               cset = *buf & 7;
                                                cs_fest = *buf & 8;
                                                break;
                                        case 3:
@@ -1066,33 +1120,33 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment)
                                continue;
                        }
                        /* No, locate it in the table */
-                       if (cs == 0) {
-                               for (i = 0; i < we_0_len; i++)
+                       if (cset == 0) {
+                               for (i = 0; i < WE_0_LEN; i++)
                                        if (*buf == we_0[i].nr)
                                                break;
 
                                /* When found, give appropriate msg */
-                               if (i != we_0_len) {
+                               if (i != WE_0_LEN) {
                                        dp += sprintf(dp, "  %s\n", we_0[i].descr);
                                        dp += we_0[i].f(dp, buf);
                                } else
-                                       dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
-                       } else if (cs == 6) {
-                               for (i = 0; i < we_6_len; i++)
+                                       dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
+                       } else if (cset == 6) {
+                               for (i = 0; i < WE_6_LEN; i++)
                                        if (*buf == we_6[i].nr)
                                                break;
 
                                /* When found, give appropriate msg */
-                               if (i != we_6_len) {
+                               if (i != WE_6_LEN) {
                                        dp += sprintf(dp, "  %s\n", we_6[i].descr);
                                        dp += we_6[i].f(dp, buf);
                                } else
-                                       dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+                                       dp += sprintf(dp, "  Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
                        } else
-                               dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+                               dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
                        /* Skip to next element */
                        if (cs_fest == 8) {
-                               cs = cs_old;
+                               cset = cs_old;
                                cs_old = 0;
                                cs_fest = 0;
                        }
@@ -1170,6 +1224,6 @@ dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment)
        } else {
                dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
        }
-       dp += sprintf(dp, "\n");
-       HiSax_putstatus(sp, sp->dlogspace);
+       *dp = 0;
+       HiSax_putstatus(cs, NULL, cs->dlog);
 }
index b878cb699d9c1dffc2c3bd2f11454b27382ca833..17ac5c60200c198be1777f4d6c36b94615f5c85c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: rawhdlc.c,v 1.2 1998/02/09 10:53:51 keil Exp $
+/* $Id: rawhdlc.c,v 1.3 1998/06/17 19:51:21 he Exp $
 
  * rawhdlc.c     support routines for cards that don't support HDLC
  *
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
new file mode 100644 (file)
index 0000000..479880b
--- /dev/null
@@ -0,0 +1,277 @@
+/* $Id: s0box.c,v 2.1 1998/04/15 16:38:24 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: 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);
+}
index 46d3edaf05b6a429b866f72e1413a19caff4ad95..85e64001a37d2e504956d710a5d290300aac607f 100644 (file)
@@ -1,11 +1,14 @@
-/* $Id: sedlbauer.c,v 1.6 1998/02/09 18:46:06 keil Exp $
+/* $Id: sedlbauer.c,v 1.9 1998/11/15 23:55:20 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
+ *              includes support for the Sedlbauer speed star (speed star II),
+ *              support for the Sedlbauer speed fax+,
+ *              support for the Sedlbauer ISDN-Controller PC/104 and
+ *              support for the Sedlbauer speed pci
+ *              derived from the original file asuscom.c from Karsten Keil
  *
  * Copyright (C) 1997,1998 Marcus Niemann (for the modifications to
- *                                         the original file dynalink.c)
+ *                                         the original file asuscom.c)
  *
  * Author     Marcus Niemann (niemann@www-bib.fh-bielefeld.de)
  *
  *            Edgar Toernig
  *
  * $Log: sedlbauer.c,v $
+ * Revision 1.9  1998/11/15 23:55:20  keil
+ * changes from 2.0
+ *
+ * Revision 1.8  1998/08/13 23:34:51  keil
+ * starting speedfax+ (ISAR) support
+ *
+ * Revision 1.7  1998/04/15 16:44:33  keil
+ * new init code
+ *
  * Revision 1.6  1998/02/09 18:46:06  keil
  * Support for Sedlbauer PCMCIA (Marcus Niemann)
  *
  *
  */
 
+/* Supported cards:
+ * Card:       Chip:           Configuration:  Comment:
+ * ---------------------------------------------------------------------
+ * Speed Card  ISAC_HSCX       DIP-SWITCH
+ * Speed Win   ISAC_HSCX       ISAPNP
+ * Speed Fax+  ISAC_ISAR       ISAPNP          #HDLC works#
+ * Speed Star  ISAC_HSCX       CARDMGR
+ * Speed Win2  IPAC            ISAPNP
+ * ISDN PC/104 IPAC            DIP-SWITCH
+ * Speed Star2 IPAC            CARDMGR
+ * Speed PCI   IPAC            PNP             
+ *
+ * Important:
+ * For the sedlbauer speed fax+ to work properly you have to download 
+ * the firmware onto the card.
+ * For example: hisaxctrl <DriverID> 9 ISAR.BIN
+*/
+
+#define SEDLBAUER_PCI 1
+
 #define __NO_VERSION__
+#include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
+#include "ipac.h"
 #include "hscx.h"
+#include "isar.h"
 #include "isdnl1.h"
+#include <linux/pci.h>
 
 extern const char *CardType[];
 
-const char *Sedlbauer_revision = "$Revision: 1.6 $";
+const char *Sedlbauer_revision = "$Revision: 1.9 $";
 
 const char *Sedlbauer_Types[] =
-{"None", "Speed Card", "Speed Win", "Speed Star"};
+       {"None", "speed card/win", "speed star", "speed fax+", 
+       "speed win II / ISDN PC/104", "speed star II", "speed pci"};
+
+#ifdef SEDLBAUER_PCI
+#define PCI_VENDOR_SEDLBAUER   0xe159
+#define PCI_SPEEDPCI_ID        0x02
+#endif
  
-#define SEDL_SPEED_CARD 1
-#define SEDL_SPEED_WIN  2
-#define SEDL_SPEED_STAR 3
+#define SEDL_SPEED_CARD_WIN    1
+#define SEDL_SPEED_STAR        2
+#define SEDL_SPEED_FAX         3
+#define SEDL_SPEED_WIN2_PC104  4
+#define SEDL_SPEED_STAR2       5
+#define SEDL_SPEED_PCI         6
+
+#define SEDL_CHIP_TEST         0
+#define SEDL_CHIP_ISAC_HSCX    1
+#define SEDL_CHIP_ISAC_ISAR    2
+#define SEDL_CHIP_IPAC         3
+
+#define SEDL_BUS_ISA           1
+#define SEDL_BUS_PCI           2
+#define        SEDL_BUS_PCMCIA         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_HSCX_ISA_RESET_ON 0
+#define SEDL_HSCX_ISA_RESET_OFF        1
+#define SEDL_HSCX_ISA_ISAC     2
+#define SEDL_HSCX_ISA_HSCX     3
+#define SEDL_HSCX_ISA_ADR      4
+
+#define SEDL_HSCX_PCMCIA_RESET 0
+#define SEDL_HSCX_PCMCIA_ISAC  1
+#define SEDL_HSCX_PCMCIA_HSCX  2
+#define SEDL_HSCX_PCMCIA_ADR   4
+
+#define SEDL_ISAR_ISA_ISAC             4
+#define SEDL_ISAR_ISA_ISAR             6
+#define SEDL_ISAR_ISA_ADR              8
+#define SEDL_ISAR_ISA_ISAR_RESET_ON    10
+#define SEDL_ISAR_ISA_ISAR_RESET_OFF   12
 
-#define SEDL_PCMCIA_RESET      0
-#define SEDL_PCMCIA_ISAC       1
-#define SEDL_PCMCIA_HSCX       2
-#define SEDL_PCMCIA_ADR                4
+#define SEDL_IPAC_ANY_ADR      0
+#define SEDL_IPAC_ANY_IPAC     2
+
+#define SEDL_IPAC_PCI_BASE     0
+#define SEDL_IPAC_PCI_ADR      0xc0
+#define SEDL_IPAC_PCI_IPAC     0xc8
 
 #define SEDL_RESET      0x3    /* same as DOS driver */
 
@@ -138,6 +205,29 @@ WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
        writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
 }
 
+static u_char
+ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
+{
+        return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80));}
+
+static void
+WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+        writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset|0x80, value);
+}
+
+static void
+ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
+{
+        readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
+}
+
+static void
+WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
+{
+        writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
+}
+
 static u_char
 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
@@ -152,6 +242,34 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
                 cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value);
 }
 
+/* ISAR access routines
+ * mode = 0 access with IRQ on
+ * mode = 1 access with IRQ off
+ * mode = 2 access with IRQ off and using last offset
+ */
+  
+static u_char
+ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
+{      
+       if (mode == 0)
+               return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset));
+       else if (mode == 1)
+               byteout(cs->hw.sedl.adr, offset);
+       return(bytein(cs->hw.sedl.hscx));
+}
+
+static void
+WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
+{
+       if (mode == 0)
+               writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value);
+       else {
+               if (mode == 1)
+                       byteout(cs->hw.sedl.adr, offset);
+               byteout(cs->hw.sedl.hscx, value);
+       }
+}
+
 /*
  * fast interrupt HSCX stuff goes here
  */
@@ -180,7 +298,7 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
                return;
        }
 
-        if ((cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) && (*cs->busy_flag == 1)) {
+       if ((cs->hw.sedl.bus == SEDL_BUS_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");
@@ -223,11 +341,101 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        }
 }
 
+static void
+sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char ista, val, icnt = 20;
+
+       if (!cs) {
+               printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n");
+               return;
+       }
+       ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
+Start_IPAC:
+       if (cs->debug & L1_DEB_IPAC)
+               debugl1(cs, "IPAC ISTA %02X", ista);
+       if (ista & 0x0f) {
+               val = readreg(cs->hw.sedl.adr, cs->hw.sedl.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.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80);
+               if (val) {
+                       isac_interrupt(cs, val);
+               }
+       }
+       if (ista & 0x10) {
+               val = 0x01;
+               isac_interrupt(cs, val);
+       }
+       ista  = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
+       if ((ista & 0x3f) && icnt) {
+               icnt--;
+               goto Start_IPAC;
+       }
+       if (!icnt)
+               printk(KERN_WARNING "Sedlbauer IRQ LOOP\n");
+       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF);
+       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0);
+}
+
+static void
+sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
+{
+       struct IsdnCardState *cs = dev_id;
+       u_char val;
+       int cnt = 20;
+
+       if (!cs) {
+               printk(KERN_WARNING "Sedlbauer: Spurious interrupt!\n");
+               return;
+       }
+
+       val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
+      Start_ISAR:
+       if (val & ISAR_IRQSTA)
+               isar_int_main(cs);
+       val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
+      Start_ISAC:
+       if (val)
+               isac_interrupt(cs, val);
+       val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
+       if ((val & ISAR_IRQSTA) && --cnt) {
+               if (cs->debug & L1_DEB_HSCX)
+                       debugl1(cs, "ISAR IntStat after IntRoutine");
+               goto Start_ISAR;
+       }
+       val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
+       if (val && --cnt) {
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "ISAC IntStat after IntRoutine");
+               goto Start_ISAC;
+       }
+       if (!cnt)
+               printk(KERN_WARNING "Sedlbauer IRQ LOOP\n");
+
+       writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0);
+       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
+       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
+       writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK);
+}
+
 void
 release_io_sedlbauer(struct IsdnCardState *cs)
 {
-       int bytecnt = 8;
+       int bytecnt = (cs->subtyp == SEDL_SPEED_FAX) ? 16 : 8;
 
+       if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
+               bytecnt = 256;
+       }
        if (cs->hw.sedl.cfg_reg)
                release_region(cs->hw.sedl.cfg_reg, bytecnt);
 }
@@ -237,16 +445,36 @@ 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;
-               schedule_timeout(1);
-               byteout(cs->hw.sedl.reset_off, 0);      /* Reset Off */
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(1);
-               restore_flags(flags);
+       printk(KERN_INFO "Sedlbauer: resetting card\n");
+
+       if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) &&
+          (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) {
+               if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
+                       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
+                       save_flags(flags);
+                       sti();
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+                       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+                       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0);
+                       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
+                       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0);
+                       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
+                       writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
+                       restore_flags(flags);
+               } else {                
+                       byteout(cs->hw.sedl.reset_on, SEDL_RESET);      /* Reset On */
+                       save_flags(flags);
+                       sti();
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+                       byteout(cs->hw.sedl.reset_off, 0);      /* Reset Off */
+                       current->state = TASK_INTERRUPTIBLE;
+                       schedule_timeout(1);
+                       restore_flags(flags);
+               }
        }
 }
 
@@ -261,94 +489,256 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        release_io_sedlbauer(cs);
                        return(0);
                case CARD_SETIRQ:
-                       return(request_irq(cs->irq, &sedlbauer_interrupt,
+                       if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+                               return(request_irq(cs->irq, &sedlbauer_interrupt_isar,
                                        I4L_IRQ_FLAG, "HiSax", cs));
+                       } else if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
+                               return(request_irq(cs->irq, &sedlbauer_interrupt_ipac,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+                       } else {
+                               return(request_irq(cs->irq, &sedlbauer_interrupt,
+                                       I4L_IRQ_FLAG, "HiSax", cs));
+                       }
                case CARD_INIT:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+                               clear_pending_isac_ints(cs);
+                               writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
+                                       ISAR_IRQBIT, 0);
+                               initisac(cs);
+                               initisar(cs);
+                               /* Reenable all IRQ */
+                               cs->writeisac(cs, ISAC_MASK, 0);
+                               /* RESET Receiver and Transmitter */
+                               cs->writeisac(cs, ISAC_CMDR, 0x41);
+                       } else {
+                               inithscxisac(cs, 3);
+                       }
                        return(0);
                case CARD_TEST:
                        return(0);
+               case CARD_LOAD_FIRM:
+                       if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+                               if (isar_load_firmware(cs, arg))
+                                       return(1);
+                               else 
+                                       ll_run(cs);
+                       }
+                       return(0);
        }
        return(0);
 }
 
+
+#ifdef SEDLBAUER_PCI
+static  int pci_index __initdata = 0;
+#endif
+
 __initfunc(int
 setup_sedlbauer(struct IsdnCard *card))
 {
-       int bytecnt;
+       int bytecnt, ver, val;
        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;
+               cs->subtyp = SEDL_SPEED_CARD_WIN;
+               cs->hw.sedl.bus = SEDL_BUS_ISA;
+               cs->hw.sedl.chip = SEDL_CHIP_TEST;
        } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) {    
                cs->subtyp = SEDL_SPEED_STAR;
+               cs->hw.sedl.bus = SEDL_BUS_PCMCIA;
+               cs->hw.sedl.chip = SEDL_CHIP_TEST;
+       } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) {       
+               cs->subtyp = SEDL_SPEED_FAX;
+               cs->hw.sedl.bus = SEDL_BUS_ISA;
+               cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
        } 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;
+       if (card->para[1]) {
+               cs->hw.sedl.cfg_reg = card->para[1];
+               cs->irq = card->para[0];
+               if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+                       bytecnt = 16;
+               }
        } 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,
+/* Probe for Sedlbauer speed pci */
+#if SEDLBAUER_PCI
+#if CONFIG_PCI
+               for (; pci_index < 255; pci_index++) {
+                       unsigned char pci_bus, pci_device_fn;
+                       unsigned int ioaddr;
+                       unsigned char irq;
+
+                       if (pcibios_find_device (PCI_VENDOR_SEDLBAUER,
+                                               PCI_SPEEDPCI_ID, pci_index,
+                                               &pci_bus, &pci_device_fn) != 0) {
+                               continue;
+                       }
+                       pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                       PCI_INTERRUPT_LINE, &irq);
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                       PCI_BASE_ADDRESS_0, &ioaddr);
+                       cs->irq = irq;
+                       cs->hw.sedl.cfg_reg = ioaddr & PCI_BASE_ADDRESS_IO_MASK; 
+                       if (!cs->hw.sedl.cfg_reg) {
+                               printk(KERN_WARNING "Sedlbauer: No IO-Adr for PCI card found\n");
+                               return(0);
+                       }
+                       cs->hw.sedl.bus = SEDL_BUS_PCI;
+                       cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+                       cs->subtyp = SEDL_SPEED_PCI;
+                       bytecnt = 256;
+                       byteout(cs->hw.sedl.cfg_reg, 0xff);
+                       byteout(cs->hw.sedl.cfg_reg, 0x00);
+                       byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+                       byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
+                       break;
+               }       
+               if (pci_index == 255) {
+                       printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+                       return(0);
+               }
+               pci_index++;
+#else
+               printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
+               return (0);
+#endif /* CONFIG_PCI */
+#endif /* SEDLBAUER_PCI */
+       }       
+       
+               /* 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)) {
+       if (cs->hw.sedl.bus != SEDL_BUS_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);
+                       "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",
+              "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n",
               cs->hw.sedl.cfg_reg,
+              cs->hw.sedl.cfg_reg + bytecnt,
               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);
+
+/*
+ * testing ISA and PCMCIA Cards for IPAC, default is ISAC 
+ * do not test for PCI card, because ports are different
+ * and PCI card uses only IPAC (for the moment)
+ */    
+       if (cs->hw.sedl.bus != SEDL_BUS_PCI) {
+               val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR,
+                       cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID);
+               if (val == 1) {
+               /* IPAC */
+                       cs->subtyp = SEDL_SPEED_WIN2_PC104;
+                       if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
+                               cs->subtyp = SEDL_SPEED_STAR2;
+                       }
+                       cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+               } else {
+               /* ISAC_HSCX oder ISAC_ISAR */
+                       if (cs->hw.sedl.chip == SEDL_CHIP_TEST) {
+                               cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX;
+                       }
+               }
+       }
+
+/*
+ * hw.sedl.chip is now properly set
+ */
+       printk(KERN_INFO "Sedlbauer: %s detected\n",
+               Sedlbauer_Types[cs->subtyp]);
+
+
+       if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
+       /* IPAC */
+               if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
+                       cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR;
+                       cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
+                       cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
+               } else {
+                       cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR;
+                       cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
+                       cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
+               }
+                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;
+
+               val = readreg(cs->hw.sedl.adr,cs->hw.sedl.isac, IPAC_ID);
+                printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val);
+               reset_sedlbauer(cs);
+       } else {
+       /* ISAC_HSCX oder ISAC_ISAR */
+               cs->readisac = &ReadISAC;
+               cs->writeisac = &WriteISAC;
+               cs->readisacfifo = &ReadISACfifo;
+               cs->writeisacfifo = &WriteISACfifo;
+               if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
+                       cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ADR;
+                       cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAC;
+                       cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR;
+                       cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_ON;
+                       cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_ISAR_ISA_ISAR_RESET_OFF;
+                       cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
+                       cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
+                       test_and_set_bit(HW_ISAR, &cs->HW_Flags);
+       
+                       ISACVersion(cs, "Sedlbauer:");
+               
+                       cs->BC_Read_Reg = &ReadISAR;
+                       cs->BC_Write_Reg = &WriteISAR;
+                       cs->BC_Send_Data = &isar_fill_fifo;
+                       ver = ISARVersion(cs, "Sedlbauer:");
+                       if (ver < 0) {
+                               printk(KERN_WARNING
+                                       "Sedlbauer: wrong ISAR version (ret = %d)\n", ver);
+                               release_io_sedlbauer(cs);
+                               return (0);
+                       }
+               } else {
+                       if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
+                               cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR;
+                               cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC;
+                               cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX;
+                               cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
+                               cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
+                       } else {
+                               cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR;
+                               cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC;
+                               cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX;
+                               cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON;
+                               cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF;
+                       }
+                       ISACVersion(cs, "Sedlbauer:");
+               
+                       if (HscxVersion(cs, "Sedlbauer:")) {
+                               printk(KERN_WARNING
+                                       "Sedlbauer: wrong HSCX versions check IO address\n");
+                               release_io_sedlbauer(cs);
+                               return (0);
+                       }
+                       reset_sedlbauer(cs);
+               }
        }
        return (1);
 }
index 43d0641da357ffd26fa898d7cc827dcb59da3f22..655abfadc534cd3be218f994826198f874e17b6e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sportster.c,v 1.5 1998/02/02 13:29:46 keil Exp $
+/* $Id: sportster.c,v 1.7 1998/11/15 23:55:22 keil Exp $
 
  * sportster.c     low level stuff for USR Sportster internal TA
  *
@@ -7,6 +7,12 @@
  * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
  *
  * $Log: sportster.c,v $
+ * Revision 1.7  1998/11/15 23:55:22  keil
+ * changes from 2.0
+ *
+ * Revision 1.6  1998/04/15 16:44:35  keil
+ * new init code
+ *
  * Revision 1.5  1998/02/02 13:29:46  keil
  * fast io
  *
@@ -30,7 +36,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.5 $";
+const char *sportster_revision = "$Revision: 1.7 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -187,12 +193,10 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        return(request_irq(cs->irq, &sportster_interrupt,
                                        I4L_IRQ_FLAG, "HiSax", cs));
                case CARD_INIT:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       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);
index a520787469aeb7c228b4b0cc77532fe3607ad594..c9d94fe4dc7908319a1134a6b2ff6e73834af0de 100644 (file)
@@ -1,12 +1,34 @@
-/* $Id: tei.c,v 2.7 1998/02/12 23:08:11 keil Exp $
+/* $Id: tei.c,v 2.11 1998/11/15 23:55:24 keil Exp $
 
- * Author       Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
+ *             This file is (c) under GNU PUBLIC LICENSE
+ *             For changes and modifications please read
+ *             ../../../Documentation/isdn/HiSax.cert
+ *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
  * $Log: tei.c,v $
+ * Revision 2.11  1998/11/15 23:55:24  keil
+ * changes from 2.0
+ *
+ * Revision 2.10  1998/05/25 14:08:10  keil
+ * HiSax 3.0
+ * fixed X.75 and leased line to work again
+ * Point2Point and fixed TEI are runtime options now:
+ *    hisaxctrl <id> 7 1  set PTP
+ *    hisaxctrl <id> 8 <TEIVALUE *2 >
+ *    set fixed TEI to TEIVALUE (0-63)
+ *
+ * Revision 2.9  1998/05/25 12:58:23  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.8  1998/03/07 22:57:07  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 2.7  1998/02/12 23:08:11  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
@@ -50,7 +72,7 @@
 #include "isdnl2.h"
 #include <linux/random.h>
 
-const char *tei_revision = "$Revision: 2.7 $";
+const char *tei_revision = "$Revision: 2.11 $";
 
 #define ID_REQUEST     1
 #define ID_ASSIGNED    2
@@ -151,26 +173,24 @@ put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
        bp[2] = ri & 0xff;
        bp[3] = m_id;
        bp[4] = (tei << 1) | 1;
-       st->l2.l2l1(st, PH_DATA_REQ, skb);
+       st->l2.l2l1(st, PH_DATA | REQUEST, skb);
 }
 
 static void
 tei_id_request(struct FsmInst *fi, int event, void *arg)
 {
        struct PStack *st = fi->userdata;
-       char tmp[64];
 
        if (st->l2.tei != -1) {
-               sprintf(tmp, "assign request for allready asigned tei %d",
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "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);
-       }
+       if (st->ma.debug)
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "assign request ri %d", st->ma.ri);
        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);
@@ -184,26 +204,24 @@ tei_id_assign(struct FsmInst *fi, int event, void *arg)
        struct sk_buff *skb = arg;
        struct IsdnCardState *cs;
        int ri, tei;
-       char tmp[64];
 
        ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
        tei = skb->data[4] >> 1;
-       if (st->ma.debug) {
-               sprintf(tmp, "identity assign ri %d tei %d", ri, tei);
-               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
-       }
+       if (st->ma.debug)
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "identity assign ri %d tei %d", ri, tei);
        if ((ost = findtei(st, tei))) {         /* same tei is in use */
                if (ri != ost->ma.ri) {
-                       sprintf(tmp, "possible duplicate assignment tei %d", tei);
-                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
-                       ost->l2.l2tei(ost, MDL_ERROR_REQ, NULL);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m,
+                               "possible duplicate assignment tei %d", tei);
+                       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->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) tei);
+               st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
                cs = (struct IsdnCardState *) st->l1.hardware;
-               cs->cardmsg(cs, MDL_ASSIGN_REQ, NULL);
+               cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
        }
 }
 
@@ -213,14 +231,12 @@ tei_id_denied(struct FsmInst *fi, int event, void *arg)
        struct PStack *st = fi->userdata;
        struct sk_buff *skb = arg;
        int ri, tei;
-       char tmp[64];
 
        ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
        tei = skb->data[4] >> 1;
-       if (st->ma.debug) {
-               sprintf(tmp, "identity denied ri %d tei %d", ri, tei);
-               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
-       }
+       if (st->ma.debug)
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "identity denied ri %d tei %d", ri, tei);
 }
 
 static void
@@ -229,13 +245,11 @@ 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->ma.debug)
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "identity check req tei %d", tei);
        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);
@@ -250,19 +264,17 @@ tei_id_remove(struct FsmInst *fi, int event, void *arg)
        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->ma.debug)
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "identity remove tei %d", tei);
        if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
                FsmDelTimer(&st->ma.t202, 5);
                FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
-               st->ma.manl2(st, MDL_REMOVE_REQ, 0);
+               st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
                cs = (struct IsdnCardState *) st->l1.hardware;
-               cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+               cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
        }
 }
 
@@ -270,12 +282,10 @@ 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);
-       }
+       if (st->ma.debug)
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "id verify request for tei %d", st->l2.tei);
        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);
@@ -286,24 +296,21 @@ 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);
-               }
+               if (st->ma.debug)
+                       st->ma.tei_m.printdebug(&st->ma.tei_m,
+                               "assign req(%d) ri %d", 4 - st->ma.N202,
+                               st->ma.ri);
                put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
                FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
        } else {
-               sprintf(tmp, "assign req failed");
-               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
-               st->ma.manl2(st, MDL_ERROR_IND, 0);
+               st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed");
+               st->l3.l3l2(st, MDL_ERROR | RESPONSE, 0);
                cs = (struct IsdnCardState *) st->l1.hardware;
-               cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+               cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
                FsmChangeState(fi, ST_TEI_NOP);
        }
 }
@@ -312,23 +319,21 @@ 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",
+               if (st->ma.debug)
+                       st->ma.tei_m.printdebug(&st->ma.tei_m,
+                               "id verify req(%d) for tei %d",
                                3 - st->ma.N202, st->l2.tei);
-                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
-               }
                put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
                FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4);
        } else {
-               sprintf(tmp, "verify req for tei %d failed", st->l2.tei);
-               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
-               st->ma.manl2(st, MDL_REMOVE_REQ, 0);
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "verify req for tei %d failed", st->l2.tei);
+               st->l3.l3l2(st, MDL_REMOVE | REQUEST, 0);
                cs = (struct IsdnCardState *) st->l1.hardware;
-               cs->cardmsg(cs, MDL_REMOVE_REQ, NULL);
+               cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
                FsmChangeState(fi, ST_TEI_NOP);
        }
 }
@@ -338,31 +343,34 @@ tei_l1l2(struct PStack *st, int pr, void *arg)
 {
        struct sk_buff *skb = arg;
        int mt;
-       char tmp[64];
 
-       if (pr == PH_DATA_IND) {
+       if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       if (pr == (PH_DATA | INDICATION)) {
                if (skb->len < 3) {
-                       sprintf(tmp, "short mgr frame %d/3", skb->len);
-                       st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m,
+                               "short mgr frame %ld/3", skb->len);
                } else if (((skb->data[0] >> 2) != TEI_SAPI) ||
                           ((skb->data[1] >> 1) != GROUP_TEI)) {
-                       sprintf(tmp, "wrong mgr sapi/tei %x/%x",
+                       st->ma.tei_m.printdebug(&st->ma.tei_m,
+                               "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);
+                       st->ma.tei_m.printdebug(&st->ma.tei_m,
+                               "mgr frame is not ui %x", skb->data[2]);
                } else {
                        skb_pull(skb, 3);
                        if (skb->len < 5) {
-                               sprintf(tmp, "short mgr frame %d/5", skb->len);
-                               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+                               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                                       "short mgr frame %ld/5", skb->len);
                        } else if (skb->data[0] != TEI_ENTITY_ID) {
                                /* wrong management entity identifier, ignore */
-                               sprintf(tmp, "tei handler wrong entity id %x\n",
+                               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                                       "tei handler wrong entity id %x",
                                        skb->data[0]);
-                               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
                        } else {
                                mt = skb->data[3];
                                if (mt == ID_ASSIGNED)
@@ -374,15 +382,14 @@ tei_l1l2(struct PStack *st, int pr, void *arg)
                                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);
+                                       st->ma.tei_m.printdebug(&st->ma.tei_m,
+                                               "tei handler wrong mt %x\n", mt);
                                }
                        }
                }
        } else {
-               sprintf(tmp, "tei handler wrong pr %x\n", pr);
-               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
+               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                       "tei handler wrong pr %x\n", pr);
        }
        dev_kfree_skb(skb);
 }
@@ -390,20 +397,24 @@ tei_l1l2(struct PStack *st, int pr, void *arg)
 static void
 tei_l2tei(struct PStack *st, int pr, void *arg)
 {
+       struct IsdnCardState *cs;
+
+       if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
+               if (pr == (MDL_ASSIGN | INDICATION)) {
+                       if (st->ma.debug)
+                               st->ma.tei_m.printdebug(&st->ma.tei_m,
+                                       "fixed assign tei %d", st->l2.tei);
+                       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_IND):
-#ifdef TEI_FIXED
-                       if (st->ma.debug) {
-                               char tmp[64];
-                               sprintf(tmp, "fixed assign tei %d", TEI_FIXED);
-                               st->ma.tei_m.printdebug(&st->ma.tei_m, tmp);
-                       }
-                       st->ma.manl2(st, MDL_ASSIGN_REQ, (void *) (int) TEI_FIXED);
-#else
+               case (MDL_ASSIGN | INDICATION):
                        FsmEvent(&st->ma.tei_m, EV_IDREQ, arg);
-#endif
                        break;
-               case (MDL_ERROR_REQ):
+               case (MDL_ERROR | REQUEST):
                        FsmEvent(&st->ma.tei_m, EV_VERIFY, arg);
                        break;
                default:
@@ -412,14 +423,14 @@ tei_l2tei(struct PStack *st, int pr, void *arg)
 }
 
 static void
-tei_debug(struct FsmInst *fi, char *s)
+tei_debug(struct FsmInst *fi, char *fmt, ...)
 {
+       va_list args;
        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);
+       va_start(args, fmt);
+       VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args);
+       va_end(args);
 }
 
 void
@@ -439,9 +450,8 @@ setstack_tei(struct PStack *st)
 }
 
 void
-init_tei(struct IsdnCardState *sp, int protocol)
+init_tei(struct IsdnCardState *cs, int protocol)
 {
-
 }
 
 void
index f7e38253bf598495cbaf89e236dbc76cd629181c..180eee6a1c404d3d7c5b1fbc34181294855f325b 100644 (file)
@@ -1,11 +1,17 @@
-/* $Id: teleint.c,v 1.5 1998/02/02 13:40:47 keil Exp $
+/* $Id: teleint.c,v 1.7 1998/11/15 23:55:26 keil Exp $
 
  * teleint.c     low level stuff for TeleInt isdn cards
  *
- * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author     Karsten Keil (keil@isdn4linux.de)
  *
  *
  * $Log: teleint.c,v $
+ * Revision 1.7  1998/11/15 23:55:26  keil
+ * changes from 2.0
+ *
+ * Revision 1.6  1998/04/15 16:45:31  keil
+ * new init code
+ *
  * Revision 1.5  1998/02/02 13:40:47  keil
  * fast io
  *
@@ -32,7 +38,7 @@
 
 extern const char *CardType[];
 
-const char *TeleInt_revision = "$Revision: 1.5 $";
+const char *TeleInt_revision = "$Revision: 1.7 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -64,17 +70,20 @@ static inline void
 readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
        register u_char ret;
-       int max_delay = 2000;
+       register int max_delay = 20000;
+       register int i;
+       
        byteout(ale, off);
-
-       ret = HFC_BUSY & bytein(ale);
-       while (ret && --max_delay)
+       for (i = 0; i<size; i++) {
                ret = HFC_BUSY & bytein(ale);
-       if (!max_delay) {
-               printk(KERN_WARNING "TeleInt Busy not inaktive\n");
-               return;
+               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);
        }
-       insb(adr, data, size);
 }
 
 
@@ -104,18 +113,21 @@ static inline void
 writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
 {
        register u_char ret;
-       int max_delay = 2000;
-
+       register int max_delay = 20000;
+       register int i;
+       
        /* fifo write without cli because it's allready done  */
        byteout(ale, off);
-       ret = HFC_BUSY & bytein(ale);
-       while (ret && --max_delay)
+       for (i = 0; i<size; i++) {
                ret = HFC_BUSY & bytein(ale);
-       if (!max_delay) {
-               printk(KERN_WARNING "TeleInt Busy not inaktive\n");
-               return;
+               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]);
        }
-       outsb(adr, data, size);
 }
 
 /* Interface functions */
@@ -157,11 +169,8 @@ ReadHFC(struct IsdnCardState *cs, int data, u_char reg)
                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);
-               }
+               if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
+                       debugl1(cs, "hfc RD %02x %02x", reg, ret);
        } else
                ret = bytein(cs->hw.hfc.addr | 1);
        return (ret);
@@ -174,11 +183,8 @@ WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
        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);
-       }
+       if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
+               debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value);
 }
 
 static void
@@ -271,6 +277,9 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        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);
index 7cd173154b3a153f6d700df4b65867daa6da534d..3137a8b7e19cb019b2d090773f91c4e1d474ec2c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 2.6 1998/02/03 23:27:47 keil Exp $
+/* $Id: teles0.c,v 2.8 1998/04/15 16:44:28 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 2.8  1998/04/15 16:44:28  keil
+ * new init code
+ *
+ * Revision 2.7  1998/03/07 22:57:08  tsbogend
+ * made HiSax working on Linux/Alpha
+ *
  * Revision 2.6  1998/02/03 23:27:47  keil
  * IRQ 9
  *
@@ -48,7 +54,7 @@
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 2.6 $";
+const char *teles0_revision = "$Revision: 2.8 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -62,7 +68,7 @@ readisac(unsigned int adr, u_char off)
 static inline void
 writeisac(unsigned int adr, u_char off, u_char data)
 {
-       writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off);
+       writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
 }
 
 
@@ -77,14 +83,14 @@ static inline void
 writehscx(unsigned int adr, int hscx, u_char off, u_char data)
 {
        writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
-              ((off & 1) ? 0x1ff : 0) + off);
+              ((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);
 }
@@ -93,16 +99,17 @@ 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);
 }
@@ -111,9 +118,10 @@ 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);
+       register u_char *ad = (u_char *) ((long)adr + (hscx ? 0x1c0 : 0x180));
+       for (i = 0; i < size; i++) {
+               writeb(data[i], ad); mb();
+       }
 }
 
 /* Interface functions */
@@ -264,9 +272,9 @@ reset_teles0(struct IsdnCardState *cs)
                byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
                HZDELAY(HZ / 10 + 1);
        }
-       writeb(0, cs->hw.teles0.membase + 0x80);
+       writeb(0, cs->hw.teles0.membase + 0x80); mb();
        HZDELAY(HZ / 5 + 1);
-       writeb(1, cs->hw.teles0.membase + 0x80);
+       writeb(1, cs->hw.teles0.membase + 0x80); mb();
        HZDELAY(HZ / 5 + 1);
        restore_flags(flags);
        return(0);
@@ -286,10 +294,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        return(request_irq(cs->irq, &teles0_interrupt,
                                        I4L_IRQ_FLAG, "HiSax", cs));
                case CARD_INIT:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       inithscxisac(cs, 3);
                        return(0);
                case CARD_TEST:
                        return(0);
index 871b10e4aab44159f4ad6b67c1c2add34b26605e..297ccb740f969acb7b7bf9b344045fc7a414295b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: teles3.c,v 2.7 1998/02/02 13:29:48 keil Exp $
+/* $Id: teles3.c,v 2.10 1999/02/15 14:37:15 cpetig Exp $
 
  * teles3.c     low level stuff for Teles 16.3 & PNP isdn cards
  *
  *              Beat Doebeli
  *
  * $Log: teles3.c,v $
+ * Revision 2.10  1999/02/15 14:37:15  cpetig
+ * oops, missed something in last commit
+ *
+ * Revision 2.9  1999/02/15 14:11:02  cpetig
+ * fixed a bug with Teles PCMCIA, it doesn't have a config register
+ *
+ * Revision 2.8  1998/04/15 16:44:30  keil
+ * new init code
+ *
  * Revision 2.7  1998/02/02 13:29:48  keil
  * fast io
  *
@@ -69,7 +78,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.7 $";
+const char *teles3_revision = "$Revision: 2.10 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -214,15 +223,14 @@ void
 release_io_teles3(struct IsdnCardState *cs)
 {
        if (cs->typ == ISDN_CTYPE_TELESPCMCIA)
-               release_region(cs->hw.teles3.cfg_reg, 97);
+               release_region(cs->hw.teles3.hscx[0], 97);
        else {
-               if (cs->hw.teles3.cfg_reg) {
+               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);
        }
 }
@@ -305,10 +313,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
                        return(request_irq(cs->irq, &teles3_interrupt,
                                        I4L_IRQ_FLAG, "HiSax", cs));
                case CARD_INIT:
-                       clear_pending_isac_ints(cs);
-                       clear_pending_hscx_ints(cs);
-                       initisac(cs);
-                       inithscx(cs);
+                       inithscxisac(cs, 3);
                        return(0);
                case CARD_TEST:
                        return(0);
@@ -342,7 +347,7 @@ setup_teles3(struct IsdnCard *card))
                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.cfg_reg = 0;
                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;
@@ -362,12 +367,12 @@ setup_teles3(struct IsdnCard *card))
        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)) {
+               if (check_region((cs->hw.teles3.hscx[0]), 97)) {
                        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 + 96);
+                              cs->hw.teles3.hscx[0],
+                              cs->hw.teles3.hscx[0] + 96);
                        return (0);
                } else
                        request_region(cs->hw.teles3.hscx[0], 97, "HiSax Teles PCMCIA");
@@ -400,13 +405,12 @@ setup_teles3(struct IsdnCard *card))
                               CardType[cs->typ],
                               cs->hw.teles3.isac + 32,
                               cs->hw.teles3.isac + 64);
-                       if (cs->hw.teles3.cfg_reg) {
+                       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(cs->hw.teles3.isac + 32, 32, "HiSax isac");
@@ -416,13 +420,12 @@ setup_teles3(struct IsdnCard *card))
                               CardType[cs->typ],
                               cs->hw.teles3.hscx[0] + 32,
                               cs->hw.teles3.hscx[0] + 64);
-                       if (cs->hw.teles3.cfg_reg) {
+                       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
@@ -433,13 +436,12 @@ setup_teles3(struct IsdnCard *card))
                               CardType[cs->typ],
                               cs->hw.teles3.hscx[1] + 32,
                               cs->hw.teles3.hscx[1] + 64);
-                       if (cs->hw.teles3.cfg_reg) {
+                       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
index 3042f7139dd3c14c0d570700497d413fc9bef0ce..8ba6a311a70b9508f1f251390f21d40cf6f9ab06 100644 (file)
@@ -1,11 +1,14 @@
-/* $Id: teles3c.c,v 1.2 1998/02/02 13:27:07 keil Exp $
+/* $Id: teles3c.c,v 1.3 1998/11/15 23:55:27 keil Exp $
 
  * teles3c.c     low level stuff for teles 16.3c
  *
- * Author     Karsten Keil (keil@temic-ech.spacenet.de)
+ * Author     Karsten Keil (keil@isdn4linux.de)
  *
  *
  * $Log: teles3c.c,v $
+ * Revision 1.3  1998/11/15 23:55:27  keil
+ * changes from 2.0
+ *
  * Revision 1.2  1998/02/02 13:27:07  keil
  * New
  *
 
 extern const char *CardType[];
 
-const char *teles163c_revision = "$Revision: 1.2 $";
+const char *teles163c_revision = "$Revision: 1.3 $";
 
 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");
@@ -36,16 +38,12 @@ t163c_interrupt(int intno, void *dev_id, struct pt_regs *regs)
        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);
-               }
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "teles3c: stat(%02x) s1(%02x)", stat, val);
                hfc2bds0_interrupt(cs, val);
        } else {
-               if (cs->debug & L1_DEB_ISAC) {
-                       sprintf(tmp, "teles3c: irq_no_irq stat(%02x)", stat);
-                       debugl1(cs, tmp);
-               }
+               if (cs->debug & L1_DEB_ISAC)
+                       debugl1(cs, "teles3c: irq_no_irq stat(%02x)", stat);
        }
 }
 
@@ -110,13 +108,9 @@ 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);
-       }
+       if (cs->debug & L1_DEB_ISAC)
+               debugl1(cs, "teles3c: card_msg %x", mt);
        switch (mt) {
                case CARD_RESET:
                        reset_t163c(cs);
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
new file mode 100644 (file)
index 0000000..dcbdd48
--- /dev/null
@@ -0,0 +1,371 @@
+/* $Id: telespci.c,v 2.5 1998/11/15 23:55:28 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 2.5  1998/11/15 23:55:28  keil
+ * changes from 2.0
+ *
+ * Revision 2.4  1998/10/05 09:38:08  keil
+ * Fix register addressing
+ *
+ * Revision 2.3  1998/05/25 12:58:26  keil
+ * HiSax golden code from certification, Don't use !!!
+ * No leased lines, no X75, but many changes.
+ *
+ * Revision 2.1  1998/04/15 16:38:23  keil
+ * Add S0Box and Teles PCI support
+ *
+ *
+ */
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "hscx.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+
+extern const char *CardType[];
+
+const char *telespci_revision = "$Revision: 2.5 $";
+
+#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)
+{
+       iounmap((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 | SA_SHIRQ, "HiSax", cs));
+               case CARD_INIT:
+                       inithscxisac(cs, 3);
+                       return(0);
+               case CARD_TEST:
+                       return(0);
+       }
+       return(0);
+}
+
+static         struct pci_dev *dev_tel __initdata = NULL;
+
+__initfunc(int
+setup_telespci(struct IsdnCard *card))
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       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
+       if (!pci_present()) {
+               printk(KERN_ERR "TelesPCI: no PCI bus present\n");
+               return(0);
+       }
+       if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) {
+               cs->irq = dev_tel->irq;
+               if (!cs->irq) {
+                       printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
+                       return(0);
+               }
+               cs->hw.teles0.membase = (u_int) ioremap(dev_tel->base_address[0],
+                       PAGE_SIZE);
+               printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
+                       dev_tel->base_address[0], dev_tel->irq);
+       } else {
+               printk(KERN_WARNING "TelesPCI: No PCI card found\n");
+               return(0);
+       }
+#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 fe57373446025b4ba34bd5cfdb7b6e94245e1e3b..d08730e17c2ef7e58dd078399beb72fbd394fd24 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.49 1998/02/13 11:14:15 keil Exp $
+/* $Id: icn.c,v 1.56 1999/04/12 13:15:07 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.56  1999/04/12 13:15:07  fritz
+ * Fixed a cast.
+ *
+ * Revision 1.55  1999/04/12 12:34:02  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.54  1999/01/05 18:29:39  he
+ * merged remaining schedule_timeout() changes from 2.1.127
+ *
+ * Revision 1.53  1998/06/17 19:51:28  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.52  1998/05/20 19:29:58  tsbogend
+ * fixed bug introduced by changes for new BSENT callback
+ *
+ * Revision 1.51  1998/03/07 22:29:55  fritz
+ * Adapted Detlef's chenges for 2.1.
+ *
+ * Revision 1.50  1998/03/07 17:41:54  detabc
+ * add d-channel connect and disconnect support statcallback
+ * from icn low-level to link->level
+ *
  * Revision 1.49  1998/02/13 11:14:15  keil
  * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
  *
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.49 $";
+*revision = "$Revision: 1.56 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -232,10 +256,10 @@ icn_free_queue(icn_card * card, int channel)
        cli();
        card->xlen[channel] = 0;
        card->sndcount[channel] = 0;
-       if (card->xskb[channel]) {
+       if ((skb = card->xskb[channel])) {
                card->xskb[channel] = NULL;
                restore_flags(flags);
-               dev_kfree_skb(card->xskb[channel]);
+               dev_kfree_skb(skb);
        } else
                restore_flags(flags);
 }
@@ -529,6 +553,11 @@ icn_pollbchan_send(int channel, icn_card * card)
                                        cmd.parm.length = card->xlen[channel];
                                        card->interface.statcallb(&cmd);
                                }
+                       } else {
+                               save_flags(flags);
+                               cli();
+                               card->xskb[channel] = skb;
+                               restore_flags(flags);
                        }
                        card->xmit_lock[channel] = 0;
                        if (!icn_trymaplock_channel(card, mch))
@@ -580,8 +609,11 @@ 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     */
+       /*
+       ** add d-channel connect and disconnect support to link-level
+       */
+       {"DCON_",          ISDN_STAT_DCONN, 10},        /* D-Channel connected        */
+       {"DDIS_",          ISDN_STAT_DHUP,  11},        /* 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  */
@@ -630,7 +662,33 @@ icn_parse_status(u_char * status, int channel, icn_card * card)
        cmd.driver = card->myid;
        cmd.arg = channel;
        switch (action) {
+       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;
+                               
+                               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);
+                       } else
+                               restore_flags(flags);
+                       
+                       break;
                case 1:
+                       icn_free_queue(card,channel);
                        card->flags |= (channel) ?
                            ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
                        break;
@@ -1539,7 +1597,7 @@ icn_command(isdn_ctrl * c, icn_card * card)
                                                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");
+                                               c->parm.num[0] ? (char *)(c->parm.num) : "0123456789");
                                i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
                        }
                        break;
index 4aba68b38fe0bb124dbd0863bc009598b4e9a8a8..3bd2819cedb85b3d97c9f6acf81e795027a33aa5 100644 (file)
@@ -318,9 +318,9 @@ static char *icn_id2 = "\0";
 #ifdef MODULE
 MODULE_AUTHOR("Fritz Elfert");
 MODULE_PARM(portbase, "i");
-MODULE_PARM_DESC(portbase, "Port address of first card");
+MODULE_PARM_DESC(portbase, "Port adress of first card");
 MODULE_PARM(membase, "i");
-MODULE_PARM_DESC(membase, "Shared memory address of all cards");
+MODULE_PARM_DESC(membase, "Shared memory adress of all cards");
 MODULE_PARM(icn_id, "s");
 MODULE_PARM_DESC(icn_id, "ID-String of first card");
 MODULE_PARM(icn_id2, "s");
index d097366ed5d9f427a9401698b04122ba5c4e5302..67307a0ec37a9f9cb546e6359d8bc8f7f3d3021b 100644 (file)
@@ -1,9 +1,10 @@
-/* $Id: isdn_audio.c,v 1.10 1998/02/20 17:09:40 fritz Exp $
+/* $Id: isdn_audio.c,v 1.13 1999/04/12 12:33:09 fritz Exp $
 
  * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
  * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
+ * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.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
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_audio.c,v $
+ * Revision 1.13  1999/04/12 12:33:09  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.12  1998/07/26 18:48:43  armin
+ * Added silence detection in voice receive mode.
+ *
+ * Revision 1.11  1998/04/10 10:35:10  paul
+ * fixed (silly?) warnings from egcs on Alpha.
+ *
  * Revision 1.10  1998/02/20 17:09:40  fritz
  * Changes for recent kernels.
  *
@@ -61,7 +71,7 @@
 #include "isdn_audio.h"
 #include "isdn_common.h"
 
-char *isdn_audio_revision = "$Revision: 1.10 $";
+char *isdn_audio_revision = "$Revision: 1.13 $";
 
 /*
  * Misc. lookup-tables.
@@ -276,7 +286,7 @@ static inline void
 isdn_audio_tlookup(const char *table, char *buff, unsigned long n)
 {
        while (n--)
-               *buff++ = table[*buff];
+               *buff++ = table[*(unsigned char *)buff];
 }
 #endif
 
@@ -660,3 +670,92 @@ isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt)
                len -= c;
        }
 }
+
+silence_state *
+isdn_audio_silence_init(silence_state * s)
+{
+       if (!s)
+               s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC);
+       if (s) {
+               s->idx = 0;
+               s->state = 0;
+       }
+       return s;
+}
+
+void
+isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt)
+{
+       silence_state *s = info->silence_state;
+       int i;
+       signed char c;
+
+       if (!info->emu.vpar[1]) return;
+
+       for (i = 0; i < len; i++) {
+               if (fmt)
+                   c = isdn_audio_alaw_to_ulaw[*buf++];
+                       else
+                   c = *buf++;
+
+               if (c > 0) c -= 128;
+               c = abs(c);
+
+               if (c > (info->emu.vpar[1] * 4)) { 
+                       s->idx = 0;
+                       s->state = 1; 
+               } else {
+                       if (s->idx < 210000) s->idx++; 
+               }
+       }
+}
+
+void
+isdn_audio_eval_silence(modem_info * info)
+{
+       silence_state *s = info->silence_state;
+       struct sk_buff *skb;
+       unsigned long flags;
+       int di;
+       int ch;
+       char what;
+       char *p;
+
+       what = ' ';
+
+       if (s->idx > (info->emu.vpar[2] * 800)) { 
+               s->idx = 0;
+               if (!s->state) {        /* silence from beginning of rec */ 
+                       what = 's';
+               } else {
+                       what = 'q';
+               }
+       }
+               if ((what == 's') || (what == 'q')) {
+                       printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
+                               (what=='s') ? "silence":"quiet");
+                       skb = dev_alloc_skb(2);
+                       p = (char *) skb_put(skb, 2);
+                       p[0] = 0x10;
+                       p[1] = what;
+                       if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
+                               printk(KERN_WARNING
+                                      "isdn_audio: insufficient skb_headroom, dropping\n");
+                               kfree_skb(skb);
+                               return;
+                       }
+                       ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
+                       ISDN_AUDIO_SKB_LOCK(skb) = 0;
+                       save_flags(flags);
+                       cli();
+                       di = info->isdn_driver;
+                       ch = info->isdn_channel;
+                       __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
+                       dev->drv[di]->rcvcount[ch] += 2;
+                       restore_flags(flags);
+                       /* Schedule dequeuing */
+                       if ((dev->modempoll) && (info->rcvsched))
+                               isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+                       wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
+               } 
+}
index 0cf8267cfa59e8e9d37cb88d8eca1105114e9dac..ee33ce020b9a7f2e9935958a3b08d9615917dfa2 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_audio.h,v 1.5 1997/02/03 22:45:21 fritz Exp $
+/* $Id: isdn_audio.h,v 1.7 1999/04/12 12:33:11 fritz Exp $
 
  * Linux ISDN subsystem, audio conversion and compression (linklevel).
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_audio.h,v $
+ * Revision 1.7  1999/04/12 12:33:11  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.6  1998/07/26 18:48:44  armin
+ * Added silence detection in voice receive mode.
+ *
  * Revision 1.5  1997/02/03 22:45:21  fritz
  * Reformatted according CodingStyle
  *
@@ -51,6 +57,11 @@ typedef struct dtmf_state {
        int buf[DTMF_NPOINTS];
 } dtmf_state;
 
+typedef struct silence_state {
+       int state;
+       unsigned int idx;
+} silence_state;
+
 extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
 extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
 extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
@@ -60,3 +71,6 @@ extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out);
 extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
 extern void isdn_audio_eval_dtmf(modem_info *);
 dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
+extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
+extern void isdn_audio_eval_silence(modem_info *);
+silence_state *isdn_audio_silence_init(silence_state *);
diff --git a/drivers/isdn/isdn_bsdcomp.c b/drivers/isdn/isdn_bsdcomp.c
new file mode 100644 (file)
index 0000000..92012c8
--- /dev/null
@@ -0,0 +1,934 @@
+/*
+ * BSD compression module
+ *
+ * Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp
+ * The whole module is now SKB based.
+ *
+ * Compile with:
+ *  gcc -O2 -I/usr/src/linux/include -D__KERNEL__ -DMODULE -c isdn_bsdcomp.c
+ */
+
+/*
+ * Original copyright notice:
+ *
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef MODULE
+#error This file must be compiled as a module.
+#endif
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/sched.h>       /* to get the struct task_struct */
+#include <linux/string.h>      /* used in new tty drivers */
+#include <linux/signal.h>      /* used in new tty drivers */
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/byteorder.h>
+#include <asm/types.h>
+
+#include <linux/if.h>
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
+#include <linux/ioctl.h>
+
+#include <linux/ppp_defs.h>
+
+#include <linux/isdn.h>
+#include <linux/isdn_ppp.h>
+/* #include <linux/netprotocol.h> */
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_arp.h>
+#include <linux/ppp-comp.h>
+
+#include "isdn_ppp.h"
+
+#define BSD_VERSION(x) ((x) >> 5)
+#define BSD_NBITS(x)   ((x) & 0x1F)
+
+#define BSD_CURRENT_VERSION    1
+
+#define DEBUG 1
+
+/*
+ * A dictionary for doing BSD compress.
+ */
+
+struct bsd_dict {
+       u32 fcode;
+       u16 codem1;             /* output of hash table -1 */
+       u16 cptr;               /* map code to hash table entry */
+};
+
+struct bsd_db {
+       int            totlen;          /* length of this structure */
+       unsigned int   hsize;           /* size of the hash table */
+       unsigned char  hshift;          /* used in hash function */
+       unsigned char  n_bits;          /* current bits/code */
+       unsigned char  maxbits;         /* maximum bits/code */
+       unsigned char  debug;           /* non-zero if debug desired */
+       unsigned char  unit;            /* ppp unit number */
+       u16 seqno;                      /* sequence # of next packet */
+       unsigned int   mru;             /* size of receive (decompress) bufr */
+       unsigned int   maxmaxcode;      /* largest valid code */
+       unsigned int   max_ent;         /* largest code in use */
+       unsigned int   in_count;        /* uncompressed bytes, aged */
+       unsigned int   bytes_out;       /* compressed bytes, aged */
+       unsigned int   ratio;           /* recent compression ratio */
+       unsigned int   checkpoint;      /* when to next check the ratio */
+       unsigned int   clear_count;     /* times dictionary cleared */
+       unsigned int   incomp_count;    /* incompressible packets */
+       unsigned int   incomp_bytes;    /* incompressible bytes */
+       unsigned int   uncomp_count;    /* uncompressed packets */
+       unsigned int   uncomp_bytes;    /* uncompressed bytes */
+       unsigned int   comp_count;      /* compressed packets */
+       unsigned int   comp_bytes;      /* compressed bytes */
+       unsigned short  *lens;          /* array of lengths of codes */
+       struct bsd_dict *dict;          /* dictionary */
+       int xmit;
+};
+
+#define BSD_OVHD       2               /* BSD compress overhead/packet */
+#define MIN_BSD_BITS   9
+#define BSD_INIT_BITS  MIN_BSD_BITS
+#define MAX_BSD_BITS   15
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define CLEAR  256                     /* table clear output code */
+#define FIRST  257                     /* first free entry */
+#define LAST   255
+
+#define MAXCODE(b)     ((1 << (b)) - 1)
+#define BADCODEM1      MAXCODE(MAX_BSD_BITS);
+
+#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \
+                                        ^ (unsigned long)(prefix))
+#define BSD_KEY(prefix,suffix)         ((((unsigned long)(suffix)) << 16) \
+                                        + (unsigned long)(prefix))
+
+#define CHECK_GAP      10000           /* Ratio check interval */
+
+#define RATIO_SCALE_LOG        8
+#define RATIO_SCALE    (1<<RATIO_SCALE_LOG)
+#define RATIO_MAX      (0x7fffffff>>RATIO_SCALE_LOG)
+
+/*
+ * clear the dictionary
+ */
+
+static void bsd_clear(struct bsd_db *db)
+{
+       db->clear_count++;
+       db->max_ent      = FIRST-1;
+       db->n_bits       = BSD_INIT_BITS;
+       db->bytes_out    = 0;
+       db->in_count     = 0;
+       db->incomp_count = 0;
+       db->ratio            = 0;
+       db->checkpoint   = CHECK_GAP;
+}
+
+/*
+ * If the dictionary is full, then see if it is time to reset it.
+ *
+ * Compute the compression ratio using fixed-point arithmetic
+ * with 8 fractional bits.
+ *
+ * Since we have an infinite stream instead of a single file,
+ * watch only the local compression ratio.
+ *
+ * Since both peers must reset the dictionary at the same time even in
+ * the absence of CLEAR codes (while packets are incompressible), they
+ * must compute the same ratio.
+ */
+static int bsd_check (struct bsd_db *db)       /* 1=output CLEAR */
+{
+    unsigned int new_ratio;
+
+    if (db->in_count >= db->checkpoint)
+      {
+       /* age the ratio by limiting the size of the counts */
+       if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
+         {
+           db->in_count  -= (db->in_count  >> 2);
+           db->bytes_out -= (db->bytes_out >> 2);
+         }
+       
+       db->checkpoint = db->in_count + CHECK_GAP;
+       
+       if (db->max_ent >= db->maxmaxcode)
+         {
+           /* Reset the dictionary only if the ratio is worse,
+            * or if it looks as if it has been poisoned
+            * by incompressible data.
+            *
+            * This does not overflow, because
+            *  db->in_count <= RATIO_MAX.
+            */
+
+           new_ratio = db->in_count << RATIO_SCALE_LOG;
+           if (db->bytes_out != 0)
+             {
+               new_ratio /= db->bytes_out;
+             }
+           
+           if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
+             {
+               bsd_clear (db);
+               return 1;
+             }
+           db->ratio = new_ratio;
+         }
+      }
+    return 0;
+}
+
+/*
+ * Return statistics.
+ */
+
+static void bsd_stats (void *state, struct compstat *stats)
+{
+       struct bsd_db *db = (struct bsd_db *) state;
+    
+       stats->unc_bytes    = db->uncomp_bytes;
+       stats->unc_packets  = db->uncomp_count;
+       stats->comp_bytes   = db->comp_bytes;
+       stats->comp_packets = db->comp_count;
+       stats->inc_bytes    = db->incomp_bytes;
+       stats->inc_packets  = db->incomp_count;
+       stats->in_count     = db->in_count;
+       stats->bytes_out    = db->bytes_out;
+}
+
+/*
+ * Reset state, as on a CCP ResetReq.
+ */
+static void bsd_reset (void *state,unsigned char code, unsigned char id,
+                       unsigned char *data, unsigned len,
+                       struct isdn_ppp_resetparams *rsparm)
+{
+       struct bsd_db *db = (struct bsd_db *) state;
+
+       bsd_clear(db);
+       db->seqno       = 0;
+       db->clear_count = 0;
+}
+
+/*
+ * Release the compression structure
+ */
+static void bsd_free (void *state)
+{
+       struct bsd_db *db = (struct bsd_db *) state;
+
+       if (db) {
+               /*
+                * Release the dictionary
+                */
+               if (db->dict) {
+                       vfree (db->dict);
+                       db->dict = NULL;
+               }
+
+               /*
+                * Release the string buffer
+                */
+               if (db->lens) {
+                       vfree (db->lens);
+                       db->lens = NULL;
+               }
+
+               /*
+                * Finally release the structure itself.
+                */
+               kfree (db);
+               MOD_DEC_USE_COUNT;
+       }
+}
+
+
+/*
+ * Allocate space for a (de) compressor.
+ */
+static void *bsd_alloc (struct isdn_ppp_comp_data *data)
+{
+       int bits;
+       unsigned int hsize, hshift, maxmaxcode;
+       struct bsd_db *db;
+       int decomp;
+
+       static unsigned int htab[][2] = {
+               { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , 
+               { 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 } 
+       };
+               
+       if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
+               || BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
+               return NULL;
+
+       bits = BSD_NBITS(data->options[0]);
+
+       if(bits < 9 || bits > 15)
+               return NULL;
+
+       hsize = htab[bits-9][0];
+       hshift = htab[bits-9][1];
+       
+       /*
+        * Allocate the main control structure for this instance.
+        */
+       maxmaxcode = MAXCODE(bits);
+       db = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),GFP_KERNEL);
+       if (!db)
+               return NULL;
+
+       memset (db, 0, sizeof(struct bsd_db));
+
+       db->xmit = data->flags & IPPP_COMP_FLAG_XMIT;
+       decomp = db->xmit ? 0 : 1;
+
+       /*
+        * Allocate space for the dictionary. This may be more than one page in
+        * length.
+        */
+       db->dict = (struct bsd_dict *) vmalloc (hsize * sizeof (struct bsd_dict));
+       if (!db->dict) {
+               bsd_free (db);
+               return NULL;
+       }
+
+       MOD_INC_USE_COUNT;
+
+       /*
+        * If this is the compression buffer then there is no length data.
+        * For decompression, the length information is needed as well.
+        */
+       if (!decomp)
+               db->lens = NULL;
+       else {
+               db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
+                       sizeof (db->lens[0]));
+               if (!db->lens) {
+                       bsd_free (db); /* calls MOD_DEC_USE_COUNT; */
+                       return (NULL);
+               }
+       }
+
+       /*
+        * Initialize the data information for the compression code
+        */
+       db->totlen     = sizeof (struct bsd_db) + (sizeof (struct bsd_dict) * hsize);
+       db->hsize      = hsize;
+       db->hshift     = hshift;
+       db->maxmaxcode = maxmaxcode;
+       db->maxbits    = bits;
+
+       return (void *) db;
+}
+
+/*
+ * Initialize the database.
+ */
+static int bsd_init (void *state, struct isdn_ppp_comp_data *data, int unit, int debug)
+{
+       struct bsd_db *db = state;
+       int indx;
+       int decomp;
+
+       if(!state || !data) {
+               printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n",unit,(long)state,(long)data);
+               return 0;
+       }
+
+       decomp = db->xmit ? 0 : 1;
+    
+       if (data->optlen != 1 || data->num != CI_BSD_COMPRESS
+               || (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION)
+               || (BSD_NBITS(data->options[0]) != db->maxbits)
+               || (decomp && db->lens == NULL)) {
+               printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n",data->optlen,data->num,data->options[0],decomp,(unsigned long)db->lens);
+               return 0;
+       }
+
+       if (decomp)
+               for(indx=LAST;indx>=0;indx--)
+                       db->lens[indx] = 1;
+
+       indx = db->hsize;
+       while (indx-- != 0) {
+               db->dict[indx].codem1 = BADCODEM1;
+               db->dict[indx].cptr   = 0;
+       }
+
+       db->unit = unit;
+       db->mru  = 0;
+
+       db->debug = 1;
+    
+       bsd_reset(db,0,0,NULL,0,NULL);
+    
+       return 1;
+}
+
+/*
+ * Obtain pointers to the various structures in the compression tables
+ */
+
+#define dict_ptrx(p,idx) &(p->dict[idx])
+#define lens_ptrx(p,idx) &(p->lens[idx])
+
+#ifdef DEBUG
+static unsigned short *lens_ptr(struct bsd_db *db, int idx)
+{
+       if ((unsigned int) idx > (unsigned int) db->maxmaxcode) {
+               printk (KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx);
+               idx = 0;
+       }
+       return lens_ptrx (db, idx);
+}
+
+static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
+{
+       if ((unsigned int) idx >= (unsigned int) db->hsize) {
+               printk (KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx);
+               idx = 0;
+       }
+       return dict_ptrx (db, idx);
+}
+
+#else
+#define lens_ptr(db,idx) lens_ptrx(db,idx)
+#define dict_ptr(db,idx) dict_ptrx(db,idx)
+#endif
+
+/*
+ * compress a packet
+ */
+static int bsd_compress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,int proto)
+{
+       struct bsd_db *db;
+       int hshift;
+       unsigned int max_ent;
+       unsigned int n_bits;
+       unsigned int bitno;
+       unsigned long accm;
+       int ent;
+       unsigned long fcode;
+       struct bsd_dict *dictp;
+       unsigned char c;
+       int hval,disp,ilen,mxcode;
+       unsigned char *rptr = skb_in->data;
+       int isize = skb_in->len;
+
+#define OUTPUT(ent)                    \
+  {                                    \
+    bitno -= n_bits;                   \
+    accm |= ((ent) << bitno);          \
+    do {                               \
+        if(skb_out && skb_tailroom(skb_out) > 0)       \
+               *(skb_put(skb_out,1)) = (unsigned char) (accm>>24); \
+       accm <<= 8;                     \
+       bitno += 8;                     \
+    } while (bitno <= 24);             \
+  }
+
+       /*
+        * If the protocol is not in the range we're interested in,
+        * just return without compressing the packet.  If it is,
+        * the protocol becomes the first byte to compress.
+        */
+       printk(KERN_DEBUG "bsd_compress called with %x\n",proto);
+       
+       ent = proto;
+       if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1) )
+               return 0;
+
+       db      = (struct bsd_db *) state;
+       hshift  = db->hshift;
+       max_ent = db->max_ent;
+       n_bits  = db->n_bits;
+       bitno   = 32;
+       accm    = 0;
+       mxcode  = MAXCODE (n_bits);
+       
+       /* This is the PPP header information */
+       if(skb_out && skb_tailroom(skb_out) >= 2) {
+               char *v = skb_put(skb_out,2);
+               /* we only push our own data on the header,
+                 AC,PC and protos is pushed by caller  */
+               v[0] = db->seqno >> 8;
+               v[1] = db->seqno;
+       }
+
+       ilen   = ++isize; /* This is off by one, but that is what is in draft! */
+
+       while (--ilen > 0) {
+               c     = *rptr++;
+               fcode = BSD_KEY  (ent, c);
+               hval  = BSD_HASH (ent, c, hshift);
+               dictp = dict_ptr (db, hval);
+       
+               /* Validate and then check the entry. */
+               if (dictp->codem1 >= max_ent)
+                       goto nomatch;
+
+               if (dictp->fcode == fcode) {
+                       ent = dictp->codem1 + 1;
+                       continue;       /* found (prefix,suffix) */
+               }
+       
+               /* continue probing until a match or invalid entry */
+               disp = (hval == 0) ? 1 : hval;
+
+               do {
+                       hval += disp;
+                       if (hval >= db->hsize)
+                               hval -= db->hsize;
+                       dictp = dict_ptr (db, hval);
+                       if (dictp->codem1 >= max_ent)
+                               goto nomatch;
+               } while (dictp->fcode != fcode);
+
+               ent = dictp->codem1 + 1;        /* finally found (prefix,suffix) */
+               continue;
+       
+nomatch:
+               OUTPUT(ent);            /* output the prefix */
+       
+               /* code -> hashtable */
+               if (max_ent < db->maxmaxcode) {
+                       struct bsd_dict *dictp2;
+                       struct bsd_dict *dictp3;
+                       int indx;
+
+                       /* expand code size if needed */
+                       if (max_ent >= mxcode) {
+                               db->n_bits = ++n_bits;
+                               mxcode = MAXCODE (n_bits);
+                       }
+           
+                       /* 
+                        * Invalidate old hash table entry using
+                        * this code, and then take it over.
+                        */
+                       dictp2 = dict_ptr (db, max_ent + 1);
+                       indx   = dictp2->cptr;
+                       dictp3 = dict_ptr (db, indx);
+
+                       if (dictp3->codem1 == max_ent)
+                               dictp3->codem1 = BADCODEM1;
+
+                       dictp2->cptr   = hval;
+                       dictp->codem1  = max_ent;
+                       dictp->fcode = fcode;
+                       db->max_ent    = ++max_ent;
+
+                       if (db->lens) {
+                               unsigned short *len1 = lens_ptr (db, max_ent);
+                               unsigned short *len2 = lens_ptr (db, ent);
+                               *len1 = *len2 + 1;
+                       }
+               }
+               ent = c;
+       }
+    
+       OUTPUT(ent);            /* output the last code */
+
+       if(skb_out)
+               db->bytes_out    += skb_out->len; /* Do not count bytes from here */
+       db->uncomp_bytes += isize;
+       db->in_count     += isize;
+       ++db->uncomp_count;
+       ++db->seqno;
+
+       if (bitno < 32)
+               ++db->bytes_out; /* must be set before calling bsd_check */
+
+       /*
+        * Generate the clear command if needed
+        */
+
+       if (bsd_check(db))
+               OUTPUT (CLEAR);
+
+       /*
+        * Pad dribble bits of last code with ones.
+        * Do not emit a completely useless byte of ones.
+        */
+       if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0) 
+               *(skb_put(skb_out,1)) = (unsigned char) ((accm | (0xff << (bitno-8))) >> 24);
+    
+       /*
+        * Increase code size if we would have without the packet
+        * boundary because the decompressor will do so.
+        */
+       if (max_ent >= mxcode && max_ent < db->maxmaxcode)
+               db->n_bits++;
+
+       /* If output length is too large then this is an incompressible frame. */
+       if (!skb_out || (skb_out && skb_out->len >= skb_in->len) ) {
+               ++db->incomp_count;
+               db->incomp_bytes += isize;
+               return 0;
+       }
+
+       /* Count the number of compressed frames */
+       ++db->comp_count;
+       db->comp_bytes += skb_out->len;
+       return skb_out->len;
+
+#undef OUTPUT
+}
+
+/*
+ * Update the "BSD Compress" dictionary on the receiver for
+ * incompressible data by pretending to compress the incoming data.
+ */
+static void bsd_incomp (void *state, struct sk_buff *skb_in,int proto)
+{
+       bsd_compress (state, skb_in, NULL, proto);
+}
+
+/*
+ * Decompress "BSD Compress".
+ */
+static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out,
+                          struct isdn_ppp_resetparams *rsparm)
+{
+       struct bsd_db *db;
+       unsigned int max_ent;
+       unsigned long accm;
+       unsigned int bitno;             /* 1st valid bit in accm */
+       unsigned int n_bits;
+       unsigned int tgtbitno;  /* bitno when we have a code */
+       struct bsd_dict *dictp;
+       int seq;
+       unsigned int incode;
+       unsigned int oldcode;
+       unsigned int finchar;
+       unsigned char *p,*ibuf;
+       int ilen;
+       int codelen;
+       int extra;
+
+       db       = (struct bsd_db *) state;
+       max_ent  = db->max_ent;
+       accm     = 0;
+       bitno    = 32;          /* 1st valid bit in accm */
+       n_bits   = db->n_bits;
+       tgtbitno = 32 - n_bits; /* bitno when we have a code */
+
+       printk(KERN_DEBUG "bsd_decompress called\n");
+
+       if(!skb_in || !skb_out) {
+               printk(KERN_ERR "bsd_decompress called with NULL parameter\n");
+               return DECOMP_ERROR;
+       }
+    
+       /*
+        * Get the sequence number.
+        */
+       if( (p = skb_pull(skb_in,2)) == NULL) {
+               return DECOMP_ERROR;
+       }
+       p-=2;
+       seq   = (p[0] << 8) + p[1];
+       ilen  = skb_in->len;
+       ibuf = skb_in->data;
+
+       /*
+        * Check the sequence number and give up if it differs from
+        * the value we're expecting.
+        */
+       if (seq != db->seqno) {
+               if (db->debug) {
+                       printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n",
+                               db->unit, seq, db->seqno - 1);
+               }
+               return DECOMP_ERROR;
+       }
+
+       ++db->seqno;
+       db->bytes_out += ilen;
+
+       if(skb_tailroom(skb_out) > 0)
+               *(skb_put(skb_out,1)) = 0;
+       else
+               return DECOMP_ERR_NOMEM;
+    
+       oldcode = CLEAR;
+
+       /*
+        * Keep the checkpoint correctly so that incompressible packets
+        * clear the dictionary at the proper times.
+        */
+
+       for (;;) {
+               if (ilen-- <= 0) {
+                       db->in_count += (skb_out->len - 1); /* don't count the header */
+                       break;
+               }
+
+               /*
+                * Accumulate bytes until we have a complete code.
+                * Then get the next code, relying on the 32-bit,
+                * unsigned accm to mask the result.
+                */
+
+               bitno -= 8;
+               accm  |= *ibuf++ << bitno;
+               if (tgtbitno < bitno)
+                       continue;
+
+               incode = accm >> tgtbitno;
+               accm <<= n_bits;
+               bitno += n_bits;
+
+               /*
+                * The dictionary must only be cleared at the end of a packet.
+                */
+       
+               if (incode == CLEAR) {
+                       if (ilen > 0) {
+                               if (db->debug)
+                                       printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit);
+                               return DECOMP_FATALERROR;       /* probably a bug */
+                       }
+                       bsd_clear(db);
+                       break;
+               }
+
+               if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
+                       || (incode > max_ent && oldcode == CLEAR)) {
+                       if (db->debug) {
+                               printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
+                                       db->unit, incode, oldcode);
+                               printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n",
+                                       max_ent, skb_out->len, db->seqno);
+                       }
+                       return DECOMP_FATALERROR;       /* probably a bug */
+               }
+       
+               /* Special case for KwKwK string. */
+               if (incode > max_ent) {
+                       finchar = oldcode;
+                       extra   = 1;
+               } else {
+                       finchar = incode;
+                       extra   = 0;
+               }
+
+               codelen = *(lens_ptr (db, finchar));
+               if( skb_tailroom(skb_out) < codelen + extra) {
+                       if (db->debug) {
+                               printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit);
+#ifdef DEBUG
+                               printk(KERN_DEBUG "  len=%d, finchar=0x%x, codelen=%d,skblen=%d\n",
+                                       ilen, finchar, codelen, skb_out->len);
+#endif
+                       }
+                       return DECOMP_FATALERROR;
+               }
+
+               /*
+                * Decode this code and install it in the decompressed buffer.
+                */
+
+               p     = skb_put(skb_out,codelen);
+               p += codelen;
+               while (finchar > LAST) {
+                       struct bsd_dict *dictp2 = dict_ptr (db, finchar);
+           
+                       dictp = dict_ptr (db, dictp2->cptr);
+
+#ifdef DEBUG
+                       if (--codelen <= 0 || dictp->codem1 != finchar-1) {
+                               if (codelen <= 0) {
+                                       printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit);
+                                       printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent);
+                               } else {
+                                       if (dictp->codem1 != finchar-1) {
+                                               printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",db->unit, incode, finchar);
+                                               printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1);
+                                       }
+                               }
+                               return DECOMP_FATALERROR;
+                       }
+#endif
+
+                       {
+                               u32 fcode = dictp->fcode;
+                               *--p    = (fcode >> 16) & 0xff;
+                               finchar = fcode & 0xffff;
+                       }
+               }
+               *--p = finchar;
+       
+#ifdef DEBUG
+               if (--codelen != 0)
+                       printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);
+#endif
+       
+               if (extra)              /* the KwKwK case again */
+                       *(skb_put(skb_out,1)) = finchar;
+       
+               /*
+                * If not first code in a packet, and
+                * if not out of code space, then allocate a new code.
+                *
+                * Keep the hash table correct so it can be used
+                * with uncompressed packets.
+                */
+               if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
+                       struct bsd_dict *dictp2, *dictp3;
+                       u16  *lens1,  *lens2;
+                       unsigned long fcode;
+                       int hval, disp, indx;
+           
+                       fcode = BSD_KEY(oldcode,finchar);
+                       hval  = BSD_HASH(oldcode,finchar,db->hshift);
+                       dictp = dict_ptr (db, hval);
+           
+                       /* look for a free hash table entry */
+                       if (dictp->codem1 < max_ent) {
+                               disp = (hval == 0) ? 1 : hval;
+                               do {
+                                       hval += disp;
+                                       if (hval >= db->hsize)
+                                               hval -= db->hsize;
+                                       dictp = dict_ptr (db, hval);
+                               } while (dictp->codem1 < max_ent);
+                       }
+           
+                       /*
+                        * Invalidate previous hash table entry
+                        * assigned this code, and then take it over
+                        */
+
+                       dictp2 = dict_ptr (db, max_ent + 1);
+                       indx   = dictp2->cptr;
+                       dictp3 = dict_ptr (db, indx);
+
+                       if (dictp3->codem1 == max_ent)
+                               dictp3->codem1 = BADCODEM1;
+
+                       dictp2->cptr   = hval;
+                       dictp->codem1  = max_ent;
+                       dictp->fcode = fcode;
+                       db->max_ent    = ++max_ent;
+
+                       /* Update the length of this string. */
+                       lens1  = lens_ptr (db, max_ent);
+                       lens2  = lens_ptr (db, oldcode);
+                       *lens1 = *lens2 + 1;
+           
+                       /* Expand code size if needed. */
+                       if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
+                               db->n_bits = ++n_bits;
+                               tgtbitno   = 32-n_bits;
+                       }
+               }
+               oldcode = incode;
+       }
+
+       ++db->comp_count;
+       ++db->uncomp_count;
+       db->comp_bytes   += skb_in->len - BSD_OVHD;
+       db->uncomp_bytes += skb_out->len;
+
+       if (bsd_check(db)) {
+               if (db->debug)
+                       printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n",
+                               db->unit, db->seqno - 1);
+       }
+       return skb_out->len;
+}
+
+/*************************************************************
+ * Table of addresses for the BSD compression module
+ *************************************************************/
+
+static struct isdn_ppp_compressor ippp_bsd_compress = {
+       NULL,NULL,              /* prev,next: overwritten by isdn_ppp */
+       CI_BSD_COMPRESS,        /* compress_proto */
+       bsd_alloc,              /* alloc */
+       bsd_free,               /* free */
+       bsd_init,               /* init */
+       bsd_reset,              /* reset */
+       bsd_compress,           /* compress */
+       bsd_decompress,         /* decompress */
+       bsd_incomp,             /* incomp */
+       bsd_stats               /* comp_stat */
+};
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+int init_module(void)
+{
+       int answer = isdn_ppp_register_compressor (&ippp_bsd_compress);
+       if (answer == 0)
+               printk (KERN_INFO "PPP BSD Compression module registered\n");
+       return answer;
+}
+
+void cleanup_module(void)
+{
+       isdn_ppp_unregister_compressor (&ippp_bsd_compress);
+}
diff --git a/drivers/isdn/isdn_budget.c b/drivers/isdn/isdn_budget.c
new file mode 100644 (file)
index 0000000..985c97b
--- /dev/null
@@ -0,0 +1,206 @@
+/* $Id: isdn_budget.c,v 1.3 1998/10/23 10:18:39 paul Exp $
+ *
+ * Linux ISDN subsystem, budget-accounting for network interfaces.
+ *
+ * Copyright 1997       by Christian Lademann <cal@zls.de>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * $Log: isdn_budget.c,v $
+ * Revision 1.3  1998/10/23 10:18:39  paul
+ * Implementation of "dialmode" (successor of "status")
+ * You also need current isdnctrl for this!
+ *
+ * Revision 1.2  1998/03/07 23:17:30  fritz
+ * Added RCS keywords
+ * Bugfix: Did not compile without isdn_dumppkt beeing enabled.
+ *
+ */
+
+/*
+30.06.97:cal:angelegt
+04.11.97:cal:budget.period: int --> time_t
+*/
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/isdn.h>
+#include "isdn_common.h"
+#include "isdn_net.h"
+
+#ifdef CONFIG_ISDN_BUDGET
+
+#define        VERBOSE_PRINTK(v, l, p...)      { \
+       if(dev->net_verbose >= (v)) { \
+               printk(l ## p); \
+       } else { ; } \
+}
+
+
+int
+isdn_net_budget(int type, struct device *ndev) {
+       isdn_net_local          *lp = (isdn_net_local *)ndev->priv;
+       int                     i, ret = 0;
+
+       switch(type) {
+       case ISDN_BUDGET_INIT:
+               for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
+                       lp->budget [i] .amount = -1;
+                       lp->budget [i] .used = 0;
+                       lp->budget [i] .period = (time_t)0;
+                       lp->budget [i] .period_started = (time_t)0;
+                       lp->budget [i] .last_check = CURRENT_TIME;
+                       lp->budget [i] .notified = 0;
+               }
+
+               return(0);
+               break;
+
+       case ISDN_BUDGET_CHECK_DIAL:
+       case ISDN_BUDGET_CHECK_CHARGE:
+       case ISDN_BUDGET_CHECK_ONLINE:
+               ret = 0;
+
+               for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
+                       if(lp->budget [i] .amount < 0)
+                               continue;
+
+                       if(lp->budget [i] .period_started + lp->budget [i] .period < CURRENT_TIME) {
+                               lp->budget [i] .used = 0;
+                               lp->budget [i] .period_started = CURRENT_TIME;
+                               lp->budget [i] .notified = 0;
+                       }
+
+                       if(lp->budget [i] .used >= lp->budget [i] .amount)
+                               ret |= (1 << i);
+               }
+
+               switch(type) {
+               case ISDN_BUDGET_CHECK_DIAL:
+                       if(! ret) {
+                               lp->budget [ISDN_BUDGET_DIAL] .used++;
+                               lp->budget [ISDN_BUDGET_DIAL] .last_check = CURRENT_TIME;
+                       }
+                       break;
+
+               case ISDN_BUDGET_CHECK_CHARGE:
+                       lp->budget [ISDN_BUDGET_CHARGE] .used++;
+                       lp->budget [ISDN_BUDGET_CHARGE] .last_check = CURRENT_TIME;
+                       break;
+
+               case ISDN_BUDGET_CHECK_ONLINE:
+                       if(lp->budget [ISDN_BUDGET_ONLINE] .last_check) {
+                               lp->budget [ISDN_BUDGET_ONLINE] .used += (CURRENT_TIME - lp->budget [ISDN_BUDGET_ONLINE] .last_check);
+                       }
+
+                       lp->budget [ISDN_BUDGET_ONLINE] .last_check = CURRENT_TIME;
+                       break;
+               }
+
+/*
+               if(ret)
+                       lp->flags |= ISDN_NET_DM_OFF;
+*/
+               for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) {
+                       if(ret & (1 << i) && ! lp->budget [i] .notified) {
+                               switch(i) {
+                               case ISDN_BUDGET_DIAL:
+                                       printk(KERN_WARNING "isdn_budget: dial budget used up.\n");
+                                       break;
+
+                               case ISDN_BUDGET_CHARGE:
+                                       printk(KERN_WARNING "isdn_budget: charge budget used up.\n");
+                                       break;
+
+                               case ISDN_BUDGET_ONLINE:
+                                       printk(KERN_WARNING "isdn_budget: online budget used up.\n");
+                                       break;
+
+                               default:
+                                       printk(KERN_WARNING "isdn_budget: budget #%d used up.\n", i);
+                                       break;
+                               }
+
+                               lp->budget [i] .notified = 1;
+                       }
+               }
+
+               return(ret);
+               break;
+
+       case ISDN_BUDGET_START_ONLINE:
+               lp->budget [ISDN_BUDGET_ONLINE] .last_check = CURRENT_TIME;
+               return(0);
+
+               break;
+       }
+
+       return(-1);
+}
+
+
+int
+isdn_budget_ioctl(isdn_ioctl_budget *iocmd) {
+       isdn_net_dev            *p = isdn_net_findif(iocmd->name);
+
+       if(p) {
+               switch(iocmd->command) {
+               case ISDN_BUDGET_SET_BUDGET:
+                       if(! suser())
+                               return(-EPERM);
+
+                       if(iocmd->budget < 0 || iocmd->budget > ISDN_BUDGET_NUM_BUDGET)
+                               return(-EINVAL);
+
+                       if(iocmd->amount < 0)
+                               iocmd->amount = -1;
+
+                       p->local->budget [iocmd->budget] .amount = iocmd->amount;
+                       p->local->budget [iocmd->budget] .period = iocmd->period;
+
+                       if(iocmd->used <= 0)
+                               p->local->budget [iocmd->budget] .used = 0;
+                       else
+                               p->local->budget [iocmd->budget] .used = iocmd->used;
+
+                       if(iocmd->period_started == (time_t)0)
+                               p->local->budget [iocmd->budget] .period_started = CURRENT_TIME;
+                       else
+                               p->local->budget [iocmd->budget] .period_started = iocmd->period_started;
+
+                       return(0);
+                       break;
+
+               case ISDN_BUDGET_GET_BUDGET:
+                       if(iocmd->budget < 0 || iocmd->budget > ISDN_BUDGET_NUM_BUDGET)
+                               return(-EINVAL);
+
+                       iocmd->amount = p->local->budget [iocmd->budget] .amount;
+                       iocmd->used = p->local->budget [iocmd->budget] .used;
+                       iocmd->period = p->local->budget [iocmd->budget] .period;
+                       iocmd->period_started = p->local->budget [iocmd->budget] .period_started;
+
+                       return(0);
+                       break;
+
+               default:
+                       return(-EINVAL);
+                       break;
+               }
+       }
+       return(-ENODEV);
+}
+#endif
index 30a4a77033cea3048a7d8e2562bf79b39ac5fe7b..06fa3e7d7ffca2c69ab2d7e3fe537b873a18b86e 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_cards.c,v 1.7 1998/02/20 17:24:28 fritz Exp $
+/* $Id: isdn_cards.c,v 1.9 1999/04/12 12:33:11 fritz Exp $
 
  * Linux ISDN subsystem, initialization for non-modularized drivers.
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_cards.c,v $
+ * Revision 1.9  1999/04/12 12:33:11  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.8  1999/03/29 11:13:23  armin
+ * Added eicon driver init.
+ *
  * Revision 1.7  1998/02/20 17:24:28  fritz
  * Added ACT2000 init.
  *
@@ -56,6 +62,10 @@ extern void HiSax_init(void);
 extern void pcbit_init(void);
 #endif
 
+#ifdef CONFIG_ISDN_DRV_EICON
+extern void eicon_init(void);
+#endif
+
 #ifdef CONFIG_ISDN_DRV_AVMB1
 extern void avmb1_init(void);
 extern void capi_init(void);
@@ -88,4 +98,7 @@ isdn_cards_init(void)
 #if CONFIG_ISDN_DRV_ACT2000
        act2000_init();
 #endif
+#if CONFIG_ISDN_DRV_EICON
+       eicon_init();
+#endif
 }
index e6e2aa12763f7bb43472d253b1be89389dd44d48..78173e7470d25258f3f610a20aabd1bdcf41ac17 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_cards.h,v 1.2 1997/02/03 23:31:55 fritz Exp $
+/* $Id: isdn_cards.h,v 1.3 1999/04/12 12:33:13 fritz Exp $
 
  * Linux ISDN subsystem, initialization for non-modularized drivers.
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_cards.h,v $
+ * Revision 1.3  1999/04/12 12:33:13  fritz
+ * Changes from 2.0 tree.
+ *
  * Revision 1.2  1997/02/03 23:31:55  fritz
  * Reformatted according CodingStyle
  *
index 9f32ec5e67dcecddeabf72c857cb3d99674eeea1..779a327face44adde0564c46ebed811d73b66ef3 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_common.c,v 1.55 1998/02/23 23:35:32 fritz Exp $
+/* $Id: isdn_common.c,v 1.75 1999/04/18 14:06:47 fritz Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Note: This file differs from the corresponding revision as present in the
- * isdn4linux CVS repository because some later bug fixes have been extracted
- * from the repository and merged into this file. -- Henner Eisen
- *
  * $Log: isdn_common.c,v $
+ * Revision 1.75  1999/04/18 14:06:47  fritz
+ * Removed TIMRU stuff.
+ *
+ * Revision 1.74  1999/04/12 13:16:45  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.73  1999/04/12 12:33:15  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.72  1999/03/02 12:04:44  armin
+ * -added ISDN_STAT_ADDCH to increase supported channels after
+ *  register_isdn().
+ * -ttyI now goes on-hook on ATZ when B-Ch is connected.
+ * -added timer-function for register S7 (Wait for Carrier).
+ * -analog modem (ISDN_PROTO_L2_MODEM) implementations.
+ * -on L2_MODEM a string will be appended to the CONNECT-Message,
+ *  which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN.
+ * -variable "dialing" used for ATA also, for interrupting call
+ *  establishment and register S7.
+ *
+ * Revision 1.71  1999/01/28 09:10:43  armin
+ * Fixed bad while-loop in isdn_readbch().
+ *
+ * Revision 1.70  1999/01/15 19:58:54  he
+ * removed compatibiltity macro
+ *
+ * Revision 1.69  1998/09/07 21:59:58  he
+ * flush method for 2.1.118 and above
+ * updated IIOCTLNETGPN
+ *
+ * Revision 1.68  1998/08/31 21:09:45  he
+ * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface'
+ *     peer phone number)
+ *
+ * Revision 1.67  1998/06/26 15:12:21  fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 1.66  1998/06/17 19:50:41  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.65  1998/06/07 00:20:00  fritz
+ * abc cleanup.
+ *
+ * Revision 1.64  1998/06/02 12:10:03  detabc
+ * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
+ * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
+ *
+ * Revision 1.63  1998/05/03 17:40:38  detabc
+ * Include abc-extension-support for >= 2.1.x Kernels in
+ * isdn_net.c and isdn_common.c. alpha-test OK and running !
+ *
+ * Revision 1.62  1998/04/14 16:28:43  he
+ * Fixed user space access with interrupts off and remaining
+ * copy_{to,from}_user() -> -EFAULT return codes
+ *
+ * Revision 1.61  1998/03/22 18:50:46  hipp
+ * Added BSD Compression for syncPPP .. UNTESTED at the moment
+ *
+ * Revision 1.60  1998/03/19 13:18:18  keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
+ * Revision 1.59  1998/03/09 17:46:23  he
+ * merged in 2.1.89 changes
+ *
+ * Revision 1.58  1998/03/07 22:35:24  fritz
+ * Starting generic module support (Nothing usable yet).
+ *
+ * Revision 1.57  1998/03/07 18:21:01  cal
+ * Dynamic Timeout-Rule-Handling vs. 971110 included
+ *
+ * Revision 1.56  1998/02/25 17:49:38  he
+ * Changed return codes caused be failing copy_{to,from}_user to -EFAULT
+ *
  * Revision 1.55  1998/02/23 23:35:32  fritz
  * Eliminated some compiler warnings.
  *
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static char *isdn_revision = "$Revision: 1.55 $";
+static char *isdn_revision = "$Revision: 1.75 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -290,13 +364,36 @@ static int isdn_writebuf_stub(int, int, const u_char *, int, int);
 void
 isdn_MOD_INC_USE_COUNT(void)
 {
+       int i;
+
        MOD_INC_USE_COUNT;
+       for (i = 0; i < dev->drivers; i++) {
+               isdn_ctrl cmd;
+
+               cmd.driver = i;
+               cmd.arg = 0;
+               cmd.command = ISDN_CMD_LOCK;
+               isdn_command(&cmd);
+               dev->drv[i]->locks++;
+       }
 }
 
 void
 isdn_MOD_DEC_USE_COUNT(void)
 {
+       int i;
+
        MOD_DEC_USE_COUNT;
+       for (i = 0; i < dev->drivers; i++)
+               if (dev->drv[i]->locks > 0) {
+                       isdn_ctrl cmd;
+
+                       cmd.driver = i;
+                       cmd.arg = 0;
+                       cmd.command = ISDN_CMD_UNLOCK;
+                       isdn_command(&cmd);
+                       dev->drv[i]->locks--;
+               }
 }
 
 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
@@ -312,6 +409,82 @@ isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
 }
 #endif
 
+/*
+ * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
+ * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
+ */
+static int
+isdn_star(char *s, char *p)
+{
+       while (isdn_wildmat(s, p)) {
+               if (*++s == '\0')
+                       return (2);
+       }
+       return (0);
+}
+
+/*
+ * Shell-type Pattern-matching for incoming caller-Ids
+ * This function gets a string in s and checks, if it matches the pattern
+ * given in p.
+ *
+ * Return:
+ *   0 = match.
+ *   1 = no match.
+ *   2 = no match. Would eventually match, if s would be longer.
+ *
+ * Possible Patterns:
+ *
+ * '?'     matches one character
+ * '*'     matches zero or more characters
+ * [xyz]   matches the set of characters in brackets.
+ * [^xyz]  matches any single character not in the set of characters
+ */
+
+int
+isdn_wildmat(char *s, char *p)
+{
+       register int last;
+       register int matched;
+       register int reverse;
+       register int nostar = 1;
+
+       for (; *p; s++, p++)
+               switch (*p) {
+                       case '\\':
+                               /*
+                                * Literal match with following character,
+                                * fall through.
+                                */
+                               p++;
+                       default:
+                               if (*s != *p)
+                                       return (*s == '\0')?2:1;
+                               continue;
+                       case '?':
+                               /* Match anything. */
+                               if (*s == '\0')
+                                       return (2);
+                               continue;
+                       case '*':
+                               nostar = 0;     
+                               /* Trailing star matches everything. */
+                               return (*++p ? isdn_star(s, p) : 0);
+                       case '[':
+                               /* [^....] means inverse character class. */
+                               if ((reverse = (p[1] == '^')))
+                                       p++;
+                               for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
+                                       /* This next line requires a good C compiler. */
+                                       if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
+                                               matched = 1;
+                               if (matched == reverse)
+                                       return (1);
+                               continue;
+               }
+       return (*s == '\0')?0:nostar;
+}
+
 static void
 isdn_free_queue(struct sk_buff_head *queue)
 {
@@ -345,7 +518,6 @@ static void
 isdn_timer_funct(ulong dummy)
 {
        int tf = dev->tflags;
-
        if (tf & ISDN_TIMER_FAST) {
                if (tf & ISDN_TIMER_MODEMREAD)
                        isdn_tty_readmodem();
@@ -374,13 +546,16 @@ isdn_timer_funct(ulong dummy)
                                if (tf & ISDN_TIMER_KEEPALIVE)
                                        isdn_net_slarp_out();
                        }
+                       if (tf & ISDN_TIMER_CARRIER)
+                               isdn_tty_carrier_timeout();
 #if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
                        if (tf & ISDN_TIMER_IPPP)
                                isdn_ppp_timer_timeout();
 #endif
                }
        }
-       if (tf) {
+       if (tf) 
+       {
                int flags;
 
                save_flags(flags);
@@ -506,6 +681,29 @@ isdn_all_eaz(int di, int ch)
        isdn_command(&cmd);
 }
 
+/*
+ * Begin of a CAPI like LL<->HL interface, currently used only for 
+ * supplementary service (CAPI 2.0 part III)
+ */
+#include "avmb1/capicmd.h"  /* this should be moved in a common place */
+
+int
+isdn_capi_rec_hl_msg(capi_msg *cm) {
+       
+       int di;
+       int ch;
+       
+       di = (cm->adr.Controller & 0x7f) -1;
+       ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f);
+       switch(cm->Command) {
+               case CAPI_FACILITY:
+                       /* in the moment only handled in tty */
+                       return(isdn_tty_capi_facility(cm));
+               default:
+                       return(-1);
+       }
+}
+
 static int
 isdn_status_callback(isdn_ctrl * c)
 {
@@ -540,13 +738,13 @@ isdn_status_callback(isdn_ctrl * c)
                        wake_up_interruptible(&dev->drv[di]->st_waitq);
                        break;
                case ISDN_STAT_RUN:
-                       dev->drv[di]->running = 1;
+                       dev->drv[di]->flags |= DRV_FLAG_RUNNING;
                        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
                                if (dev->drvmap[i] == di)
                                        isdn_all_eaz(di, dev->chanmap[i]);
                        break;
                case ISDN_STAT_STOP:
-                       dev->drv[di]->running = 0;
+                       dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
                        break;
                case ISDN_STAT_ICALL:
                        if (i < 0)
@@ -562,19 +760,17 @@ isdn_status_callback(isdn_ctrl * c)
                                return 0;
                        }
                        /* Try to find a network-interface which will accept incoming call */
-                       cmd.driver = di;
-                       cmd.arg = c->arg;
-                       cmd.command = ISDN_CMD_LOCK;
-                       isdn_command(&cmd);
                        r = isdn_net_find_icall(di, c->arg, i, c->parm.setup);
                        switch (r) {
                                case 0:
                                        /* No network-device replies.
-                                        * Try ttyI's
+                                        * Try ttyI's.
+                                        * These return 0 on no match, 1 on match and
+                                        * 3 on eventually match, if CID is longer.
                                         */
-                                       if (isdn_tty_find_icall(di, c->arg, c->parm.setup) >= 0)
-                                               retval = 1;
-                                       else if (dev->drv[di]->reject_bus) {
+                                       retval = isdn_tty_find_icall(di, c->arg, c->parm.setup);
+                                       if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
+                                               /* No tty responding */
                                                cmd.driver = di;
                                                cmd.arg = c->arg;
                                                cmd.command = ISDN_CMD_HANGUP;
@@ -606,13 +802,14 @@ isdn_status_callback(isdn_ctrl * c)
                                        /* ... then start callback. */
                                        isdn_net_dial();
                                        break;
+                               case 5:
+                                       /* Number would eventually match, if longer */
+                                       retval = 3;
+                                       break;
                        }
-                       if (retval != 1) {
-                               cmd.driver = di;
-                               cmd.arg = c->arg;
-                               cmd.command = ISDN_CMD_UNLOCK;
-                               isdn_command(&cmd);
-                       }
+#ifdef ISDN_DEBUG_STATCALLB
+                       printk(KERN_DEBUG "ICALL: ret=%d\n", retval);
+#endif
                        return retval;
                        break;
                case ISDN_STAT_CINF:
@@ -664,7 +861,7 @@ isdn_status_callback(isdn_ctrl * c)
 #endif
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
                                return 0;
-                       dev->drv[di]->flags &= ~(1 << (c->arg));
+                       dev->drv[di]->online &= ~(1 << (c->arg));
                        isdn_info_update();
                        /* Signal hangup to network-devices */
                        if (isdn_net_stat_callback(i, c))
@@ -682,7 +879,7 @@ isdn_status_callback(isdn_ctrl * c)
                        /* Signal B-channel-connect to network-devices */
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
                                return 0;
-                       dev->drv[di]->flags |= (1 << (c->arg));
+                       dev->drv[di]->online |= (1 << (c->arg));
                        isdn_info_update();
                        if (isdn_net_stat_callback(i, c))
                                break;
@@ -698,7 +895,7 @@ isdn_status_callback(isdn_ctrl * c)
 #endif
                        if (dev->global_flags & ISDN_GLOBAL_STOPPED)
                                return 0;
-                       dev->drv[di]->flags &= ~(1 << (c->arg));
+                       dev->drv[di]->online &= ~(1 << (c->arg));
                        isdn_info_update();
 #ifdef CONFIG_ISDN_X25
                        /* Signal hangup to network-devices */
@@ -723,6 +920,9 @@ isdn_status_callback(isdn_ctrl * c)
                                break;
                        break;
                case ISDN_STAT_ADDCH:
+                       if (isdn_add_channels(dev->drv[di], di, c->arg, 1))
+                               return -1;
+                       isdn_info_update();
                        break;
                case ISDN_STAT_UNLOAD:
                        save_flags(flags);
@@ -741,6 +941,9 @@ isdn_status_callback(isdn_ctrl * c)
                                isdn_free_queue(&dev->drv[di]->rpqueue[i]);
                        kfree(dev->drv[di]->rpqueue);
                        kfree(dev->drv[di]->rcv_waitq);
+#if LINUX_VERSION_CODE < 131841
+                       kfree(dev->drv[di]->snd_waitq);
+#endif
                        kfree(dev->drv[di]);
                        dev->drv[di] = NULL;
                        dev->drvid[di][0] = '\0';
@@ -749,6 +952,8 @@ isdn_status_callback(isdn_ctrl * c)
                        return 0;
                case ISDN_STAT_L1ERR:
                        break;
+               case CAPI_PUT_MESSAGE:
+                       return(isdn_capi_rec_hl_msg(&c->parm.cmsg));
                default:
                        return -1;
        }
@@ -784,7 +989,11 @@ isdn_getnum(char **p)
  * of the mapping (di,ch)<->minor, happen during the sleep? --he 
  */
 int
+#if LINUX_VERSION_CODE < 131841
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep)
+#else
 isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
+#endif
 {
        int left;
        int count;
@@ -818,7 +1027,8 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
 
                        dflag = 0;
                        count_pull = count_put = 0;
-                       while ((count_pull < skb->len) && (left-- > 0)) {
+                       while ((count_pull < skb->len) && (left > 0)) {
+                               left--;
                                if (dev->drv[di]->DLEflag & DLEmask) {
                                        *cp++ = DLE;
                                        dev->drv[di]->DLEflag &= ~DLEmask;
@@ -893,8 +1103,6 @@ isdn_minor2chan(int minor)
        return (dev->chanmap[minor]);
 }
 
-#define INF_DV 0x01             /* Data version for /dev/isdninfo */
-
 static char *
 isdn_statstr(void)
 {
@@ -930,7 +1138,7 @@ isdn_statstr(void)
        p = istatbuf + strlen(istatbuf);
        for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
                if (dev->drv[i]) {
-                       sprintf(p, "%ld ", dev->drv[i]->flags);
+                       sprintf(p, "%ld ", dev->drv[i]->online);
                        p = istatbuf + strlen(istatbuf);
                } else {
                        sprintf(p, "? ");
@@ -996,7 +1204,7 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
                drvidx = isdn_minor2drv(minor);
                if (drvidx < 0)
                        return -ENODEV;
-               if (!dev->drv[drvidx]->running)
+               if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
                        return -ENODEV;
                chidx = isdn_minor2chan(minor);
                if(  ! (p = kmalloc(count,GFP_KERNEL))  ) return -ENOMEM;
@@ -1066,7 +1274,7 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
                drvidx = isdn_minor2drv(minor);
                if (drvidx < 0)
                        return -ENODEV;
-               if (!dev->drv[drvidx]->running)
+               if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
                        return -ENODEV;
                chidx = isdn_minor2chan(minor);
                while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
@@ -1080,7 +1288,7 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
                /*
                 * We want to use the isdnctrl device to load the firmware
                 *
-                if (!dev->drv[drvidx]->running)
+                if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
                 return -ENODEV;
                 */
                if (dev->drv[drvidx]->interface->writecmd)
@@ -1131,143 +1339,6 @@ isdn_poll(struct file *file, poll_table * wait)
        return POLLERR;
 }
 
-/* 
- * This accesses user space with interrupts off, but is not needed by
- * any of the isdn4k-util programs anyway. Thus, in contrast to your
- * first impression after looking at the code, fixing is trival!*/
-#if 0 
-static int
-isdn_set_allcfg(char *src)
-{
-       int ret;
-       int i;
-       ulong flags;
-       isdn_net_ioctl_cfg cfg;
-       isdn_net_ioctl_phone phone;
-
-       if ((ret = isdn_net_rmall()))
-               return ret;
-       if (copy_from_user((char *) &i, src, sizeof(int))) return -EFAULT;
-       save_flags(flags);
-       cli();
-       src += sizeof(int);
-       while (i) {
-               int phone_len;
-               int out_flag;
-
-               if (copy_from_user((char *) &cfg, src, sizeof(cfg))) {
-                       restore_flags(flags);
-                       return -EFAULT;
-               }
-               src += sizeof(cfg);
-               if (!isdn_net_new(cfg.name, NULL)) {
-                       restore_flags(flags);
-                       return -EIO;
-               }
-               if ((ret = isdn_net_setcfg(&cfg))) {
-                       restore_flags(flags);
-                       return ret;
-               }
-               phone_len = out_flag = 0;
-               while (out_flag < 2) {
-                       if ((ret = verify_area(VERIFY_READ, src, 1))) {
-                               restore_flags(flags);
-                               return ret;
-                       }
-                       get_user(phone.phone[phone_len], src++);
-                       if ((phone.phone[phone_len] == ' ') ||
-                           (phone.phone[phone_len] == '\0')) {
-                               if (phone_len) {
-                                       phone.phone[phone_len] = '\0';
-                                       strcpy(phone.name, cfg.name);
-                                       phone.outgoing = out_flag;
-                                       if ((ret = isdn_net_addphone(&phone))) {
-                                               restore_flags(flags);
-                                               return ret;
-                                       }
-                               } else
-                                       out_flag++;
-                               phone_len = 0;
-                       }
-                       if (++phone_len >= sizeof(phone.phone))
-                               printk(KERN_WARNING
-                                      "%s: IIOCSETSET phone number too long, ignored\n",
-                                      cfg.name);
-               }
-               i--;
-       }
-       restore_flags(flags);
-       return 0;
-}
-
-static int
-isdn_get_allcfg(char *dest)
-{
-       isdn_net_ioctl_cfg cfg;
-       isdn_net_ioctl_phone phone;
-       isdn_net_dev *p;
-       ulong flags;
-       int ret;
-
-       /* Walk through netdev-chain */
-       save_flags(flags);
-       cli();
-       p = dev->netdev;
-       while (p) {
-               isdn_net_local *lp = p->local;
-
-               if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) {
-                       restore_flags(flags);
-                       return ret;
-               }
-               strcpy(cfg.eaz, lp->msn);
-               cfg.exclusive = lp->exclusive;
-               if (lp->pre_device >= 0) {
-                       sprintf(cfg.drvid, "%s,%d", dev->drvid[lp->pre_device],
-                               lp->pre_channel);
-               } else
-                       cfg.drvid[0] = '\0';
-               cfg.onhtime = lp->onhtime;
-               cfg.charge = lp->charge;
-               cfg.l2_proto = lp->l2_proto;
-               cfg.l3_proto = lp->l3_proto;
-               cfg.p_encap = lp->p_encap;
-               cfg.secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
-               cfg.callback = (lp->flags & ISDN_NET_CALLBACK) ? 1 : 0;
-               cfg.chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
-               cfg.ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
-               cfg.chargeint = lp->chargeint;
-               if (copy_to_user(dest, lp->name, 10)) {
-                       restore_flags(flags);
-                       return -EFAULT;
-               }
-               dest += 10;
-               if (copy_to_user(dest, (char *) &cfg, sizeof(cfg))) {
-                       restore_flags(flags);
-                       return -EFAULT;
-               }
-               dest += sizeof(cfg);
-               strcpy(phone.name, lp->name);
-               phone.outgoing = 0;
-               if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
-                       restore_flags(flags);
-                       return ret;
-               } else
-                       dest += ret;
-               strcpy(phone.name, lp->name);
-               phone.outgoing = 1;
-               if ((ret = isdn_net_getphones(&phone, dest)) < 0) {
-                       restore_flags(flags);
-                       return ret;
-               } else
-                       dest += ret;
-               put_user(0, dest);
-               p = p->next;
-       }
-       restore_flags(flags);
-       return 0;
-}
-#endif
 
 static int
 isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
@@ -1315,6 +1386,17 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                } else
                                        return -EINVAL;
                                break;
+#ifdef CONFIG_NETDEVICES
+                       case IIOCNETGPN:
+                               /* Get peer phone number of a connected 
+                                * isdn network interface */
+                               if (arg) {
+                                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+                                               return -EFAULT;
+                                       return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+                               } else
+                                       return -EINVAL;
+#endif
                        default:
                                return -EINVAL;
                }
@@ -1326,7 +1408,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                if (drvidx < 0)
                        return -ENODEV;
                chidx = isdn_minor2chan(minor);
-               if (!dev->drv[drvidx]->running)
+               if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
                        return -ENODEV;
                return 0;
        }
@@ -1512,26 +1594,11 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                }
                                if (drvidx == -1)
                                        return -ENODEV;
-                               dev->drv[drvidx]->reject_bus = iocts.arg;
-                               return 0;
-#if 0
-                       case IIOCGETSET:
-                               /* Get complete setup (all network-interfaces and profile-
-                                  settings of all tty-devices */
-                               if (arg)
-                                       return (isdn_get_allcfg((char *) arg));
+                               if (iocts.arg)
+                                       dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
                                else
-                                       return -EINVAL;
-                               break;
-                       case IIOCSETSET:
-                               /* Set complete setup (all network-interfaces and profile-
-                                  settings of all tty-devices */
-                               if (arg)
-                                       return (isdn_set_allcfg((char *) arg));
-                               else
-                                       return -EINVAL;
-                               break;
-#endif
+                                       dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
+                               return 0;
                        case IIOCSIGPRF:
                                dev->profd = current;
                                return 0;
@@ -1543,7 +1610,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                        int i;
 
                                        if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-                                       (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
+                                       (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN)
                                                   * ISDN_MAX_CHANNELS)))
                                                return ret;
 
@@ -1555,8 +1622,11 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                                if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
                                                        return -EFAULT;
                                                p += ISDN_MSNLEN;
+                                               if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
+                                                       return -EFAULT;
+                                               p += ISDN_LMSNLEN;
                                        }
-                                       return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
+                                       return (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
                                } else
                                        return -EINVAL;
                                break;
@@ -1720,7 +1790,6 @@ isdn_open(struct inode *ino, struct file *filep)
        uint minor = MINOR(ino->i_rdev);
        int drvidx;
        int chidx;
-       isdn_ctrl c;
 
        if (minor == ISDN_MINOR_STATUS) {
                infostruct *p;
@@ -1743,31 +1812,25 @@ isdn_open(struct inode *ino, struct file *filep)
                if (drvidx < 0)
                        return -ENODEV;
                chidx = isdn_minor2chan(minor);
-               if (!dev->drv[drvidx]->running)
+               if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
                        return -ENODEV;
-               if (!(dev->drv[drvidx]->flags & (1 << chidx)))
+               if (!(dev->drv[drvidx]->online & (1 << chidx)))
                        return -ENODEV;
-               c.command = ISDN_CMD_LOCK;
-               c.driver = drvidx;
-               isdn_command(&c);
-               MOD_INC_USE_COUNT;
+               isdn_MOD_INC_USE_COUNT();
                return 0;
        }
        if (minor <= ISDN_MINOR_CTRLMAX) {
                drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
                if (drvidx < 0)
                        return -ENODEV;
-               c.command = ISDN_CMD_LOCK;
-               c.driver = drvidx;
-               MOD_INC_USE_COUNT;
-               isdn_command(&c);
+               isdn_MOD_INC_USE_COUNT();
                return 0;
        }
 #ifdef CONFIG_ISDN_PPP
        if (minor <= ISDN_MINOR_PPPMAX) {
                int ret;
                if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
-                       MOD_INC_USE_COUNT;
+                       isdn_MOD_INC_USE_COUNT();
                return ret;
        }
 #endif
@@ -1778,13 +1841,12 @@ static int
 isdn_close(struct inode *ino, struct file *filep)
 {
        uint minor = MINOR(ino->i_rdev);
-       int drvidx;
-       isdn_ctrl c;
 
-       MOD_DEC_USE_COUNT;
        if (minor == ISDN_MINOR_STATUS) {
                infostruct *p = dev->infochain;
                infostruct *q = NULL;
+
+               MOD_DEC_USE_COUNT;
                while (p) {
                        if (p->private == (char *) &(filep->private_data)) {
                                if (q)
@@ -1800,24 +1862,12 @@ isdn_close(struct inode *ino, struct file *filep)
                printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
                return 0;
        }
-       if (minor < ISDN_MINOR_CTRL) {
-               drvidx = isdn_minor2drv(minor);
-               if (drvidx < 0)
-                       return 0;
-               c.command = ISDN_CMD_UNLOCK;
-               c.driver = drvidx;
-               isdn_command(&c);
+       isdn_MOD_DEC_USE_COUNT();
+       if (minor < ISDN_MINOR_CTRL)
                return 0;
-       }
        if (minor <= ISDN_MINOR_CTRLMAX) {
-               drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-               if (drvidx < 0)
-                       return 0;
                if (dev->profd == current)
                        dev->profd = NULL;
-               c.command = ISDN_CMD_UNLOCK;
-               c.driver = drvidx;
-               isdn_command(&c);
                return 0;
        }
 #ifdef CONFIG_ISDN_PPP
@@ -1871,7 +1921,6 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
        ulong flags;
        ulong features;
        ulong vfeatures;
-       isdn_ctrl cmd;
 
        save_flags(flags);
        cli();
@@ -1889,7 +1938,7 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                        if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
                        ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
                                continue;
-                       if ((dev->drv[d]->running)) {
+                       if (dev->drv[d]->flags & DRV_FLAG_RUNNING) {
                                if (((dev->drv[d]->interface->features & features) == features) ||
                                    (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
                                     (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
@@ -1897,10 +1946,6 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                                                dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
                                                dev->usage[i] |= usage;
                                                isdn_info_update();
-                                               cmd.driver = d;
-                                               cmd.arg = 0;
-                                               cmd.command = ISDN_CMD_LOCK;
-                                               isdn_command(&cmd);
                                                restore_flags(flags);
                                                return i;
                                        } else {
@@ -1908,10 +1953,6 @@ isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                                                        dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
                                                        dev->usage[i] |= usage;
                                                        isdn_info_update();
-                                                       cmd.driver = d;
-                                                       cmd.arg = 0;
-                                                       cmd.command = ISDN_CMD_LOCK;
-                                                       isdn_command(&cmd);
                                                        restore_flags(flags);
                                                        return i;
                                                }
@@ -1931,7 +1972,6 @@ isdn_free_channel(int di, int ch, int usage)
 {
        int i;
        ulong flags;
-       isdn_ctrl cmd;
 
        save_flags(flags);
        cli();
@@ -1945,12 +1985,6 @@ isdn_free_channel(int di, int ch, int usage)
                        dev->obytes[i] = 0;
                        isdn_info_update();
                        isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
-                       cmd.driver = di;
-                       cmd.arg = ch;
-                       cmd.command = ISDN_CMD_UNLOCK;
-                       restore_flags(flags);
-                       isdn_command(&cmd);
-                       return;
                }
        restore_flags(flags);
 }
@@ -1995,7 +2029,6 @@ isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
                copy_from_user(skb_put(skb, len), buf, len);
        else
                memcpy(skb_put(skb, len), buf, len);
-
        ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
        if (ret <= 0)
                dev_kfree_skb(skb);
@@ -2051,19 +2084,180 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
        return ret;
 }
 
+int
+register_isdn_module(isdn_module *m) {
+#if 0
+       isdn_module_list **pp = &dev->modules;
+       isdn_module *new = kmalloc(sizeof(isdn_module_list), GFP_KERNEL);
+
+       if (!new) {
+               printk(KERN_WARNING "isdn: Out of memory in register_isdn_module\n");
+               return -1;
+       }
+       while (*pp && (*pp)->orig != m)
+               pp = &(*pp)->next;
+       if (*pp != NULL) {
+               printk(KERN_WARNING "isdn: Module %s already registered\n", m->name);
+               return -1;
+       }
+       while (*pp && ((*pp)->module.priority < m->priority))
+               pp = &(*pp)->next;
+       new->next = *pp;
+       new->orig = m;
+       new->module = *m;
+       *pp = new;
+#endif
+       return 0;
+}
+
+int
+unregister_isdn_module(isdn_module *m) {
+#if 0
+       isdn_module_list **pp = &dev->modules;
+
+       while (*pp && *pp != m)
+               pp = &(*pp)->next;
+       if (*pp == NULL) {
+               printk(KERN_WARNING "isdn: Module %s not found\n", m->name);
+               return -1;
+       }
+#endif
+       return 0;
+}
+
+int
+isdn_add_channels(driver *d, int drvidx, int n, int adding)
+{
+       int j, k, m;
+       ulong flags;
+
+#if LINUX_VERSION_CODE >= 131841
+       init_waitqueue_head(&d->st_waitq);
+#endif
+       if (d->flags & DRV_FLAG_RUNNING)
+               return -1;
+       if (n < 1)
+               return 0;
+
+       m = (adding) ? d->channels + n : n;
+
+       if (dev->channels + n > ISDN_MAX_CHANNELS) {
+               printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
+                      ISDN_MAX_CHANNELS);
+               return -1;
+       }
+
+       if ((adding) && (d->rcverr))
+               kfree(d->rcverr);
+       if (!(d->rcverr = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) {
+               printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
+               return -1;
+       }
+       memset((char *) d->rcverr, 0, sizeof(int) * m);
+
+       if ((adding) && (d->rcvcount))
+               kfree(d->rcvcount);
+       if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) {
+               printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
+               if (!adding) kfree(d->rcverr);
+               return -1;
+       }
+       memset((char *) d->rcvcount, 0, sizeof(int) * m);
+
+       if ((adding) && (d->rpqueue)) {
+               for (j = 0; j < d->channels; j++)
+                       isdn_free_queue(&d->rpqueue[j]);
+               kfree(d->rpqueue);
+       }
+       if (!(d->rpqueue =
+             (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) {
+               printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
+               if (!adding) {
+                       kfree(d->rcvcount);
+                       kfree(d->rcverr);
+               }
+               return -1; 
+       }
+       for (j = 0; j < m; j++) {
+               skb_queue_head_init(&d->rpqueue[j]);
+       }
+
+       if ((adding) && (d->rcv_waitq))
+               kfree(d->rcv_waitq);
+#if LINUX_VERSION_CODE < 131841
+       if (!(d->rcv_waitq = (struct wait_queue **)
+             kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) {
+#else
+       d->rcv_waitq = (wait_queue_head_t *)
+               kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL);
+       if (!d->rcv_waitq) {
+#endif
+               printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
+               if (!adding) {
+                       kfree(d->rpqueue);
+                       kfree(d->rcvcount);
+                       kfree(d->rcverr);
+               }
+               return -1;
+       }
+#if LINUX_VERSION_CODE < 131841
+       memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * m);
+
+       if ((adding) && (d->snd_waitq))
+               kfree(d->snd_waitq);
+       if (!(d->snd_waitq = (struct wait_queue **)
+             kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) {
+               printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n");
+               if (!adding) {
+                       kfree(d->rcv_waitq);
+                       kfree(d->rpqueue);
+                       kfree(d->rcvcount);
+                       kfree(d->rcverr);
+               }
+               return -1;
+       }
+       memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * m);
+#else
+       d->snd_waitq = d->rcv_waitq + m;
+       for (j = 0; j < m; j++) {
+               init_waitqueue_head(&d->rcv_waitq[m]);
+               init_waitqueue_head(&d->snd_waitq[m]);
+       }
+#endif
+
+       dev->channels += n;
+       save_flags(flags);
+       cli();
+       for (j = d->channels; j < m; j++)
+               for (k = 0; k < ISDN_MAX_CHANNELS; k++)
+                       if (dev->chanmap[k] < 0) {
+                               dev->chanmap[k] = j;
+                               dev->drvmap[k] = drvidx;
+                               break;
+                       }
+       restore_flags(flags);
+       d->channels = m;
+       return 0;
+}
+
 /*
  * Low-level-driver registration
  */
 
 EXPORT_SYMBOL(register_isdn);
+EXPORT_SYMBOL(register_isdn_module);
+EXPORT_SYMBOL(unregister_isdn_module);
+#ifdef CONFIG_ISDN_PPP
+EXPORT_SYMBOL(isdn_ppp_register_compressor);
+EXPORT_SYMBOL(isdn_ppp_unregister_compressor);
+#endif
 
 int
 register_isdn(isdn_if * i)
 {
        driver *d;
-       int n,
-        j,
-        k;
+       int j;
        ulong flags;
        int drvidx;
 
@@ -2072,12 +2266,6 @@ register_isdn(isdn_if * i)
                       ISDN_MAX_DRIVERS);
                return 0;
        }
-       n = i->channels;
-       if (dev->channels + n > ISDN_MAX_CHANNELS) {
-               printk(KERN_WARNING "register_isdn: Max. %d channels supported\n",
-                      ISDN_MAX_CHANNELS);
-               return 0;
-       }
        if (!i->writebuf_skb) {
                printk(KERN_WARNING "register_isdn: No write routine given.\n");
                return 0;
@@ -2087,59 +2275,22 @@ register_isdn(isdn_if * i)
                return 0;
        }
        memset((char *) d, 0, sizeof(driver));
-       init_waitqueue_head(&d->st_waitq); 
-       if (!(d->rcverr = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) {
-               printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
-               kfree(d);
-               return 0;
-       }
-       memset((char *) d->rcverr, 0, sizeof(int) * n);
-       if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * n, GFP_KERNEL))) {
-               printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
-               kfree(d->rcverr);
-               kfree(d);
-               return 0;
-       }
-       memset((char *) d->rcvcount, 0, sizeof(int) * n);
-       if (!(d->rpqueue =
-             (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
-               printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
-               kfree(d->rcvcount);
-               kfree(d->rcverr);
-               kfree(d);
-               return 0;
-       }
-       for (j = 0; j < n; j++) {
-               skb_queue_head_init(&d->rpqueue[j]);
-       }
-       d->rcv_waitq = (wait_queue_head_t *)
-               kmalloc(sizeof(wait_queue_head_t) * 2 * n, GFP_KERNEL);
-       if (!d->rcv_waitq) { 
-               printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
-               kfree(d->rpqueue);
-               kfree(d->rcvcount);
-               kfree(d->rcverr);
-               kfree(d);
-               return 0;
-       }
-       d->snd_waitq = d->rcv_waitq + n;                
-       for (j = 0; j < n; j++) { 
-               init_waitqueue_head(&d->rcv_waitq[n]); 
-               init_waitqueue_head(&d->snd_waitq[n]); 
-       }
-       d->channels = n;
-       d->loaded = 1;
+
        d->maxbufsize = i->maxbufsize;
        d->pktcount = 0;
        d->stavail = 0;
-       d->running = 0;
-       d->flags = 0;
+       d->flags = DRV_FLAG_LOADED;
+       d->online = 0;
        d->interface = i;
+       d->channels = 0;
        for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
                if (!dev->drv[drvidx])
                        break;
+       if (isdn_add_channels(d, drvidx, i->channels, 0)) {
+               kfree(d);
+               return 0;
+       }
        i->channels = drvidx;
-
        i->rcvcallb_skb = isdn_receive_skb_callback;
        i->statcallb = isdn_status_callback;
        if (!strlen(i->id))
@@ -2149,15 +2300,7 @@ register_isdn(isdn_if * i)
        for (j = 0; j < drvidx; j++)
                if (!strcmp(i->id, dev->drvid[j]))
                        sprintf(i->id, "line%d", drvidx);
-       for (j = 0; j < n; j++)
-               for (k = 0; k < ISDN_MAX_CHANNELS; k++)
-                       if (dev->chanmap[k] < 0) {
-                               dev->chanmap[k] = j;
-                               dev->drvmap[k] = drvidx;
-                               break;
-                       }
        dev->drv[drvidx] = d;
-       dev->channels += n;
        strcpy(dev->drvid[drvidx], i->id);
        isdn_info_update();
        dev->drivers++;
@@ -2209,15 +2352,21 @@ isdn_init(void)
        memset((char *) dev, 0, sizeof(isdn_dev));
        init_timer(&dev->timer);
        dev->timer.function = isdn_timer_funct;
+#if LINUX_VERSION_CODE < 131841
+       dev->sem = MUTEX;
+#else
        init_MUTEX(&dev->sem);
-       init_waitqueue_head(&dev->info_waitq); 
+       init_waitqueue_head(&dev->info_waitq);
+#endif
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
                dev->drvmap[i] = -1;
                dev->chanmap[i] = -1;
                dev->m_idx[i] = -1;
                strcpy(dev->num[i], "???");
+#if LINUX_VERSION_CODE >= 131841
                init_waitqueue_head(&dev->mdm.info[i].open_wait);
                init_waitqueue_head(&dev->mdm.info[i].close_wait);
+#endif
        }
        if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
                printk(KERN_WARNING "isdn: Could not register control devices\n");
index a8513fe5018ce455b9c5194abe16b6d56cff2335..3ba4855b72ae1611543df8c3361ef702fbf22e14 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_common.h,v 1.9 1998/02/20 17:19:01 fritz Exp $
+/* $Id: isdn_common.h,v 1.15 1999/04/18 14:06:50 fritz Exp $
 
  * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Note: This file differs from the corresponding revision as present in the
- * isdn4linux CVS repository because some later bug fixes have been extracted
- * from the repository and merged into this file. -- Henner Eisen
- *
  * $Log: isdn_common.h,v $
+ * Revision 1.15  1999/04/18 14:06:50  fritz
+ * Removed TIMRU stuff.
+ *
+ * Revision 1.14  1999/04/12 12:33:18  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.13  1999/03/02 12:04:47  armin
+ * -added ISDN_STAT_ADDCH to increase supported channels after
+ *  register_isdn().
+ * -ttyI now goes on-hook on ATZ when B-Ch is connected.
+ * -added timer-function for register S7 (Wait for Carrier).
+ * -analog modem (ISDN_PROTO_L2_MODEM) implementations.
+ * -on L2_MODEM a string will be appended to the CONNECT-Message,
+ *  which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN.
+ * -variable "dialing" used for ATA also, for interrupting call
+ *  establishment and register S7.
+ *
+ * Revision 1.12  1998/06/26 15:12:27  fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 1.11  1998/04/14 16:28:47  he
+ * Fixed user space access with interrupts off and remaining
+ * copy_{to,from}_user() -> -EFAULT return codes
+ *
+ * Revision 1.10  1998/03/07 18:21:03  cal
+ * Dynamic Timeout-Rule-Handling vs. 971110 included
+ *
  * Revision 1.9  1998/02/20 17:19:01  fritz
  * Added common stub for sending commands to lowlevel.
  *
@@ -90,10 +115,16 @@ extern char *isdn_map_eaz2msn(char *msn, int di);
 extern void isdn_timer_ctrl(int tf, int onoff);
 extern void isdn_unexclusive_channel(int di, int ch);
 extern int isdn_getnum(char **);
+#if LINUX_VERSION_CODE < 131841
+extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**);
+#else
 extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
+#endif
 extern int isdn_get_free_channel(int, int, int, int, int);
 extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
 extern int register_isdn(isdn_if * i);
+extern int isdn_wildmat(char *, char *);
+extern int isdn_add_channels(driver *, int, int, int);
 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
 extern void isdn_dumppkt(char *, u_char *, int, int);
 #endif
index 0d9abb22635bfa872081873aeea071f931ee28c9..1ca6c34e383bc33135dad195d29cf142dda610f5 100644 (file)
@@ -1,10 +1,21 @@
-/* $Id: isdn_concap.c,v 1.2 1998/01/31 22:49:21 keil Exp $
+/* $Id: isdn_concap.c,v 1.5 1998/10/30 18:44:48 he Exp $
  
  * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
  * stuff goes here. Stuff that depends only on the concap protocol goes to
  * another -- protocol specific -- source file.
  *
  * $Log: isdn_concap.c,v $
+ * Revision 1.5  1998/10/30 18:44:48  he
+ * pass return value from isdn_net_dial_req for dialmode change
+ *
+ * Revision 1.4  1998/10/30 17:55:24  he
+ * dialmode for x25iface and multulink ppp
+ *
+ * Revision 1.3  1998/05/26 22:39:22  he
+ * sync'ed with 2.1.102 where appropriate (CAPABILITY changes)
+ * concap typo
+ * cleared dev.tbusy in isdn_net BCONN status callback
+ *
  * Revision 1.2  1998/01/31 22:49:21  keil
  * correct comments
  *
 #include <linux/concap.h>
 #include "isdn_concap.h"
 
-/* The declaration of this (or a plublic variant thereof) should really go
-   in linux/isdn.h. But we really need it here (and isdn_ppp, like us, also
-   refers to that private function currently owned by isdn_net.c) */
-extern int isdn_net_force_dial_lp(isdn_net_local *);
-
 
 /* The following set of device service operations are for encapsulation
-   protocols that require for reliable datalink sematics. That means:
+   protocols that require for reliable datalink semantics. That means:
 
    - before any data is to be submitted the connection must explicitly
      be set up.
@@ -66,9 +72,9 @@ int isdn_concap_dl_connect_req(struct concap_proto *concap)
        IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name);
 
        /* dial ... */
-       ret = isdn_net_force_dial_lp( lp );
+       ret = isdn_net_dial_req( lp );
        if ( ret ) IX25DEBUG("dialing failed\n");
-       return 0;
+       return ret;
 }
 
 int isdn_concap_dl_disconn_req(struct concap_proto *concap)
index daafceb1a6c49c3655af383ba32cec75a45a90df..9e4426af0890146ab57cc40c716c1d6c6504a2b1 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_net.c,v 1.55 1998/02/23 19:38:22 fritz Exp $
+/* $Id: isdn_net.c,v 1.84 1999/04/18 14:06:55 fritz Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Note: This file differs from the corresponding revision as present in the
- * isdn4linux CVS repository because some later bug fixes have been extracted
- * from the repository and merged into this file. -- Henner Eisen
- *
  * $Log: isdn_net.c,v $
+ * Revision 1.84  1999/04/18 14:06:55  fritz
+ * Removed TIMRU stuff.
+ *
+ * Revision 1.83  1999/04/12 12:33:23  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.82  1999/01/17 00:55:58  he
+ * added mark_bh in BCONN statcallb and cleaned up some dead code
+ *
+ * Revision 1.81  1999/01/15 16:36:52  he
+ * replaced icmp_send() by dst_link_failure()
+ *
+ * Revision 1.80  1998/12/01 13:06:22  paul
+ * Also huptimeout with dialmode == manual
+ *
+ * Revision 1.79  1998/10/30 17:55:27  he
+ * dialmode for x25iface and multulink ppp
+ *
+ * Revision 1.78  1998/10/26 18:20:46  he
+ * re-inserted p=p->next in isdn_net_find_icall() (fixes kernel lock up
+ * on incoming call not matching the first interface)
+ *
+ * Revision 1.77  1998/10/23 10:18:44  paul
+ * Implementation of "dialmode" (successor of "status")
+ * You also need current isdnctrl for this!
+ *
+ * Revision 1.76  1998/09/07 22:00:05  he
+ * flush method for 2.1.118 and above
+ * updated IIOCTLNETGPN
+ *
+ * Revision 1.75  1998/08/31 21:09:50  he
+ * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface'
+ *     peer phone number)
+ *
+ * Revision 1.74  1998/07/30 11:28:32  paul
+ * printk message only appeared when status is off and interface is rawIP,
+ * which is confusing for people who don't know about "isdnctrl status <if> on".
+ *
+ * Revision 1.73  1998/06/26 22:01:37  keil
+ * tx_queue_len = 5 was too small
+ *
+ * Revision 1.72  1998/06/26 15:12:31  fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 1.71  1998/06/18 22:43:08  fritz
+ * Bugfix: Setting ndev->do_ioctl had beed accidetly removed at abc-cleanup.
+ *
+ * Revision 1.70  1998/06/17 19:50:49  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.69  1998/06/09 12:27:37  cal
+ * Changed default of local netdev flags: ISDN_NET_STOPPED is default now,
+ * so autodial is suppressed for that device until it is switched on using
+ * 'isdnctrl status dev-name on'.
+ *
+ * Revision 1.68  1998/06/07 00:20:05  fritz
+ * abc cleanup.
+ *
+ * Revision 1.67  1998/06/02 12:10:08  detabc
+ * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
+ * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
+ *
+ * Revision 1.66  1998/05/26 22:39:24  he
+ * sync'ed with 2.1.102 where appropriate (CAPABILITY changes)
+ * concap typo
+ * cleared dev.tbusy in isdn_net BCONN status callback
+ *
+ * Revision 1.65  1998/05/22 10:01:11  detabc
+ * in case of a icmp-unreach condition the tcp-keepalive-entrys
+ * will be dropped from the internal double-link-list (only abc-extension).
+ * send icmp unreach only if the skb->protocol == ETH_P_IP
+ * speedup abc-no-dchan  redial
+ *
+ * Revision 1.64  1998/05/07 19:58:39  detabc
+ * bugfix in abc_delayed_hangup
+ * optimize keepalive-tests for abc_rawip
+ *
+ * Revision 1.63  1998/05/05 23:23:36  detabc
+ * change ICMP_HOST_UNREACH to ICMP_NET_UNREACH (only abc-ext.)
+ * set dev->tbusy to zero in isdn_net_unreachable() (only abc-ext.)
+ * drop all new packets and send ICMP_NET_UNREACH for
+ * min. dialwait to max. dialwait * 6 time. (only abc-ext.)
+ * change random-deliver of packets (small first) from all emcapsulation
+ * to only rawip with ABC-Router-Flag enabled.
+ *
+ * Revision 1.62  1998/05/03 17:40:42  detabc
+ * Include abc-extension-support for >= 2.1.x Kernels in
+ * isdn_net.c and isdn_common.c. alpha-test OK and running !
+ *
+ * Revision 1.61  1998/04/16 19:19:42  keil
+ * Fix from vger (tx max qlength)
+ *
+ * Revision 1.60  1998/04/14 16:28:49  he
+ * Fixed user space access with interrupts off and remaining
+ * copy_{to,from}_user() -> -EFAULT return codes
+ *
+ * Revision 1.59  1998/03/07 22:37:33  fritz
+ * Bugfix: restore_flags missing.
+ *
+ * Revision 1.58  1998/03/07 18:21:05  cal
+ * Dynamic Timeout-Rule-Handling vs. 971110 included
+ *
+ * Revision 1.57  1998/02/25 18:31:13  fritz
+ * Added debugging output in adjust_header.
+ *
+ * Revision 1.56  1998/02/25 17:49:42  he
+ * Changed return codes caused be failing copy_{to,from}_user to -EFAULT
+ *
  * Revision 1.55  1998/02/23 19:38:22  fritz
  * Corrected check for modified feature-flags.
  *
 #include <linux/isdn.h>
 #include <net/arp.h>
 #include <net/dst.h>
-#ifndef DEV_NUMBUFFS
 #include <net/pkt_sched.h>
-#endif
 #include <linux/inetdevice.h>
 #include "isdn_common.h"
 #include "isdn_net.h"
 /* Prototypes */
 
 int isdn_net_force_dial_lp(isdn_net_local *);
-static int isdn_net_wildmat(char *s, char *p);
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
 static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
-#ifdef DEV_NUMBUFFS
-static void dev_purge_queues(struct device *dev);      /* move this to net/core/dev.c */
-#endif
 
-char *isdn_net_revision = "$Revision: 1.55 $";
+char *isdn_net_revision = "$Revision: 1.84 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -293,16 +395,21 @@ isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
                
                dst_link_failure(skb);
        }
+       else {  /* dial not triggered by rawIP packet */
+               printk(KERN_DEBUG "isdn_net: %s: %s\n",
+                          dev->name,
+                          (reason != NULL) ? reason : "reason unknown");
+       }
 }
 
 static void
 isdn_net_reset(struct device *dev)
 {
 #ifdef CONFIG_ISDN_X25
-       struct concap_device_ops * dops = 
+       struct concap_device_ops * dops =
                ( (isdn_net_local *) dev->priv ) -> dops;
-       struct concap_proto * cprot = 
-               ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; 
+       struct concap_proto * cprot =
+               ( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
 #endif
        ulong flags;
 
@@ -311,7 +418,7 @@ isdn_net_reset(struct device *dev)
        dev->interrupt = 0;
        dev->tbusy = 0;
 #ifdef CONFIG_ISDN_X25
-       if( cprot && cprot -> pops && dops ) 
+       if( cprot && cprot -> pops && dops )
                cprot -> pops -> restart ( cprot, dev, dops );
 #endif
        restore_flags(flags);
@@ -338,7 +445,7 @@ isdn_net_open(struct device *dev)
                if (ifa != NULL)
                        memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
        }
+
        /* If this interface has slaves, start them also */
 
        if ((p = (((isdn_net_local *) dev->priv)->slave))) {
@@ -362,6 +469,7 @@ isdn_net_bind_channel(isdn_net_local * lp, int idx)
 
        save_flags(flags);
        cli();
+       lp->flags |= ISDN_NET_CONNECTED;
        lp->isdn_device = dev->drvmap[idx];
        lp->isdn_channel = dev->chanmap[idx];
        dev->rx_netdev[idx] = lp->netdev;
@@ -387,10 +495,6 @@ isdn_net_unbind_channel(isdn_net_local * lp)
                dev_kfree_skb(lp->sav_skb);
                lp->sav_skb = NULL;
        }
-#ifdef DEV_NUMBUFFS
-       if (!lp->master)        /* purge only for master device */
-               dev_purge_queues(&lp->netdev->dev);
-#else
        if (!lp->master) {      /* reset only master device */
                /* Moral equivalent of dev_purge_queues():
                   BEWARE! This chunk of code cannot be called from hardware
@@ -398,7 +502,6 @@ isdn_net_unbind_channel(isdn_net_local * lp)
                 */
                qdisc_reset(lp->netdev->dev.qdisc);
        }
-#endif
        lp->dialstate = 0;
        dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
        dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
@@ -444,7 +547,13 @@ isdn_net_autohup()
                if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
                        anymore = 1;
                        l->huptimer++;
-                       if ((l->onhtime) && (l->huptimer > l->onhtime)) {
+                       /*
+                        * if there is some dialmode where timeout-hangup
+                        * should _not_ be done, check for that here
+                        */
+                       if ((l->onhtime) &&
+                           (l->huptimer > l->onhtime))
+                       {
                                if (l->hupflags & ISDN_MANCHARGE &&
                                    l->hupflags & ISDN_CHARGEHUP) {
                                        while (jiffies - l->chargetime > l->chargeint)
@@ -469,6 +578,11 @@ isdn_net_autohup()
                                } else if (l->hupflags & ISDN_INHUP)
                                        isdn_net_hangup(&p->dev);
                        }
+
+                       if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
+                               isdn_net_hangup(&p->dev);
+                               break;
+                       }
                }
                p = (isdn_net_dev *) p->next;
        }
@@ -487,7 +601,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
 {
        isdn_net_dev *p = dev->st_netdev[idx];
        int cmd = c->command;
-       
+
        if (p) {
                isdn_net_local *lp = p->local;
 #ifdef CONFIG_ISDN_X25
@@ -538,23 +652,12 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
                                   failed. If there are generic encap protocol
                                   receiver routines signal the closure of
                                   the link*/
-                               
-                               if( !(lp->flags & ISDN_NET_CONNECTED) 
+
+                               if( !(lp->flags & ISDN_NET_CONNECTED)
                                    && pops && pops -> disconn_ind )
                                        pops -> disconn_ind(cprot);
 #endif /* CONFIG_ISDN_X25 */
                                if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
-                                       lp->flags &= ~ISDN_NET_CONNECTED;
-                                       if (lp->first_skb) {
-                                               dev_kfree_skb(lp->first_skb);
-                                               lp->first_skb = NULL;
-                                       }
-                                       if (lp->sav_skb) {
-                                               dev_kfree_skb(lp->sav_skb);
-                                               lp->sav_skb = NULL;
-                                       }
-                                       isdn_free_channel(lp->isdn_device, lp->isdn_channel,
-                                                         ISDN_USAGE_NET);
 #ifdef CONFIG_ISDN_PPP
                                        isdn_ppp_free(lp);
 #endif
@@ -562,10 +665,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
                                        printk(KERN_INFO "%s: remote hangup\n", lp->name);
                                        printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
                                               lp->charge);
-                                       lp->isdn_device = -1;
-                                       lp->isdn_channel = -1;
-                                       dev->st_netdev[idx] = NULL;
-                                       dev->rx_netdev[idx] = NULL;
+                                       isdn_net_unbind_channel(lp);
                                        return 1;
                                }
                                break;
@@ -607,6 +707,11 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
                                                lp->chargetime = jiffies;
                                                printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n",
                                                lp->name, lp->chargetime);
+
+                                               /* reset dial-timeout */
+                                               lp->dialstarted = 0;
+                                               lp->dialwait_timer = 0;
+
                                                /* Immediately send first skb to speed up arp */
 #ifdef CONFIG_ISDN_PPP
                                                if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
@@ -617,13 +722,13 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
                                                if( pops )
                                                        if( pops->connect_ind)
                                                                pops->connect_ind(cprot);
-
 #endif /* CONFIG_ISDN_X25 */
                                                if (lp->first_skb) {
-                                                       
+
                                                        if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
                                                                lp->first_skb = NULL;
-                                               } else {
+                                               }
+                                               else {
                                                        /*
                                                         * dev.tbusy is usually cleared implicitly by isdn_net_xmit(,,lp->first_skb).
                                                         * With an empty lp->first_skb, we need to do this ourselves
@@ -721,6 +826,13 @@ isdn_net_dial(void)
                                        break;
                                }
                                anymore = 1;
+
+                               if(lp->dialtimeout > 0)
+                                       if(lp->dialstarted == 0 || jiffies > (lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
+                                               lp->dialstarted = jiffies;
+                                               lp->dialwait_timer = 0;
+                                       }
+
                                lp->dialstate++;
                                /* Fall through */
                        case 2:
@@ -735,12 +847,22 @@ isdn_net_dial(void)
                                lp->dialretry = 0;
                                anymore = 1;
                                lp->dialstate++;
-                               /* Falls through */
+                               /* Fall through */
                        case 3:
                                /* Setup interface, dial current phone-number, switch to next number.
                                 * If list of phone-numbers is exhausted, increment
                                 * retry-counter.
                                 */
+                               if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) {
+                                       char *s;
+                                       if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+                                               s = "dial suppressed: isdn system stopped";
+                                       else
+                                               s = "dial suppressed: dialmode `off'";
+                                       isdn_net_unreachable(&p->dev, lp->first_skb, s);
+                                       isdn_net_hangup(&p->dev);
+                                       break;
+                               }
                                cmd.driver = lp->isdn_device;
                                cmd.command = ISDN_CMD_SETL2;
                                cmd.arg = lp->isdn_channel + (lp->l2_proto << 8);
@@ -765,6 +887,16 @@ isdn_net_dial(void)
                                        lp->dialstate = 4;
                                        printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
                                } else {
+                                       if(lp->dialtimeout > 0)
+                                               if(jiffies > (lp->dialstarted + lp->dialtimeout)) {
+                                                       restore_flags(flags);
+                                                       lp->dialwait_timer = jiffies + lp->dialwait;
+                                                       lp->dialstarted = 0;
+                                                       isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out");
+                                                       isdn_net_hangup(&p->dev);
+                                                       break;
+                                               }
+
                                        sprintf(cmd.parm.setup.phone, "%s", lp->dial->num);
                                        /*
                                         * Switch to next number or back to start if at end of list.
@@ -772,6 +904,17 @@ isdn_net_dial(void)
                                        if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) {
                                                lp->dial = lp->phone[1];
                                                lp->dialretry++;
+
+                                               if (lp->dialretry > lp->dialmax) {
+                                                       restore_flags(flags);
+                                                       if (lp->dialtimeout == 0) {
+                                                               lp->dialwait_timer = jiffies + lp->dialwait;
+                                                               lp->dialstarted = 0;
+                                                               isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times");
+                                                       }
+                                                       isdn_net_hangup(&p->dev);
+                                                       break;
+                                               }
                                        }
                                        restore_flags(flags);
                                        cmd.driver = lp->isdn_device;
@@ -786,7 +929,7 @@ isdn_net_dial(void)
                                                isdn_info_update();
                                        }
                                        printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
-                                              lp->dialretry - 1, cmd.parm.setup.phone);
+                                              lp->dialretry, cmd.parm.setup.phone);
                                        lp->dtimer = 0;
 #ifdef ISDN_DEBUG_NET_DIAL
                                        printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
@@ -810,15 +953,11 @@ isdn_net_dial(void)
                                break;
                        case 4:
                                /* Wait for D-Channel-connect.
-                                * If timeout and max retries not
-                                * reached, switch back to state 3.
+                                * If timeout, switch back to state 3.
+                                * Dialmax-handling moved to state 3.
                                 */
-                               if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) {
-                                       if (lp->dialretry < lp->dialmax) {
-                                               lp->dialstate = 3;
-                                       } else
-                                               isdn_net_hangup(&p->dev);
-                               }
+                               if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
+                                       lp->dialstate = 3;
                                anymore = 1;
                                break;
                        case 5:
@@ -895,7 +1034,8 @@ isdn_net_dial(void)
                                /* Remote does callback. Hangup after cbdelay, then wait for incoming
                                 * call (in state 4).
                                 */
-                               if (lp->dtimer++ > lp->cbdelay) {
+                               if (lp->dtimer++ > lp->cbdelay)
+                               {
                                        printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
                                        lp->dtimer = 0;
                                        lp->dialstate = 4;
@@ -930,7 +1070,6 @@ isdn_net_hangup(struct device *d)
 #endif
 
        if (lp->flags & ISDN_NET_CONNECTED) {
-               lp->flags &= ~ISDN_NET_CONNECTED;
                printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
 #ifdef CONFIG_ISDN_PPP
                isdn_ppp_free(lp);
@@ -938,7 +1077,7 @@ isdn_net_hangup(struct device *d)
 #ifdef CONFIG_ISDN_X25
                /* try if there are generic encap protocol
                   receiver routines and signal the closure of
-                  the link */          
+                  the link */
                if( pops && pops -> disconn_ind )
                  pops -> disconn_ind(cprot);
 #endif /* CONFIG_ISDN_X25 */
@@ -968,7 +1107,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
        char addinfo[100];
 
        addinfo[0] = '\0';
-       /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ 
+       /* This check stolen from 2.1.72 dev_queue_xmit_nit() */
        if (skb->nh.raw < skb->data || skb->nh.raw >= skb->tail) {
                /* fall back to old isdn_net_log_packet method() */
                char * buf = skb->data;
@@ -1062,20 +1201,17 @@ isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
        if (ret == len) {
                lp->transcount += len;
                clear_bit(0, (void *) &(ndev->tbusy));
-               mark_bh(NET_BH);
                return 0;
        }
        if (ret < 0) {
                dev_kfree_skb(skb);
                lp->stats.tx_errors++;
                clear_bit(0, (void *) &(ndev->tbusy));
-               mark_bh(NET_BH);
                return 0;
        }
        return 1;
 }
 
-
 /*
  *  Helper function for isdn_net_start_xmit.
  *  When called, the connection is already established.
@@ -1150,9 +1286,11 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct device *dev)
        if (!skb)
                return;
        if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
-               ulong pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN;
-               if (pullsize)
+               int pullsize = (ulong)skb->nh.raw - (ulong)skb->data - ETH_HLEN;
+               if (pullsize > 0) {
+                       printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize);
                        skb_pull(skb, pullsize);
+               }
        }
 }
 
@@ -1166,7 +1304,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
 {
        isdn_net_local *lp = (isdn_net_local *) ndev->priv;
 #ifdef CONFIG_ISDN_X25
-       struct concap_proto * cprot = lp -> netdev -> cprot; 
+       struct concap_proto * cprot = lp -> netdev -> cprot;
 #endif
 
        if (ndev->tbusy) {
@@ -1179,7 +1317,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
        ndev->tbusy = 1; /* left instead of obsolete test_and_set_bit() */
 #ifdef CONFIG_ISDN_X25
 /* At this point hard_start_xmit() passes control to the encapsulation
-   protocol (if present). 
+   protocol (if present).
    For X.25 auto-dialing is completly bypassed because:
    - It does not conform with the semantics of a reliable datalink
      service as needed by X.25 PLP.
@@ -1205,17 +1343,46 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
 #endif
                if (!(lp->flags & ISDN_NET_CONNECTED)) {
                        int chi;
+                       /* only do autodial if allowed by config */
+                       if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
+                               isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
+                               dev_kfree_skb(skb);
+                               ndev->tbusy = 0;
+                               return 0;
+                       }
                        if (lp->phone[1]) {
                                ulong flags;
                                save_flags(flags);
                                cli();
+
+                               if(lp->dialwait_timer <= 0)
+                                       if(lp->dialstarted > 0 && lp->dialtimeout > 0 && jiffies < lp->dialstarted + lp->dialtimeout + lp->dialwait)
+                                               lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait;
+
+                               if(lp->dialwait_timer > 0) {
+                                       if(jiffies < lp->dialwait_timer) {
+                                               isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
+                                               dev_kfree_skb(skb);
+                                               ndev->tbusy = 0;
+                                               restore_flags(flags);
+                                               return 0;
+                                       } else
+                                               lp->dialwait_timer = 0;
+                               }
+
                                /* Grab a free ISDN-Channel */
-                               if ((chi =
+                               if (((chi =
                                     isdn_get_free_channel(ISDN_USAGE_NET,
                                                           lp->l2_proto,
                                                           lp->l3_proto,
                                                           lp->pre_device,
-                                                lp->pre_channel)) < 0) {
+                                                lp->pre_channel)) < 0) &&
+                                       ((chi =
+                                    isdn_get_free_channel(ISDN_USAGE_NET,
+                                                          lp->l2_proto,
+                                                          lp->l3_proto,
+                                                          lp->pre_device,
+                                                lp->pre_channel^1)) < 0)) {
                                        restore_flags(flags);
                                        isdn_net_unreachable(ndev, skb,
                                                           "No channel");
@@ -1227,7 +1394,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                if (dev->net_verbose)
                                        isdn_net_log_skb(skb, lp);
                                lp->dialstate = 1;
-                               lp->flags |= ISDN_NET_CONNECTED;
                                /* Connect interface with channel */
                                isdn_net_bind_channel(lp, chi);
 #ifdef CONFIG_ISDN_PPP
@@ -1290,8 +1456,8 @@ isdn_net_close(struct device *dev)
 {
        struct device *p;
 #ifdef CONFIG_ISDN_X25
-       struct concap_proto * cprot = 
-               ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; 
+       struct concap_proto * cprot =
+               ( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
        /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */
 #endif
 
@@ -1304,9 +1470,9 @@ isdn_net_close(struct device *dev)
                /* If this interface has slaves, stop them also */
                while (p) {
 #ifdef CONFIG_ISDN_X25
-                       cprot = ( (isdn_net_local *) p->priv ) 
-                               -> netdev -> cprot; 
-                       if( cprot && cprot -> pops ) 
+                       cprot = ( (isdn_net_local *) p->priv )
+                               -> netdev -> cprot;
+                       if( cprot && cprot -> pops )
                                cprot -> pops -> close( cprot );
 #endif
                        isdn_net_hangup(p);
@@ -1392,7 +1558,7 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
        int len;
        cisco_hdr *ch;
        cisco_slarp *s;
-       
+
        if (!skb) {
                printk(KERN_WARNING
                       "%s: Could not allocate SLARP reply\n", lp->name);
@@ -1406,7 +1572,7 @@ isdn_net_slarp_send(isdn_net_local *lp, int is_reply)
        s = (cisco_slarp *)skb_put(skb, sizeof(cisco_slarp));
        if (is_reply) {
                s->code = htonl(CISCO_SLARP_REPLY);
-               memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32));
+               memset(&s->slarp.reply.ifaddr, 0, sizeof(__u32));
                memset(&s->slarp.reply.netmask, 0, sizeof(__u32));
        } else {
                lp->cisco_myseq++;
@@ -1589,7 +1755,7 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
                default:
 #ifdef CONFIG_ISDN_X25
                  /* try if there are generic sync_device receiver routines */
-                       if(cprot) if(cprot -> pops) 
+                       if(cprot) if(cprot -> pops)
                                if( cprot -> pops -> data_ind){
                                        cprot -> pops -> data_ind(cprot,skb);
                                        return;
@@ -1600,6 +1766,7 @@ isdn_net_receive(struct device *ndev, struct sk_buff *skb)
                        kfree_skb(skb);
                        return;
        }
+
        netif_rx(skb);
        return;
 }
@@ -1788,16 +1955,12 @@ isdn_net_init(struct device *ndev)
        ndev->type = ARPHRD_ETHER;
        ndev->addr_len = ETH_ALEN;
 
-       ndev->tx_queue_len = 10; /* for clients without MPPP 5 is better.  */
+       /* for clients with MPPP maybe higher values better */
+       ndev->tx_queue_len = 30;
 
        for (i = 0; i < ETH_ALEN; i++)
                ndev->broadcast[i] = 0xff;
 
-#ifdef DEV_NUMBUFFS
-       for (i = 0; i < DEV_NUMBUFFS; i++)
-               skb_queue_head_init(&ndev->buffs[i]);
-#endif
-
        /* The ISDN-specific entries in the device structure. */
        ndev->open = &isdn_net_open;
        ndev->hard_start_xmit = &isdn_net_start_xmit;
@@ -1813,86 +1976,15 @@ isdn_net_init(struct device *ndev)
                                max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
 
        ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
-
        ndev->stop = &isdn_net_close;
        ndev->get_stats = &isdn_net_get_stats;
        ndev->rebuild_header = &isdn_net_rebuild_header;
-
 #ifdef CONFIG_ISDN_PPP
        ndev->do_ioctl = isdn_ppp_dev_ioctl;
 #endif
        return 0;
 }
 
-/*
- * I picked the pattern-matching-functions from an old GNU-tar version (1.10)
- * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz)
- */
-
-static int
-isdn_net_Star(char *s, char *p)
-{
-       while (isdn_net_wildmat(s, p) == 0)
-               if (*++s == '\0')
-                       return (0);
-       return (1);
-}
-
-/*
- * Shell-type Pattern-matching for incoming caller-Ids
- * This function gets a string in s and checks, if it matches the pattern
- * given in p. It returns 1 on success, 0 otherwise.
- *
- * Possible Patterns:
- *
- * '?'     matches one character
- * '*'     matches zero or more characters
- * [xyz]   matches the set of characters in brackets.
- * [^xyz]  matches any single character not in the set of characters
- */
-
-static int
-isdn_net_wildmat(char *s, char *p)
-{
-       register int last;
-       register int matched;
-       register int reverse;
-
-       for (; *p; s++, p++)
-               switch (*p) {
-                       case '\\':
-                               /*
-                                * Literal match with following character,
-                                * fall through.
-                                */
-                               p++;
-                       default:
-                               if (*s != *p)
-                                       return (0);
-                               continue;
-                       case '?':
-                               /* Match anything. */
-                               if (*s == '\0')
-                                       return (0);
-                               continue;
-                       case '*':
-                               /* Trailing star matches everything. */
-                               return (*++p ? isdn_net_Star(s, p) : 1);
-                       case '[':
-                               /* [^....] means inverse character class. */
-                               if ((reverse = (p[1] == '^')))
-                                       p++;
-                               for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
-                                       /* This next line requires a good C compiler. */
-                                       if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
-                                               matched = 1;
-                               if (matched == reverse)
-                                       return (0);
-                               continue;
-               }
-       return (*s == '\0');
-}
-
 static void
 isdn_net_swapbind(int drvidx)
 {
@@ -1945,6 +2037,8 @@ isdn_net_swap_usage(int i1, int i2)
  *               2 = Reject call, wait cbdelay, then call back
  *               3 = Reject call
  *               4 = Wait cbdelay, then call back
+ *               5 = No appropriate interface for this call,
+ *                   would eventually match if CID was longer.
  */
 int
 isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
@@ -1953,6 +2047,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
        int si1;
        int si2;
        int ematch;
+       int wret;
        int swapped;
        int sidx = 0;
        isdn_net_dev *p;
@@ -1987,13 +2082,13 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
        }
        n = (isdn_net_phone *) 0;
        p = dev->netdev;
-       ematch = 0;
+       ematch = wret = swapped = 0;
 #ifdef ISDN_DEBUG_NET_ICALL
        printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
               dev->usage[idx]);
 #endif
-       swapped = 0;
        while (p) {
+               int matchret;
                isdn_net_local *lp = p->local;
 
                /* If last check has triggered as binding-swap, revert it */
@@ -2006,18 +2101,22 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                break;
                }
                swapped = 0;
-               if (!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz))
+               if (!(matchret = isdn_wildmat(eaz, isdn_map_eaz2msn(lp->msn, di))))
                        ematch = 1;
+               /* Remember if more numbers eventually can match */
+               if (matchret > wret)
+                       wret = matchret;
 #ifdef ISDN_DEBUG_NET_ICALL
                printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
                       lp->name, lp->msn, lp->flags, lp->dialstate);
 #endif
-               if ((!strcmp(isdn_map_eaz2msn(lp->msn, di), eaz)) &&    /* EAZ is matching   */
-                   (((!(lp->flags & ISDN_NET_CONNECTED)) &&    /* but not connected */
-                     (USG_NONE(dev->usage[idx]))) ||   /* and ch. unused or */
-                    ((((lp->dialstate == 4) || (lp->dialstate == 12)) &&       /* if dialing        */
-                      (!(lp->flags & ISDN_NET_CALLBACK)))      /* but no callback   */
-                    ))) {
+               if ((!matchret) &&                                        /* EAZ is matching   */
+                   (((!(lp->flags & ISDN_NET_CONNECTED)) &&              /* but not connected */
+                     (USG_NONE(dev->usage[idx]))) ||                     /* and ch. unused or */
+                    ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing        */
+                      (!(lp->flags & ISDN_NET_CALLBACK)))                /* but no callback   */
+                    )))
+                        {
 #ifdef ISDN_DEBUG_NET_ICALL
                        printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
                               lp->pre_device, lp->pre_channel);
@@ -2085,8 +2184,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
 #ifdef ISDN_DEBUG_NET_ICALL
                                                printk(KERN_DEBUG "n_fi: already on 2nd channel\n");
 #endif
-                                               p = (isdn_net_dev *) p->next;
-                                               continue;
                                        }
                                }
                        }
@@ -2096,7 +2193,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                        n = lp->phone[0];
                        if (lp->flags & ISDN_NET_SECURE) {
                                while (n) {
-                                       if (isdn_net_wildmat(nr, n->num))
+                                       if (!isdn_wildmat(nr, n->num))
                                                break;
                                        n = (isdn_net_phone *) n->next;
                                }
@@ -2105,7 +2202,21 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
 #ifdef ISDN_DEBUG_NET_ICALL
                                printk(KERN_DEBUG "n_fi: match3\n");
 #endif
-                               /* Here we got an interface matched, now see if it is up.
+                               /* matching interface found */
+
+                               /*
+                                * Is the state STOPPED?
+                                * If so, no dialin is allowed,
+                                * so reject actively.
+                                * */
+                               if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
+                                       restore_flags(flags);
+                                       printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
+                                              lp->name);
+                                       return 3;
+                               }
+                               /*
+                                * Is the interface up?
                                 * If not, reject the call actively.
                                 */
                                if (!p->dev.start) {
@@ -2140,6 +2251,17 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                }
                                if (lp->flags & ISDN_NET_CALLBACK) {
                                        int chi;
+                                       /*
+                                        * Is the state MANUAL?
+                                        * If so, no callback can be made,
+                                        * so reject actively.
+                                        * */
+                                       if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
+                                               restore_flags(flags);
+                                               printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
+                                                      lp->name);
+                                               return 3;
+                                       }
                                        printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
                                               lp->name, nr, eaz);
                                        if (lp->phone[1]) {
@@ -2155,7 +2277,6 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                                                /* Setup dialstate. */
                                                lp->dtimer = 0;
                                                lp->dialstate = 11;
-                                               lp->flags |= ISDN_NET_CONNECTED;
                                                /* Connect interface with channel */
                                                isdn_net_bind_channel(lp, chi);
 #ifdef CONFIG_ISDN_PPP
@@ -2217,10 +2338,10 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
                p = (isdn_net_dev *) p->next;
        }
        /* If none of configured EAZ/MSN matched and not verbose, be silent */
-       if (ematch || dev->net_verbose)
+       if (!ematch || dev->net_verbose)
                printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz);
        restore_flags(flags);
-       return 0;
+       return (wret == 2)?5:0;
 }
 
 /*
@@ -2253,6 +2374,7 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
                        ulong flags;
                        save_flags(flags);
                        cli();
+
                        /* Grab a free ISDN-Channel */
                        if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
                                                         lp->l3_proto,
@@ -2263,7 +2385,6 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
                                return -EAGAIN;
                        }
                        lp->dialstate = 1;
-                       lp->flags |= ISDN_NET_CONNECTED;
                        /* Connect interface with channel */
                        isdn_net_bind_channel(lp, chi);
 #ifdef CONFIG_ISDN_PPP
@@ -2284,6 +2405,20 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
                return -EBUSY;
 }
 
+/*
+ * This is called from certain upper protocol layers (multilink ppp
+ * and x25iface encapsulation module) that want to initiate dialing
+ * themselves.
+ */
+int
+isdn_net_dial_req(isdn_net_local * lp)
+{
+       /* is there a better error code? */
+       if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
+
+       return isdn_net_force_dial_lp(lp);
+}
+
 /*
  * Force a net-interface to dial out.
  * This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
@@ -2383,8 +2518,13 @@ isdn_net_new(char *name, struct device *master)
        netdev->local->onhtime = 10;    /* Default hangup-time for saving costs
           of those who forget configuring this */
        netdev->local->dialmax = 1;
-       netdev->local->flags = ISDN_NET_CBHUP;  /* Hangup before Callback */
+       netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;     /* Hangup before Callback, manual dial */
        netdev->local->cbdelay = 25;    /* Wait 5 secs before Callback */
+       netdev->local->dialtimeout = -1;  /* Infinite Dial-Timeout */
+       netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
+       netdev->local->dialstarted = 0;   /* Jiffies of last dial-start */
+       netdev->local->dialwait_timer = 0;  /* Jiffies of earliest next dial-start */
+
        /* Put into to netdev-chain */
        netdev->next = (void *) dev->netdev;
        dev->netdev = netdev;
@@ -2465,7 +2605,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        save_flags(flags);
                        cli(); /* avoid races with incoming events trying to
                                  call cprot->pops methods */
-                       if( cprot && cprot -> pops ) 
+                       if( cprot && cprot -> pops )
                                cprot -> pops -> proto_del ( cprot );
                        p -> cprot = NULL;
                        lp -> dops = NULL;
@@ -2479,7 +2619,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        p -> cprot = isdn_concap_new( cfg -> p_encap );
                        /* p -> cprot == NULL now if p_encap is not supported
                           by means of the concap_proto mechanism */
-                       /* the protocol is not configured yet; this will 
+                       /* the protocol is not configured yet; this will
                           happen later when isdn_net_reset() is called */
 #endif
                }
@@ -2508,7 +2648,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        if( cfg->p_encap >= 0 &&
                            cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP )
                                break;
-                       printk(KERN_WARNING 
+                       printk(KERN_WARNING
                               "%s: encapsulation protocol %d not supported\n",
                               p->local->name, cfg->p_encap);
                        return -EINVAL;
@@ -2583,6 +2723,8 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                lp->triggercps = cfg->triggercps;
                lp->slavedelay = cfg->slavedelay * HZ;
                lp->pppbind = cfg->pppbind;
+               lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
+               lp->dialwait = cfg->dialwait * HZ;
                if (cfg->secure)
                        lp->flags |= ISDN_NET_SECURE;
                else
@@ -2604,6 +2746,16 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                                lp->flags &= ~ISDN_NET_CALLBACK;
                                break;
                }
+               lp->flags &= ~ISDN_NET_DIALMODE_MASK;   /* first all bits off */
+               if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
+                       /* old isdnctrl version, where only 0 or 1 is given */
+                       printk(KERN_WARNING
+                            "Old isdnctrl version detected! Please update.\n");
+                       lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */
+               }
+               else {
+                       lp->flags |= cfg->dialmode;  /* turn on selected bits */
+               }
                if (cfg->chargehup)
                        lp->hupflags |= ISDN_CHARGEHUP;
                else
@@ -2671,6 +2823,7 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
                if (lp->flags & ISDN_NET_CBOUT)
                        cfg->callback = 2;
                cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
+               cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
                cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
                cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
                cfg->cbdelay = lp->cbdelay;
@@ -2680,6 +2833,8 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
                cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
                    (lp->chargeint / HZ) : 0;
                cfg->pppbind = lp->pppbind;
+               cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
+               cfg->dialwait = lp->dialwait / HZ;
                if (lp->slave)
                        strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
                else
@@ -2749,9 +2904,37 @@ isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
 }
 
 /*
- * Delete a phone-number from an interface.
+ * Copy a string containing the peer's phone number of a connected interface
+ * to user space.
  */
+int
+isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
+{
+       isdn_net_dev *p = isdn_net_findif(phone->name);
+       int ch, dv, idx;
 
+       if (!p) return -ENODEV;
+       /*
+        * Theoretical race: while this executes, the remote number might
+        * become invalid (hang up) or change (new connection), resulting
+         * in (partially) wrong number copied to user. This race
+        * currently ignored.
+        */
+       ch = p->local->isdn_channel;
+       dv = p->local->isdn_device;
+       if(ch<0 && dv<0) return -ENOTCONN;
+       idx = isdn_dc2minor(dv, ch);
+       if (idx<0) return -ENODEV;
+       /* for pre-bound channels, we need this extra check */
+       if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN;
+       strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN);
+       phone->outgoing=USG_OUTGOING(idx);
+       if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT;
+       return 0;
+}
+/*
+ * Delete a phone-number from an interface.
+ */
 int
 isdn_net_delphone(isdn_net_ioctl_phone * phone)
 {
@@ -2957,21 +3140,3 @@ isdn_net_rmall(void)
        restore_flags(flags);
        return 0;
 }
-
-#ifdef DEV_NUMBUFFS
-/*
- * helper function to flush device queues
- * the better place would be net/core/dev.c
- */
-static void
-dev_purge_queues(struct device *dev)
-{
-       int i;
-       for (i = 0; i < DEV_NUMBUFFS; i++) {
-               struct sk_buff *skb;
-               while ((skb = skb_dequeue(&dev->buffs[i])))
-                       dev_kfree_skb(skb);
-       }
-
-}
-#endif
index 19a084dd2189b97e8c2f7d2d731002b77f8a0629..79d4ff6154d78dc5652af7d199720f436ae794b6 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_net.h,v 1.6 1997/10/09 21:28:54 fritz Exp $
+/* $Id: isdn_net.h,v 1.9 1999/04/12 12:33:27 fritz Exp $
 
  * header for Linux ISDN subsystem, network related functions (linklevel).
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_net.h,v $
+ * Revision 1.9  1999/04/12 12:33:27  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.8  1998/10/30 17:55:33  he
+ * dialmode for x25iface and multulink ppp
+ *
+ * Revision 1.7  1998/08/31 21:09:55  he
+ * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface'
+ *     peer phone number)
+ *
  * Revision 1.6  1997/10/09 21:28:54  fritz
  * New HL<->LL interface:
  *   New BSENT callback with nr. of bytes included.
@@ -99,6 +109,7 @@ extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
 extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
 extern int isdn_net_addphone(isdn_net_ioctl_phone *);
 extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *);
+extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *);
 extern int isdn_net_delphone(isdn_net_ioctl_phone *);
 extern int isdn_net_find_icall(int, int, int, setup_parm);
 extern void isdn_net_hangup(struct device *);
@@ -111,3 +122,4 @@ extern int isdn_net_send_skb(struct device *, isdn_net_local *,
                             struct sk_buff *);
 extern int isdn_net_rcv_skb(int, struct sk_buff *);
 extern void isdn_net_slarp_out(void);
+extern int isdn_net_dial_req(isdn_net_local *);
index aaaac3fdc7fa28ac30f1c67c8a42f09ef6537d5e..7bce66d44e423b59988e397de211bf3eba0967a2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.33 1998/02/20 17:11:54 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.47 1999/04/18 14:06:59 fritz Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Note: This file differs from the corresponding revision as present in the
- * isdn4linux CVS repository because some later bug fixes have been extracted
- * from the repository and merged into this file. -- Henner Eisen
- *
  * $Log: isdn_ppp.c,v $
+ * Revision 1.47  1999/04/18 14:06:59  fritz
+ * Removed TIMRU stuff.
+ *
+ * Revision 1.46  1999/04/12 12:33:35  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.45  1998/12/30 17:48:24  paul
+ * fixed syncPPP callback out
+ *
+ * Revision 1.44  1998/10/30 17:55:34  he
+ * dialmode for x25iface and multulink ppp
+ *
+ * Revision 1.43  1998/10/29 17:23:54  hipp
+ * Minor MPPP fixes, verboser logging.
+ *
+ * Revision 1.42  1998/07/20 11:30:07  hipp
+ * Readded compression check
+ *
+ * Revision 1.41  1998/07/08 16:50:57  hipp
+ * Compression changes
+ *
+ * Revision 1.40  1998/04/06 19:07:27  hipp
+ * added check, whether compression is enabled.
+ *
+ * Revision 1.39  1998/03/25 22:46:53  hipp
+ * Some additional CCP changes.
+ *
+ * Revision 1.38  1998/03/24 16:33:06  hipp
+ * More CCP changes. BSD compression now "works" on a local loopback link.
+ * Moved some isdn_ppp stuff from isdn.h to isdn_ppp.h
+ *
+ * Revision 1.37  1998/03/22 18:50:49  hipp
+ * Added BSD Compression for syncPPP .. UNTESTED at the moment
+ *
+ * Revision 1.36  1998/03/09 17:46:30  he
+ * merged in 2.1.89 changes
+ *
+ * Revision 1.35  1998/03/07 18:21:11  cal
+ * Dynamic Timeout-Rule-Handling vs. 971110 included
+ *
+ * Revision 1.34  1998/02/25 17:49:48  he
+ * Changed return codes caused be failing copy_{to,from}_user to -EFAULT
+ *
  * Revision 1.33  1998/02/20 17:11:54  fritz
  * Changes for recent kernels.
  *
  * experimental for dynamic addressing: readdress IP frames
  */
 #undef ISDN_SYNCPPP_READDRESS
+#define CONFIG_ISDN_CCP 1
 
 #include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/version.h>
-#include <linux/isdn.h>
 #include <linux/poll.h>
+#include <linux/isdn.h>
+#include <linux/ppp-comp.h>
+
 #include "isdn_common.h"
 #include "isdn_ppp.h"
 #include "isdn_net.h"
@@ -180,13 +222,33 @@ static int isdn_ppp_closewait(int slot);
 static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
                                 struct sk_buff *skb, int proto);
 static int isdn_ppp_if_get_unit(char *namebuf);
-static int isdn_ppp_set_compressor(struct ippp_struct *is,int num);
+static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);
 static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
-                               struct ippp_struct *,struct ippp_struct *);
+                               struct ippp_struct *,struct ippp_struct *,int proto);
 static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
-                               struct sk_buff *skb);
+                               struct sk_buff *skb,int proto);
 static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
        struct ippp_struct *is,struct ippp_struct *master,int type);
+static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+        struct sk_buff *skb);
+
+/* New CCP stuff */
+static void isdn_ppp_ccp_kickup(struct ippp_struct *is);
+static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
+                                   unsigned char code, unsigned char id,
+                                   unsigned char *data, int len);
+static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
+static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
+                                         unsigned char id);
+static void isdn_ppp_ccp_timer_callback(unsigned long closure);
+static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
+                                                     unsigned char id);
+static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
+                                    struct isdn_ppp_resetparams *rp);
+static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
+                                       unsigned char id);
+
+
 
 #ifdef CONFIG_ISDN_MPP
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
@@ -199,18 +261,16 @@ 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.33 $";
+char *isdn_ppp_revision = "$Revision: 1.47 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 static struct isdn_ppp_compressor *ipc_head = NULL;
 
-extern int isdn_net_force_dial_lp(isdn_net_local *);
-
 /*
  * frame log (debug)
  */
 static void
-isdn_ppp_frame_log(char *info, char *data, int len, int maxlen)
+isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot)
 {
        int cnt,
         j,
@@ -223,13 +283,14 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen)
        for (i = 0, cnt = 0; cnt < maxlen; i++) {
                for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
                        sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
-               printk(KERN_DEBUG "%s[%d]: %s\n", info, i, buf);
+               printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf);
        }
 }
 
 /*
  * unbind isdn_net_local <=> ippp-device
  * note: it can happen, that we hangup/free the master before the slaves
+ *       in this case we bind another lp to the master device
  */
 int
 isdn_ppp_free(isdn_net_local * lp)
@@ -267,8 +328,7 @@ isdn_ppp_free(isdn_net_local * lp)
        if ((is->state & IPPP_CONNECT))
                isdn_ppp_closewait(lp->ppp_slot);       /* force wakeup on ippp device */
        else if (is->state & IPPP_ASSIGNED)
-               is->state = IPPP_OPEN;  /* fallback to 'OPEN but not ASSIGEND' staet */
-
+               is->state = IPPP_OPEN;  /* fallback to 'OPEN but not ASSIGNED' state */
 
        if (is->debug & 0x1)
                printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
@@ -320,14 +380,16 @@ isdn_ppp_bind(isdn_net_local * lp)
                        }
                }
        } else {
-               for (i = 0; i < ISDN_MAX_CHANNELS; i++)
-                       if (ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN)
+               for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+                       if (ippp_table[i]->minor == lp->pppbind &&
+                           (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
                                break;
+               }
        }
 
        if (i >= ISDN_MAX_CHANNELS) {
                restore_flags(flags);
-               printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n");
+               printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
                return -1;
        }
        unit = isdn_ppp_if_get_unit(lp->name);  /* get unit number from interface name .. ugly! */
@@ -336,6 +398,15 @@ isdn_ppp_bind(isdn_net_local * lp)
                return -1;
        }
        lp->ppp_slot = i;
+
+       /* reset some values */
+       lp->netdev->ib.bundled = 0;
+       lp->netdev->ib.next_num = 0;
+       lp->netdev->ib.modify = 0;
+       lp->netdev->ib.last = NULL;
+       lp->netdev->ib.min = 0;
+       lp->netdev->ib.sq = NULL;
+
        is = ippp_table[i];
        is->lp = lp;
        is->unit = unit;
@@ -359,7 +430,10 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp)
 
        ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
 
-       wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+#if LINUX_VERSION_CODE < 131841
+       if (ippp_table[lp->ppp_slot]->wq)
+#endif
+               wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
 }
 
 /*
@@ -376,7 +450,11 @@ isdn_ppp_closewait(int slot)
                return 0;
        is = ippp_table[slot];
 
+#if LINUX_VERSION_CODE < 131841
+       if (is->state && is->wq)
+#else
        if (is->state)
+#endif
                wake_up_interruptible(&is->wq);
 
        is->state = IPPP_CLOSEWAIT;
@@ -417,14 +495,19 @@ isdn_ppp_open(int min, struct file *file)
        }
        is = file->private_data = ippp_table[slot];
 
+#if 0
        if (is->debug & 0x1)
+#endif
                printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
 
        /* compression stuff */
-       is->compressor = NULL;
-       is->decomp_stat = is->comp_stat = NULL;
-       is->link_compressor = NULL;
-       is->link_decomp_stat = is->link_comp_stat = NULL;
+       is->link_compressor   = is->compressor = NULL;
+       is->link_decompressor = is->decompressor = NULL;
+       is->link_comp_stat    = is->comp_stat = NULL;
+       is->link_decomp_stat  = is->decomp_stat = NULL;
+       is->compflags = 0;
+
+       is->reset = isdn_ppp_ccp_reset_alloc(is);
 
        is->lp = NULL;
        is->mp_seqno = 0;       /* MP sequence number */
@@ -436,9 +519,11 @@ isdn_ppp_open(int min, struct file *file)
        is->mru = 1524;         /* MRU, default 1524 */
        is->maxcid = 16;        /* VJ: maxcid */
        is->tk = current;
-       /* next two are redundant, but be paranoid */ 
-       init_waitqueue_head(&is->wq);  /* read() wait queue */
-       init_waitqueue_head(&is->wql);  /* select() wait queue */
+#if LINUX_VERSION_CODE < 131841
+       is->wq = NULL;          /* read() wait queue */
+#else
+       init_waitqueue_head(&is->wq);
+#endif
        is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
        is->last = is->rq;
        is->minor = min;
@@ -491,10 +576,30 @@ isdn_ppp_release(int min, struct file *file)
        is->last = is->rq;
 
 #ifdef CONFIG_ISDN_PPP_VJ
+/* TODO: if this was the previous master: link the slcomp to the new master */
        slhc_free(is->slcomp);
        is->slcomp = NULL;
 #endif
 
+/* TODO: if this was the previous master: link the the stuff to the new master */
+       if(is->comp_stat)
+               is->compressor->free(is->comp_stat);
+       if(is->link_comp_stat)
+               is->link_compressor->free(is->link_comp_stat);
+       if(is->link_decomp_stat)
+               is->link_decompressor->free(is->link_decomp_stat);
+       if(is->decomp_stat)
+               is->decompressor->free(is->decomp_stat);
+        is->compressor   = is->link_compressor   = NULL;
+        is->decompressor = is->link_decompressor = NULL;
+       is->comp_stat    = is->link_comp_stat    = NULL;
+        is->decomp_stat  = is->link_decomp_stat  = NULL;
+
+       if(is->reset)
+               kfree(is->reset);
+       is->reset = NULL;
+
+       /* this slot is ready for new connections */
        is->state = 0;
 }
 
@@ -505,7 +610,7 @@ static int
 get_arg(void *b, void *val, int len)
 {
        if (len <= 0)
-               len = sizeof(unsigned long);
+               len = sizeof(void *);
        if (copy_from_user((void *) val, b, len))
                return -EFAULT;
        return 0;
@@ -515,15 +620,12 @@ get_arg(void *b, void *val, int len)
  * set arg .. ioctl helper
  */
 static int
-set_arg(void *b, unsigned long val, void *str)
+set_arg(void *b, void *val,int len)
 {
-       if (!str) {
-               if (copy_to_user(b, (void *) &val, 4))
-                       return -EFAULT;
-       } else {
-               if (copy_to_user(b, str, val))
-                       return -EFAULT;
-       }
+       if(len <= 0)
+               len = sizeof(void *);
+       if (copy_to_user(b, (void *) val, len))
+               return -EFAULT;
        return 0;
 }
 
@@ -534,9 +636,10 @@ int
 isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
 {
        unsigned long val;
-       int num,r;
+       int r,i,j;
        struct ippp_struct *is;
        isdn_net_local *lp;
+       struct isdn_ppp_comp_data data;
 
        is = (struct ippp_struct *) file->private_data;
        lp = is->lp;
@@ -552,7 +655,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
 #ifdef CONFIG_ISDN_MPP
                        if (!(is->state & IPPP_CONNECT))
                                return -EINVAL;
-                       if ((r = get_arg((void *) arg, &val, 0)))
+                       if ((r = get_arg((void *) arg, &val, sizeof(val) )))
                                return r;
                        printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
                               (int) min, (int) is->unit, (int) val);
@@ -562,24 +665,30 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
 #endif
                        break;
                case PPPIOCGUNIT:       /* get ppp/isdn unit number */
-                       if ((r = set_arg((void *) arg, is->unit, NULL)))
+                       if ((r = set_arg((void *) arg, &is->unit, sizeof(is->unit) )))
+                               return r;
+                       break;
+               case PPPIOCGIFNAME:
+                       if(!lp)
+                               return -EINVAL;
+                       if ((r = set_arg((void *) arg, lp->name,strlen(lp->name))))
                                return r;
                        break;
                case PPPIOCGMPFLAGS:    /* get configuration flags */
-                       if ((r = set_arg((void *) arg, is->mpppcfg, NULL)))
+                       if ((r = set_arg((void *) arg, &is->mpppcfg, sizeof(is->mpppcfg) )))
                                return r;
                        break;
                case PPPIOCSMPFLAGS:    /* set configuration flags */
-                       if ((r = get_arg((void *) arg, &val, 0)))
+                       if ((r = get_arg((void *) arg, &val, sizeof(val) )))
                                return r;
                        is->mpppcfg = val;
                        break;
                case PPPIOCGFLAGS:      /* get configuration flags */
-                       if ((r = set_arg((void *) arg, is->pppcfg, NULL)))
+                       if ((r = set_arg((void *) arg, &is->pppcfg,sizeof(is->pppcfg) )))
                                return r;
                        break;
                case PPPIOCSFLAGS:      /* set configuration flags */
-                       if ((r = get_arg((void *) arg, &val, 0))) {
+                       if ((r = get_arg((void *) arg, &val, sizeof(val) ))) {
                                return r;
                        }
                        if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
@@ -598,12 +707,12 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
                        if (lp) {
                                struct ppp_idle pidle;
                                pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
-                               if ((r = set_arg((void *) arg, sizeof(struct ppp_idle), &pidle)))
+                               if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle))))
                                         return r;
                        }
                        break;
                case PPPIOCSMRU:        /* set receive unit size for PPP */
-                       if ((r = get_arg((void *) arg, &val, 0)))
+                       if ((r = get_arg((void *) arg, &val, sizeof(val) )))
                                return r;
                        is->mru = val;
                        break;
@@ -612,7 +721,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
                case PPPIOCSMPMTU:
                        break;
                case PPPIOCSMAXCID:     /* set the maximum compression slot id */
-                       if ((r = get_arg((void *) arg, &val, 0)))
+                       if ((r = get_arg((void *) arg, &val, sizeof(val) )))
                                return r;
                        val++;
                        if (is->maxcid != val) {
@@ -635,31 +744,33 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
                        }
                        break;
                case PPPIOCGDEBUG:
-                       if ((r = set_arg((void *) arg, is->debug, 0)))
+                       if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) )))
                                return r;
                        break;
                case PPPIOCSDEBUG:
-                       if ((r = get_arg((void *) arg, &val, 0)))
+                       if ((r = get_arg((void *) arg, &val, sizeof(val) )))
                                return r;
                        is->debug = val;
                        break;
                case PPPIOCGCOMPRESSORS:
                        {
-                               unsigned long protos = 0;
+                               unsigned long protos[8] = {0,};
                                struct isdn_ppp_compressor *ipc = ipc_head;
                                while(ipc) {
-                                       protos |= (0x1<<ipc->num);
+                                       j = ipc->num / (sizeof(long)*8);
+                                       i = ipc->num % (sizeof(long)*8);
+                                       if(j < 8)
+                                               protos[j] |= (0x1<<i);
                                        ipc = ipc->next;
                                }
-                               if ((r = set_arg((void *) arg, protos, 0)))
+                               if ((r = set_arg((void *) arg,protos,8*sizeof(long) )))
                                        return r;
                        }
                        break;
                case PPPIOCSCOMPRESSOR:
-                       if ((r = get_arg((void *) arg, &num, sizeof(int))))
+                       if ((r = get_arg((void *) arg, &data, sizeof(struct isdn_ppp_comp_data))))
                                return r;
-                       return isdn_ppp_set_compressor(is, num);
-                       break;
+                       return isdn_ppp_set_compressor(is, &data);
                case PPPIOCGCALLINFO:
                        {
                                struct pppcallinfo pci;
@@ -678,7 +789,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
                                        if(lp->flags & ISDN_NET_CALLBACK)
                                                pci.calltype |= CALLTYPE_CALLBACK;
                                }
-                               return set_arg((void *)arg,sizeof(struct pppcallinfo),&pci);
+                               return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo));
                        }
                default:
                        break;
@@ -701,9 +812,12 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
                printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
                                MINOR(file->f_dentry->d_inode->i_rdev));
 
+       /* just registers wait_queue hook. This doesn't really wait. */
        poll_wait(file, &is->wq, wait);
 
        if (!(is->state & IPPP_OPEN)) {
+               if(is->state == IPPP_CLOSEWAIT)
+                       return POLLHUP;
                printk(KERN_DEBUG "isdn_ppp: device not open\n");
                return POLLERR;
        }
@@ -777,7 +891,10 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
        is->last = bl->next;
        restore_flags(flags);
 
-       wake_up_interruptible(&is->wq);
+#if LINUX_VERSION_CODE < 131841
+       if (is->wq)
+#endif
+               wake_up_interruptible(&is->wq);
 
        return len;
 }
@@ -863,7 +980,8 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
                if (lp->isdn_device < 0 || lp->isdn_channel < 0)
                        return 0;
 
-               if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 &&
+               if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
+                       lp->dialstate == 0 &&
                    (lp->flags & ISDN_NET_CONNECTED)) {
                        int cnt;
                        struct sk_buff *skb;
@@ -876,8 +994,11 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
                                return -EFAULT;
                        if (is->debug & 0x40) {
                                printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
-                               isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
+                               isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
                        }
+
+                       isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */
+
                        if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
                                if (lp->sav_skb) {
                                        dev_kfree_skb(lp->sav_skb);
@@ -910,8 +1031,6 @@ isdn_ppp_init(void)
                        return -1;
                }
                memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
-               init_waitqueue_head(&ippp_table[i]->wq); 
-               init_waitqueue_head(&ippp_table[i]->wql); 
                ippp_table[i]->state = 0;
                ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
                ippp_table[i]->last = ippp_table[i]->rq;
@@ -963,8 +1082,9 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
        is = ippp_table[lp->ppp_slot];
 
        if (is->debug & 0x4) {
-               printk(KERN_DEBUG "ippp_receive: len: %d\n", (int) skb->len);
-               isdn_ppp_frame_log("receive", skb->data, skb->len, 32);
+               printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
+                      (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len);
+               isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
        }
        if (net_dev->local->master) {
                printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
@@ -982,13 +1102,18 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
 #ifdef CONFIG_ISDN_MPP
        if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
                int sqno_end;
-               
-               if(proto == PPP_LINK_COMP) {
-                       printk(KERN_DEBUG "received single link compressed frame\n");
-                       skb = isdn_ppp_decompress(skb,is,NULL);
-                       if(!skb)
-                               return;
-                       proto = isdn_ppp_strip_proto(skb);
+
+               if(is->compflags & SC_LINK_DECOMP_ON) { 
+                       if(proto == PPP_LINK_COMP) {
+                               if(is->debug & 0x10)
+                                       printk(KERN_DEBUG "received single link compressed frame\n");
+                               skb = isdn_ppp_decompress(skb,is,NULL,proto);
+                               if(!skb)
+                                       return;
+                               proto = isdn_ppp_strip_proto(skb);
+                       }
+                       else
+                               isdn_ppp_decompress(skb,is,NULL,proto);
                }
 
                if (proto == PPP_MP) {
@@ -1055,7 +1180,8 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                                }
                                min_sqno &= mask;
                                for (lpq = net_dev->queue;;) {
-                                       ippp_table[lpq->ppp_slot]->last_link_seqno &= mask;
+                                       if(ippp_table[lpq->ppp_slot]->last_link_seqno >= 0)
+                                               ippp_table[lpq->ppp_slot]->last_link_seqno &= mask;
                                        lpq = lpq->next;
                                        if (lpq == net_dev->queue)
                                                break;
@@ -1150,17 +1276,31 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
 
        if (is->debug & 0x10) {
                printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
-               isdn_ppp_frame_log("rpush", skb->data, skb->len, 32);
+               isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
        }
 
        if(proto == PPP_COMP) {
                if(!lp->master)
-                       skb = isdn_ppp_decompress(skb,is,is);
+                       skb = isdn_ppp_decompress(skb,is,is,proto);
                else
-                       skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]);
-               if(!skb)
+                       skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto);
+
+               if(!skb) {
+                       printk(KERN_DEBUG "ippp: compressed frame discarded!\n");
                        return;
+               }
+
                proto = isdn_ppp_strip_proto(skb);
+               if (is->debug & 0x10) {
+                       printk(KERN_DEBUG "RPostDecomp, skb %d %04x\n", (int) skb->len, proto);
+                       isdn_ppp_frame_log("R-Decomp", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
+               }
+       }
+       else if(is->compflags & SC_DECOMP_ON)  { /* If decomp is ON */
+               if(!lp->master)
+                       isdn_ppp_decompress(skb,is,is,proto);
+               else
+                       isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto);
        }
 
        switch (proto) {
@@ -1227,7 +1367,13 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
 #endif
                        break;
                case PPP_CCP:
-                       isdn_ppp_receive_ccp(net_dev,lp,skb);
+               case PPP_LINK_CCP:
+                       isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
+                       /* Dont pop up ResetReq/Ack stuff to the daemon any
+                          longer - the job is done already */
+                       if(skb->data[0] == CCP_RESETREQ ||
+                          skb->data[0] == CCP_RESETACK)
+                               break;
                        /* fall through */
                default:
                        isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot);     /* push data to pppd device */
@@ -1235,10 +1381,10 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
                        return;
        }
 
+       /* Reset hangup-timer */
+       lp->huptimer = 0;
        netif_rx(skb);
        /* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */
-       /* Reset hangup-timer */
-       lp->huptimer = 0;
 
        return;
 }
@@ -1339,7 +1485,6 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
                lp = nlp;
        }
        ipt = ippp_table[lp->ppp_slot];
-
        lp->huptimer = 0;
 
        /*
@@ -1355,6 +1500,8 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 
        if (ipt->debug & 0x4)
                printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
+        if (ipts->debug & 0x40)
+                isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,lp->ppp_slot);
 
 #ifdef CONFIG_ISDN_PPP_VJ
        if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {    /* ipts here? probably yes, but check this again */
@@ -1394,10 +1541,11 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
        }
 #endif
 
-    /*
-     * normal or bundle compression
-     */
-       skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
+       /*
+        * normal (single link) or bundle compression
+        */
+       if(ipts->compflags & SC_COMP_ON)
+               skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
 
        if (ipt->debug & 0x24)
                printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
@@ -1431,9 +1579,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 #endif
 
        /*
-        * 'link' compression 
+        * 'link in bundle' compression  ...
         */
-       skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
+       if(ipt->compflags & SC_LINK_COMP_ON)
+               skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
 
        if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
                unsigned char *data = isdn_ppp_skb_push(&skb,1);
@@ -1460,7 +1609,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 
        if (ipts->debug & 0x40) {
                printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
-               isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
+               isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
        }
        if (isdn_net_send_skb(dev, lp, skb)) {
                if (lp->sav_skb) {      /* whole sav_skb processing with disabled IRQs ?? */
@@ -1474,6 +1623,12 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
 
 #ifdef CONFIG_ISDN_MPP
 
+/*
+ * free SQ queue
+ * -------------
+ * Note: We need two queues for MPPP. The SQ queue holds fully (re)assembled frames,
+ * that can't be delivered, because there is an outstanding earlier frame
+ */
 static void
 isdn_ppp_free_sqqueue(isdn_net_dev * p)
 {
@@ -1490,6 +1645,12 @@ isdn_ppp_free_sqqueue(isdn_net_dev * p)
 
 }
 
+/*
+ * free MP queue
+ * -------------
+ * Note: The MP queue holds all frame fragments of frames, that can't be
+ * reassembled, because there is at least one missing fragment.
+ */
 static void 
 isdn_ppp_free_mpqueue(isdn_net_dev * p)
 {
@@ -1551,7 +1712,9 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
        return 0;
 }
 
-
+/*
+ * Mask sequence numbers in MP queue
+ */
 static void
 isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
 {
@@ -1562,6 +1725,11 @@ isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
        }
 }
 
+/*
+ * put a fragment at the right place into the MP queue 
+ * Also checks, whether this fragment completes a frame. In this case
+ * the fragments are copied together into one SKB
+ */
 static int
 isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno)
 {
@@ -1762,13 +1930,11 @@ isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
                slhc_toss(ippp_table[dev->local->ppp_slot]->slcomp);
 #endif
 }
+#endif
 
 /*
  * a buffered packet timed-out?
  */
-
-#endif
-
 void
 isdn_ppp_timer_timeout(void)
 {
@@ -1940,7 +2106,7 @@ isdn_ppp_dial_slave(char *name)
        if (!sdev)
                return 2;
 
-       isdn_net_force_dial_lp((isdn_net_local *) sdev->priv);
+       isdn_net_dial_req((isdn_net_local *) sdev->priv);
        return 0;
 #else
        return -1;
@@ -1981,47 +2147,440 @@ isdn_ppp_hangup_slave(char *name)
 /*
  * PPP compression stuff
  */
-static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master)
+
+
+/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
+   generate a CCP Reset-Request or tear down CCP altogether */
+
+static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
+{
+       isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
+}
+
+/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
+   but absolutely nontrivial. The most abstruse problem we are facing is
+   that the generation, reception and all the handling of timeouts and
+   resends including proper request id management should be entirely left
+   to the (de)compressor, but indeed is not covered by the current API to
+   the (de)compressor. The API is a prototype version from PPP where only
+   some (de)compressors have yet been implemented and all of them are
+   rather simple in their reset handling. Especially, their is only one
+   outstanding ResetAck at a time with all of them and ResetReq/-Acks do
+   not have parameters. For this very special case it was sufficient to
+   just return an error code from the decompressor and have a single
+   reset() entry to communicate all the necessary information between
+   the framework and the (de)compressor. Bad enough, LZS is different
+   (and any other compressor may be different, too). It has multiple
+   histories (eventually) and needs to Reset each of them independently
+   and thus uses multiple outstanding Acks and history numbers as an
+   additional parameter to Reqs/Acks.
+   All that makes it harder to port the reset state engine into the
+   kernel because it is not just the same simple one as in (i)pppd but
+   it must be able to pass additional parameters and have multiple out-
+   standing Acks. We are trying to achieve the impossible by handling
+   reset transactions independent by their id. The id MUST change when
+   the data portion changes, thus any (de)compressor who uses more than
+   one resettable state must provide and recognize individual ids for
+   each individual reset transaction. The framework itself does _only_
+   differentiate them by id, because it has no other semantics like the
+   (de)compressor might.
+   This looks like a major redesign of the interface would be nice,
+   but I don't have an idea how to do it better. */
+
+/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
+   getting that lengthy because there is no simple "send-this-frame-out"
+   function above but every wrapper does a bit different. Hope I guess
+   correct in this hack... */
+
+static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
+                                   unsigned char code, unsigned char id,
+                                   unsigned char *data, int len)
+{
+       struct sk_buff *skb;
+       unsigned char *p;
+       int count;
+       int cnt = 0;
+       isdn_net_local *lp = is->lp;
+
+       /* Alloc large enough skb */
+       skb = dev_alloc_skb(len + 16);
+       if(!skb) {
+               printk(KERN_WARNING
+                      "ippp: CCP cannot send reset - out of memory\n");
+               return;
+       }
+
+       /* We may need to stuff an address and control field first */
+       if(!(is->pppcfg & SC_COMP_AC)) {
+               p = skb_put(skb, 2);
+               *p++ = 0xff;
+               *p++ = 0x03;
+       }
+
+       /* Stuff proto, code, id and length */
+       p = skb_put(skb, 6);
+       *p++ = (proto >> 8);
+       *p++ = (proto & 0xff);
+       *p++ = code;
+       *p++ = id;
+       cnt = 4 + len;
+       *p++ = (cnt >> 8);
+       *p++ = (cnt & 0xff);
+
+       /* Now stuff remaining bytes */
+       if(len) {
+               p = skb_put(skb, len);
+               memcpy(p, data, len);
+       }
+
+       /* skb is now ready for xmit */
+       printk(KERN_DEBUG "Sending CCP Frame:\n");
+       isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+
+       /* Just ripped from isdn_ppp_write. Dunno whether it makes sense,
+          especially dunno what the sav_skb stuff is good for. */
+
+       count = skb->len;
+       if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel,
+                                         1, skb)) != count) {
+               if (lp->sav_skb) {
+                       dev_kfree_skb(lp->sav_skb);
+                       printk(KERN_INFO
+                              "isdn_ppp_write: freeing sav_skb (%d,%d)!\n",
+                              cnt, count);
+               } else
+                       printk(KERN_INFO
+                              "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n",
+                              cnt, count);
+               lp->sav_skb = skb;
+       }
+}
+
+/* Allocate the reset state vector */
+static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
+{
+       struct ippp_ccp_reset *r;
+       printk(KERN_DEBUG "ippp_ccp: allocating reset data structure\n");
+       r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
+       if(!r)
+               return NULL;
+       memset(r, 0, sizeof(struct ippp_ccp_reset));
+       is->reset = r;
+       return r;
+}
+
+/* Free a given state and clear everything up for later reallocation */
+static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
+                                         unsigned char id)
+{
+       struct ippp_ccp_reset_state *rs;
+
+       if(is->reset->rs[id]) {
+               printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
+               rs = is->reset->rs[id];
+               /* Make sure the kernel will not call back later */
+               if(rs->ta)
+                       del_timer(&rs->timer);
+               is->reset->rs[id] = NULL;
+               kfree(rs);
+       } else {
+               printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
+       }
+}
+
+/* The timer callback function which is called when a ResetReq has timed out,
+   aka has never been answered by a ResetAck */
+static void isdn_ppp_ccp_timer_callback(unsigned long closure)
+{
+       struct ippp_ccp_reset_state *rs =
+               (struct ippp_ccp_reset_state *)closure;
+
+       if(!rs) {
+               printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
+               return;
+       }
+       if(rs->ta && rs->state == CCPResetSentReq) {
+               /* We are correct here */
+               printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
+                      rs->id);
+               if(!rs->expra) {
+                       /* Hmm, there is no Ack really expected. We can clean
+                          up the state now, it will be reallocated if the
+                          decompressor insists on another reset */
+                       rs->ta = 0;
+                       isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
+                       return;
+               }
+               /* Push it again */
+               isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
+                                       rs->data, rs->dlen);
+               /* Restart timer */
+               rs->timer.expires = jiffies + HZ*5;
+               add_timer(&rs->timer);
+       } else {
+               printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
+                      rs->state);
+       }
+}
+
+/* Allocate a new reset transaction state */
+static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
+                                                     unsigned char id)
+{
+       struct ippp_ccp_reset_state *rs;
+       if(is->reset->rs[id]) {
+               printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
+                      id);
+               return NULL;
+       } else {
+               rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
+               if(!rs)
+                       return NULL;
+               memset(rs, 0, sizeof(struct ippp_ccp_reset_state));
+               rs->state = CCPResetIdle;
+               rs->is = is;
+               rs->id = id;
+               rs->timer.data = (unsigned long)rs;
+               rs->timer.function = isdn_ppp_ccp_timer_callback;
+               is->reset->rs[id] = rs;
+       }
+       return rs;
+}
+
+
+/* A decompressor wants a reset with a set of parameters - do what is
+   necessary to fulfill it */
+static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
+                                    struct isdn_ppp_resetparams *rp)
+{
+       struct ippp_ccp_reset_state *rs;
+
+       if(rp->valid) {
+               /* The decompressor defines parameters by itself */
+               if(rp->rsend) {
+                       /* And he wants us to send a request */
+                       if(!(rp->idval)) {
+                               printk(KERN_ERR "ippp_ccp: decompressor must"
+                                      " specify reset id\n");
+                               return;
+                       }
+                       if(is->reset->rs[rp->id]) {
+                               /* There is already a transaction in existence
+                                  for this id. May be still waiting for a
+                                  Ack or may be wrong. */
+                               rs = is->reset->rs[rp->id];
+                               if(rs->state == CCPResetSentReq && rs->ta) {
+                                       printk(KERN_DEBUG "ippp_ccp: reset"
+                                              " trans still in progress"
+                                              " for id %d\n", rp->id);
+                               } else {
+                                       printk(KERN_WARNING "ippp_ccp: reset"
+                                              " trans in wrong state %d for"
+                                              " id %d\n", rs->state, rp->id);
+                               }
+                       } else {
+                               /* Ok, this is a new transaction */
+                               printk(KERN_DEBUG "ippp_ccp: new trans for id"
+                                      " %d to be started\n", rp->id);
+                               rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
+                               if(!rs) {
+                                       printk(KERN_ERR "ippp_ccp: out of mem"
+                                              " allocing ccp trans\n");
+                                       return;
+                               }
+                               rs->state = CCPResetSentReq;
+                               rs->expra = rp->expra;
+                               if(rp->dtval) {
+                                       rs->dlen = rp->dlen;
+                                       memcpy(rs->data, rp->data, rp->dlen);
+                               }
+                               /* HACK TODO - add link comp here */
+                               isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
+                                                       CCP_RESETREQ, rs->id,
+                                                       rs->data, rs->dlen);
+                               /* Start the timer */
+                               rs->timer.expires = jiffies + 5*HZ;
+                               add_timer(&rs->timer);
+                               rs->ta = 1;
+                       }
+               } else {
+                       printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
+               }
+       } else {
+               /* The reset params are invalid. The decompressor does not
+                  care about them, so we just send the minimal requests
+                  and increase ids only when an Ack is received for a
+                  given id */
+               if(is->reset->rs[is->reset->lastid]) {
+                       /* There is already a transaction in existence
+                          for this id. May be still waiting for a
+                          Ack or may be wrong. */
+                       rs = is->reset->rs[is->reset->lastid];
+                       if(rs->state == CCPResetSentReq && rs->ta) {
+                               printk(KERN_DEBUG "ippp_ccp: reset"
+                                      " trans still in progress"
+                                      " for id %d\n", rp->id);
+                       } else {
+                               printk(KERN_WARNING "ippp_ccp: reset"
+                                      " trans in wrong state %d for"
+                                      " id %d\n", rs->state, rp->id);
+                       }
+               } else {
+                       printk(KERN_DEBUG "ippp_ccp: new trans for id"
+                              " %d to be started\n", is->reset->lastid);
+                       rs = isdn_ppp_ccp_reset_alloc_state(is,
+                                                           is->reset->lastid);
+                       if(!rs) {
+                               printk(KERN_ERR "ippp_ccp: out of mem"
+                                      " allocing ccp trans\n");
+                               return;
+                       }
+                       rs->state = CCPResetSentReq;
+                       /* We always expect an Ack if the decompressor doesnt
+                          know better */
+                       rs->expra = 1;
+                       rs->dlen = 0;
+                       /* HACK TODO - add link comp here */
+                       isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
+                                               rs->id, NULL, 0);
+                       /* Start the timer */
+                       rs->timer.expires = jiffies + 5*HZ;
+                       add_timer(&rs->timer);
+                       rs->ta = 1;
+               }
+       }
+}
+
+/* An Ack was received for this id. This means we stop the timer and clean
+   up the state prior to calling the decompressors reset routine. */
+static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
+                                       unsigned char id)
 {
-#if 1
-       printk(KERN_ERR "compression not included!\n");
-       dev_kfree_skb(skb);
-       return NULL;
+       struct ippp_ccp_reset_state *rs = is->reset->rs[id];
+
+       if(rs) {
+               if(rs->ta && rs->state == CCPResetSentReq) {
+                       /* Great, we are correct */
+                       if(!rs->expra)
+                               printk(KERN_DEBUG "ippp_ccp: ResetAck received"
+                                      " for id %d but not expected\n", id);
+               } else {
+                       printk(KERN_INFO "ippp_ccp: ResetAck received out of"
+                              "sync for id %d\n", id);
+               }
+               if(rs->ta) {
+                       rs->ta = 0;
+                       del_timer(&rs->timer);
+               }
+               isdn_ppp_ccp_reset_free_state(is, id);
+       } else {
+               printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
+                      " %d\n", id);
+       }
+       /* Make sure the simple reset stuff uses a new id next time */
+       is->reset->lastid++;
+}
+
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,
+       int proto)
+{
+#ifndef CONFIG_ISDN_CCP
+       if(proto == PPP_COMP || proto == PPP_LINK_COMP) {
+               printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n");
+               dev_kfree_skb(skb);
+               return NULL;
+       }
+       return skb;
 #else
+       void *stat = NULL;
+       struct isdn_ppp_compressor *ipc = NULL;
+       struct sk_buff *skb_out;
+       int len;
+       struct ippp_struct *ri;
+       struct isdn_ppp_resetparams rsparm;
+       unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
+
        if(!master) {
                /* 
-                * single link compression 
+                * single link decompression 
                 */
-               if(!is->link_compressor) {
-                       printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+               if(!is->link_decompressor) {
+                       printk(KERN_ERR "ippp: no link decompressor defined!\n");
                        dev_kfree_skb(skb);
                        return NULL;
                }
                if(!is->link_decomp_stat) {
-                       printk(KERN_DEBUG "ippp: initialize link compressor\n");
+                       printk(KERN_DEBUG "ippp: no link decompressor data allocated\n");
+                       dev_kfree_skb(skb);
+                       return NULL;
                }
-/*
-               -> decompress link
-*/
-    }
+               stat = is->link_decomp_stat;
+               ipc = is->link_decompressor;
+               ri = is;
+       }
        else {
                /*
                 * 'normal' or bundle-compression 
                 */
-               if(!master->compressor) {
-                       printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+               if(!master->decompressor) {
+                       printk(KERN_ERR "ippp: no decompressor defined!\n");
                        dev_kfree_skb(skb);
                        return NULL;
                }
                if(!master->decomp_stat) {
-#if 0
-                       master->decomp_stat = (master->compressor->decomp_alloc)( .. );
-#endif
-                       printk(KERN_DEBUG "ippp: initialize compressor\n");
+                       printk(KERN_DEBUG "ippp: no decompressor data allocated\n");
+                       dev_kfree_skb(skb);
+                       return NULL;
                }
+               stat = master->decomp_stat;
+               ipc = master->decompressor;
+               ri = master;
+       }
+
+       /*
+       printk(KERN_DEBUG "ippp: Decompress valid!\n");
+       */
+
+       if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) {
+               /* Set up reset params for the decompressor */
+               memset(&rsparm, 0, sizeof(rsparm));
+               rsparm.data = rsdata;
+               rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
+
+/* !!!HACK,HACK,HACK!!! 2048 is only assumed */
+               skb_out = dev_alloc_skb(2048);
+               len = ipc->decompress(stat,skb,skb_out, &rsparm);
+               dev_kfree_skb(skb);
+               if(len <= 0) {
+                 /* Ok, some error */
+                 switch(len) {
+                 case DECOMP_ERROR:
+                   ri->pppcfg |= SC_DC_ERROR;
+                   printk(KERN_INFO "ippp: decomp wants reset %s params\n",
+                          rsparm.valid ? "with" : "without");
+
+                   isdn_ppp_ccp_reset_trans(ri, &rsparm);
+
+                   break;
+                 case DECOMP_FATALERROR:
+                   ri->pppcfg |= SC_DC_FERROR;
+                   /* Kick ipppd to recognize the error */
+                   isdn_ppp_ccp_kickup(ri);
+                   break;
+                 }
+                 /* Did I see a leak here ? */
+                 dev_kfree_skb(skb_out);
+                 return NULL;
+               }
+               return skb_out;
+       }
+       else {
+               /*
+               printk(KERN_DEBUG "isdn_ppp: [%d] Calling incomp with this frame!\n",is->unit);
+               */
+               ipc->incomp(stat,skb,proto);
+               return skb;
        }
-       
-       return skb;
 #endif
 }
 
@@ -2035,19 +2594,29 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc
 static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
        struct ippp_struct *is,struct ippp_struct *master,int type)
 {
-#if 1  
-       return skb_in;
-#else
     int ret;
     int new_proto;
     struct isdn_ppp_compressor *compressor;
     void *stat;
     struct sk_buff *skb_out;
 
+#ifdef CONFIG_ISDN_CCP
+       /* we do not compress control protocols */
+    if(*proto < 0 || *proto > 0x3fff) {
+#else
+    {
+#endif
+      return skb_in;
+    }
+
        if(type) { /* type=1 => Link compression */
+#if 0
                compressor = is->link_compressor;
                stat = is->link_comp_stat;
                new_proto = PPP_LINK_COMP;
+#else
+               return skb_in;
+#endif
        }
        else {
                if(!master) {
@@ -2062,15 +2631,16 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
        }
 
        if(!compressor) {
-               printk(KERN_ERR "No compressor set!\n");
+               printk(KERN_ERR "isdn_ppp: No compressor set!\n");
                return skb_in;
        }
        if(!stat) {
-               /* init here ? */
+               printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
                return skb_in;
        }
 
-       skb_out = dev_alloc_skb(skb_in->len);
+       /* Allow for at least 150 % expansion (for now) */
+       skb_out = dev_alloc_skb(skb_in->len + skb_in->len/2 + 32);
        if(!skb_out)
                return skb_in;
 
@@ -2083,24 +2653,225 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
        dev_kfree_skb(skb_in);
        *proto = new_proto;
        return skb_out;
-#endif
-
 }
 
 /*
  * we received a CCP frame .. 
- * not a clean solution, but we SHOULD handle a few cased in the kernel
+ * not a clean solution, but we MUST handle a few cases in the kernel
  */
 static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
-        struct sk_buff *skb)
+        struct sk_buff *skb,int proto)
 {
-#if 0
-       printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n",
-               skb->data[0],skb->data[1],skb->data[2],skb->data[3],
-               skb->data[4],skb->data[5],skb->data[6],skb->data[7] );
-#endif
+       struct ippp_struct *is = ippp_table[lp->ppp_slot];
+       struct ippp_struct *mis;
+       int len;
+       struct isdn_ppp_resetparams rsparm;
+       unsigned char rsdata[IPPP_RESET_MAXDATABYTES];  
+
+       printk(KERN_DEBUG "Received CCP frame from peer\n");
+       isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+
+       if(lp->master)
+               mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
+       else
+               mis = is;
+
+       switch(skb->data[0]) {
+       case CCP_CONFREQ:
+       case CCP_TERMREQ:
+       case CCP_TERMACK:
+               if(is->debug & 0x10)
+                       printk(KERN_DEBUG "Disable (de)compression here!\n");
+               if(proto == PPP_CCP)
+                       mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);           
+               else
+                       is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON);          
+               break;
+       case CCP_CONFACK:
+               /* if we RECEIVE an ackowledge we enable the decompressor */
+               if(is->debug & 0x10)
+                       printk(KERN_DEBUG "Enable decompression here!\n");
+               if(proto == PPP_CCP)
+                       mis->compflags |= SC_DECOMP_ON;
+               else
+                       is->compflags |= SC_LINK_DECOMP_ON;
+               break;
+
+       case CCP_RESETACK:
+               printk(KERN_DEBUG "Received ResetAck from peer\n");
+               len = (skb->data[2] << 8) | skb->data[3];
+               len -= 4;
+
+               if(proto == PPP_CCP) {
+                       /* If a reset Ack was outstanding for this id, then
+                          clean up the state engine */
+                       isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
+                       if(mis->decompressor && mis->decomp_stat)
+                               mis->decompressor->
+                                       reset(mis->decomp_stat,
+                                             skb->data[0],
+                                             skb->data[1],
+                                             len ? &skb->data[4] : NULL,
+                                             len, NULL);
+                       /* TODO: This is not easy to decide here */
+                       mis->compflags &= ~SC_DECOMP_DISCARD;
+                       mis->pppcfg &= ~SC_DC_ERROR;
+               }
+               else {
+                       isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
+                       if(is->link_decompressor && is->link_decomp_stat)
+                               is->link_decompressor->
+                                       reset(is->link_decomp_stat,
+                                             skb->data[0],
+                                             skb->data[1],
+                                             len ? &skb->data[4] : NULL,
+                                             len, NULL);
+                       /* TODO: neither here */
+                       is->compflags &= ~SC_LINK_DECOMP_DISCARD;
+                       is->pppcfg &= ~SC_DC_ERROR;
+               }
+               break;
+
+       case CCP_RESETREQ:
+               printk(KERN_DEBUG "Received ResetReq from peer\n");
+               /* Receiving a ResetReq means we must reset our compressor */
+               /* Set up reset params for the reset entry */
+               memset(&rsparm, 0, sizeof(rsparm));
+               rsparm.data = rsdata;
+               rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; 
+               /* Isolate data length */
+               len = (skb->data[2] << 8) | skb->data[3];
+               len -= 4;
+               if(proto == PPP_CCP) {
+                       if(mis->compressor && mis->comp_stat)
+                               mis->compressor->
+                                       reset(mis->comp_stat,
+                                             skb->data[0],
+                                             skb->data[1],
+                                             len ? &skb->data[4] : NULL,
+                                             len, &rsparm);
+               }
+               else {
+                       if(is->link_compressor && is->link_comp_stat)
+                               is->link_compressor->
+                                       reset(is->link_comp_stat,
+                                             skb->data[0],
+                                             skb->data[1],
+                                             len ? &skb->data[4] : NULL,
+                                             len, &rsparm);
+               }
+               /* Ack the Req as specified by rsparm */
+               if(rsparm.valid) {
+                       /* Compressor reset handler decided how to answer */
+                       if(rsparm.rsend) {
+                               /* We should send a Frame */
+                               isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
+                                                       rsparm.idval ? rsparm.id
+                                                       : skb->data[1],
+                                                       rsparm.dtval ?
+                                                       rsparm.data : NULL,
+                                                       rsparm.dtval ?
+                                                       rsparm.dlen : 0);
+                       } else {
+                               printk(KERN_DEBUG "ResetAck suppressed\n");
+                       }
+               } else {
+                       /* We answer with a straight reflected Ack */
+                       isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
+                                               skb->data[1],
+                                               len ? &skb->data[4] : NULL,
+                                               len);
+               }
+               break;
+       }
+}
+
+
+/*
+ * Daemon sends a CCP frame ...
+ */
+
+/* TODO: Clean this up with new Reset semantics */
+
+static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
+{
+       struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot];
+       int proto;
+       unsigned char *data;
+
+       if(!skb || skb->len < 3)
+               return;
+
+       /* Daemon may send with or without address and control field comp */
+       data = skb->data;
+       if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
+               data += 2;
+               if(skb->len < 5)
+                       return;
+       }
+
+       proto = ((int)data[0]<<8)+data[1];
+       if(proto != PPP_CCP && proto != PPP_LINK_CCP)
+               return;
+
+       printk(KERN_DEBUG "Received CCP frame from daemon:\n");
+       isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+
+        if(lp->master)
+                mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
+        else
+                mis = is;
+       
+       if(mis != is)
+               printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
+       
+        switch(data[2]) {
+       case CCP_CONFREQ:
+       case CCP_TERMREQ:
+       case CCP_TERMACK:
+               if(is->debug & 0x10)
+                       printk(KERN_DEBUG "Disable (de)compression here!\n");
+               if(proto == PPP_CCP)
+                       is->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON);
+               else
+                       is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON);
+               break;
+       case CCP_CONFACK:
+               /* if we SEND an ackowledge we can/must enable the compressor */
+               if(is->debug & 0x10)
+                       printk(KERN_DEBUG "Enable compression here!\n");
+               if(proto == PPP_CCP)
+                       is->compflags |= SC_COMP_ON;
+               else
+                       is->compflags |= SC_LINK_COMP_ON;
+               break;
+       case CCP_RESETACK:
+               /* If we send a ACK we should reset our compressor */
+               if(is->debug & 0x10)
+                       printk(KERN_DEBUG "Reset decompression state here!\n");
+               printk(KERN_DEBUG "ResetAck from daemon passed by\n");
+               if(proto == PPP_CCP) {
+                       /* link to master? */
+                       if(is->compressor && is->comp_stat)
+                               is->compressor->reset(is->comp_stat, 0, 0,
+                                                     NULL, 0, NULL);
+                       is->compflags &= ~SC_COMP_DISCARD;      
+               }
+               else {
+                       if(is->link_compressor && is->link_comp_stat)
+                               is->link_compressor->reset(is->link_comp_stat,
+                                                          0, 0, NULL, 0, NULL);
+                       is->compflags &= ~SC_LINK_COMP_DISCARD; 
+               }
+               break;
+       case CCP_RESETREQ:
+               /* Just let it pass by */
+               printk(KERN_DEBUG "ResetReq from daemon passed by\n");
+               break;
+       }
 }
 
+
 int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
 {
        ipc->next = ipc_head;
@@ -2124,15 +2895,63 @@ int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
        return 0;
 }
 
-static int isdn_ppp_set_compressor(struct ippp_struct *is,int num)
+static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
 {
        struct isdn_ppp_compressor *ipc = ipc_head;
+       int ret;
+       void *stat;
+       int num = data->num;
+
+       if(is->debug & 0x10)
+               printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit,
+                       (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num);
 
        while(ipc) {
                if(ipc->num == num) {
-                       return 0;       
-                       is->compressor = ipc;
-                       is->link_compressor = ipc;
+                       stat = ipc->alloc(data);
+                       if(stat) {
+                               ret = ipc->init(stat,data,is->unit,0);
+                               if(!ret) {
+                                       printk(KERN_ERR "Can't init (de)compression!\n");
+                                       ipc->free(stat);
+                                       stat = NULL;
+                                       break;
+                               }
+                       }
+                       else {
+                               printk(KERN_ERR "Can't alloc (de)compression!\n");
+                               break;
+                       }
+
+                        if(data->flags & IPPP_COMP_FLAG_XMIT) {
+                               if(data->flags & IPPP_COMP_FLAG_LINK) {
+                                       if(is->link_comp_stat)
+                                               is->link_compressor->free(is->link_comp_stat);
+                                       is->link_comp_stat = stat;
+                                       is->link_compressor = ipc;
+                               }
+                               else {
+                                       if(is->comp_stat)
+                                               is->compressor->free(is->comp_stat);
+                                       is->comp_stat = stat;
+                                       is->compressor = ipc;
+                               }
+                       }
+                        else {
+                               if(data->flags & IPPP_COMP_FLAG_LINK) {
+                                       if(is->link_decomp_stat)
+                                               is->link_decompressor->free(is->link_decomp_stat);
+                                       is->link_decomp_stat = stat;
+                                       is->link_decompressor = ipc;
+                               }
+                               else {
+                                       if(is->decomp_stat)
+                                               is->decompressor->free(is->decomp_stat);
+                                       is->decomp_stat = stat;
+                                       is->decompressor = ipc;
+                               }
+                       }
+                       return 0;
                }
                ipc = ipc->next;
        }
@@ -2140,16 +2959,3 @@ static int isdn_ppp_set_compressor(struct ippp_struct *is,int num)
 }
 
 
-#if 0
-static struct symbol_table isdn_ppp_syms =
-{
-#include <linux/symtab_begin.h>
-       X(isdn_ppp_register_compressor),
-       X(isdn_ppp_unregister_compressor),
-#include <linux/symtab_end.h>
-};
-#endif
-
-
-
-
index 0e05af08b53509f45d568f729c1a543d02a7243c..2c60240a59ff581740f8ee46e2cb9caa0465eb20 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.h,v 1.12 1998/01/31 22:07:48 keil Exp $
+/* $Id: isdn_ppp.h,v 1.13 1998/03/22 18:50:50 hipp Exp $
 
  * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_ppp.h,v $
+ * Revision 1.13  1998/03/22 18:50:50  hipp
+ * Added BSD Compression for syncPPP .. UNTESTED at the moment
+ *
  * Revision 1.12  1998/01/31 22:07:48  keil
  * changes for newer kernels
  *
@@ -84,6 +87,9 @@ extern void isdn_ppp_release(int, struct file *);
 extern int isdn_ppp_dial_slave(char *);
 extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
 
+extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
+extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
+
 #define IPPP_OPEN      0x01
 #define IPPP_CONNECT   0x02
 #define IPPP_CLOSEWAIT 0x04
diff --git a/drivers/isdn/isdn_timru.c b/drivers/isdn/isdn_timru.c
new file mode 100644 (file)
index 0000000..db8218a
--- /dev/null
@@ -0,0 +1,916 @@
+/* $Id: isdn_timru.c,v 1.2 1998/03/07 23:17:28 fritz Exp $
+ *
+ * Linux ISDN subsystem, timeout-rules for network interfaces.
+ *
+ * Copyright 1997       by Christian Lademann <cal@zls.de>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
+ *
+ * $Log: isdn_timru.c,v $
+ * Revision 1.2  1998/03/07 23:17:28  fritz
+ * Added RCS keywords
+ * Bugfix: Did not compile without isdn_dumppkt beeing enabled.
+ *
+ */
+
+/*
+02.06.97:cal:
+    - ISDN_TIMRU_PACKET_NONE = 0 definiert, die anderen ISDN_TIMRU_PACKET_* -
+      Definitionen jeweils inkrementiert
+
+    - isdn_net_recalc_timeout():
+      - In der Schleife zum Finden einer passenden Regel wurde in jedem Fall
+        die Wildcard-Kette durchsucht. Jetzt nicht mehr.
+      - beim Testen einer Bringup-Regel wird der anfaengliche Timeout auf den
+        Hangup-Timeout des Devices gesetzt (lp->onhtime).
+
+10.06.97:cal:
+    - isdn_net_recalc_timeout(): rule->neg-Handling gesaeubert: eine Regel passt
+      genau dann, wenn match(rule) XOR rule->neg und das bei allen Regeltypen.
+    - isdn_net_add_rule(): rule->timeout bei BRINGUP immer 1, sonst > 0.
+    - alle return(-1), die zu ioctl-Calls zurueckgehen --> return(-EINVAL).
+    - div. Leerzeilen geloescht / eingefuegt; alle return's "geklammert".
+
+12.06.97:cal:
+    - isdn_net_recalc_timeout(): Falls IP-Masquerading verwendet wird, kann mit
+      der neuen Option CONFIG_TIMRU_USE_MASQ der Regel-Match auf die ursprueng-
+      lichen Adressen und nicht auf die der Firewall angewendet werden. Dazu ist
+      ein Patch in net/ipv4/ip_masq.c notwendig: ip_masq_in_get_2 muss
+      exportiert werden.
+
+26.06.97:cal:
+    - isdn_net_add_rule(): rule->timeout darf bei BRINGUP >= 0 sein. Damit
+      laesst sich folgende Systax erreichen: "Falls Paket passt, starte die
+      Verbindung NICHT", wie es im Stand 970602 moeglich war.
+    - isdn_net_recalc_timeout(): BRINGUP: initial timeout wird auf den in der
+      passenden Regel gefundenen Timeout gesetzt. Ist dieser 0, so wird die
+      Verbindung nicht aufgebaut.
+
+16.10.97:cal:
+    - isdn_net_recalc_timeout(): beachte Fake-Header, der bei ausgehenden
+      SyncPPP-Paketen eingesetzt wird;
+      TimRu's "recalc timeout:" - Meldungen in einer Zeile
+
+04.11.97:cal:
+    - isdn_net.c, isdn_net_new(): Timeout-Rules nicht mehr automatisch
+      alloziieren;
+    - isdn_net.c, isdn_net_autohup(): AutoHup auch durchfuehren, wenn keine
+      Timeout-Rules alloziiert sind.
+*/
+/*
+TODO:
+
+- Masq-Adressen statt Paketadresse ausgeben, falls die Masq-Adressen verwendet
+  werden.
+
+- Masq-Adressen-Verwendung als Option in den Regeln vorsehen
+
+- TCP-Flags als Regel-Optionen
+
+- weitere Verfeinerungen fuer Nicht-TCP/IP-Pakete
+*/
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/isdn.h>
+#include <linux/if_arp.h>
+#include <linux/in.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#ifdef CONFIG_ISDN_TIMRU_USE_MASQ
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
+#endif
+#include "isdn_common.h"
+#include "isdn_net.h"
+#ifdef CONFIG_ISDN_PPP
+#include "isdn_ppp.h"
+#endif
+
+#ifdef CONFIG_ISDN_TIMEOUT_RULES
+
+static int
+isdn_timru_match(isdn_timeout_rule *this, isdn_timeout_rule *rule);
+
+
+#define printk_ip(a)    printk("%ld.%ld.%ld.%ld",(ntohl(a)>>24)&0xFF,\
+                                             (ntohl(a)>>16)&0xFF,\
+                                             (ntohl(a)>>8)&0xFF,\
+                                             (ntohl(a))&0xFF)
+#define printk_port(a)  printk("%d",ntohs(a))
+
+
+#define        VERBOSE_PRINTK(v, l, p...)      { \
+       if(dev->net_verbose >= (v)) { \
+               printk(l ## p); \
+       } else { ; } \
+}
+
+
+int
+isdn_net_recalc_timeout(int type, int prot, struct device *ndev, void *buf, ulong arg) {
+       isdn_net_local          *lp = (isdn_net_local *)ndev->priv;
+       struct sk_buff          *skb;
+       struct iphdr            *ip;
+       struct icmphdr          *icmp;
+       struct tcphdr           *tcp;
+       struct udphdr           *udp;
+#ifdef CONFIG_ISDN_TIMRU_USE_MASQ
+#ifdef CONFIG_IP_MASQUERADE
+       struct ip_masq          *masq;
+       int                     m_prot;
+       __u32                   m_saddr, m_daddr;
+       __u16                   m_sport, m_dport;
+       int                     check_for_masq;
+#endif
+#endif
+
+       isdn_timeout_rule       match_rule;
+
+/*
+       char                    *cbuf;
+*/
+       int                     ppp_proto, ppp_hdrlen = 0, new_timeout;
+
+
+       match_rule.type = type;
+       match_rule.protfam = ISDN_TIMRU_PROTFAM_WILDCARD;
+
+       if(dev->net_verbose > 4) {
+               printk(KERN_DEBUG "recalc_timeout:");
+               switch(type) {
+               case ISDN_TIMRU_BRINGUP:        printk("BRINGUP, "); break;
+               case ISDN_TIMRU_KEEPUP_IN:      printk("KEEPUP_IN, "); break;
+               case ISDN_TIMRU_KEEPUP_OUT:     printk("KEEPUP_OUT, "); break;
+               default:
+                       printk("ERROR\n");
+                       return(-1);
+                       break;
+               }
+       }
+
+       switch(prot) {
+       case ISDN_TIMRU_PACKET_PPP:
+       case ISDN_TIMRU_PACKET_PPP_NO_HEADER:
+               if(prot == ISDN_TIMRU_PACKET_PPP) {
+                       ppp_proto = PPP_PROTOCOL((char *)buf);
+/*
+                       cbuf = (char *)(buf + PPP_HDRLEN);
+*/
+               } else {
+                       ppp_proto = (int)arg;
+/*
+                       cbuf = (char *)buf;
+*/
+               }
+
+               match_rule.protfam = ISDN_TIMRU_PROTFAM_PPP;
+               match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_WILDCARD;
+
+               switch(ppp_proto) {
+               case PPP_IPCP:
+                       match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_IPCP;
+                       VERBOSE_PRINTK(5, "", "PPP/IPCP\n");
+                       break;
+
+               case PPP_IPXCP:
+                       match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_IPXCP;
+                       VERBOSE_PRINTK(5, "", "PPP/IPXCP\n");
+                       break;
+
+               case PPP_CCP:
+                       match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_CCP;
+                       VERBOSE_PRINTK(5, "", "PPP/CCP\n");
+                       break;
+
+               case PPP_LCP:
+                       match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_LCP;
+                       VERBOSE_PRINTK(5, "", "PPP/LCP\n");
+                       break;
+
+               case PPP_PAP:
+                       match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_PAP;
+                       VERBOSE_PRINTK(5, "", "PPP/PAP\n");
+                       break;
+
+               case PPP_LQR:
+                       match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_LQR;
+                       VERBOSE_PRINTK(5, "", "PPP/LQR\n");
+                       break;
+
+               case PPP_CHAP:
+                       match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_CHAP;
+                       VERBOSE_PRINTK(5, "", "PPP/CHAP\n");
+                       break;
+
+               default:
+                       match_rule.rule.ppp.protocol = ISDN_TIMRU_PPP_WILDCARD;
+
+                       if(dev->net_verbose >= 5) {
+                               printk("PPP/? (%x)\n", ppp_proto);
+#ifdef ISDN_DEBUG_NET_DUMP
+                               isdn_dumppkt("R:", (u_char *)buf, 40, 40);
+#endif
+                       }
+                       break;
+               }
+               break;
+
+       case ISDN_TIMRU_PACKET_SKB:
+               skb = (struct sk_buff *)buf;
+
+#ifdef CONFIG_ISDN_PPP
+               if((type == ISDN_TIMRU_BRINGUP ||
+               type == ISDN_TIMRU_KEEPUP_OUT) &&
+               lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+                       /* jump over fake header. */
+                       ppp_hdrlen = IPPP_MAX_HEADER;
+               }
+#endif
+
+
+               switch(ntohs(skb->protocol)) {
+               case ETH_P_IP:
+/*
+                       if(!(ip = skb->ip_hdr))
+*/
+                               ip = (struct iphdr *)(skb->data + ppp_hdrlen);
+
+                       match_rule.protfam = ISDN_TIMRU_PROTFAM_IP;
+                       match_rule.rule.ip.saddr.s_addr = ip->saddr;
+                       match_rule.rule.ip.daddr.s_addr = ip->daddr;
+                       match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
+
+                       switch(ip->protocol) {
+                       case IPPROTO_ICMP:
+                               if(!(icmp = (struct icmphdr *)((unsigned long *)ip+ip->ihl))) {
+                                       VERBOSE_PRINTK(5, "", "IP/ICMP HDR-ERR\n");
+                               } else {
+                                       match_rule.rule.ip.protocol = ISDN_TIMRU_IP_ICMP;
+                                       match_rule.rule.ip.pt.type.from = icmp->type;
+
+                                       if(dev->net_verbose >= 5) {
+                                               printk("IP/ICMP ");
+                                               printk_ip(ip->saddr);
+                                               printk(" --> ");
+                                               printk_ip(ip->daddr);
+                                               printk("/");
+                                               printk_port(icmp->type);
+                                               printk("\n");
+                                       }
+                               }
+                               break;
+       
+                       case IPPROTO_IGMP:
+                               match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
+                               VERBOSE_PRINTK(5, "", "IP/IGMP\n");
+                               break;
+       
+                       case IPPROTO_IPIP:
+                               match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
+                               VERBOSE_PRINTK(5, "", "IP/IPIP\n");
+                               break;
+       
+                       case IPPROTO_TCP:
+                               if(!(tcp = (struct tcphdr *)((unsigned long *)ip+ip->ihl))) {
+                                       VERBOSE_PRINTK(5, "", "IP/TCP HDR-ERR\n");
+                               } else {
+                                       match_rule.rule.ip.protocol = ISDN_TIMRU_IP_TCP;
+                                       match_rule.rule.ip.pt.port.s_from = tcp->source;
+                                       match_rule.rule.ip.pt.port.d_from = tcp->dest;
+
+                                       if(dev->net_verbose >= 5) {
+                                               printk("IP/TCP ");
+                                               printk_ip(ip->saddr);
+                                               printk("/");
+                                               printk_port(tcp->source);
+                                               printk(" --> ");
+                                               printk_ip(ip->daddr);
+                                               printk("/");
+                                               printk_port(tcp->dest);
+                                               printk("\n");
+                                       }
+                               }
+                               break;
+       
+                       case IPPROTO_EGP:
+                               match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
+                               VERBOSE_PRINTK(5, "", "IP/EGP\n");
+                               break;
+       
+                       case IPPROTO_PUP:
+                               match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
+                               VERBOSE_PRINTK(5, "" "IP/PUP\n");
+                               break;
+       
+                       case IPPROTO_UDP:
+                               if(!(udp=(struct udphdr *)((unsigned long *)ip+ip->ihl))) {
+                                       VERBOSE_PRINTK(5, "", "IP/UDP HDR-ERR\n");
+                               } else {
+                                       match_rule.rule.ip.protocol = ISDN_TIMRU_IP_UDP;
+                                       match_rule.rule.ip.pt.port.s_from = udp->source;
+                                       match_rule.rule.ip.pt.port.d_from = udp->dest;
+
+                                       if(dev->net_verbose >= 5) {
+                                               printk("IP/UDP ");
+                                               printk_ip(ip->saddr);
+                                               printk("/");
+                                               printk_port(udp->source);
+                                               printk(" --> ");
+                                               printk_ip(ip->daddr);
+                                               printk("/");
+                                               printk_port(udp->dest);
+                                               printk("\n");
+                                       }
+                               }
+                               break;
+
+                       case IPPROTO_IDP:
+                               match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
+                               VERBOSE_PRINTK(5, "", "IP/IDP\n");
+                               break;
+       
+                       default:
+                               match_rule.rule.ip.protocol = ISDN_TIMRU_IP_WILDCARD;
+                               if(dev->net_verbose >= 5) {
+                                       printk("IP/? (%x)\n", ip->protocol);
+#ifdef ISDN_DEBUG_NET_DUMP
+                                       isdn_dumppkt("R:", (u_char *)skb, skb->len, 180);
+#endif
+                               }
+                               break;
+                       }
+                       break;
+
+               case ETH_P_ARP:
+                       VERBOSE_PRINTK(5, "", "ARP/?\n");
+                       break;
+
+               case ETH_P_IPX:
+                       VERBOSE_PRINTK(5, "", "IPX/?\n");
+                       break;
+
+               case ETH_P_802_2:
+                       VERBOSE_PRINTK(5, "", "802.2/?\n");
+                       break;
+
+               case ETH_P_802_3:
+                       VERBOSE_PRINTK(5, "", "802.3/?\n");
+                       break;
+
+               default:
+                       if(dev->net_verbose >= 5) {
+                               printk("?/? (%x)\n", ntohs(skb->protocol));
+#ifdef ISDN_DEBUG_NET_DUMP
+                               isdn_dumppkt("R:", (u_char *)skb, skb->len, 1800);
+#endif
+                       }
+                       break;
+               }
+
+#ifdef CONFIG_ISDN_TIMRU_USE_MASQ
+#ifdef CONFIG_IP_MASQUERADE
+               check_for_masq = 0;
+               m_saddr = m_daddr = (__u32)0;
+               m_sport = m_dport = (__u16)0;
+               m_prot = 0;
+
+               switch(match_rule.protfam) {
+               case ISDN_TIMRU_PROTFAM_IP:
+                       m_saddr = match_rule.rule.ip.saddr.s_addr;
+                       m_daddr = match_rule.rule.ip.daddr.s_addr;
+
+                       switch(match_rule.rule.ip.protocol) {
+                       case ISDN_TIMRU_IP_TCP:
+                               m_prot = IPPROTO_TCP;
+                               m_sport = match_rule.rule.ip.pt.port.s_from;
+                               m_dport = match_rule.rule.ip.pt.port.d_from;
+                               check_for_masq = 1;
+                               break;
+
+                       case ISDN_TIMRU_IP_UDP:
+                               m_prot = IPPROTO_UDP;
+                               m_sport = match_rule.rule.ip.pt.port.s_from;
+                               m_dport = match_rule.rule.ip.pt.port.d_from;
+                               check_for_masq = 1;
+                               break;
+
+#if 0
+#ifdef CONFIG_IP_MASQUERADE_ICMP
+                       case ISDN_TIMRU_IP_ICMP:
+                               m_sport = match_rule.rule.ip.pt.type.from;
+                               m_dport = 0;
+                               check_for_masq = 1;
+                               break;
+#endif
+#endif
+                       }
+                       break;
+               }
+
+               if(check_for_masq) {
+                       masq = NULL;
+
+                       switch(type) {
+                       case ISDN_TIMRU_BRINGUP:
+                       case ISDN_TIMRU_KEEPUP_OUT:
+                               if((masq = ip_masq_in_get_2(m_prot, m_daddr, m_dport, m_saddr, m_sport))) {
+                                       match_rule.rule.ip.saddr.s_addr = m_saddr;
+                                       match_rule.rule.ip.daddr.s_addr = m_daddr;
+                                       switch(m_prot) {
+                                       case IPPROTO_TCP:
+                                       case IPPROTO_UDP:
+                                               match_rule.rule.ip.pt.port.s_from = m_sport;
+                                               match_rule.rule.ip.pt.port.d_from = m_dport;
+                                               break;
+                                       }
+                               }
+                               break;
+
+                       case ISDN_TIMRU_KEEPUP_IN:
+                               if((masq = ip_masq_in_get_2(m_prot, m_saddr, m_sport, m_daddr, m_dport))) {
+                                       match_rule.rule.ip.saddr.s_addr = m_daddr;
+                                       match_rule.rule.ip.daddr.s_addr = m_saddr;
+                                       switch(m_prot) {
+                                       case IPPROTO_TCP:
+                                       case IPPROTO_UDP:
+                                               match_rule.rule.ip.pt.port.s_from = m_sport;
+                                               match_rule.rule.ip.pt.port.d_from = m_dport;
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+
+                       if(masq && dev->net_verbose >= 5) {
+                               printk(KERN_DEBUG "MASQ-TIMRU: ");
+                               printk_ip(masq->maddr);
+                               printk("/");
+                               printk_port(masq->mport);
+                               printk(": ");
+                               printk_ip(masq->saddr);
+                               printk("/");
+                               printk_port(masq->sport);
+                               printk(" --> ");
+                               printk_ip(masq->daddr);
+                               printk("/");
+                               printk_port(masq->dport);
+                               printk("\n");
+                       }
+               }
+#endif
+#endif
+               break;
+       }
+
+       new_timeout = lp->onhtime;
+
+       if(prot && lp->timeout_rules) {
+               isdn_timeout_rule       *head, *tor;
+               int                     pf, found_match, i;
+
+               pf = match_rule.protfam;
+               found_match = 0;
+
+               while(1) {
+                       head = tor = lp->timeout_rules->timru[type][pf];
+                       i = 0;
+                       while(tor) {
+                               if((isdn_timru_match(&match_rule, tor) > 0) ^ (tor->neg > 0)) {
+                                       found_match = 1;
+                                       new_timeout = tor->timeout;
+                               }
+
+                               if(found_match) {
+#ifdef DEBUG_RULES
+                                       printk(KERN_DEBUG "Rule %d-%d-%d matches\n", type, pf, i);
+#endif
+                                       break;
+                               }
+
+                               if(tor->next == head)
+                                       tor = NULL;
+                               else {
+                                       tor = tor->next;
+                                       i++;
+                               }
+                       }
+
+                       if(! found_match && pf != ISDN_TIMRU_PROTFAM_WILDCARD)
+                               pf = ISDN_TIMRU_PROTFAM_WILDCARD;
+                       else
+                               break;
+               }
+
+               if(! found_match) {
+                       new_timeout = lp->timeout_rules->defaults[type];
+#ifdef DEBUG_RULES
+                       printk("No rule matches: using default\n");
+#endif
+               }
+       }
+
+       if(type == ISDN_TIMRU_BRINGUP) {
+               if(new_timeout > 0) {
+                       lp->huptimeout = new_timeout;
+                       lp->huptimer = 0;
+               }
+       } else {
+               if(new_timeout > lp->huptimeout
+               || lp->huptimeout - lp->huptimer < new_timeout) {
+                       lp->huptimeout = new_timeout;
+                       lp->huptimer = 0;
+               }
+       }
+
+       return(new_timeout);
+}
+
+
+static int
+isdn_timru_match(isdn_timeout_rule *this, isdn_timeout_rule *rule) {
+       if(this->protfam != rule->protfam)
+               return(0);
+
+       switch(rule->protfam) {
+       case ISDN_TIMRU_PROTFAM_WILDCARD:
+               return(1);
+               break;
+
+       case ISDN_TIMRU_PROTFAM_PPP:
+               if(rule->rule.ppp.protocol == ISDN_TIMRU_PPP_WILDCARD
+               || rule->rule.ppp.protocol == this->rule.ppp.protocol)
+                       return(1);
+               break;
+
+       case ISDN_TIMRU_PROTFAM_IP:
+               if((this->rule.ip.saddr.s_addr & rule->rule.ip.smask.s_addr) != rule->rule.ip.saddr.s_addr
+               || (this->rule.ip.daddr.s_addr & rule->rule.ip.dmask.s_addr) != rule->rule.ip.daddr.s_addr)
+                       return(0);
+
+               if(rule->rule.ip.protocol == ISDN_TIMRU_IP_WILDCARD)
+                       return(1);
+
+               if(rule->rule.ip.protocol != this->rule.ip.protocol)
+                       return(0);
+
+               switch(rule->rule.ip.protocol) {
+               case ISDN_TIMRU_IP_ICMP:
+                       if(this->rule.ip.pt.type.from < rule->rule.ip.pt.type.from
+                       || this->rule.ip.pt.type.from > rule->rule.ip.pt.type.to)
+                               return(0);
+                       break;
+
+               case ISDN_TIMRU_IP_TCP:
+               case ISDN_TIMRU_IP_UDP:
+                       if(this->rule.ip.pt.port.s_from < rule->rule.ip.pt.port.s_from
+                       || this->rule.ip.pt.port.s_from > rule->rule.ip.pt.port.s_to)
+                               return(0);
+
+                       if(this->rule.ip.pt.port.d_from < rule->rule.ip.pt.port.d_from
+                       || this->rule.ip.pt.port.d_from > rule->rule.ip.pt.port.d_to)
+                               return(0);
+
+                       break;
+               }
+               break;
+       }
+
+       return(1);
+}
+
+
+static int
+isdn_timru_rule_equals(isdn_timeout_rule *this, isdn_timeout_rule *rule) {
+       if(this->neg != rule->neg
+       || this->protfam != rule->protfam)
+               return(0);
+
+       switch(rule->protfam) {
+       case ISDN_TIMRU_PROTFAM_PPP:
+               if(this->rule.ppp.protocol != rule->rule.ppp.protocol)
+                       return(0);
+               break;
+
+       case ISDN_TIMRU_PROTFAM_IP:
+               if(this->rule.ip.protocol != rule->rule.ip.protocol
+               || this->rule.ip.saddr.s_addr != rule->rule.ip.saddr.s_addr
+               || this->rule.ip.smask.s_addr != rule->rule.ip.smask.s_addr
+               || this->rule.ip.daddr.s_addr != rule->rule.ip.daddr.s_addr
+               || this->rule.ip.dmask.s_addr != rule->rule.ip.dmask.s_addr)
+                       return(0);
+
+               switch(rule->rule.ip.protocol) {
+               case ISDN_TIMRU_IP_ICMP:
+                       if(this->rule.ip.pt.type.from != rule->rule.ip.pt.type.from
+                       || this->rule.ip.pt.type.to != rule->rule.ip.pt.type.to)
+                               return(0);
+                       break;
+
+               case ISDN_TIMRU_IP_TCP:
+               case ISDN_TIMRU_IP_UDP:
+                       if(this->rule.ip.pt.port.s_from != rule->rule.ip.pt.port.s_from
+                       || this->rule.ip.pt.port.s_to != rule->rule.ip.pt.port.s_to
+                       || this->rule.ip.pt.port.d_from != rule->rule.ip.pt.port.d_from
+                       || this->rule.ip.pt.port.d_to != rule->rule.ip.pt.port.d_to)
+                               return(0);
+
+                       break;
+               }
+               break;
+       }
+
+       return(1);
+}
+
+
+int
+isdn_timru_alloc_timeout_rules(struct device *ndev) {
+       isdn_net_local  *lp = (isdn_net_local *)ndev->priv;
+       int             i, j;
+       ulong           flags;
+
+       save_flags(flags);
+       cli();
+       if(!(lp->timeout_rules = (struct isdn_timeout_rules *)kmalloc(sizeof(struct isdn_timeout_rules), GFP_KERNEL))) {
+               restore_flags(flags);
+               printk(KERN_WARNING "isdn_timru: failed to allocate memory.\n");
+               return(-ENOMEM);
+       }
+
+       memset((char *)lp->timeout_rules, 0, sizeof(struct isdn_timeout_rules));
+
+       for(i = 0; i < ISDN_TIMRU_NUM_CHECK; i++) {
+               lp->timeout_rules->defaults[i] = lp->onhtime;
+               for(j = 0; j < ISDN_TIMRU_NUM_PROTFAM; j++)
+                       lp->timeout_rules->timru[i][j] = NULL;
+       }
+
+       restore_flags(flags);
+       return(0);
+}
+
+
+int
+isdn_timru_free_timeout_rules(struct device *ndev) {
+       isdn_net_local          *lp = (isdn_net_local *)ndev->priv;
+       isdn_timeout_rule       *head, *this, *next;
+       int                     i, j;
+       ulong                   flags;
+
+       if(!lp->timeout_rules)
+               return(-1);
+
+       save_flags(flags);
+       cli();
+       for(i = 0; i < ISDN_TIMRU_NUM_CHECK; i++)
+               for(j = 0; j < ISDN_TIMRU_NUM_CHECK; j++)
+                       if((head = lp->timeout_rules->timru[i][j])) {
+                               this = head;
+                               do {
+                                       next = this->next;
+                                       kfree(this);
+                               } while(next == head);
+                       }
+
+       kfree(lp->timeout_rules);
+       lp->timeout_rules = NULL;
+
+       restore_flags(flags);
+       return(0);
+}
+
+
+int
+isdn_timru_add_rule(int where, struct device *ndev, isdn_timeout_rule *rule) {
+       isdn_net_local          *lp = (isdn_net_local *)ndev->priv;
+       isdn_timeout_rule       **head;
+       ulong                   flags;
+       int                     ret;
+
+       if(!lp->timeout_rules)
+               if((ret = isdn_timru_alloc_timeout_rules(ndev)))
+                       return(ret);
+
+       if(rule->timeout < 0)
+               return(-EINVAL);
+
+       save_flags(flags);
+       cli();
+
+       head = &(lp->timeout_rules->timru[rule->type][rule->protfam]);
+
+       if(! *head)
+               rule->next = rule->prev = *head = rule;
+       else {
+               rule->next = *head;
+               rule->prev = (*head)->prev;
+               (*head)->prev->next = rule;
+               (*head)->prev = rule;
+
+               if(where == 0)  /* add to head of chain */
+                       *head = rule;
+       }
+
+       restore_flags(flags);
+       return(0);
+}
+
+
+int
+isdn_timru_del_rule(struct device *ndev, isdn_timeout_rule *rule) {
+       isdn_net_local                  *lp = (isdn_net_local *)ndev->priv;
+       isdn_timeout_rule       **head, *this;
+       ulong                           flags;
+
+       if(!lp->timeout_rules)
+               return(-EINVAL);
+
+       save_flags(flags);
+       cli();
+
+       head = &(lp->timeout_rules->timru[rule->type][rule->protfam]);
+
+       if(! *head) {
+               restore_flags(flags);
+               return(-EINVAL);
+       }
+
+       this = *head;
+       do {
+               if(isdn_timru_rule_equals(this, rule)) {
+                       if(this->next != this) {        /* more than one rule */
+                               this->prev->next = this->next;
+                               this->next->prev = this->prev;
+
+                               if(this == *head)
+                                       *head = this->next;
+                       } else
+                               *head = NULL;
+
+                       kfree(this);
+                       restore_flags(flags);
+                       return(0);
+               } else
+                       this = this->next;
+       } while(this == *head);
+
+       restore_flags(flags);
+       return(-EINVAL);
+}
+
+
+int
+isdn_timru_set_default(int type, struct device *ndev, int def) {
+       isdn_net_local  *lp = (isdn_net_local *)ndev->priv;
+       ulong           flags;
+       int             ret;
+
+       if(!lp->timeout_rules)
+               if((ret = isdn_timru_alloc_timeout_rules(ndev)))
+                       return(ret);
+
+       if(def < 0)
+               return(-EINVAL);
+
+       save_flags(flags);
+       cli();
+
+       lp->timeout_rules->defaults[type] = def;
+
+       restore_flags(flags);
+       return(0);
+}
+
+
+int
+isdn_timru_get_rule(struct device *ndev, isdn_timeout_rule **rule, int i, int j, int k) {
+       isdn_net_local                  *lp = (isdn_net_local *)ndev->priv;
+       isdn_timeout_rule       *head, *this;
+       int                             l;
+       ulong                           flags;
+
+       if(!lp->timeout_rules
+       || i < 0 || i > ISDN_TIMRU_NUM_CHECK
+       || j < 0 || j > ISDN_TIMRU_NUM_PROTFAM
+       || k < 0)
+               return(-EINVAL);
+
+       save_flags(flags);
+       cli();
+
+       if(!(this = head = lp->timeout_rules->timru[i][j])) {
+               restore_flags(flags);
+               return(-EINVAL);
+       }
+
+       for(l = 0; l < k; l++) {
+               if(this->next == head) {
+                       restore_flags(flags);
+                       return(-EINVAL);
+               }
+               this = this->next;
+       }
+
+       *rule = this;
+       restore_flags(flags);
+       return(0);
+}
+
+
+int
+isdn_timru_get_default(int type, struct device *ndev, int *ret) {
+       isdn_net_local  *lp = (isdn_net_local *)ndev->priv;
+       ulong           flags;
+
+       if(!lp->timeout_rules)
+               return(-EINVAL);
+
+       save_flags(flags);
+       cli();
+
+       *ret = lp->timeout_rules->defaults[type];
+
+       restore_flags(flags);
+       return(0);
+}
+
+
+int
+isdn_timru_ioctl_add_rule(isdn_ioctl_timeout_rule *iorule)
+{
+       isdn_net_dev            *p = isdn_net_findif(iorule->name);
+       isdn_timeout_rule       *r;
+
+       if(p) {
+               if(iorule->where < 0) { /* set default */
+                       return(isdn_timru_set_default(iorule->type, &p->dev, iorule->defval));
+               } else {
+                       if(!(r = (isdn_timeout_rule *) kmalloc(sizeof(isdn_timeout_rule), GFP_KERNEL)))
+                               return(-ENOMEM);
+                       memcpy((char *)r, (char *)&iorule->rule, sizeof(isdn_timeout_rule));
+                       return(isdn_timru_add_rule(iorule->where, &p->dev, r));
+               }
+       }
+       return(-ENODEV);
+}
+
+
+int
+isdn_timru_ioctl_del_rule(isdn_ioctl_timeout_rule *iorule)
+{
+       isdn_net_dev            *p = isdn_net_findif(iorule->name);
+       isdn_timeout_rule       *r;
+
+       if(p) {
+               if(!(r = (isdn_timeout_rule *) kmalloc(sizeof(isdn_timeout_rule), GFP_KERNEL)))
+                       return(-ENOMEM);
+               memcpy((char *)r, (char *)&iorule->rule, sizeof(isdn_timeout_rule));
+               return(isdn_timru_del_rule(&p->dev, r));
+       }
+       return(-ENODEV);
+}
+
+
+int
+isdn_timru_ioctl_get_rule(isdn_ioctl_timeout_rule *iorule)
+{
+       int                     ret, def;
+       isdn_net_dev            *p = isdn_net_findif(iorule->name);
+       isdn_timeout_rule       *r;
+
+       if(p) {
+               if(iorule->where < 0) { /* get default */
+                       if((ret = isdn_timru_get_default(iorule->type, &p->dev, &def)) < 0)
+                               return(ret);
+
+                       iorule->protfam = p->local->huptimer;
+                       iorule->index = p->local->huptimeout;
+                       iorule->defval = def;
+               } else {
+                       if(isdn_timru_get_rule(&p->dev, &r, iorule->type, iorule->protfam, iorule->index))
+                               return(-ENOMEM);
+
+                       memcpy((char *)&iorule->rule, (char *)r, sizeof(isdn_timeout_rule));
+               }
+               return(0);
+       }
+       return(-ENODEV);
+}
+
+#endif
index 1c77c6c009f6ff58ac4051b84e86872688e7e5b4..bfa895424886acc7c8aa5f4bc19ccfc0f21072b5 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_tty.c,v 1.47 1998/02/22 19:44:14 fritz Exp $
+/* $Id: isdn_tty.c,v 1.63 1999/04/12 12:33:39 fritz Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  *
  * This program is free software; you can redistribute it and/or modify
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.c,v $
+ * Revision 1.63  1999/04/12 12:33:39  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.62  1999/03/02 12:04:48  armin
+ * -added ISDN_STAT_ADDCH to increase supported channels after
+ *  register_isdn().
+ * -ttyI now goes on-hook on ATZ when B-Ch is connected.
+ * -added timer-function for register S7 (Wait for Carrier).
+ * -analog modem (ISDN_PROTO_L2_MODEM) implementations.
+ * -on L2_MODEM a string will be appended to the CONNECT-Message,
+ *  which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN.
+ * -variable "dialing" used for ATA also, for interrupting call
+ *  establishment and register S7.
+ *
+ * Revision 1.61  1999/01/27 22:53:11  he
+ * minor updates (spellings, jiffies wrap around in isdn_tty)
+ *
+ * Revision 1.60  1998/11/15 23:57:32  keil
+ * changes for 2.1.127
+ *
+ * Revision 1.59  1998/08/20 13:50:15  keil
+ * More support for hybrid modem (not working yet)
+ *
+ * Revision 1.58  1998/07/26 18:48:45  armin
+ * Added silence detection in voice receive mode.
+ *
+ * Revision 1.57  1998/06/26 15:12:36  fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 1.56  1998/06/18 23:31:51  fritz
+ * Replaced cli()/restore_flags() in isdn_tty_write() by locking.
+ * Removed direct-senddown feature in isdn_tty_write because it will
+ * never succeed with locking and is useless anyway.
+ *
+ * Revision 1.55  1998/06/17 19:50:55  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.54  1998/06/07 00:20:13  fritz
+ * abc cleanup.
+ *
+ * Revision 1.53  1998/06/02 12:10:16  detabc
+ * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
+ * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
+ *
+ * Revision 1.52  1998/03/19 13:18:21  keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
+ * Revision 1.51  1998/03/08 14:26:11  detabc
+ * change kfree_skb to dev_kfree_skb
+ * remove SET_SKB_FREE
+ *
+ * Revision 1.50  1998/03/08 13:14:28  detabc
+ * abc-extension support for kernels > 2.1.x
+ * first try (sorry experimental)
+ *
+ * Revision 1.49  1998/03/08 00:01:59  fritz
+ * Bugfix: Lowlevel module usage and channel usage were not
+ *         reset on NO DCHANNEL.
+ *
+ * Revision 1.48  1998/03/07 12:28:15  tsbogend
+ * fixed kernel unaligned traps on Linux/Alpha
+ *
  * Revision 1.47  1998/02/22 19:44:14  fritz
  * Bugfixes and improvements regarding V.110, V.110 now running.
  *
@@ -254,7 +321,7 @@ static int bit2si[8] =
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.47 $";
+char *isdn_tty_revision = "$Revision: 1.63 $";
 
 #define DLE 0x10
 #define ETX 0x03
@@ -270,6 +337,8 @@ char *isdn_tty_revision = "$Revision: 1.47 $";
 #define REG_LF        4
 #define REG_BS        5
 
+#define REG_WAITC     7
+
 #define REG_RESP     12
 #define BIT_RESP      1
 #define REG_RESPNUM  12
@@ -287,8 +356,6 @@ char *isdn_tty_revision = "$Revision: 1.47 $";
 #define REG_CPPP     12
 #define BIT_CPPP    128
 
-#define REG_DELXMT   13
-#define BIT_DELXMT    1
 #define REG_T70      13
 #define BIT_T70       2
 #define BIT_T70_EXT  32
@@ -300,6 +367,8 @@ char *isdn_tty_revision = "$Revision: 1.47 $";
 #define BIT_CIDONCE  16
 #define REG_RUNG     13
 #define BIT_RUNG     64
+#define REG_RESRXT   13
+#define BIT_RESRXT  128
 
 #define REG_L2PROT   14
 #define REG_L3PROT   15
@@ -389,6 +458,8 @@ isdn_tty_readmodem(void)
                                r = 0;
 #ifdef CONFIG_ISDN_AUDIO
                                isdn_audio_eval_dtmf(info);
+                               if ((info->vonline & 1) && (info->emu.vpar[1]))
+                                       isdn_audio_eval_silence(info);
 #endif
                                if ((tty = info->tty)) {
                                        if (info->mcr & UART_MCR_RTS) {
@@ -445,6 +516,8 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
        
        if (info->vonline)
                isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
+       if ((info->vonline & 1) && (info->emu.vpar[1]))
+               isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
 #endif
        if ((info->online < 2)
 #ifdef CONFIG_ISDN_AUDIO
@@ -566,8 +639,8 @@ isdn_tty_tint(modem_info * info)
                                           info->isdn_channel, 1, skb)) == len) {
                struct tty_struct *tty = info->tty;
                info->send_outstanding++;
-               info->msr |= UART_MSR_CTS;
-               info->lsr |= UART_LSR_TEMT;
+               info->msr &= ~UART_MSR_CTS;
+               info->lsr &= ~UART_LSR_TEMT;
                if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
                    tty->ldisc.write_wakeup)
                        (tty->ldisc.write_wakeup) (tty);
@@ -579,8 +652,6 @@ isdn_tty_tint(modem_info * info)
                dev_kfree_skb(skb);
                return;
        }
-       if (slen)
-               skb_pull(skb, slen);
        skb_queue_head(&info->xmit_queue, skb);
 }
 
@@ -702,7 +773,6 @@ isdn_tty_senddown(modem_info * info)
        int audio_len;
 #endif
        struct sk_buff *skb;
-       unsigned long flags;
 
 #ifdef CONFIG_ISDN_AUDIO
        if (info->vonline & 4) {
@@ -717,18 +787,20 @@ isdn_tty_senddown(modem_info * info)
                }
        }
 #endif
-       save_flags(flags);
-       cli();
-       if (!(buflen = info->xmit_count)) {
-               restore_flags(flags);
+       if (!(buflen = info->xmit_count))
                return;
-       }
-       if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
+       if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
                info->msr &= ~UART_MSR_CTS;
-       info->lsr &= ~UART_LSR_TEMT;
+       info->lsr &= ~UART_LSR_TEMT;    
+       /* info->xmit_count is modified here and in isdn_tty_write().
+        * So we return here if isdn_tty_write() is in the
+        * critical section.
+        */
+       atomic_inc(&info->xmit_lock);
+       if (!(atomic_dec_and_test(&info->xmit_lock)))
+               return;
        if (info->isdn_driver < 0) {
                info->xmit_count = 0;
-               restore_flags(flags);
                return;
        }
        skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
@@ -742,7 +814,6 @@ isdn_tty_senddown(modem_info * info)
        skb = dev_alloc_skb(skb_res + buflen);
 #endif
        if (!skb) {
-               restore_flags(flags);
                printk(KERN_WARNING
                       "isdn_tty: Out of memory in ttyI%d senddown\n",
                       info->line);
@@ -751,7 +822,6 @@ isdn_tty_senddown(modem_info * info)
        skb_reserve(skb, skb_res);
        memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
        info->xmit_count = 0;
-       restore_flags(flags);
 #ifdef CONFIG_ISDN_AUDIO
        if (info->vonline & 2) {
                /* For now, ifmt is fixed to 1 (alaw), since this
@@ -859,7 +929,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
                        break;
                }
 #ifdef CONFIG_ISDN_AUDIO
-       if (si == 1) {
+       if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
                l2 = ISDN_PROTO_L2_TRANS;
                usg = ISDN_USAGE_VOICE;
        }
@@ -907,9 +977,11 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
                cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
                cmd.command = ISDN_CMD_DIAL;
                info->dialing = 1;
+               info->emu.carrierwait = 0;
                strcpy(dev->num[i], n);
                isdn_info_update();
                isdn_command(&cmd);
+               isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
        }
 }
 
@@ -942,6 +1014,10 @@ isdn_tty_modem_hup(modem_info * info, int local)
                kfree(info->dtmf_state);
                info->dtmf_state = NULL;
        }
+       if (info->silence_state) {
+               kfree(info->silence_state);
+               info->silence_state = NULL;
+       }
        if (info->adpcms) {
                kfree(info->adpcms);
                info->adpcms = NULL;
@@ -965,8 +1041,9 @@ isdn_tty_modem_hup(modem_info * info, int local)
                }
                isdn_all_eaz(info->isdn_driver, info->isdn_channel);
                info->emu.mdmreg[REG_RINGCNT] = 0;
-               usage = (info->emu.mdmreg[REG_SI1I] == 1) ?
-                   ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
+               usage = ((info->emu.mdmreg[REG_SI1I] != 1) || 
+                   (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ?
+                       ISDN_USAGE_MODEM : ISDN_USAGE_VOICE;
                isdn_free_channel(info->isdn_driver, info->isdn_channel,
                                  usage);
        }
@@ -978,6 +1055,226 @@ isdn_tty_modem_hup(modem_info * info, int local)
        }
 }
 
+/*
+ * Begin of a CAPI like interface, currently used only for 
+ * supplementary service (CAPI 2.0 part III)
+ */
+#include "avmb1/capicmd.h"  /* this should be moved in a common place */
+
+int
+isdn_tty_capi_facility(capi_msg *cm) {
+       return(-1); /* dummy */
+}
+
+/* isdn_tty_suspend() tries to suspend the current tty connection
+ */
+static void
+isdn_tty_suspend(char *id, modem_info * info, atemu * m)
+{
+       isdn_ctrl cmd;
+       
+       int l;
+
+       if (!info)
+               return;
+
+#ifdef ISDN_DEBUG_MODEM_SERVICES
+       printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
+#endif
+       l = strlen(id);
+       if ((info->isdn_driver >= 0) && l) {
+               cmd.parm.cmsg.Length = l+17;
+               cmd.parm.cmsg.Command = CAPI_FACILITY;
+               cmd.parm.cmsg.Subcommand = CAPI_REQ;
+               cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
+               cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
+               cmd.parm.cmsg.para[1] = 0;
+               cmd.parm.cmsg.para[2] = l + 3;
+               cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
+               cmd.parm.cmsg.para[4] = 0;
+               cmd.parm.cmsg.para[5] = l;
+               strncpy(&cmd.parm.cmsg.para[6], id, l);
+               cmd.command = CAPI_PUT_MESSAGE;
+               cmd.driver = info->isdn_driver;
+               cmd.arg = info->isdn_channel;
+               isdn_command(&cmd);
+       }
+}
+
+/* isdn_tty_resume() tries to resume a suspended call
+ * setup of the lower levels before that. unfortunatly here is no
+ * checking for compatibility of used protocols implemented by Q931
+ * It does the same things like isdn_tty_dial, the last command
+ * is different, may be we can merge it.
+ */
+
+static void
+isdn_tty_resume(char *id, modem_info * info, atemu * m)
+{
+       int usg = ISDN_USAGE_MODEM;
+       int si = 7;
+       int l2 = m->mdmreg[REG_L2PROT];
+       isdn_ctrl cmd;
+       ulong flags;
+       int i;
+       int j;
+       int l;
+
+       l = strlen(id);
+       if (!l) {
+               isdn_tty_modem_result(4, info);
+               return;
+       }
+       for (j = 7; j >= 0; j--)
+               if (m->mdmreg[REG_SI1] & (1 << j)) {
+                       si = bit2si[j];
+                       break;
+               }
+#ifdef CONFIG_ISDN_AUDIO
+       if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
+               l2 = ISDN_PROTO_L2_TRANS;
+               usg = ISDN_USAGE_VOICE;
+       }
+#endif
+       m->mdmreg[REG_SI1I] = si2bit[si];
+       save_flags(flags);
+       cli();
+       i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+       if (i < 0) {
+               restore_flags(flags);
+               isdn_tty_modem_result(6, info);
+       } else {
+               info->isdn_driver = dev->drvmap[i];
+               info->isdn_channel = dev->chanmap[i];
+               info->drv_index = i;
+               dev->m_idx[i] = info->line;
+               dev->usage[i] |= ISDN_USAGE_OUTGOING;
+               info->last_dir = 1;
+//             strcpy(info->last_num, n);
+               isdn_info_update();
+               restore_flags(flags);
+               cmd.driver = info->isdn_driver;
+               cmd.arg = info->isdn_channel;
+               cmd.command = ISDN_CMD_CLREAZ;
+               isdn_command(&cmd);
+               strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+               cmd.driver = info->isdn_driver;
+               cmd.command = ISDN_CMD_SETEAZ;
+               isdn_command(&cmd);
+               cmd.driver = info->isdn_driver;
+               cmd.command = ISDN_CMD_SETL2;
+               info->last_l2 = l2;
+               cmd.arg = info->isdn_channel + (l2 << 8);
+               isdn_command(&cmd);
+               cmd.driver = info->isdn_driver;
+               cmd.command = ISDN_CMD_SETL3;
+               cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+               isdn_command(&cmd);
+               cmd.driver = info->isdn_driver;
+               cmd.arg = info->isdn_channel;
+               cmd.parm.cmsg.Length = l+17;
+               cmd.parm.cmsg.Command = CAPI_FACILITY;
+               cmd.parm.cmsg.Subcommand = CAPI_REQ;
+               cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
+               cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
+               cmd.parm.cmsg.para[1] = 0;
+               cmd.parm.cmsg.para[2] = l+3;
+               cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
+               cmd.parm.cmsg.para[4] = 0;
+               cmd.parm.cmsg.para[5] = l;
+               strncpy(&cmd.parm.cmsg.para[6], id, l);
+               cmd.command =CAPI_PUT_MESSAGE;
+/*             info->dialing = 1;
+               strcpy(dev->num[i], n);
+               isdn_info_update();
+*/
+               isdn_command(&cmd);
+       }
+}
+
+/* isdn_tty_send_msg() sends a message to a HL driver
+ * This is used for hybrid modem cards to send AT commands to it
+ */
+
+static void
+isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
+{
+       int usg = ISDN_USAGE_MODEM;
+       int si = 7;
+       int l2 = m->mdmreg[REG_L2PROT];
+       isdn_ctrl cmd;
+       ulong flags;
+       int i;
+       int j;
+       int l;
+
+       l = strlen(msg);
+       if (!l) {
+               isdn_tty_modem_result(4, info);
+               return;
+       }
+       for (j = 7; j >= 0; j--)
+               if (m->mdmreg[REG_SI1] & (1 << j)) {
+                       si = bit2si[j];
+                       break;
+               }
+#ifdef CONFIG_ISDN_AUDIO
+       if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
+               l2 = ISDN_PROTO_L2_TRANS;
+               usg = ISDN_USAGE_VOICE;
+       }
+#endif
+       m->mdmreg[REG_SI1I] = si2bit[si];
+       save_flags(flags);
+       cli();
+       i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+       if (i < 0) {
+               restore_flags(flags);
+               isdn_tty_modem_result(6, info);
+       } else {
+               info->isdn_driver = dev->drvmap[i];
+               info->isdn_channel = dev->chanmap[i];
+               info->drv_index = i;
+               dev->m_idx[i] = info->line;
+               dev->usage[i] |= ISDN_USAGE_OUTGOING;
+               info->last_dir = 1;
+               isdn_info_update();
+               restore_flags(flags);
+               cmd.driver = info->isdn_driver;
+               cmd.arg = info->isdn_channel;
+               cmd.command = ISDN_CMD_CLREAZ;
+               isdn_command(&cmd);
+               strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+               cmd.driver = info->isdn_driver;
+               cmd.command = ISDN_CMD_SETEAZ;
+               isdn_command(&cmd);
+               cmd.driver = info->isdn_driver;
+               cmd.command = ISDN_CMD_SETL2;
+               info->last_l2 = l2;
+               cmd.arg = info->isdn_channel + (l2 << 8);
+               isdn_command(&cmd);
+               cmd.driver = info->isdn_driver;
+               cmd.command = ISDN_CMD_SETL3;
+               cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+               isdn_command(&cmd);
+               cmd.driver = info->isdn_driver;
+               cmd.arg = info->isdn_channel;
+               cmd.parm.cmsg.Length = l+14;
+               cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
+               cmd.parm.cmsg.Subcommand = CAPI_REQ;
+               cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
+               cmd.parm.cmsg.para[0] = l+1;
+               strncpy(&cmd.parm.cmsg.para[1], msg, l);
+               cmd.parm.cmsg.para[l+1] = 0xd;
+               cmd.command =CAPI_PUT_MESSAGE;
+/*             info->dialing = 1;
+               strcpy(dev->num[i], n);
+               isdn_info_update();
+*/
+               isdn_command(&cmd);
+       }
+}
+
 static inline int
 isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
 {
@@ -1138,15 +1435,16 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
 {
        int c;
        int total = 0;
-       ulong flags;
        modem_info *info = (modem_info *) tty->driver_data;
 
        if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
                return 0;
        if (!tty)
                return 0;
-       save_flags(flags);
-       cli();
+       if (from_user)
+               down(&info->write_sem);
+       /* See isdn_tty_senddown() */
+       atomic_inc(&info->xmit_lock);
        while (1) {
                c = MIN(count, info->xmit_size - info->xmit_count);
                if (info->isdn_driver >= 0)
@@ -1205,10 +1503,6 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
                        } else
 #endif
                                info->xmit_count += c;
-                       if (m->mdmreg[REG_DELXMT] & BIT_DELXMT) {
-                               isdn_tty_senddown(info);
-                               isdn_tty_tint(info);
-                       }
                } else {
                        info->msr |= UART_MSR_CTS;
                        info->lsr |= UART_LSR_TEMT;
@@ -1228,7 +1522,9 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
        }
        if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
                isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
-       restore_flags(flags);
+       atomic_dec(&info->xmit_lock);
+       if (from_user)
+               up(&info->write_sem);
        return total;
 }
 
@@ -1359,7 +1655,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;
 }
 
@@ -1383,7 +1679,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;
 }
 
@@ -1567,7 +1863,12 @@ isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
 static int
 isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
 {
-       DECLARE_WAITQUEUE(wait, current); 
+#if LINUX_VERSION_CODE < 131841
+       struct wait_queue wait =
+       {current, NULL};
+#else
+       DECLARE_WAITQUEUE(wait, NULL);
+#endif
        int do_clocal = 0;
        unsigned long flags;
        int retval;
@@ -1891,6 +2192,7 @@ isdn_tty_reset_profile(atemu * m)
        m->profile[19] = 0;
        m->profile[20] = 0;
        m->pmsn[0] = '\0';
+       m->plmsn[0] = '\0';
 }
 
 #ifdef CONFIG_ISDN_AUDIO
@@ -1911,6 +2213,7 @@ isdn_tty_modem_reset_regs(modem_info * info, int force)
        if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
                memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
                memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
+               memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
                info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
        }
 #ifdef CONFIG_ISDN_AUDIO
@@ -1924,6 +2227,7 @@ modem_write_profile(atemu * m)
 {
        memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG);
        memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
+       memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
        if (dev->profd)
                send_sig(SIGIO, dev->profd, 1);
 }
@@ -1987,6 +2291,11 @@ isdn_tty_modem_init(void)
        }
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
                info = &m->info[i];
+#if LINUX_VERSION_CODE < 131841
+               info->write_sem = MUTEX;
+#else
+               init_MUTEX(&info->write_sem);
+#endif
                sprintf(info->last_cause, "0000");
                sprintf(info->last_num, "none");
                info->last_dir = 0;
@@ -2003,8 +2312,13 @@ isdn_tty_modem_init(void)
                info->blocked_open = 0;
                info->callout_termios = m->cua_modem.init_termios;
                info->normal_termios = m->tty_modem.init_termios;
+#if LINUX_VERSION_CODE < 131841
+               info->open_wait = 0;
+               info->close_wait = 0;
+#else
                init_waitqueue_head(&info->open_wait);
                init_waitqueue_head(&info->close_wait);
+#endif
                info->isdn_driver = -1;
                info->isdn_channel = -1;
                info->drv_index = -1;
@@ -2023,25 +2337,67 @@ isdn_tty_modem_init(void)
        return 0;
 }
 
+static int
+isdn_tty_match_icall(char *cid, atemu *emu, int di)
+{
+#ifdef ISDN_DEBUG_MODEM_ICALL
+       printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n",
+              emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di),
+              emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]);
+#endif
+       if (strlen(emu->lmsn)) {
+               char *p = emu->lmsn;
+               char *q;
+               int  tmp;
+               int  ret = 0;
+
+               while (1) {
+                       if ((q = strchr(p, ';')))
+                               *q = '\0';
+                       if ((tmp = isdn_wildmat(cid, isdn_map_eaz2msn(p, di))) > ret)
+                               ret = tmp;
+#ifdef ISDN_DEBUG_MODEM_ICALL
+                       printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
+                              p, isdn_map_eaz2msn(emu->msn, di), tmp);
+#endif
+                       if (q) {
+                               *q = ';';
+                               p = q;
+                               p++;
+                       }
+                       if (!tmp)
+                               return 0;
+                       if (!q)
+                               break;
+               }
+               return ret;
+       } else
+               return isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di));
+}
+
 /*
  * An incoming call-request has arrived.
  * Search the tty-devices for an appropriate device and bind
  * it to the ISDN-Channel.
- * Return Index to dev->mdm or -1 if none found.
+ * Return:
+ *
+ *  0 = No matching device found.
+ *  1 = A matching device found.
+ *  3 = No match found, but eventually would match, if
+ *      CID is longer.
  */
 int
 isdn_tty_find_icall(int di, int ch, setup_parm setup)
 {
        char *eaz;
        int i;
+       int wret;
        int idx;
        int si1;
        int si2;
        char nr[32];
        ulong flags;
 
-       save_flags(flags);
-       cli();
        if (!setup.phone[0]) {
                nr[0] = '0';
                nr[1] = '\0';
@@ -2058,17 +2414,14 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
 #ifdef ISDN_DEBUG_MODEM_ICALL
        printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
 #endif
+       wret = 0;
+       save_flags(flags);
+       cli();
        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
                modem_info *info = &dev->mdm.info[i];
-#ifdef ISDN_DEBUG_MODEM_ICALL
-               printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i,
-                      info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di),
-                      info->emu.mdmreg[REG_SI1], info->emu.mdmreg[REG_SI2]);
-#endif
-               if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di),
-                            eaz)) &&                             /* EAZ is matching */
-                   (info->emu.mdmreg[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */
-                   (info->emu.mdmreg[REG_SI2] == si2)) {         /* SI2 is matching */
+
+               if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */
+                   (info->emu.mdmreg[REG_SI2] == si2)) {         /* SI2 is matching */
                        idx = isdn_dc2minor(di, ch);
 #ifdef ISDN_DEBUG_MODEM_ICALL
                        printk(KERN_DEBUG "m_fi: match1\n");
@@ -2080,34 +2433,42 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
 #ifndef FIX_FILE_TRANSFER
                                (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
 #endif
-                           (info->isdn_driver == -1) &&
-                           (info->isdn_channel == -1) &&
-                           (USG_NONE(dev->usage[idx]))) {
-                               info->isdn_driver = di;
-                               info->isdn_channel = ch;
-                               info->drv_index = idx;
-                               dev->m_idx[idx] = info->line;
-                               dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
-                               dev->usage[idx] |= (si1 == 1) ? ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
-                               strcpy(dev->num[idx], nr);
-                               info->emu.mdmreg[REG_SI1I] = si2bit[si1];
-                               info->emu.mdmreg[REG_PLAN] = setup.plan;
-                               info->emu.mdmreg[REG_SCREEN] = setup.screen;
-                               isdn_info_update();
-                               restore_flags(flags);
-                               printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
-                                      info->line);
-                               info->msr |= UART_MSR_RI;
-                               isdn_tty_modem_result(2, info);
-                               isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
-                               return info->line;
+                               (info->isdn_driver == -1) &&
+                               (info->isdn_channel == -1) &&
+                               (USG_NONE(dev->usage[idx]))) {
+                               int matchret;
+
+                               if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
+                                       wret = matchret;
+                               if (!matchret) {                  /* EAZ is matching */
+                                       info->isdn_driver = di;
+                                       info->isdn_channel = ch;
+                                       info->drv_index = idx;
+                                       dev->m_idx[idx] = info->line;
+                                       dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
+                                       dev->usage[idx] |= ((si1 != 1) || (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ? 
+                                               ISDN_USAGE_MODEM : ISDN_USAGE_VOICE;
+                                       strcpy(dev->num[idx], nr);
+                                       strcpy(info->emu.cpn, eaz);
+                                       info->emu.mdmreg[REG_SI1I] = si2bit[si1];
+                                       info->emu.mdmreg[REG_PLAN] = setup.plan;
+                                       info->emu.mdmreg[REG_SCREEN] = setup.screen;
+                                       isdn_info_update();
+                                       restore_flags(flags);
+                                       printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
+                                              info->line);
+                                       info->msr |= UART_MSR_RI;
+                                       isdn_tty_modem_result(2, info);
+                                       isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
+                                       return 1;
+                               }
                        }
                }
        }
-       printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
-              dev->drv[di]->reject_bus ? "rejected" : "ignored");
        restore_flags(flags);
-       return -1;
+       printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
+              ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored");
+       return (wret == 2)?3:0;
 }
 
 #define TTY_IS_ACTIVE(info) \
@@ -2128,7 +2489,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
                         case ISDN_STAT_CINF:
                                 printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
                                 info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
-                                if (e == c->parm.num)
+                                if (e == (char *)c->parm.num)
                                        info->emu.charge = 0;
                                
                                 break;                 
@@ -2169,10 +2530,11 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
                                printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
 #endif
                                if (TTY_IS_ACTIVE(info)) {
-                                       if (info->dialing == 1) {
-                                               info->dialing = 0;
+                                       if (info->dialing == 1) 
                                                isdn_tty_modem_result(7, info);
-                                       }
+                                       if (info->dialing > 1) 
+                                               isdn_tty_modem_result(3, info);
+                                       info->dialing = 0;
 #ifdef ISDN_DEBUG_MODEM_HUP
                                        printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
 #endif
@@ -2191,14 +2553,20 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
                                if (TTY_IS_ACTIVE(info)) {
                                        info->msr |= UART_MSR_DCD;
                                        info->emu.charge = 0;
-                                       if (info->dialing) {
-                                               info->dialing = 0;
+                                       if (info->dialing & 0xf)
                                                info->last_dir = 1;
-                                       else
+                                       else
                                                info->last_dir = 0;
+                                       info->dialing = 0;
                                        info->rcvsched = 1;
-                                       if (USG_MODEM(dev->usage[i]))
-                                               isdn_tty_modem_result(5, info);
+                                       if (USG_MODEM(dev->usage[i])) {
+                                               if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
+                                                       strcpy(info->emu.connmsg, c->parm.num);
+                                                       isdn_tty_modem_result(1, info);
+                                               }
+                                               else
+                                                       isdn_tty_modem_result(5, info);
+                                       }
                                        if (USG_VOICE(dev->usage[i]))
                                                isdn_tty_modem_result(11, info);
                                        return 1;
@@ -2228,11 +2596,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c)
                                                sprintf(info->last_cause, "0000");
                                                isdn_tty_modem_result(6, info);
                                        }
-                                       info->msr &= ~UART_MSR_DCD;
-                                       if (info->online) {
-                                               isdn_tty_modem_result(3, info);
-                                               info->online = 0;
-                                       }
+                                       isdn_tty_modem_hup(info, 0);
                                        return 1;
                                }
                                break;
@@ -2393,7 +2757,7 @@ isdn_tty_modem_result(int code, modem_info * info)
         "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
         "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
        ulong flags;
-       char s[10];
+       char s[ISDN_MSNLEN+10];
 
        switch (code) {
                case 2:
@@ -2473,7 +2837,20 @@ isdn_tty_modem_result(int code, modem_info * info)
                        }
                        isdn_tty_at_cout(msg[code], info);
                        switch (code) {
+                               case 1:
+                                       switch (m->mdmreg[REG_L2PROT]) {
+                                               case ISDN_PROTO_L2_MODEM:
+                                                       isdn_tty_at_cout(" ", info);
+                                                       isdn_tty_at_cout(m->connmsg, info);
+                                                       break;
+                                       }
+                                       break;
                                case 2:
+                                       /* Append CPN, if enabled */
+                                       if ((m->mdmreg[REG_RESRXT] & BIT_RESRXT)) {
+                                               sprintf(s, "/%s", m->cpn);
+                                               isdn_tty_at_cout(s, info);
+                                       }
                                        /* Print CID only once, _after_ 1.st RING */
                                        if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
                                            (m->mdmreg[REG_RINGCNT] == 1)) {
@@ -2560,7 +2937,9 @@ isdn_tty_show_profile(int ridx, modem_info * info)
 static void
 isdn_tty_get_msnstr(char *n, char **p)
 {
-       while ((*p[0] >= '0' && *p[0] <= '9') || (*p[0] == ','))
+       while ((*p[0] >= '0' && *p[0] <= '9') ||
+              /* Why a comma ??? */
+              (*p[0] == ','))
                *n++ = *p[0]++;
        *n = '\0';
 }
@@ -2626,6 +3005,9 @@ isdn_tty_report(modem_info * info)
                case ISDN_PROTO_L2_TRANS:
                        isdn_tty_at_cout("transparent", info);
                        break;
+               case ISDN_PROTO_L2_MODEM:
+                       isdn_tty_at_cout("modem", info);
+                       break;
                default:
                        isdn_tty_at_cout("unknown", info);
                        break;
@@ -2668,6 +3050,8 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
        int i;
        char rb[100];
 
+#define MAXRB (sizeof(rb) - 1)
+
        switch (*p[0]) {
                case 'B':
                        /* &B - Set Buffersize */
@@ -2719,6 +3103,15 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
                        isdn_tty_reset_profile(m);
                        isdn_tty_modem_reset_regs(info, 1);
                        break;
+               case 'L':
+                       /* &L -Set Numbers to listen on */
+                       p[0]++;
+                       i = 0;
+                       while ((strchr("0123456789,*[]?;", *p[0])) &&
+                              (i < ISDN_LMSNLEN))
+                               m->lmsn[i++] = *p[0]++;
+                       m->lmsn[i] = '\0';
+                       break;
                case 'R':
                        /* &R - Set V.110 bitrate adaption */
                        p[0]++;
@@ -2774,6 +3167,11 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
                        sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
                                strlen(m->msn) ? m->msn : "None");
                        isdn_tty_at_cout(rb, info);
+                       if (strlen(m->lmsn)) {
+                               isdn_tty_at_cout("\r\nListen: ", info);
+                               isdn_tty_at_cout(m->lmsn, info);
+                               isdn_tty_at_cout("\r\n", info);
+                       }
                        break;
                case 'W':
                        /* &W - Write Profile */
@@ -2939,9 +3337,10 @@ isdn_tty_cmd_ATA(modem_info * info)
 #ifdef CONFIG_ISDN_AUDIO
                /* If more than one bit set in reg18, autoselect Layer2 */
                if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
-                       if (m->mdmreg[REG_SI1I] == 1)
-                               l2 = ISDN_PROTO_L2_TRANS;
-                       else
+                       if (m->mdmreg[REG_SI1I] == 1) {
+                               if (l2 != ISDN_PROTO_L2_MODEM)
+                                       l2 = ISDN_PROTO_L2_TRANS;
+                       } else
                                l2 = ISDN_PROTO_L2_X75I;
                }
 #endif
@@ -2957,7 +3356,10 @@ isdn_tty_cmd_ATA(modem_info * info)
                cmd.driver = info->isdn_driver;
                cmd.arg = info->isdn_channel;
                cmd.command = ISDN_CMD_ACCEPTD;
+               info->dialing = 16;
+               info->emu.carrierwait = 0;
                isdn_command(&cmd);
+               isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
        } else
                isdn_tty_modem_result(8, info);
 }
@@ -3221,6 +3623,11 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
                                printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
                                PARSE_ERROR1;
                        }
+                       info->silence_state = isdn_audio_silence_init(info->silence_state);
+                       if (!info->silence_state) {
+                               printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n");
+                               PARSE_ERROR1;
+                       }
                        if (m->vpar[3] < 5) {
                                info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
                                if (!info->adpcmr) {
@@ -3247,31 +3654,27 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
                                        break;
                                case '=':
                                        p[0]++;
-                                       switch (*p[0]) {
-                                               case '0':
-                                               case '1':
-                                               case '2':
-                                               case '3':
-                                                       par1 = isdn_getnum(p);
-                                                       if ((par1 < 0) || (par1 > 31))
-                                                               PARSE_ERROR1;
-                                                       if (*p[0] != ',')
-                                                               PARSE_ERROR1;
-                                                       p[0]++;
-                                                       par2 = isdn_getnum(p);
-                                                       if ((par2 < 0) || (par2 > 255))
-                                                               PARSE_ERROR1;
-                                                       m->vpar[1] = par1;
-                                                       m->vpar[2] = par2;
-                                                       break;
-                                               case '?':
-                                                       p[0]++;
-                                                       isdn_tty_at_cout("\r\n<0-31>,<0-255>",
-                                                                  info);
-                                                       break;
-                                               default:
+                                       if ((*p[0]>='0') && (*p[0]<='9')) {
+                                               par1 = isdn_getnum(p);
+                                               if ((par1 < 0) || (par1 > 31))
                                                        PARSE_ERROR1;
-                                       }
+                                               if (*p[0] != ',')
+                                                       PARSE_ERROR1;
+                                               p[0]++;
+                                               par2 = isdn_getnum(p);
+                                               if ((par2 < 0) || (par2 > 255))
+                                                       PARSE_ERROR1;
+                                               m->vpar[1] = par1;
+                                               m->vpar[2] = par2;
+                                               break;
+                                       } else 
+                                       if (*p[0] == '?') {
+                                               p[0]++;
+                                               isdn_tty_at_cout("\r\n<0-31>,<0-255>",
+                                                          info);
+                                               break;
+                                       } else
+                                       PARSE_ERROR1;
                                        break;
                                default:
                                        PARSE_ERROR1;
@@ -3445,7 +3848,7 @@ isdn_tty_parse_at(modem_info * info)
                                p++;
                                if (info->msr & UART_MSR_DCD)
                                        /* if B-Channel is up */
-                                       isdn_tty_modem_result(5, info);
+                                       isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info);
                                else
                                        isdn_tty_modem_result(3, info);
                                return;
@@ -3486,29 +3889,46 @@ isdn_tty_parse_at(modem_info * info)
                        case 'Z':
                                /* Z - Load Registers from Profile */
                                p++;
+                               if (info->msr & UART_MSR_DCD) {
+                                       info->online = 0;
+                                       isdn_tty_on_hook(info);
+                               }
                                isdn_tty_modem_reset_regs(info, 1);
                                break;
-#ifdef CONFIG_ISDN_AUDIO
                        case '+':
                                p++;
                                switch (*p) {
+#ifdef CONFIG_ISDN_AUDIO
                                        case 'F':
                                                p++;
                                                if (isdn_tty_cmd_PLUSF(&p, info))
                                                        return;
                                                break;
                                        case 'V':
-                                               if (!(m->mdmreg[REG_SI1] & 1))
+                                               if ((!(m->mdmreg[REG_SI1] & 1)) ||
+                                                       (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM))
                                                        PARSE_ERROR;
                                                p++;
                                                if (isdn_tty_cmd_PLUSV(&p, info))
                                                        return;
                                                break;
+#endif                          /* CONFIG_ISDN_AUDIO */
+                                       case 'S':       /* SUSPEND */
+                                               p++;
+                                               isdn_tty_get_msnstr(ds, &p);
+                                               isdn_tty_suspend(ds, info, m);
+                                               break;
+                                       case 'R':       /* RESUME */
+                                               isdn_tty_get_msnstr(ds, &p);
+                                               isdn_tty_resume(ds, info, m);
+                                       case 'M':       /* MESSAGE */
+                                               p++;
+                                               isdn_tty_send_msg(info, m, p);
+                                               break;
                                        default:
                                                PARSE_ERROR;
                                }
                                break;
-#endif                          /* CONFIG_ISDN_AUDIO */
                        case '&':
                                p++;
                                if (isdn_tty_cmd_ATand(&p, info))
@@ -3673,3 +4093,28 @@ isdn_tty_modem_xmit(void)
        }
        isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
 }
+
+/*
+ * Check all channels if we have a 'no carrier' timeout.
+ * Timeout value is set by Register S7.
+ */
+void
+isdn_tty_carrier_timeout(void)
+{
+       int ton = 0;
+       int i;
+
+       for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+               modem_info *info = &dev->mdm.info[i];
+               if (info->dialing) {
+                       if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
+                               info->dialing = 0;
+                               isdn_tty_modem_result(3, info);
+                               isdn_tty_modem_hup(info, 1);
+                       }
+                       else
+                               ton = 1;
+               }
+       }
+       isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
+}
index 986cb54f7640d36ee3841bba9535e83a50816972..663648e58018b892ad0e8a241cd86a510ae34d66 100644 (file)
@@ -1,8 +1,8 @@
-/* $Id: isdn_tty.h,v 1.10 1997/03/02 14:29:26 fritz Exp $
+/* $Id: isdn_tty.h,v 1.13 1999/04/12 12:33:46 fritz Exp $
 
  * header for Linux ISDN subsystem, tty related functions (linklevel).
  *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
  *
  * This program is free software; you can redistribute it and/or modify
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdn_tty.h,v $
+ * Revision 1.13  1999/04/12 12:33:46  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.12  1999/03/02 12:04:51  armin
+ * -added ISDN_STAT_ADDCH to increase supported channels after
+ *  register_isdn().
+ * -ttyI now goes on-hook on ATZ when B-Ch is connected.
+ * -added timer-function for register S7 (Wait for Carrier).
+ * -analog modem (ISDN_PROTO_L2_MODEM) implementations.
+ * -on L2_MODEM a string will be appended to the CONNECT-Message,
+ *  which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN.
+ * -variable "dialing" used for ATA also, for interrupting call
+ *  establishment and register S7.
+ *
+ * Revision 1.11  1998/03/19 13:18:27  keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
  * Revision 1.10  1997/03/02 14:29:26  fritz
  * More ttyI related cleanup.
  *
@@ -56,6 +74,7 @@
 
 extern void isdn_tty_modem_escape(void);
 extern void isdn_tty_modem_ring(void);
+extern void isdn_tty_carrier_timeout(void);
 extern void isdn_tty_modem_xmit(void);
 extern int isdn_tty_modem_init(void);
 extern void isdn_tty_readmodem(void);
@@ -63,3 +82,4 @@ extern int isdn_tty_find_icall(int, int, setup_parm);
 extern void isdn_tty_cleanup_xmit(modem_info *);
 extern int isdn_tty_stat_callback(int, isdn_ctrl *);
 extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
+extern int isdn_tty_capi_facility(capi_msg *cm); 
index 2ae21fcf38ef26470195a392d1cd13ee9d27f461..d0594fe34520770c1ad488e0db5bea56bcb502cb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn_x25iface.c,v 1.3 1998/02/20 17:25:20 fritz Exp $
+/* $Id: isdn_x25iface.c,v 1.6 1999/01/27 22:53:19 he Exp $
  * stuff needed to support the Linux X.25 PLP code on top of devices that
  * can provide a lab_b service using the concap_proto mechanism.
  * This module supports a network interface wich provides lapb_sematics
  * goes to another -- device related -- concap_proto support source file.
  *
  * $Log: isdn_x25iface.c,v $
+ * Revision 1.6  1999/01/27 22:53:19  he
+ * minor updates (spellings, jiffies wrap around in isdn_tty)
+ *
+ * Revision 1.5  1998/10/30 17:55:39  he
+ * dialmode for x25iface and multulink ppp
+ *
+ * Revision 1.4  1998/06/17 19:51:00  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
  * Revision 1.3  1998/02/20 17:25:20  fritz
  * Changes for recent kernels.
  *
@@ -302,7 +313,12 @@ int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
        case 0x01: /* dl_connect request */
                if( *state == WAN_DISCONNECTED ){
                        *state = WAN_CONNECTING;
-                       cprot -> dops -> connect_req(cprot);
+                       ret = cprot -> dops -> connect_req(cprot);
+                       if(ret){
+                               /* reset state and notify upper layer about
+                                * immidiatly failed attempts */
+                               isdn_x25iface_disconn_ind(cprot);
+                       }
                } else {
                        illegal_state_warn( *state, firstbyte );
                }
index 46d4f651843fd1a67c91733f7fa74880c4118f37..2e580e1c7a611784cf5e3cbd8d3204612b99de79 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.c,v 1.4 1998/02/24 21:39:05 he Exp $
+/* $Id: isdnloop.c,v 1.8 1998/11/18 18:59:43 armin Exp $
 
  * ISDN low-level module implementing a dummy loop driver.
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdnloop.c,v $
+ * Revision 1.8  1998/11/18 18:59:43  armin
+ * changes for 2.1.127
+ *
+ * Revision 1.7  1998/10/30 18:58:03  he
+ * typecast to suppress a compiler warning
+ *
+ * Revision 1.6  1998/06/17 19:51:37  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.5  1998/04/14 20:59:32  he
+ * merged 2.1.94 changes
+ *
  * Revision 1.4  1998/02/24 21:39:05  he
  * L2_PROT_X25DTE / DCE
  * additional state 17 and new internal signal messages "BCON_I"
@@ -42,7 +56,7 @@
 #include "isdnloop.h"
 
 static char
-*revision = "$Revision: 1.4 $";
+*revision = "$Revision: 1.8 $";
 
 static int isdnloop_addcard(char *);
 
@@ -1312,7 +1326,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
                                                        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");
+                                                       c->parm.num[0] ? c->parm.num : (u_char *) "0123456789");
                                        i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
                                }
                                break;
index cacd686d7202733703bf86127358d863a7491c4e..42906c143ee3e833b46b4b9d94810336c0799362 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.h,v 1.2 1997/10/01 09:22:07 fritz Exp $
+/* $Id: isdnloop.h,v 1.3 1998/04/14 20:59:35 he Exp $
 
  * Loopback lowlevel module for testing of linklevel.
  *
@@ -19,6 +19,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * $Log: isdnloop.h,v $
+ * Revision 1.3  1998/04/14 20:59:35  he
+ * merged 2.1.94 changes
+ *
  * Revision 1.2  1997/10/01 09:22:07  fritz
  * Removed old compatibility stuff for 2.0.X kernels.
  * From now on, this code is for 2.1.X ONLY!
index 14c0bdcb89cdc04630792ff9f86f7550b2fde623..afa22b7401a67270d9565d8370829b2436fbbb20 100644 (file)
  *        callbacks for the FSM
  */
 
+/*
+ * Fix: 19981230 - Carlos Morgado <chbm@techie.com>
+ * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN 
+ * NULL pointer dereference in cb_in_1 (originally fixed in 2.0)
+ */
+
+
 #define __NO_VERSION__
 
 #include <linux/module.h>
@@ -164,12 +171,24 @@ void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
          *  ictl.num >= strlen() + strlen() + 5
          */
 
+       if (cbdata->data.setup.CallingPN == NULL) {
+               printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n");
+               strcpy(ictl.parm.setup.phone, "0");
+       }
+       else {
                strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN);
+       }
+       if (cbdata->data.setup.CalledPN == NULL) {
+               printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n");
+               strcpy(ictl.parm.setup.eazmsn, "0");
+       }
+       else {
                strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN);
-               ictl.parm.setup.si1 = 7;
-               ictl.parm.setup.si2 = 0;
-               ictl.parm.setup.plan = 0;
-               ictl.parm.setup.screen = 0;
+       }
+       ictl.parm.setup.si1 = 7;
+       ictl.parm.setup.si2 = 0;
+       ictl.parm.setup.plan = 0;
+       ictl.parm.setup.screen = 0;
 
 #ifdef DEBUG
        printk(KERN_DEBUG "statstr: %s\n", ictl.num);
index 43c36fa9ee2c7abfd96cca886c2858684f5f50ed..a3186ac1168ed1270f885a3f7461e2b927a772c0 100644 (file)
@@ -86,6 +86,9 @@ int pcbit_init_dev(int board, int mem_base, int irq)
 
        dev_pcbit[board] = dev;
        memset(dev, 0, sizeof(struct pcbit_dev));
+#if LINUX_VERSION_CODE >= 131841
+       init_waitqueue_head(&dev->set_running_wq);
+#endif
 
        if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF )
                dev->sh_mem = (unsigned char*) mem_base;
index d284cc70f0d540b1cb8e3a140dec8950fef64705..0dbdb5fd138ff914ba8a6d3d07370db4f6c61746 100644 (file)
@@ -68,7 +68,11 @@ struct pcbit_dev {
        struct frame_buf *write_queue;
 
        /* Protocol start */
+#if LINUX_VERSION_CODE < 131841
+       struct wait_queue *set_running_wq;
+#else
        wait_queue_head_t set_running_wq;
+#endif
        struct timer_list set_running_timer;
 
        struct timer_list error_recover_timer;
index 628cdc80396fd981a043653140066d9dd317a5d5..4d4765f792470ad1e817c78095f586d9441df2c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  $Id: message.c,v 1.3 1998/01/31 22:10:55 keil Exp $
+ *  $Id: message.c,v 1.4 1999/01/05 18:29:47 he Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  message.c - functions for sending and receiving control messages
index ae7576e9483ea2820e3dda18444ed19a308288dd..f3aa41c0ba457ca7abbc8e478080690314cbacc1 100644 (file)
@@ -22,7 +22,7 @@
 static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
 static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
 static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
-static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
+static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_AUTO };
 
 extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
 extern int parport_ax_init(void);
@@ -146,8 +146,11 @@ EXPORT_SYMBOL(parport_claim);
 EXPORT_SYMBOL(parport_claim_or_block);
 EXPORT_SYMBOL(parport_release);
 EXPORT_SYMBOL(parport_register_port);
+EXPORT_SYMBOL(parport_announce_port);
 EXPORT_SYMBOL(parport_unregister_port);
 EXPORT_SYMBOL(parport_quiesce);
+EXPORT_SYMBOL(parport_register_driver);
+EXPORT_SYMBOL(parport_unregister_driver);
 EXPORT_SYMBOL(parport_register_device);
 EXPORT_SYMBOL(parport_unregister_device);
 EXPORT_SYMBOL(parport_enumerate);
@@ -157,6 +160,7 @@ EXPORT_SYMBOL(parport_proc_register);
 EXPORT_SYMBOL(parport_proc_unregister);
 EXPORT_SYMBOL(parport_probe_hook);
 EXPORT_SYMBOL(parport_parse_irqs);
+EXPORT_SYMBOL(parport_parse_dmas);
 
 void inc_parport_count(void)
 {
index 0a4e4f92150ddc4cda78bde6aca40e55d04b19a0..aea3cc97c9ad861ed50608c96cc4b6edd3a8b0d8 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/pci.h>
 
 #include <asm/io.h>
 
@@ -847,9 +848,59 @@ static int __init probe_one_port(unsigned long int base,
        if (parport_probe_hook)
                (*parport_probe_hook)(p);
 
+       /* Now that we've told the sharing engine about the port, and
+          found out its characteristics, let the high-level drivers
+          know about it. */
+       parport_announce_port (p);
+
        return 1;
 }
 
+/* Look for PCI parallel port cards. */
+static int __init parport_pc_init_pci (int irq, int dma)
+{
+       int count = 0;
+#ifdef CONFIG_PCI
+       int i;
+       struct {
+               unsigned int vendor;
+               unsigned int device;
+               unsigned int numports;
+               struct {
+                       unsigned int lo;
+                       unsigned int hi; /* -ve if not there */
+               } addr[4];
+       } cards[] = {
+               { 0, }
+       };
+
+       if (!pci_present ())
+               return 0;
+
+       for (i = 0; cards[i].vendor; i++) {
+               struct pci_dev *pcidev = NULL;
+               while ((pcidev = pci_find_device (cards[i].vendor,
+                                                 cards[i].device,
+                                                 pcidev)) != NULL) {
+                       int n;
+                       for (n = 0; n < cards[i].numports; n++) {
+                               int lo = cards[i].addr[n].lo;
+                               int hi = cards[i].addr[n].hi;
+                               int io_lo = pcidev->base_address[lo];
+                               int io_hi = ((hi < 0) ? 0 :
+                                            pcidev->base_address[hi]);
+                               io_lo &= PCI_BASE_ADDRESS_IO_MASK;
+                               io_hi &= PCI_BASE_ADDRESS_IO_MASK;
+                               count += probe_one_port (io_lo, io_hi,
+                                                        irq, dma);
+                       }
+               }
+       }
+#endif /* CONFIG_PCI */
+
+       return count;
+}
+
 int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
 {
        int count = 0, i = 0;
@@ -866,6 +917,7 @@ int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
                count += probe_one_port(0x3bc, 0x7bc, irq[0], dma[0]);
                count += probe_one_port(0x378, 0x778, irq[0], dma[0]);
                count += probe_one_port(0x278, 0x678, irq[0], dma[0]);
+               count += parport_pc_init_pci (irq[0], dma[0]);
        }
 
        return count;
@@ -874,13 +926,22 @@ int __init parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
 #ifdef MODULE
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
 static int io_hi[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
-static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
+static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
+static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
+
+MODULE_PARM_DESC(io, "base address");
 MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+
+MODULE_PARM_DESC(io_hi, "base address for ECR");
 MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+
+MODULE_PARM_DESC(irq, "irq line to use (or 'auto' or 'none')");
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
+
+MODULE_PARM_DESC(dma, "dma channel to use (or 'auto' or 'none')");
+MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 
 int init_module(void)
 {      
@@ -888,9 +949,30 @@ int init_module(void)
           the irq values. */
        unsigned int i;
        for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
-       parport_parse_irqs(i, irq, irqval);
+       if (i) {
+               if (parport_parse_irqs(i, irq, irqval)) return 1;
+               if (parport_parse_dmas(i, dma, dmaval)) return 1;
+       }
+       else {
+               /* The user can make us use any IRQs or DMAs we find. */
+               int val;
+
+               if (irq[0] && !parport_parse_irqs (1, irq, &val))
+                       switch (val) {
+                       case PARPORT_IRQ_NONE:
+                       case PARPORT_IRQ_AUTO:
+                               irqval[0] = val;
+                       }
+
+               if (dma[0] && !parport_parse_dmas (1, dma, &val))
+                       switch (val) {
+                       case PARPORT_DMA_NONE:
+                       case PARPORT_DMA_AUTO:
+                               dmaval[0] = val;
+                       }
+       }
 
-       return (parport_pc_init(io, io_hi, irqval, dma)?0:1);
+       return (parport_pc_init(io, io_hi, irqval, dmaval)?0:1);
 }
 
 void cleanup_module(void)
index f413c0a655a78ca3396d6bbbbe26081636d17bd0..929c0ad73e0ea65f66d076d8365a1264067fa852 100644 (file)
 static struct parport *portlist = NULL, *portlist_tail = NULL;
 spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
 
+static struct parport_driver *driver_chain = NULL;
+spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
+
+static void call_driver_chain (int attach, struct parport *port)
+{
+       struct parport_driver *drv;
+
+       for (drv = driver_chain; drv; drv = drv->next) {
+               if (attach)
+                       drv->attach (port);
+               else
+                       drv->detach (port);
+       }
+}
+
+int parport_register_driver (struct parport_driver *drv)
+{
+       struct parport *port;
+
+       spin_lock (&driverlist_lock);
+       drv->next = driver_chain;
+       driver_chain = drv;
+       spin_unlock (&driverlist_lock);
+
+       for (port = portlist; port; port = port->next)
+               drv->attach (port);
+
+       return 0;
+}
+
+void parport_unregister_driver (struct parport_driver *arg)
+{
+       struct parport_driver *drv = driver_chain, *olddrv = NULL;
+
+       while (drv) {
+               if (drv == arg) {
+                       spin_lock (&driverlist_lock);
+                       if (olddrv)
+                               olddrv->next = drv->next;
+                       else
+                               driver_chain = drv->next;
+                       spin_unlock (&driverlist_lock);
+                       return;
+               }
+               olddrv = drv;
+               drv = drv->next;
+       }
+}
+
 void (*parport_probe_hook)(struct parport *port) = NULL;
 
 /* Return a list of all the ports we know about. */
@@ -138,10 +187,19 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
        return tmp;
 }
 
+void parport_announce_port (struct parport *port)
+{
+       /* Let drivers know that a new port has arrived. */
+       call_driver_chain (1, port);
+}
+
 void parport_unregister_port(struct parport *port)
 {
        struct parport *p;
 
+       /* Spread the word. */
+       call_driver_chain (0, port);
+
        spin_lock(&parportlist_lock);
        if (portlist == port) {
                if ((portlist = port->next) == NULL)
@@ -517,23 +575,38 @@ void parport_release(struct pardevice *dev)
        }
 }
 
-void parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
+static int parport_parse_params (int nports, const char *str[], int val[],
+                                int automatic, int none)
 {
        unsigned int i;
-       for (i = 0; i < nports && irqstr[i]; i++) {
-               if (!strncmp(irqstr[i], "auto", 4))
-                       irqval[i] = PARPORT_IRQ_AUTO;
-               else if (!strncmp(irqstr[i], "none", 4))
-                       irqval[i] = PARPORT_IRQ_NONE;
+       for (i = 0; i < nports && str[i]; i++) {
+               if (!strncmp(str[i], "auto", 4))
+                       val[i] = automatic;
+               else if (!strncmp(str[i], "none", 4))
+                       val[i] = none;
                else {
                        char *ep;
-                       unsigned long r = simple_strtoul(irqstr[i], &ep, 0);
-                       if (ep != irqstr[i])
-                               irqval[i] = r;
+                       unsigned long r = simple_strtoul(str[i], &ep, 0);
+                       if (ep != str[i])
+                               val[i] = r;
                        else {
-                               printk("parport: bad irq specifier `%s'\n", irqstr[i]);
-                               return;
+                               printk("parport: bad specifier `%s'\n", str[i]);
+                               return -1;
                        }
                }
        }
+
+       return 0;
+}
+
+int parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
+{
+       return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO,
+                                    PARPORT_IRQ_NONE);
+}
+
+int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[])
+{
+       return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO,
+                                    PARPORT_DMA_NONE);
 }
index 124e6e7bca13cbaa3da2a65cf0b1df3300dfbd02..c0ea7c21b967a7c64b36e20ecf6bba5a1a46b128 100644 (file)
@@ -805,3 +805,4 @@ struct device loopback_dev = {
 };
 
 struct device *dev_base = &loopback_dev;
+rwlock_t dev_base_lock = RW_LOCK_UNLOCKED;
index 1111e19c73ee2af482e937de0db19f5df9acb891..491a502573765b47e3935ba3ccf92b1af553b248 100644 (file)
@@ -2023,8 +2023,10 @@ __initfunc(void arcnet_init(void))
   for (c=0; c< (arcnet_num_devs-1); c++)
     arcnet_devs[c].next=&arcnet_devs[c+1];
 
+  write_lock_bh(&dev_base_lock);
   arcnet_devs[c].next=dev_base;
   dev_base=&arcnet_devs[0];
+  write_unlock_bh(&dev_base_lock);
 
   /* Give names to those without them */
 
@@ -2078,9 +2080,11 @@ void arcnet_makename(char *device)
   for (;;)
     {
       sprintf(device, "arc%d", arcnum);
+      read_lock_bh(&dev_base_lock);
       for (dev = dev_base; dev; dev=dev->next)
        if (dev->name != device && !strcmp(dev->name, device))
          break;
+      read_unlock_bh(&dev_base_lock);
       if (!dev)
        return;
       arcnum++;
index 6116f3642b9a6a4177719550b97a82c0a1027098..4a9c60a7d51ff0a25123c24525ee12da57fbe8ea 100644 (file)
@@ -641,11 +641,16 @@ __initfunc(int bpq_init(void))
        });
 #endif
 
+       read_lock_bh(&dev_base_lock);
        for (dev = dev_base; dev != NULL; dev = dev->next) {
-               if (dev_is_ethdev(dev))
+               if (dev_is_ethdev(dev)) {
+                       read_unlock_bh(&dev_base_lock);
                        bpq_new_device(dev);
+                       read_lock_bh(&dev_base_lock);
+               }
        }
-
+       read_unlock_bh(&dev_base_lock);
+out:
        return 0;
 }
 
index 40fce3adc754f96589c02bb039dc96781d5e1bf4..2556901a3f076e27486bf795bf80d322fdc8da07 100644 (file)
@@ -533,10 +533,15 @@ int lapbeth_init(void)
 
        printk(KERN_INFO "LAPB Ethernet driver version 0.01\n");
 
+       read_lock_bh(&dev_base_lock);
        for (dev = dev_base; dev != NULL; dev = dev->next) {
-               if (dev_is_ethdev(dev))
+               if (dev_is_ethdev(dev)) {
+                       read_unlock_bh(&dev_base_lock);
                        lapbeth_new_device(dev);
+                       read_lock_bh(&dev_base_lock);
+               }
        }
+       read_unlock_bh(&dev_base_lock);
 
        return 0;
 }
index 4391bb68fe3ab226dbf1014dabfeb6cc35ab1f94..3aa066f1d9db912aec6506a5d7706ad173f13ae2 100644 (file)
@@ -91,9 +91,11 @@ init_etherdev(struct device *dev, int sizeof_priv)
                for (i = 0; i < MAX_ETH_CARDS; ++i)
                        if (ethdev_index[i] == NULL) {
                                sprintf(pname, "eth%d", i);
-                               for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next)
+                               read_lock_bh(&dev_base_lock);
+                               for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next) {
                                        if (strcmp(pname, cur_dev->name) == 0) {
                                                dev = cur_dev;
+                                               read_unlock_bh(&dev_base_lock);
                                                dev->init = NULL;
                                                sizeof_priv = (sizeof_priv + 3) & ~3;
                                                dev->priv = sizeof_priv
@@ -102,6 +104,8 @@ init_etherdev(struct device *dev, int sizeof_priv)
                                                if (dev->priv) memset(dev->priv, 0, sizeof_priv);
                                                goto found;
                                        }
+                               }
+                               read_unlock_bh(&dev_base_lock);
                        }
 
                alloc_size &= ~3;               /* Round to dword boundary. */
@@ -209,9 +213,11 @@ struct device *init_hippi_dev(struct device *dev, int sizeof_priv)
                for (i = 0; i < MAX_HIP_CARDS; ++i)
                        if (hipdev_index[i] == NULL) {
                                sprintf(pname, "hip%d", i);
-                               for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next)
+                               read_lock_bh(&dev_base_lock);
+                               for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next) {
                                        if (strcmp(pname, cur_dev->name) == 0) {
                                                dev = cur_dev;
+                                               read_unlock_bh(&dev_base_lock);
                                                dev->init = NULL;
                                                sizeof_priv = (sizeof_priv + 3) & ~3;
                                                dev->priv = sizeof_priv
@@ -220,6 +226,8 @@ struct device *init_hippi_dev(struct device *dev, int sizeof_priv)
                                                if (dev->priv) memset(dev->priv, 0, sizeof_priv);
                                                goto hipfound;
                                        }
+                               }
+                               read_unlock_bh(&dev_base_lock);
                        }
 
                alloc_size &= ~3;               /* Round to dword boundary. */
@@ -536,9 +544,11 @@ struct device *init_trdev(struct device *dev, int sizeof_priv)
                for (i = 0; i < MAX_TR_CARDS; ++i)
                        if (trdev_index[i] == NULL) {
                                sprintf(pname, "tr%d", i);
-                               for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next)
+                               read_lock_bh(&dev_base_lock);
+                               for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next) {
                                        if (strcmp(pname, cur_dev->name) == 0) {
                                                dev = cur_dev;
+                                               read_unlock_bh(&dev_base_lock);
                                                dev->init = NULL;
                                                sizeof_priv = (sizeof_priv + 3) & ~3;
                                                dev->priv = sizeof_priv
@@ -547,6 +557,8 @@ struct device *init_trdev(struct device *dev, int sizeof_priv)
                                                if (dev->priv) memset(dev->priv, 0, sizeof_priv);
                                                goto trfound;
                                        }
+                               }
+                               read_unlock_bh(&dev_base_lock);
                        }
 
                alloc_size &= ~3;               /* Round to dword boundary. */
index af0282e627d1184728b1f02686c30c260f03abf0..c33421018c05f8180d550dffc5c60160e19ea4e1 100644 (file)
@@ -2027,7 +2027,9 @@ static struct device *get_strip_dev(struct strip *strip_info)
         !memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) &&
         memcmp(&strip_info->true_dev_addr, zero_address.c, sizeof(zero_address)))
     {
-        struct device *dev = dev_base;
+        struct device *dev;
+       read_lock_bh(&dev_base_lock);
+       dev = dev_base;
         while (dev)
         {
             if (dev->type == strip_info->dev.type &&
@@ -2035,10 +2037,12 @@ static struct device *get_strip_dev(struct strip *strip_info)
             {
                 printk(KERN_INFO "%s: Transferred packet ownership to %s.\n",
                     strip_info->dev.name, dev->name);
+               read_unlock_bh(&dev_base_lock);
                 return(dev);
             }
             dev = dev->next;
         }
+       read_unlock_bh(&dev_base_lock);
     }
     return(&strip_info->dev);
 }
index da8099937ccf7b167d734c42434216dd23b4a18a..8537cf9bbf0e0fb22b638adeea1d1600ab46bda4 100644 (file)
@@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver.
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Sun Jan 17 10:57:41 1999 by makisara@home
+Last modified: Sun Apr 18 13:24:43 1999 by makisara@home
 
 
 BASICS
@@ -349,15 +349,6 @@ MTIOCGET Returns some status information.
        is set if there is no tape in the drive. GMT_EOD means either
        end of recorded data or end of tape. GMT_EOT means end of tape.
 
-The following ioctls use the structure mtlocation that contains both
-the block number and the partition number. These ioctls are available
-only for SCSI-2 tape drives and the block number is the
-device-independent logical block number defined by the standard.
-
-MTGETLOC Returns the current block and partition number.
-MTSETLOC Sets the tape to the block and partition specified by the
-       arguments.
-
 
 MISCELLANEOUS COMPILE OPTIONS
 
index 4714213bf2e337d054638be7e77c94a2a274a211..a5a825de65d7c4de9c3f451ce59f0d76fae7e27a 100644 (file)
@@ -11,7 +11,7 @@
   Copyright 1992 - 1999 Kai Makisara
                 email Kai.Makisara@metla.fi
 
-  Last modified: Sun Mar  7 09:03:17 1999 by makisara@home
+  Last modified: Tue May 18 08:32:34 1999 by makisara@home
   Some small formal changes - aeb, 950809
 */
 
@@ -164,8 +164,6 @@ st_chk_result(Scsi_Cmnd * SCpnt)
           SCpnt->request_bufflen);
     if (driver_byte(result) & DRIVER_SENSE)
       print_sense("st", SCpnt);
-    else
-      printk("\n");
   }
   else
 #endif
@@ -289,6 +287,7 @@ st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
   }
   else
       bp = (STp->buffer)->b_data;
+  SCpnt->cmd_len = 0;
   SCpnt->request.sem = &(STp->sem);
   SCpnt->request.rq_status = RQ_SCSI_BUSY;
   SCpnt->request.rq_dev = STp->devt;
@@ -3380,7 +3379,6 @@ static int st_attach(Scsi_Device * SDp){
 
    tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
    tpnt->dirty = 0;
-   tpnt->waiting = NULL;
    tpnt->in_use = 0;
    tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
    tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
index 4d5a498f3d61f4bb4b8fff57e7d33f2152d03201..2a033a8eefd64c6633ad400eb0b5bb6049f71e2a 100644 (file)
@@ -65,7 +65,6 @@ typedef struct {
 typedef struct {
   kdev_t devt;
   unsigned capacity;
-  wait_queue_head_t waiting;
   Scsi_Device* device;
   struct semaphore sem;
   ST_buffer * buffer;
index 2842966c388e97646d4e24d0f53c1e89c79820d8..ace8f30986500b00018668a980915d6c2dfa56d5 100644 (file)
@@ -33,8 +33,8 @@
  *            to make the card a four channel one: use dsp to output two
  *            channels to LINE and dac to output the other two channels to
  *            SPKR. Set the mixer to only output synth to SPKR.
- *   micz     it looks like this changes the MIC input impedance. I don't know
- *            any detail though.
+ *   micbias  sets the +5V bias to the mic if using an electretmic.
+ *            
  *
  *  Note: sync mode is not yet supported (i.e. running dsp and dac from the same
  *  clock source)
  *                     Alpha fixes reported by Peter Jones <pjones@redhat.com>
  *                     Note: joystick address handling might still be wrong on archs
  *                     other than i386
+ *    10.05.99   0.21  Added support for an electret mic for SB PCI64
+ *                     to the Linux kernel sound driver. This mod also straighten
+ *                     out the question marks around the mic impedance setting
+ *                     (micz). From Kim.Berts@fisub.mail.abb.com
+ *    11.05.99   0.22  Implemented the IMIX call to mute recording monitor.
+ *                     Guenter Geiger <geiger@epy.co.at>
  *
  * some important things missing in Ensoniq documentation:
  *
  * The card uses a 22.5792 MHz crystal.
  * The LINEIN jack may be converted to an AOUT jack by
  * setting pin 47 (XCTL0) of the ES1370 to high.
- * Pin 48 (XCTL1) of the ES1370 presumably changes the input impedance of the
- * MIC jack.
+ * Pin 48 (XCTL1) of the ES1370 sets the +5V bias for an electretmic
+ * 
  *
  */
 
@@ -190,7 +196,7 @@ static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
 #define DAC2_DIVTOSR(x) (1411200/((x)+2))
 
 #define CTRL_ADC_STOP   0x80000000  /* 1 = ADC stopped */
-#define CTRL_XCTL1      0x40000000  /* ? mic impedance */
+#define CTRL_XCTL1      0x40000000  /* electret mic bias */
 #define CTRL_OPEN       0x20000000  /* no function, can be read and written */
 #define CTRL_PCLKDIV    0x1fff0000  /* ADC/DAC2 clock divider */
 #define CTRL_SH_PCLKDIV 16
@@ -301,6 +307,7 @@ struct es1370_state {
                unsigned int recsrc;
                unsigned int modcnt;
                unsigned short micpreamp;
+               unsigned int imix;
        } mix;
 
        /* wave stuff */
@@ -839,7 +846,8 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
                        return put_user(s->mix.recsrc, (int *)arg);
                        
                 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-                       for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+                       val = SOUND_MASK_IMIX;
+                       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
                                if (mixtable[i].avail)
                                        val |= 1 << i;
                        return put_user(val, (int *)arg);
@@ -858,6 +866,9 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
                        
                 case SOUND_MIXER_CAPS:
                        return put_user(0, (int *)arg);
+               
+               case SOUND_MIXER_IMIX:
+                       return put_user(s->mix.imix, (int *)arg);
 
                default:
                        i = _IOC_NR(cmd);
@@ -870,6 +881,14 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
                return -EINVAL;
        s->mix.modcnt++;
        switch (_IOC_NR(cmd)) {
+
+       case SOUND_MIXER_IMIX:
+               if (arg == 0) 
+                       return -EFAULT;
+               get_user_ret(s->mix.imix,(int *)arg, -EFAULT);
+               val = s->mix.recsrc;
+               /* fall through */
+
        case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
                get_user_ret(val, (int *)arg, -EFAULT);
                for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
@@ -886,7 +905,10 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
                wrcodec(s, 0x13, j & 0xaa);
                wrcodec(s, 0x14, (j >> 8) & 0x17);
                wrcodec(s, 0x15, (j >> 8) & 0x0f);
-               i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc30;
+               i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
+               if (!s->mix.imix) {
+                    i &= 0xff60;  /* mute record and line monitor */
+               }
                wrcodec(s, 0x10, i);
                wrcodec(s, 0x11, i >> 8);
                return 0;
@@ -2262,7 +2284,7 @@ static int joystick[NR_DEVICE] = { 1, 0, };
 static int joystick[NR_DEVICE] = { 0, };
 #endif
 static int lineout[NR_DEVICE] = { 0, };
-static int micz[NR_DEVICE] = { 0, };
+static int micbias[NR_DEVICE] = { 0, };
 
 /* --------------------------------------------------------------------- */
 
@@ -2295,7 +2317,7 @@ __initfunc(int init_es1370(void))
 
        if (!pci_present())   /* No PCI bus in this machine! */
                return -ENODEV;
-       printk(KERN_INFO "es1370: version v0.20 time " __TIME__ " " __DATE__ "\n");
+       printk(KERN_INFO "es1370: version v0.22 time " __TIME__ " " __DATE__ "\n");
        while (index < NR_DEVICE && 
               (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
                if (pcidev->base_address[0] == 0 || 
@@ -2328,8 +2350,10 @@ __initfunc(int init_es1370(void))
                        goto err_irq;
                }
                /* initialize codec registers */
-               s->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
-               if (joystick[index]) {
+               /* note: setting CTRL_SERR_DIS is reported to break
+                * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
+               s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
+               if (joystick[index]) {
                        if (check_region(0x200, JOY_EXTENT))
                                printk(KERN_ERR "es1370: io port 0x200 in use\n");
                        else
@@ -2337,7 +2361,7 @@ __initfunc(int init_es1370(void))
                }
                if (lineout[index])
                        s->ctrl |= CTRL_XCTL0;
-               if (micz[index])
+               if (micbias[index])
                        s->ctrl |= CTRL_XCTL1;
                s->sctrl = 0;
                printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n"
@@ -2361,6 +2385,7 @@ __initfunc(int init_es1370(void))
                wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!!  */
                wrcodec(s, 0x18, 0); /* recording source is mixer */
                wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */
+               s->mix.imix = 1;
                fs = get_fs();
                set_fs(KERNEL_DS);
                val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD;
@@ -2403,8 +2428,8 @@ MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(joystick, "if 1 enables joystick interface (still need separate driver)");
 MODULE_PARM(lineout, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out");
-MODULE_PARM(micz, "1-" __MODULE_STRING(NR_DEVICE) "i");
-MODULE_PARM_DESC(micz, "changes (??) the microphone impedance");
+MODULE_PARM(micbias, "1-" __MODULE_STRING(NR_DEVICE) "i");
+MODULE_PARM_DESC(micbias, "sets the +5V bias for an electret microphone");
 
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("ES1370 AudioPCI Driver");
index eb3ba55e86e96a92e40490e918e9c69abfda9405..8bf83997d91d509734a3cc833f41c627097299f4 100644 (file)
@@ -29,6 +29,8 @@ if [ ! "$CONFIG_USB" = "n" ]; then
   bool 'USB keyboard support' CONFIG_USB_KBD
   bool 'USB audio parsing support' CONFIG_USB_AUDIO
   bool 'USB Abstract Control Model support' CONFIG_USB_ACM
+  bool 'USB printer support' CONFIG_USB_PRINTER
+  
 fi
 
 endmenu
index 3096c51b45c67905cf03c667cf4a385edcb520eb..0d910eecb1535ec5902ed10143065c8ce93675e1 100644 (file)
@@ -40,6 +40,10 @@ ifeq ($(CONFIG_USB_CPIA),y)
   USBX_OBJS += cpia.o
 endif
 
+ifeq ($(CONFIG_USB_PRINTER),y)
+  USBX_OBJS += printer.o
+endif
+
 ifeq ($(CONFIG_USB), y)
   L_OBJS += $(USBX_OBJS)
 endif
index 3d21882a8c326a9ad822053e3faa380f701ce034..ade33b5baf39836b019c5dfdf60c6d26b71342d1 100644 (file)
@@ -3,5 +3,6 @@ int usb_kbd_init(void);
 int usb_audio_init(void);
 int hub_init(void);
 int usb_acm_init(void);
+int usb_printer_init(void);
 void hub_cleanup(void);
 void usb_mouse_cleanup(void);
index 16c7b28f3b5ee49d389e68ea21d35e1b5424bb15..478de504b085b1aeb580922c5dd2cf16b5fb4a37 100644 (file)
@@ -7,13 +7,13 @@ unsigned char usb_kbd_map[256] =
     0x16,  0x2f,  0x11,  0x2d,  0x15,  0x2c,  0x02,  0x03,
 
     0x04,  0x05,  0x06,  0x07,  0x08,  0x09,  0x0a,  0x0b,
-    0x1c,  0x01,  0xd3,  0x0f,  0x39,  0x0c,  0x0d,  0x1a,
+    0x1c,  0x01,  0x0e,  0x0f,  0x39,  0x0c,  0x0d,  0x1a,
 
     0x1b,  0x2b,  0x00,  0x27,  0x28,  0x29,  0x33,  0x34,
     0x35,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,  0x40,
 
     0x41,  0x42,  0x43,  0x44,  0x57,  0x58,  0xb7,  0x46,
-    0x00,  0xd2,  0xc7,  0xc9,  0x63,  0xcf,  0xd1,  0xcd,
+    0x00,  0xd2,  0xc7,  0xc9,  0xd3,  0xcf,  0xd1,  0xcd,
 
     0xcb,  0xd0,  0xc8,  0x45,  0xb5,  0x37,  0x4a,  0x4e,
     0x9c,  0x4f,  0x50,  0x51,  0x4b,  0x4c,  0x4d,  0x47,
index fc5d1ed7f227022862d7080237dbafd3083e6fe1..6fbec256240dda257b7925ee7fd13bf5a544d536 100644 (file)
@@ -1,7 +1,6 @@
 # misc fixes
 keycode   0 = Pause
 keycode  29 = Control
-keycode  99 = Remove
 keycode  42 = Shift
 keycode  54 = Shift_R
 keycode 109 = Application
@@ -25,7 +24,7 @@ keycode 207 = End
 keycode 208 = Down
 keycode 209 = Next
 keycode 210 = Insert
-keycode 211 = Delete
+keycode 211 = Remove
 keycode 219 = Window
 keycode 220 = Window_R
 keycode 221 = Menu
index 1e98f5e8d42a67b832f06e0db79ae5a9112d70f8..b9621d2566a5c07146e9b5a30b4afd9441fefb49 100644 (file)
@@ -172,6 +172,30 @@ static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_
                        buffer++;
                        retval++;
                        state = 0;
+                       if (!--count)
+                               break;
+               }
+
+               /*
+                * SUBTLE:
+                *
+                * The only way to get here is to do a read() of
+                * more than 3 bytes: if you read a byte at a time
+                * you will just ever see states 0-2, for backwards
+                * compatibility.
+                *
+                * So you can think of this as a packet interface,
+                * where you have arbitrary-sized packets, and you
+                * only ever see the first three bytes when you read
+                * them in small chunks.
+                */
+               { /* fallthrough - dz */
+                       int dz = mouse->dz;
+                       mouse->dz = 0;
+                       put_user(dz, buffer);
+                       buffer++;
+                       retval++;
+                       state = 0;
                }
                break;
                }
index 4ab8c23260a0d72e4290fd75704de97f81f69db0..d02efe49cc0a5b1b6fc42c89581b274d8e0ec8c5 100644 (file)
@@ -62,7 +62,7 @@ static int apm_resume = 0;
 #endif
 
  
-
+static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
 static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
 static DECLARE_WAIT_QUEUE_HEAD(root_hub);
  
@@ -122,7 +122,19 @@ static int sohci_ctrl_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len
        OHCI_DEBUG( printk(" ret_status: %x\n", status); })
     return 0;                       
 } 
-                                                             
+
+static int sohci_bulk_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw)
+{  
+       *(int * )lw0 = status;
+       wake_up(&bulk_wakeup);
+
+       OHCI_DEBUG( { int i; printk("USB HC BULK<<<: %x:", ep_addr, ctrl_len);)
+       OHCI_DEBUG( printk(" data(%d):", data_len);) 
+       OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+       OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+    return 0;                       
+}
+                                                           
 static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
 {
        struct ohci * ohci = usb_dev->bus->hcpriv;
@@ -179,6 +191,40 @@ static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
        return cc_to_status[status & 0x0f];
 }
 
+static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       struct ohci * ohci = usb_dev->bus->hcpriv;
+       int status;
+       union ep_addr_ ep_addr;
+
+    ep_addr.iep = 0;
+       ep_addr.bep.ep = ((pipe >> 15) & 0x0f)          /* endpoint address */          
+                               | (pipe  & 0x80)                                /* direction */
+                               |  (11 << 5);                                   /* type = bulk*/
+       ep_addr.bep.fa  = ((pipe >> 8) & 0x7f);                         /* device address */
+       
+       status = 0xf; /* CC not Accessed */
+       OHCI_DEBUG( { int i; printk("USB HC BULK>>>: %x:", ep_addr.iep);)
+       OHCI_DEBUG( printk(" data(%d):", len);) 
+       OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+       OHCI_DEBUG( printk("\n"); })
+       
+       usb_ohci_add_ep(ohci, ep_addr.iep, 0, 1, sohci_bulk_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
+       
+       current->state = TASK_UNINTERRUPTIBLE;
+    add_wait_queue(&bulk_wakeup, &wait);   
+       ohci_trans_req(ohci, ep_addr.iep, 0, NULL, data, len, (__OHCI_BAG) &status, 0);
+
+       schedule_timeout(HZ/10);
+
+    remove_wait_queue(&bulk_wakeup, &wait); 
+     
+    OHCI_DEBUG(printk("USB HC status::: %x\n", cc_to_status[status & 0x0f]);)
+     
+       return cc_to_status[status & 0x0f];
+}
 
 static int sohci_usb_deallocate(struct usb_device *usb_dev) {
     struct ohci_device *dev = usb_to_ohci(usb_dev); 
@@ -234,8 +280,6 @@ static struct usb_device *sohci_usb_allocate(struct usb_device *parent) {
        return usb_dev;
 }
 
-/* FIXME! */
-#define sohci_bulk_msg NULL
 
 struct usb_operations sohci_device_operations = {
        sohci_usb_allocate,
@@ -567,7 +611,7 @@ static int ohci_rm_eds(struct ohci * ohci) {
   }
   writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
   writel(0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
-  writel_set((0x01<<4), &ohci->regs->control);   /* start CTRL u. (BULK list) */ 
+  writel_set((0x03<<4), &ohci->regs->control);   /* start CTRL u. (BULK list) */ 
 
   spin_unlock_irqrestore(&usb_ed_lock, flags);
   
@@ -915,6 +959,7 @@ void start_hc(struct ohci *ohci)
 {
    /*  int fminterval; */
     unsigned int mask;
+    int port_nr;
   /*  fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
        reset_hc(ohci); */
  
@@ -926,16 +971,19 @@ void start_hc(struct ohci *ohci)
        /* | OHCI_INTR_SO | OHCI_INTR_UE |OHCI_INTR_RHSC |OHCI_INTR_SF|  
                OHCI_INTR_FNO */
                
-
+       if(readl(&ohci->regs->roothub.a) & 0x100) /* global power on */
+               writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */
+       else { /* port power on */
+               for(port_nr=0; port_nr < (ohci->regs->roothub.a & 0xff); port_nr++)
+                        writel(0x100, &ohci->regs->roothub.portstatus[port_nr]);
+       }
+       wait_ms(50);            
         
        writel((0x00), &ohci->regs->control); /* USB Reset BUS */
        wait_ms(10);
          
-       writel((0x97), &ohci->regs->control); /* USB Operational  */
-       
-       writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */
-       wait_ms(50); 
-               
+       writel((0xB7), &ohci->regs->control); /* USB Operational  */
+               
        OHCI_DEBUG(printk("USB HC rstart_hc_operational: %x\n", readl(&ohci->regs->control)); )
        OHCI_DEBUG(printk("USB HC roothubstata: %x \n", readl( &(ohci->regs->roothub.a) )); )
        OHCI_DEBUG(printk("USB HC roothubstatb: %x \n", readl( &(ohci->regs->roothub.b) )); )
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
new file mode 100644 (file)
index 0000000..fb632cd
--- /dev/null
@@ -0,0 +1,412 @@
+
+/* Driver for USB Printers
+ * 
+ * (C) Michael Gee (michael@linuxspecific.com) 1999
+ * 
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/lp.h>
+
+#include <asm/spinlock.h>
+
+#include "usb.h"
+
+#define NAK_TIMEOUT (HZ)                               /* stall wait for printer */
+#define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT)       /* should not take 1 minute a page! */
+
+#ifndef USB_PRINTER_MAJOR
+#define USB_PRINTER_MAJOR 0
+#endif
+
+static int mymajor = USB_PRINTER_MAJOR;
+
+#define MAX_PRINTERS   8
+
+struct pp_usb_data {
+       struct usb_device       *pusb_dev;
+       __u8                    isopen;                 /* nz if open */
+       __u8                    noinput;                /* nz if no input stream */
+       __u8                    minor;                  /* minor number of device */
+       __u8                    status;                 /* last status from device */
+       int                     maxin, maxout;          /* max transfer size in and out */
+       char                    *obuf;                  /* transfer buffer (out only) */
+       wait_queue_head_t       wait_q;                 /* for timeouts */
+       unsigned int            last_error;             /* save for checking */
+};
+
+static struct pp_usb_data *minor_data[MAX_PRINTERS];
+
+#define PPDATA(x) ((struct pp_usb_data *)(x))
+
+unsigned char printer_read_status(struct pp_usb_data *p)
+{
+       __u8 status;
+       devrequest dr;
+       struct usb_device *dev = p->pusb_dev;
+
+       dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE | 0x80;
+       dr.request = 1;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 1;
+       if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 1)) {
+               return 0;
+       }
+       return status;
+}
+
+static int printer_check_status(struct pp_usb_data *p)
+{
+       unsigned int last = p->last_error;
+       unsigned char status = printer_read_status(p);
+
+       if (status & LP_PERRORP)
+               /* No error. */
+               last = 0;
+       else if ((status & LP_POUTPA)) {
+               if (last != LP_POUTPA) {
+                       last = LP_POUTPA;
+                       printk(KERN_INFO "usblp%d out of paper\n", p->minor);
+               }
+       } else if (!(status & LP_PSELECD)) {
+               if (last != LP_PSELECD) {
+                       last = LP_PSELECD;
+                       printk(KERN_INFO "usblp%d off-line\n", p->minor);
+               }
+       } else {
+               if (last != LP_PERRORP) {
+                       last = LP_PERRORP;
+                       printk(KERN_INFO "usblp%d on fire\n", p->minor);
+               }
+       }
+
+       p->last_error = last;
+
+       return status;
+}
+
+void printer_reset(struct pp_usb_data *p)
+{
+       devrequest dr;
+       struct usb_device *dev = p->pusb_dev;
+
+       dr.requesttype = USB_TYPE_CLASS | USB_RECIP_OTHER;
+       dr.request = 2;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 0;
+       dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+static int open_printer(struct inode * inode, struct file * file)
+{
+       struct pp_usb_data *p;
+
+       if(MINOR(inode->i_rdev) >= MAX_PRINTERS ||
+          !minor_data[MINOR(inode->i_rdev)]) {
+               return -ENODEV;
+       }
+
+       p = minor_data[MINOR(inode->i_rdev)];
+       p->minor = MINOR(inode->i_rdev);
+
+       if (p->isopen++) {
+               return -EBUSY;
+       }
+       if (!(p->obuf = (char *)__get_free_page(GFP_KERNEL))) {
+               return -ENOMEM;
+       }
+
+       printer_check_status(p);
+
+
+       file->private_data = p;
+//     printer_reset(p);
+       init_waitqueue_head(&p->wait_q);
+       return 0;
+}
+
+static int close_printer(struct inode * inode, struct file * file)
+{
+       struct pp_usb_data *p = file->private_data;
+
+       free_page((unsigned long)p->obuf);
+       p->isopen = 0;
+       file->private_data = NULL;
+       if(!p->pusb_dev) {
+               minor_data[p->minor] = NULL;
+               kfree(p);
+
+               MOD_DEC_USE_COUNT;
+
+       }
+       return 0;
+}
+
+static ssize_t write_printer(struct file * file,
+       const char * buffer, size_t count, loff_t *ppos)
+{
+       struct pp_usb_data *p = file->private_data;
+       unsigned long copy_size;
+       unsigned long bytes_written = 0;
+       unsigned long partial;
+       int result;
+       int maxretry;
+
+       do {
+               char *obuf = p->obuf;
+               unsigned long thistime;
+
+               thistime = copy_size = (count > p->maxout) ? p->maxout : count;
+               if (copy_from_user(p->obuf, buffer, copy_size))
+                       return -EFAULT;
+               maxretry = MAX_RETRY_COUNT;
+               while (thistime) {
+                       if (!p->pusb_dev)
+                               return -ENODEV;
+                       if (signal_pending(current)) {
+                               return bytes_written ? bytes_written : -EINTR;
+                       }
+                       result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
+                                        usb_sndbulkpipe(p->pusb_dev, 1), obuf, thistime, &partial);
+                       if (result & 0x08) {    /* NAK - so hold for a while */
+                               obuf += partial;
+                               thistime -= partial;
+                               if(!maxretry--)
+                                       return -ETIME;
+                                interruptible_sleep_on_timeout(&p->wait_q, NAK_TIMEOUT);
+                               continue;
+                       } else
+                               break;
+               };
+               if (result) {
+                       /* whoops - let's reset and fail the request */
+//                     printk("Whoops - %x\n", result);
+                       printer_reset(p);
+                       interruptible_sleep_on_timeout(&p->wait_q, 5*HZ);  /* let reset do its stuff */
+                       return -EIO;
+               }
+               bytes_written += copy_size;
+               count -= copy_size;
+               buffer += copy_size;
+       } while ( count > 0 );
+
+       return bytes_written ? bytes_written : -EIO;
+}
+
+static ssize_t read_printer(struct file * file,
+       char * buffer, size_t count, loff_t *ppos)
+{
+       struct pp_usb_data *p = file->private_data;
+       int read_count;
+       int this_read;
+       char buf[64];
+       unsigned long partial;
+       int result;
+
+       if (p->noinput)
+               return -EINVAL;
+
+       read_count = 0;
+       while (count) {
+               if (signal_pending(current)) {
+                       return read_count ? read_count : -EINTR;
+               }
+               if (!p->pusb_dev)
+                       return -ENODEV;
+               this_read = (count > sizeof(buf)) ? sizeof(buf) : count;
+
+               result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
+                         usb_rcvbulkpipe(p->pusb_dev, 2), buf, this_read, &partial);
+
+               /* unlike writes, we don't retry a NAK, just stop now */
+               if (result & 0x08)
+                       count = this_read = partial;
+               else if (result)
+                       return -EIO;
+
+               if (this_read) {
+                       if (copy_to_user(buffer, p->obuf, this_read))
+                               return -EFAULT;
+                       count -= this_read;
+                       read_count += this_read;
+                       buffer += this_read;
+               }
+       }
+       return read_count;
+}
+
+static int printer_probe(struct usb_device *dev)
+{
+       struct usb_interface_descriptor *interface;
+       int i;
+
+       /*
+        * FIXME - this will not cope with combined printer/scanners
+        */
+       if (dev->descriptor.bDeviceClass != 7 ||
+           dev->descriptor.bNumConfigurations != 1 ||
+           dev->config[0].bNumInterfaces != 1) {
+               return -1;
+       }
+
+       interface = dev->config->interface;
+
+       /* Lets be paranoid (for the moment)*/
+       if (interface->bInterfaceClass != 7 ||
+           interface->bInterfaceSubClass != 1 ||
+           (interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1)||
+           interface->bNumEndpoints > 2) {
+               return -1;
+       }
+
+       if (interface->endpoint[0].bEndpointAddress != 0x01 ||
+           interface->endpoint[0].bmAttributes != 0x02 ||
+           (interface->bNumEndpoints > 1 && (
+                   interface->endpoint[1].bEndpointAddress != 0x82 ||
+                   interface->endpoint[1].bmAttributes != 0x02))) {
+               return -1;
+       }
+
+       for (i=0; i<MAX_PRINTERS; i++) {
+               if (!minor_data[i])
+                       break;
+       }
+       if (i >= MAX_PRINTERS) {
+               return -1;
+       }
+
+       printk(KERN_INFO "USB Printer found at address %d\n", dev->devnum);
+
+       if (!(dev->private = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) {
+               printk( KERN_DEBUG "usb_printer: no memory!\n");
+               return -1;
+       }
+
+       memset(dev->private, 0, sizeof(struct pp_usb_data));
+       minor_data[i] = PPDATA(dev->private);
+       minor_data[i]->minor = i;
+       minor_data[i]->pusb_dev = dev;
+       minor_data[i]->maxout = interface->endpoint[0].wMaxPacketSize * 16;
+       if (minor_data[i]->maxout > PAGE_SIZE) {
+                minor_data[i]->maxout = PAGE_SIZE;
+       }
+       if (interface->bInterfaceProtocol != 2)
+               minor_data[i]->noinput = 1;
+       else {
+               minor_data[i]->maxin = interface->endpoint[1].wMaxPacketSize;
+       }
+
+        if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+               printk(KERN_INFO "  Failed to set configuration\n");
+               return -1;
+       }
+#if 0
+       {
+               __u8 status;
+               __u8 ieee_id[64];
+               devrequest dr;
+
+               /* Lets get the device id if possible */
+               dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE | 0x80;
+               dr.request = 0;
+               dr.value = 0;
+               dr.index = 0;
+               dr.length = sizeof(ieee_id) - 1;
+               if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, ieee_id, sizeof(ieee_id)-1) == 0) {
+                       if (ieee_id[1] < sizeof(ieee_id) - 1)
+                               ieee_id[ieee_id[1]+2] = '\0';
+                       else
+                               ieee_id[sizeof(ieee_id)-1] = '\0';
+                       printk(KERN_INFO "  Printer ID is %s\n", &ieee_id[2]);
+               }
+               status = printer_read_status(PPDATA(dev->private));
+               printk(KERN_INFO "  Status is %s,%s,%s\n",
+                      (status & 0x10) ? "Selected" : "Not Selected",
+                      (status & 0x20) ? "No Paper" : "Paper",
+                      (status & 0x08) ? "No Error" : "Error");
+       }
+#endif
+       return 0;
+}
+
+static void printer_disconnect(struct usb_device *dev)
+{
+       struct pp_usb_data *pp = dev->private;
+
+       if (pp->isopen) {
+               /* better let it finish - the release will do whats needed */
+               pp->pusb_dev = NULL;
+               return;
+       }
+       minor_data[pp->minor] = NULL;
+       kfree(pp);
+       dev->private = NULL;            /* just in case */
+       MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver printer_driver = {
+       "printer",
+       printer_probe,
+       printer_disconnect,
+       { NULL, NULL }
+};
+
+static struct file_operations usb_printer_fops = {
+       NULL,           /* seek */
+       read_printer,
+       write_printer,
+       NULL,           /* readdir */
+       NULL,           /* poll - out for the moment */
+       NULL,           /* ioctl */
+       NULL,           /* mmap */
+       open_printer,
+       NULL,           /* flush ? */
+       close_printer,
+       NULL,
+       NULL
+};
+
+int usb_printer_init(void)
+{
+       int result;
+
+       MOD_INC_USE_COUNT;
+       
+       if ((result = register_chrdev(USB_PRINTER_MAJOR, "usblp", &usb_printer_fops)) < 0) {
+               printk(KERN_WARNING "usbprinter: Cannot register device\n");
+               return result;
+       }
+       if (mymajor == 0) {
+               mymajor = result;
+       }
+       usb_register(&printer_driver);
+       printk(KERN_INFO "USB Printer support registered.\n");
+       return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+
+       return usb_printer_init();
+}
+
+void cleanup_module(void)
+{
+       unsigned int offset;
+
+       usb_deregister(&printer_driver);
+       unregister_chrdev(mymajor, "usblplp");
+}
+#endif
index fd2aba6da44a8a33594dd55c8b9ba13d8a878ba1..9a9ee7e3fef74eacf931364e280c5bdbc7ab48e5 100644 (file)
@@ -12,6 +12,8 @@
 
 void show_td(struct uhci_td * td)
 {
+       char *spid;
+
        printk("%08x ", td->link);
        printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
                ((td->status >> 29) & 1) ? "SPD " : "",
@@ -27,12 +29,27 @@ void show_td(struct uhci_td * td)
                ((td->status >> 18) & 1) ? "CRC/Timeo " : "",
                ((td->status >> 17) & 1) ? "BitStuff " : "",
                td->status & 0x7ff);
-       printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x ",
+       switch (td->info & 0xff) {
+       case 0x2d:
+               spid = "SETUP";
+               break;
+       case 0xe1:
+               spid = "OUT";
+               break;
+       case 0x69:
+               spid = "IN";
+               break;
+       default:
+               spid = "?";
+               break;
+       }
+       printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x(%s) ",
                td->info >> 21,
                 ((td->info >> 19) & 1) ? "DT " : "",
                 (td->info >> 15) & 15,
                 (td->info >> 8) & 127,
-                td->info & 0xff);
+                (td->info & 0xff),
+                spid);
        printk("(buf=%08x)\n", td->buffer);
 }
 
index ba80b3108feee1669fce1707763d974f7218fede..95bed335b0a580255d7d82a3e42b612f381925ac 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 /* 4/4/1999 added data toggle for interrupt pipes -keryan */
+/* 5/16/1999 added global toggles for bulk and control */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -52,17 +53,30 @@ static DECLARE_WAIT_QUEUE_HEAD(uhci_configure);
 /*
  * Return the result of a TD..
  */
-static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td)
+static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval)
 {
        unsigned int status;
+       struct uhci_td *tmp = td->first;
 
-       status = (td->status >> 16) & 0xff;
+       /* locate the first failing td, if any */
 
+       do {
+               status = (tmp->status >> 16) & 0xff;
+               if (status)
+                       break;
+               if ((tmp->link & 1) || (tmp->link & 2))
+                       break;
+               tmp = bus_to_virt(tmp->link & ~0xF);
+       } while (1);
+
+       if(rval)
+               *rval = 0;
        /* Some debugging code */
-       if (status) {
+       if (status && (!usb_pipeendpoint(tmp->info) || !(status & 0x08)) ) {
                int i = 10;
-               struct uhci_td *tmp = td->first;
-               printk("uhci_td_result() failed with status %d\n", status);
+
+               tmp = td->first;
+               printk("uhci_td_result() failed with status %x\n", status);
                show_status(dev->uhci);
                do {
                        show_td(tmp);
@@ -73,6 +87,34 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td)
                                break;
                } while (1);
        }
+       if (usb_pipeendpoint(tmp->info) && (status & 0x08)) {
+//             printk("uhci_td_result() - NAK\n");
+               /* find total length xferred and reset toggle on failed packets */
+               tmp = td->first;
+               do {
+                       /* sum up packets that did not fail */
+                       if(rval && !((tmp->status >> 16) & 0xff))
+                               *rval += (tmp->status & 0x3ff) + 1;
+
+                       /* 
+                        * Note - only the first to fail will be marked NAK
+                        */
+                       if (tmp->status & 0xFF0000) {
+                               /* must reset the toggle on any error */
+                               usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), (tmp->info >> 19) & 1);
+                               break;
+                       } 
+
+                       if ((tmp->link & 1) || (tmp->link & 2))
+                               break;
+                       tmp = bus_to_virt(tmp->link & ~0xF);
+               } while (1);
+#if 0
+               if (rval) {
+                       printk("uhci_td_result returning partial count %d\n", *rval);
+               }
+#endif
+       }
        return status;          
 }
 
@@ -207,8 +249,8 @@ static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev)
 
 static void uhci_qh_deallocate(struct uhci_qh *qh)
 {
-       if (qh->element != 1)
-               printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element);
+//     if (qh->element != 1)
+//             printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element);
 
        qh->element = 1;
        qh->link = 1;
@@ -571,7 +613,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
 
        uhci_qh_deallocate(ctrl_qh);
 
-       return uhci_td_result(dev, last);
+       return uhci_td_result(dev, last, NULL);
 }
 
 /*
@@ -601,8 +643,9 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
        struct uhci_td *first, *td, *prevtd;
        unsigned long destination, status;
        int ret;
+       int maxsze = usb_maxpacket(usb_dev, pipe);
 
-       if (len > usb_maxpacket(usb_dev->maxpacketsize) * 29)
+       if (len > maxsze * 29)
                printk("Warning, too much data for a control packet, crashing\n");
 
        first = td = uhci_td_allocate(dev);
@@ -639,7 +682,6 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
        while (len > 0) {
                /* Build the TD for control status */
                int pktsze = len;
-               int maxsze = usb_maxpacket(pipe);
 
                if (pktsze > maxsze)
                        pktsze = maxsze;
@@ -653,12 +695,13 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
                td->first = first;
                td->backptr = &prevtd->link;
 
+               data += pktsze;
+               len -= pktsze;
+
                prevtd = td;
                td = uhci_td_allocate(dev);
                prevtd->link = 4 | virt_to_bus(td);                     /* Update previous TD */
 
-               data += maxsze;
-               len -= maxsze;
        }
 
        /*
@@ -697,6 +740,12 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void
                } while (1);
        }
 
+       if (ret) {
+               __u8 *p = cmd;
+
+               printk("Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
+                      p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+       }
        return ret;
 }
 
@@ -718,7 +767,7 @@ static int uhci_bulk_completed(int status, void *buffer, void *dev_id)
 }
 
 /* td points to the last td in the list, which interrupts on completion */
-static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
+static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, unsigned long *rval)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct uhci_qh *bulk_qh = uhci_qh_allocate(dev);
@@ -780,7 +829,7 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
 
        uhci_qh_deallocate(bulk_qh);
 
-       return uhci_td_result(dev, last);
+       return uhci_td_result(dev, last, rval);
 }
 
 /*
@@ -799,15 +848,16 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
  * 31 TD's is a minimum of 248 bytes worth of bulk
  * information.
  */
-static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len)
+static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval)
 {
        struct uhci_device *dev = usb_to_uhci(usb_dev);
        struct uhci_td *first, *td, *prevtd;
        unsigned long destination, status;
        int ret;
+       int maxsze = usb_maxpacket(usb_dev, pipe);
 
-       if (len > usb_maxpacket(usb_dev->maxpacketsize) * 31)
-               printk("Warning, too much data for a bulk packet, crashing\n");
+       if (len > maxsze * 31)
+               printk("Warning, too much data for a bulk packet, crashing (%d/%d)\n", len, maxsze);
 
        /* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */
        /*
@@ -833,29 +883,33 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
        while (len > 0) {
                /* Build the TD for control status */
                int pktsze = len;
-               int maxsze = usb_maxpacket(pipe);
 
                if (pktsze > maxsze)
                        pktsze = maxsze;
 
                td->status = status;                                    /* Status */
-               td->info = destination | ((pktsze-1) << 21);            /* pktsze bytes of data */
+               td->info = destination | ((pktsze-1) << 21) |
+                        (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe)) << 19); /* pktsze bytes of data */
                td->buffer = virt_to_bus(data);
                td->backptr = &prevtd->link;
-
-               prevtd = td;
-               td = uhci_td_allocate(dev);
-               prevtd->link = 4 | virt_to_bus(td);                     /* Update previous TD */
+               td->first = first;
 
                data += maxsze;
                len -= maxsze;
+
+               if (len > 0) {
+                       prevtd = td;
+                       td = uhci_td_allocate(dev);
+                       prevtd->link = 4 | virt_to_bus(td);                     /* Update previous TD */
+               }
+
                /* Alternate Data0/1 (start with Data0) */
-               destination ^= 1 << 19;
+               usb_dotoggle(usb_dev, usb_pipeendpoint(pipe));
        }
        td->link = 1;                                   /* Terminate */
 
        /* Start it up.. */
-       ret = uhci_run_bulk(dev, first, td);
+       ret = uhci_run_bulk(dev, first, td, rval);
 
        {
                int maxcount = 100;
@@ -1154,8 +1208,8 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
        status = inw(io_addr + USBSTS);
        outw(status, io_addr + USBSTS);
 
-       if ((status & ~0x21) != 0)
-               printk("interrupt: %X\n", status);
+//     if ((status & ~0x21) != 0)
+//             printk("interrupt: %X\n", status);
 
        /* Walk the list of pending TD's to see which ones completed.. */
        uhci_interrupt_notify(uhci);
@@ -1218,12 +1272,13 @@ static void start_hc(struct uhci *uhci)
                }
        }
 
+
        outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
        outw(0, io_addr + USBFRNUM);
        outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
 
        /* Run and mark it configured with a 64-byte max packet */
-       outw(USBCMD_RS | USBCMD_CF, io_addr + USBCMD);
+       outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
 }
 
 /*
@@ -1556,7 +1611,10 @@ void cleanup_module(void)
 #endif
 }
 
-#define uhci_init init_module
+int init_modules(void)
+{
+       return uhci_init();
+}
 
 #endif
 
index 86d08cd787f10c2e10cfa5001b4e2d857f491415..34d6c20aff6508371fa185e989d8ac0f5864e717 100644 (file)
@@ -124,4 +124,8 @@ void usb_show_hub_descriptor(struct usb_hub_descriptor * desc)
        printk("\n");
 }
 
-
+void usb_show_string(struct usb_device* dev, char *id, int index)
+{
+       if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
+               printk("%s: %s\n", id, dev->stringindex[index]);
+}
index 2a084fca15f995eb837eb4194df0300bd5d2ee0f..6bd4c4d050c96a4353bf16b5347893f6f1c5d78a 100644 (file)
@@ -78,6 +78,9 @@ int usb_init(void)
 #ifdef CONFIG_USB_CPIA
        usb_cpia_init();
 #endif
+#ifdef CONFIG_USB_PRINTER
+       usb_printer_init();
+#endif
 
        usb_hub_init();
        return 0;
@@ -370,6 +373,7 @@ void usb_destroy_configuration(struct usb_device *dev)
        
        if(dev->config==NULL)
                return;
+
        for(c=0;c<dev->descriptor.bNumConfigurations;c++)
        {
                cf=&dev->config[c];
@@ -385,6 +389,11 @@ void usb_destroy_configuration(struct usb_device *dev)
                kfree(cf->interface);
        }
        kfree(dev->config);
+
+       if (dev->stringindex)
+               kfree(dev->stringindex);
+       if (dev->stringtable)
+               kfree(dev->stringtable);
 }
                        
 void usb_init_root_hub(struct usb_device *dev)
@@ -462,6 +471,8 @@ int usb_set_address(struct usb_device *dev)
 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
 {
        devrequest dr;
+       int i = 5;
+       int result;
 
        dr.requesttype = 0x80;
        dr.request = USB_REQ_GET_DESCRIPTOR;
@@ -469,7 +480,30 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
        dr.index = 0;
        dr.length = size;
 
-       return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size);
+       while (i--) {
+               if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size)))
+                       break;
+       }
+       return result;
+}
+
+int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
+{
+       devrequest dr;
+       int i = 5;
+       int result;
+
+       dr.requesttype = 0x80;
+       dr.request = USB_REQ_GET_DESCRIPTOR;
+       dr.value = (USB_DT_STRING << 8) + index;
+       dr.index = langid;
+       dr.length = size;
+
+       while (i--) {
+               if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size)))
+                       break;
+       }
+       return result;
 }
 
 int usb_get_device_descriptor(struct usb_device *dev)
@@ -593,6 +627,24 @@ int usb_set_idle(struct usb_device *dev,  int duration, int report_id)
        return 0;
 }
 
+static void usb_set_maxpacket(struct usb_device *dev)
+{
+       struct usb_endpoint_descriptor *ep;
+       struct usb_interface_descriptor *ip = dev->actconfig->interface;
+       int i;
+
+       for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
+               if (dev->actconfig->interface[i].bInterfaceNumber == dev->ifnum) {
+                       ip = &dev->actconfig->interface[i];
+                       break;
+               }
+       }
+       ep = ip->endpoint;
+       for (i=0; i<ip->bNumEndpoints; i++) {
+               dev->epmaxpacket[ep[i].bEndpointAddress & 0x0f] = ep[i].wMaxPacketSize;
+       }
+}
+
 int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 {
        devrequest dr;
@@ -606,6 +658,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
        if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
                return -1;
 
+       dev->ifnum = interface;
+       usb_set_maxpacket(dev);
        return 0;
 }
 
@@ -613,16 +667,31 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 int usb_set_configuration(struct usb_device *dev, int configuration)
 {
        devrequest dr;
-
+       int i;
+       struct usb_config_descriptor *cp = NULL;
+       
        dr.requesttype = 0;
        dr.request = USB_REQ_SET_CONFIGURATION;
        dr.value = configuration;
        dr.index = 0;
        dr.length = 0;
 
+       for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
+               if (dev->config[i].bConfigurationValue == configuration) {
+                       cp = &dev->config[i];
+                       break;
+               }
+       }
+       if (!cp) {
+               printk(KERN_INFO "usb: selecting invalid configuration %d\n", configuration);
+               return -1;
+       }
        if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
                return -1;
 
+       dev->actconfig = cp;
+       dev->toggle = 0;
+       usb_set_maxpacket(dev);
        return 0;
 }
 
@@ -671,6 +740,61 @@ int usb_get_configuration(struct usb_device *dev)
        return usb_parse_configuration(dev, buffer, bufptr - buffer);
 }
 
+int usb_get_stringtable(struct usb_device *dev)
+{
+       int i;
+       int maxindex;
+       int langid;
+       unsigned char buffer[256];
+       int totalchars;
+       struct usb_string_descriptor *sd = (struct usb_string_descriptor *)buffer;
+       char *string;
+       __u8 bLengths[USB_MAXSTRINGS+1];
+       int j;
+
+       dev->maxstring = 0;
+       if(usb_get_string(dev, 0, 0, buffer, 2) ||
+          usb_get_string(dev, 0, 0, buffer, sd->bLength))
+               return -1;
+       /* we are going to assume that the first ID is good */
+       langid = sd->wData[0];
+
+       /* whip through and find total length and max index */
+       for (maxindex = 1, totalchars = 0; maxindex<=USB_MAXSTRINGS; maxindex++) {
+               if(usb_get_string(dev, langid, maxindex, buffer, 2))
+                       break;
+               totalchars += (sd->bLength - 2)/2 + 1;
+               bLengths[maxindex] = sd->bLength;
+       }
+       if (--maxindex <= 0)
+               return -1;
+
+       /* get space for strings and index */
+       dev->stringindex = kmalloc(sizeof(char *)*maxindex, GFP_KERNEL);
+       if (!dev->stringindex)
+               return -1;
+       dev->stringtable = kmalloc(totalchars, GFP_KERNEL);
+       if (!dev->stringtable) {
+               kfree(dev->stringindex);
+               dev->stringindex = NULL;
+               return -1;
+       }
+
+       /* fill them in */
+       memset(dev->stringindex, 0, sizeof(char *)*maxindex);
+       for (i=1, string = dev->stringtable; i <= maxindex; i++) {
+               if (usb_get_string(dev, langid, i, buffer, bLengths[i]))
+                       continue;
+               dev->stringindex[i] = string;
+               for (j=0; j < (bLengths[i] - 2)/2; j++) {
+                       *string++ =  sd->wData[j];
+               }
+               *string++ = '\0';
+       }
+       dev->maxstring = maxindex;
+       return 0;
+}
+
 /*
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
@@ -684,10 +808,12 @@ void usb_new_device(struct usb_device *dev)
                dev->devnum);
 
        dev->maxpacketsize = 0;         /* Default to 8 byte max packet size */
+        dev->epmaxpacket[0] = 8;
 
        addr = dev->devnum;
        dev->devnum = 0;
 
+#if 1
        /* Slow devices */
        for (i = 0; i < 5; i++) {
                if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8))
@@ -700,10 +826,12 @@ void usb_new_device(struct usb_device *dev)
                printk("giving up\n");
                return;
        }
+#endif
 
 #if 0
        printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0);
 #endif
+       dev->epmaxpacket[0] = dev->descriptor.bMaxPacketSize0;
        switch (dev->descriptor.bMaxPacketSize0) {
                case 8: dev->maxpacketsize = 0; break;
                case 16: dev->maxpacketsize = 1; break;
@@ -716,11 +844,15 @@ void usb_new_device(struct usb_device *dev)
 
        dev->devnum = addr;
 
+#if 1
        if (usb_set_address(dev)) {
                printk("Unable to set address\n");
                /* FIXME: We should disable the port */
                return;
        }
+#else
+       usb_set_address(dev);
+#endif
 
        wait_ms(10);    /* Let the SET_ADDRESS settle */
 
@@ -734,6 +866,16 @@ void usb_new_device(struct usb_device *dev)
                return;
        }
 
+       usb_get_stringtable(dev);
+
+       dev->actconfig = dev->config;
+       dev->ifnum = 0;
+       usb_set_maxpacket(dev);
+
+       usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
+       usb_show_string(dev, "Product", dev->descriptor.iProduct);
+       usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
+
 #if 0
        printk("Vendor: %X\n", dev->descriptor.idVendor);
        printk("Product: %X\n", dev->descriptor.idProduct);
index a1e3ade7dfc985dd72644d7e0d3f236a8df68b46..62667457213ee2161bebdbfe1e833be608eb9b2e 100644 (file)
@@ -10,6 +10,7 @@ extern int usb_hub_init(void);
 extern int usb_kbd_init(void);
 extern int usb_cpia_init(void);
 extern int usb_mouse_init(void);
+extern int usb_printer_init(void);
 
 extern void hub_cleanup(void);
 extern void usb_mouse_cleanup(void);
@@ -113,6 +114,7 @@ struct usb_devmap {
 #define USB_MAXCONFIG          8
 #define USB_MAXINTERFACES      32
 #define USB_MAXENDPOINTS       32
+#define USB_MAXSTRINGS         16
 
 struct usb_device_descriptor {
        __u8  bLength;
@@ -176,6 +178,7 @@ struct usb_config_descriptor {
 struct usb_string_descriptor {
        __u8  bLength;
        __u8  bDescriptorType;
+       __u16 wData[1];
 };
 
 /* Hub descriptor */
@@ -217,7 +220,7 @@ struct usb_operations {
        struct usb_device *(*allocate)(struct usb_device *);
        int (*deallocate)(struct usb_device *);
        int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int);
-       int (*bulk_msg)(struct usb_device *, unsigned int, void *, int);
+       int (*bulk_msg)(struct usb_device *, unsigned int, void *, int, unsigned long *);
        int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
 };
 
@@ -238,12 +241,18 @@ struct usb_device {
        int devnum;                                             /* Device number on USB bus */
        int slow;                                               /* Slow device? */
        int maxpacketsize;                                      /* Maximum packet size */
-
+       __u16 toggle;                                           /* one bit for each endpoint */
+       struct usb_config_descriptor *actconfig;                /* the active configuration */
+       int epmaxpacket[16];                                    /* endpoint specific maximums */
+       int ifnum;                                              /* active interface number */
        struct usb_bus *bus;                                    /* Bus we're apart of */
        struct usb_driver *driver;                              /* Driver */
        struct usb_device_descriptor descriptor;                /* Descriptor */
        struct usb_config_descriptor *config;                   /* All of the configs */
        struct usb_device *parent;
+       char *stringtable;                                      /* Strings (multiple, null term) */
+       char **stringindex;                                     /* pointers to strings */
+       int maxstring;                                          /* max valid index */
   
        /*
         * Child devices - these can be either new devices
@@ -306,7 +315,7 @@ extern void usb_destroy_configuration(struct usb_device *dev);
  * appropriately.
  */
 
-#define usb_maxpacket(pipe)    (8 << ((pipe) & 3))
+#define usb_maxpacket(dev,pipe)        ((dev)->epmaxpacket[usb_pipeendpoint(pipe)])
 #define usb_packetid(pipe)     (((pipe) & 0x80) ? 0x69 : 0xE1)
 
 #define usb_pipedevice(pipe)   (((pipe) >> 8) & 0x7f)
@@ -323,6 +332,11 @@ extern void usb_destroy_configuration(struct usb_device *dev);
 
 #define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
 
+/* The D0/D1 toggle bits */
+#define usb_gettoggle(dev, ep) (((dev)->toggle >> ep) & 1)
+#define        usb_dotoggle(dev, ep)   ((dev)->toggle ^= (1 << ep))
+#define usb_settoggle(dev, ep, bit) ((dev)->toggle = ((dev)->toggle & (0xfffe << ep)) | (bit << ep))
+
 static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
 {
        return (dev->devnum << 8) | (endpoint << 15) | (dev->slow << 26) | dev->maxpacketsize;
@@ -338,6 +352,8 @@ static inline unsigned int __default_pipe(struct usb_device *dev)
 #define usb_rcvctrlpipe(dev,endpoint)  ((2 << 30) | __create_pipe(dev,endpoint) | 0x80)
 #define usb_sndisocpipe(dev,endpoint)  ((0 << 30) | __create_pipe(dev,endpoint))
 #define usb_rcvisocpipe(dev,endpoint)  ((0 << 30) | __create_pipe(dev,endpoint) | 0x80)
+#define usb_sndbulkpipe(dev,endpoint)  ((3 << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvbulkpipe(dev,endpoint)  ((3 << 30) | __create_pipe(dev,endpoint) | 0x80)
 #define usb_snddefctrl(dev)            ((2 << 30) | __default_pipe(dev))
 #define usb_rcvdefctrl(dev)            ((2 << 30) | __default_pipe(dev) | 0x80)
 
@@ -371,6 +387,7 @@ void usb_show_interface_descriptor(struct usb_interface_descriptor *);
 void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);
 void usb_show_hub_descriptor(struct usb_hub_descriptor *);
 void usb_show_device(struct usb_device *);
+void usb_show_string(struct usb_device* dev, char *id, int index);
 
 /*
  * Audio parsing helpers
index a4ed4eb34e8075ba69663da232c09f405afbcd0e..8a7e7bcd2f5231c4514f664acf49512bfaf756b9 100644 (file)
@@ -413,7 +413,14 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
                        return fd;
                file = fcheck(fd);
 
-               if (!file->f_op || !file->f_op->mmap) {
+               if ((fd_offset & ~PAGE_MASK) != 0) {
+                       printk(KERN_WARNING 
+                              "fd_offset is not page aligned. Please convert program: %s\n",
+                              file->f_dentry->d_name.name
+                              );
+               }
+
+               if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
                        sys_close(fd);
                        do_mmap(NULL, 0, ex.a_text+ex.a_data,
                                PROT_READ|PROT_WRITE|PROT_EXEC,
@@ -534,6 +541,24 @@ do_load_aout_library(int fd)
 
        start_addr =  ex.a_entry & 0xfffff000;
 
+       if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
+               printk(KERN_WARNING 
+                      "N_TXTOFF is not page aligned. Please convert library: %s\n",
+                      file->f_dentry->d_name.name
+                      );
+               
+               do_mmap(NULL, start_addr & PAGE_MASK, ex.a_text + ex.a_data + ex.a_bss,
+                       PROT_READ | PROT_WRITE | PROT_EXEC,
+                       MAP_FIXED| MAP_PRIVATE, 0);
+               
+               read_exec(file->f_dentry, N_TXTOFF(ex),
+                         (char *)start_addr, ex.a_text + ex.a_data, 0);
+               flush_icache_range((unsigned long) start_addr,
+                                  (unsigned long) start_addr + ex.a_text + ex.a_data);
+
+               retval = 0;
+               goto out_putf;
+       }
        /* Now use mmap to map the library into memory. */
        error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
                        PROT_READ | PROT_WRITE | PROT_EXEC,
index 82f75d1e65f8327accf042663dc260a5a090bbe0..3ea19bb535bbc7ab4c62765423c223902f6ac618 100644 (file)
@@ -739,12 +739,12 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        padzero(elf_bss);
 
 #if 0
-       printk("(start_brk) %x\n" , current->mm->start_brk);
-       printk("(end_code) %x\n" , current->mm->end_code);
-       printk("(start_code) %x\n" , current->mm->start_code);
-       printk("(end_data) %x\n" , current->mm->end_data);
-       printk("(start_stack) %x\n" , current->mm->start_stack);
-       printk("(brk) %x\n" , current->mm->brk);
+       printk("(start_brk) %lx\n" , (long) current->mm->start_brk);
+       printk("(end_code) %lx\n" , (long) current->mm->end_code);
+       printk("(start_code) %lx\n" , (long) current->mm->start_code);
+       printk("(end_data) %lx\n" , (long) current->mm->end_data);
+       printk("(start_stack) %lx\n" , (long) current->mm->start_stack);
+       printk("(brk) %lx\n" , (long) current->mm->brk);
 #endif
 
        if ( current->personality == PER_SVR4 )
diff --git a/fs/efs/.cvsignore b/fs/efs/.cvsignore
deleted file mode 100644 (file)
index 857dd22..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.depend
-.*.flags
index 629008d4d9ea4a588e5dac631be9c4dae9cff6a6..e9da4e32d6859b032aff67f467fa0edb3630aa61 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -171,7 +171,7 @@ out:
        return error;
 }
 
-#ifndef __alpha__
+#if !(defined(__alpha__) || defined(__ia64__))
 
 /*
  * sys_utime() can be implemented in user-level using sys_utimes().
index 897f3efe884feb8e69c0179bc0c6a00304b76c10..e47e3b0b4ca070e3e8920bcd4548d2302c7847b9 100644 (file)
@@ -267,8 +267,12 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
        }
 
        ret = -EINVAL;
-       if (n < 0 || n > KFDS_NR)
+       if (n < 0)
                goto out_nofds;
+
+       if (n > KFDS_NR)
+               n = KFDS_NR;
+
        /*
         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
         * since we used fdset we need to allocate memory in units of
index 0246a44a137a8f24816aa215b675ae04ec84ca5e..146790d67b4c8559a1660fa7cd08cc7f9a321bb6 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -24,7 +24,7 @@ do_revalidate(struct dentry *dentry)
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -114,7 +114,7 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf)
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__)
 /*
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
@@ -160,7 +160,7 @@ asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
        return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -208,7 +208,7 @@ asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
        return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
index a5fa79ee9dc2ab1c393691ffcdbab14c9a8d6402..754a4e8f835f7150401f6c17907a6546a3d1b2ee 100644 (file)
@@ -7,6 +7,12 @@
 #ifndef __ASM_ALPHA_PROCESSOR_H
 #define __ASM_ALPHA_PROCESSOR_H
 
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
 /*
  * We have a 42-bit user address space: 4TB user VM...
  */
index b7515c0291cd736e7a1842d1cd139d3de684b078..255888e8a6da54298320d09b6fcab28b209c2814 100644 (file)
@@ -17,14 +17,57 @@ struct semaphore {
        atomic_t count;
        atomic_t waking;                /* biased by -1 */
        wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+       long __magic;
+#endif
 };
 
-#define MUTEX ((struct semaphore) \
- { ATOMIC_INIT(1), ATOMIC_INIT(-1), NULL })
-#define MUTEX_LOCKED ((struct semaphore) \
- { ATOMIC_INIT(0), ATOMIC_INIT(-1), NULL })
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name)                , (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count)            \
+       { ATOMIC_INIT(count), ATOMIC_INIT(-1),          \
+         __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)    \
+         __SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+       __SEMAPHORE_INITIALIZER(name,1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+       struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+extern inline void sema_init (struct semaphore *sem, int val)
+{
+       /*
+        * Logically, 
+        *   *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
+        * except that gcc produces better initializing by parts yet.
+        */
+
+       atomic_set(&sem->count, val);
+       atomic_set(&sem->waking, -1);
+       init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+       sem->__magic = (long)&sem->__magic;
+#endif
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+       sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+       sema_init(sem, 0);
+}
 
-#define sema_init(sem, val)    atomic_set(&((sem)->count), val)
 
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
@@ -57,8 +100,13 @@ extern inline void down(struct semaphore * sem)
           a function that ordinarily wouldn't.  Otherwise we could
           have it done by the macro directly, which can be optimized
           the linker.  */
-       register void *pv __asm__("$27") = __down_failed;
+       register void *pv __asm__("$27");
+
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
        
+       pv = __down_failed;
        __asm__ __volatile__ (
                "/* semaphore down operation */\n"
                "1:     ldl_l   $24,%1\n"
@@ -88,8 +136,13 @@ extern inline int down_interruptible(struct semaphore * sem)
           value is in $24.  */
 
        register int ret __asm__("$24");
-       register void *pv __asm__("$27") = __down_failed_interruptible;
+       register void *pv __asm__("$27");
 
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+       
+       pv = __down_failed_interruptible;
        __asm__ __volatile__ (
                "/* semaphore down interruptible operation */\n"
                "1:     ldl_l   $24,%2\n"
@@ -144,6 +197,10 @@ extern inline int down_trylock(struct semaphore * sem)
           } while (tmp == 0);
        */
 
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+       
        __asm__ __volatile__(
                "1:     ldq_l   %1,%4\n"
                "       lda     %3,1\n"
@@ -179,8 +236,13 @@ extern inline void up(struct semaphore * sem)
           it's return address in $28.  The pv is loaded as usual.
           The gp is clobbered (in the module case) as usual.  */
 
-       register void *pv __asm__("$27") = __up_wakeup;
+       register void *pv __asm__("$27");
 
+#if WAITQUEUE_DEBUG
+       CHECK_MAGIC(sem->__magic);
+#endif
+       
+       pv = __up_wakeup;
        __asm__ __volatile__ (
                "/* semaphore up operation */\n"
                "       mb\n"
index a59e441a14de94427fc582ceb5388f162f77b2a0..f308d67b1c39a7bfec06239760b3f6d36639dfe4 100644 (file)
@@ -7,6 +7,12 @@
 #ifndef __ASM_ARM_PROCESSOR_H
 #define __ASM_ARM_PROCESSOR_H
 
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
 #define FP_SIZE 35
 
 struct fp_hard_struct {
index b98893662383e99fbb27a4dd61b342e71da94f70..43c0a3673e255df52969def9fed79851549e6295 100644 (file)
 #include <asm/math_emu.h>
 #include <asm/segment.h>
 #include <asm/page.h>
+#include <asm/types.h>
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; })
 
 /*
  *  CPU type and hardware bug flags. Kept separately for each CPU.
@@ -279,6 +286,7 @@ struct thread_struct {
 } while (0)
 
 /* Forward declaration, a strange C thing */
+struct task_struct;
 struct mm_struct;
 
 /* Free all resources held by a thread. */
index a0e4d76b640c74e7a45633d659b7904fa3a47863..ef834400ad9c3bb58a1f711c8f8a62dc04aa10fd 100644 (file)
@@ -40,6 +40,13 @@ extern atomic_t global_bh_count;
 
 extern void synchronize_bh(void);
 
+/*
+ * This is suboptimal. We only need to disable bh's locally
+ * on this CPU...
+ */
+#define local_bh_disable()     atomic_inc(&global_bh_lock)
+#define local_bh_enable()      atomic_dec(&global_bh_lock)
+
 static inline void start_bh_atomic(void)
 {
        atomic_inc(&global_bh_lock);
index 00e238407f6a6fc54e1434b2f77fd048b6c1f3d5..b447a402f956d64c1e2c3ed69e0428e6475e835e 100644 (file)
@@ -1,6 +1,35 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
+/*
+ * These are the generic versions of the spinlocks
+ * and read-write locks.. We should actually do a
+ * <linux/spinlock.h> with all of this. Oh, well.
+ */
+#define spin_lock_irqsave(lock, flags)         do { local_irq_save(flags);       spin_lock(lock); } while (0)
+#define spin_lock_irq(lock)                    do { local_irq_disable();         spin_lock(lock); } while (0)
+#define spin_lock_bh(lock)                     do { local_bh_disable();          spin_lock(lock); } while (0)
+
+#define read_lock_irqsave(lock, flags)         do { local_irq_save(flags);       read_lock(lock); } while (0)
+#define read_lock_irq(lock)                    do { local_irq_disable();         read_lock(lock); } while (0)
+#define read_lock_bh(lock)                     do { local_bh_disable();          read_lock(lock); } while (0)
+
+#define write_lock_irqsave(lock, flags)                do { local_irq_save(flags);      write_lock(lock); } while (0)
+#define write_lock_irq(lock)                   do { local_irq_disable();        write_lock(lock); } while (0)
+#define write_lock_bh(lock)                    do { local_bh_disable();         write_lock(lock); } while (0)
+
+#define spin_unlock_irqrestore(lock, flags)    do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
+#define spin_unlock_irq(lock)                  do { spin_unlock(lock);  local_irq_enable();       } while (0)
+#define spin_unlock_bh(lock)                   do { spin_unlock(lock);  local_bh_enable();        } while (0)
+
+#define read_unlock_irqrestore(lock, flags)    do { read_unlock(lock);  local_irq_restore(flags); } while (0)
+#define read_unlock_irq(lock)                  do { read_unlock(lock);  local_irq_enable();       } while (0)
+#define read_unlock_bh(lock)                   do { read_unlock(lock);  local_bh_enable();        } while (0)
+
+#define write_unlock_irqrestore(lock, flags)   do { write_unlock(lock); local_irq_restore(flags); } while (0)
+#define write_unlock_irq(lock)                 do { write_unlock(lock); local_irq_enable();       } while (0)
+#define write_unlock_bh(lock)                  do { write_unlock(lock); local_bh_enable();        } while (0)
+
 #ifndef __SMP__
 
 #define DEBUG_SPINLOCKS        0       /* 0 == no debugging, 1 == maintain lock state, 2 == full debug */
 #define spin_trylock(lock)     (1)
 #define spin_unlock_wait(lock) do { } while(0)
 #define spin_unlock(lock)      do { } while(0)
-#define spin_lock_irq(lock)    cli()
-#define spin_unlock_irq(lock)  sti()
-
-#define spin_lock_irqsave(lock, flags) \
-       do { save_flags(flags); cli(); } while (0)
-#define spin_unlock_irqrestore(lock, flags) \
-       restore_flags(flags)
 
 #elif (DEBUG_SPINLOCKS < 2)
 
@@ -46,13 +68,6 @@ typedef struct {
 #define spin_lock(x)           do { (x)->lock = 1; } while (0)
 #define spin_unlock_wait(x)    do { } while (0)
 #define spin_unlock(x)         do { (x)->lock = 0; } while (0)
-#define spin_lock_irq(x)       do { cli(); spin_lock(x); } while (0)
-#define spin_unlock_irq(x)     do { spin_unlock(x); sti(); } while (0)
-
-#define spin_lock_irqsave(x, flags) \
-       do { save_flags(flags); spin_lock_irq(x); } while (0)
-#define spin_unlock_irqrestore(x, flags) \
-       do { spin_unlock(x); restore_flags(flags); } while (0)
 
 #else /* (DEBUG_SPINLOCKS >= 2) */
 
@@ -71,11 +86,6 @@ typedef struct {
 #define spin_lock(x)           do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0)
 #define spin_unlock_wait(x)    do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0)
 #define spin_unlock(x)         do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0)
-#define spin_lock_irq(x)       do {cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock_irq(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1;} while (0)
-#define spin_unlock_irq(x)     do {cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; sti();} while (0)
-
-#define spin_lock_irqsave(x,flags)      do {save_flags(flags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock_irqsave(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1;} while (0)
-#define spin_unlock_irqrestore(x,flags) do {cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_irqrestore(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(flags);} while (0)
 
 #endif /* DEBUG_SPINLOCKS */
 
@@ -103,19 +113,6 @@ typedef struct {
 #define read_unlock(lock)      do { } while(0)
 #define write_lock(lock)       do { } while(0)
 #define write_unlock(lock)     do { } while(0)
-#define read_lock_irq(lock)    cli()
-#define read_unlock_irq(lock)  sti()
-#define write_lock_irq(lock)   cli()
-#define write_unlock_irq(lock) sti()
-
-#define read_lock_irqsave(lock, flags) \
-       do { save_flags(flags); cli(); } while (0)
-#define read_unlock_irqrestore(lock, flags) \
-       restore_flags(flags)
-#define write_lock_irqsave(lock, flags)        \
-       do { save_flags(flags); cli(); } while (0)
-#define write_unlock_irqrestore(lock, flags) \
-       restore_flags(flags)
 
 #else  /* __SMP__ */
 
@@ -168,18 +165,6 @@ __asm__ __volatile__( \
 
 #define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
 
-#define spin_lock_irq(lock) \
-       do { __cli(); spin_lock(lock); } while (0)
-
-#define spin_unlock_irq(lock) \
-       do { spin_unlock(lock); __sti(); } while (0)
-
-#define spin_lock_irqsave(lock, flags) \
-       do { __save_flags(flags); __cli(); spin_lock(lock); } while (0)
-
-#define spin_unlock_irqrestore(lock, flags) \
-       do { spin_unlock(lock); __restore_flags(flags); } while (0)
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
@@ -236,19 +221,5 @@ typedef struct {
 #define write_unlock(rw) \
        asm volatile("lock ; btrl $31,%0":"=m" (__dummy_lock(&(rw)->lock)))
 
-#define read_lock_irq(lock)    do { __cli(); read_lock(lock); } while (0)
-#define read_unlock_irq(lock)  do { read_unlock(lock); __sti(); } while (0)
-#define write_lock_irq(lock)   do { __cli(); write_lock(lock); } while (0)
-#define write_unlock_irq(lock) do { write_unlock(lock); __sti(); } while (0)
-
-#define read_lock_irqsave(lock, flags) \
-       do { __save_flags(flags); __cli(); read_lock(lock); } while (0)
-#define read_unlock_irqrestore(lock, flags) \
-       do { read_unlock(lock); __restore_flags(flags); } while (0)
-#define write_lock_irqsave(lock, flags)        \
-       do { __save_flags(flags); __cli(); write_lock(lock); } while (0)
-#define write_unlock_irqrestore(lock, flags) \
-       do { write_unlock(lock); __restore_flags(flags); } while (0)
-
 #endif /* __SMP__ */
 #endif /* __ASM_SPINLOCK_H */
index ebdb8b790f9bfa5b3c188cbef96e445569558833..147ad6da4844eeac235403c22c0044d1af61f719 100644 (file)
@@ -181,6 +181,11 @@ __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
 #define __restore_flags(x) \
 __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
 
+/* For spinlocks etc */
+#define local_irq_save(x)      __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_restore(x)   __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
+#define local_irq_disable()    __asm__ __volatile__("cli": : :"memory")
+#define local_irq_enable()     __asm__ __volatile__("sti": : :"memory")
 
 #ifdef __SMP__
 
index 9bb167608041d9b78d5c6fe3fc12d371e759e07b..3115e46c352fd0cdb2c257ca756b77a0ac0d1a27 100644 (file)
@@ -7,6 +7,12 @@
 #ifndef __ASM_M68K_PROCESSOR_H
 #define __ASM_M68K_PROCESSOR_H
 
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
 #include <asm/segment.h>
 #include <asm/fpu.h>
 
index 5dd07871f6a1e3e8a7fdda4d2b27dcd7d8e944ba..15ae6e668257f557ddea99bff8d77ceeffcada5b 100644 (file)
 #ifndef __ASM_MIPS_PROCESSOR_H
 #define __ASM_MIPS_PROCESSOR_H
 
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
 #if !defined (_LANGUAGE_ASSEMBLY)
 #include <asm/cachectl.h>
 #include <asm/mipsregs.h>
index 30a53876ee8427ea8050876fafbe2033f679efa2..39d48b6d1cddb6aa44fc6beeab28075957bf9a98 100644 (file)
@@ -83,12 +83,18 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
-       return ppc_ide_md.default_irq(base);
+       if ( ppc_ide_md.default_irq )
+               return ppc_ide_md.default_irq(base);
+       else
+               return -1;
 }
 
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
-       return ppc_ide_md.default_io_base(index);
+       if ( ppc_ide_md.default_io_base )
+               return ppc_ide_md.default_io_base(index);
+       else
+               return -1;
 }
 
 static __inline__ void ide_init_default_hwifs(void)
@@ -107,21 +113,28 @@ static __inline__ void ide_init_default_hwifs(void)
 
 static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
-       return ppc_ide_md.check_region(from, extent);
+       if ( ppc_ide_md.check_region )
+               return ppc_ide_md.check_region(from, extent);
+       else
+               return -1;
 }
 
 static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
-       ppc_ide_md.request_region(from, extent, name);
+       if ( ppc_ide_md.request_region )
+               ppc_ide_md.request_region(from, extent, name);
 }
 
 static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
-       ppc_ide_md.release_region(from, extent);
+       if ( ppc_ide_md.release_region )
+               ppc_ide_md.release_region(from, extent);
 }
 
-static __inline__ void ide_fix_driveid (struct hd_driveid *id) {
-        ppc_ide_md.fix_driveid(id);
+static __inline__ void ide_fix_driveid (struct hd_driveid *id)
+{
+        if ( ppc_ide_md.fix_driveid )
+               ppc_ide_md.fix_driveid(id);
 }
 
 #undef inb
index f77ef3df4c7752c600c177d9670f920404e9ffa6..7355f3c8dc0ca398ef6bafdbb94f43ae3f5ed85a 100644 (file)
@@ -8,11 +8,20 @@
 #ifndef __ASSEMBLY__
 /* Hardware Page Table Entry */
 typedef struct _PTE {
+#ifdef CONFIG_PPC64
+       unsigned long long vsid:52;
+       unsigned long api:5;
+       unsigned long :5;
+       unsigned long h:1;
+       unsigned long v:1;
+       unsigned long long rpn:52;
+#else /* CONFIG_PPC64 */
        unsigned long v:1;      /* Entry is valid */
        unsigned long vsid:24;  /* Virtual segment identifier */
        unsigned long h:1;      /* Hash algorithm indicator */
        unsigned long api:6;    /* Abbreviated page index */
        unsigned long rpn:20;   /* Real (physical) page number */
+#endif /* CONFIG_PPC64 */
        unsigned long    :3;    /* Unused */
        unsigned long r:1;      /* Referenced */
        unsigned long c:1;      /* Changed */
@@ -53,7 +62,11 @@ typedef struct _P601_BATU {  /* Upper part of BAT for 601 processor */
 } P601_BATU;
 
 typedef struct _BATU {         /* Upper part of BAT (all except 601) */
+#ifdef CONFIG_PPC64
+       unsigned long long bepi:47;
+#else /* CONFIG_PPC64 */
        unsigned long bepi:15;  /* Effective page index (virtual address) */
+#endif /* CONFIG_PPC64 */
        unsigned long :4;       /* Unused */
        unsigned long bl:11;    /* Block size mask */
        unsigned long vs:1;     /* Supervisor valid */
@@ -68,7 +81,11 @@ typedef struct _P601_BATL {  /* Lower part of BAT for 601 processor */
 } P601_BATL;
 
 typedef struct _BATL {         /* Lower part of BAT (all except 601) */
+#ifdef CONFIG_PPC64
+       unsigned long long brpn:47;
+#else /* CONFIG_PPC64 */
        unsigned long brpn:15;  /* Real page index (physical address) */
+#endif /* CONFIG_PPC64 */
        unsigned long :10;      /* Unused */
        unsigned long w:1;      /* Write-thru cache */
        unsigned long i:1;      /* Cache inhibit */
index 2c481490e35ff756a9009fc0018a4ca3d8d55332..10f1f0efce1d51b6943e0cf581847ac65ef9b368 100644 (file)
@@ -20,6 +20,11 @@ extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 #define flush_tlb_page local_flush_tlb_page
 #define flush_tlb_range local_flush_tlb_range
 
+extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+       /* PPC has hw page tables. */
+}
+
 /*
  * No cache flushing is required when address mappings are
  * changed, because the caches on PowerPCs are physically
index c8358cb0ba5ae73bf82c9158dea29c52a85a7152..1f587a1512d0d55216ca42481aa89271acdfc25b 100644 (file)
@@ -1,12 +1,22 @@
 #ifndef __ASM_PPC_PROCESSOR_H
 #define __ASM_PPC_PROCESSOR_H
 
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
 #include <linux/config.h>
 
 #include <asm/ptrace.h>
 #include <asm/residual.h>
 
 /* Bit encodings for Machine State Register (MSR) */
+#ifdef CONFIG_PPC64
+#define MSR_SF         (1<<63)
+#define MSR_ISF                (1<<61)
+#endif /* CONFIG_PPC64 */
 #define MSR_POW                (1<<18)         /* Enable Power Management */
 #define MSR_TGPR       (1<<17)         /* TLB Update registers in use */
 #define MSR_ILE                (1<<16)         /* Interrupt Little-Endian enable */
index 6909d7c3a72b9045e88f0d0e9a7d98dd317d23dd..9c3abcfd9bb0a356d1b858c80e127af5ebd6bcfc 100644 (file)
  */
 
 #ifndef __ASSEMBLY__
+#ifdef CONFIG_PPC64
+#define REG unsigned long /*long*/
+#else
+#define REG unsigned long
+#endif
 struct pt_regs {
-       unsigned long gpr[32];
-       unsigned long nip;
-       unsigned long msr;
-       unsigned long orig_gpr3; /* Used for restarting system calls */
-       unsigned long ctr;
-       unsigned long link;
-       unsigned long xer;
-       unsigned long ccr;
-       unsigned long mq;       /* 601 only (not used at present) */
-                               /* Used on APUS to hold IPL value. */
-       unsigned long trap;     /* Reason for being here */
-       unsigned long dar;      /* Fault registers */
-       unsigned long dsisr;
-       unsigned long result;   /* Result of a system call */
+       REG gpr[32];
+       REG nip;
+       REG msr;
+       REG orig_gpr3;  /* Used for restarting system calls */
+       REG ctr;
+       REG link;
+       REG xer;
+       REG ccr;
+       REG mq;         /* 601 only (not used at present) */
+                       /* Used on APUS to hold IPL value. */
+       REG trap;       /* Reason for being here */
+       REG dar;        /* Fault registers */
+       REG dsisr;
+       REG result;     /* Result of a system call */
 };
 #endif
 
index 6a682caa637e6bf339e0576018fb4921b9b936db..f7b87ff0d919e83e2695d2737093900365b5a31b 100644 (file)
@@ -1,27 +1,64 @@
-#ifndef _PPC_SEMAPHORE_H
-#define _PPC_SEMAPHORE_H
+#ifndef _SPARC_SEMAPHORE_H
+#define _SPARC_SEMAPHORE_H
 
 /*
- * SMP- and interrupt-safe semaphores..
- *
- * (C) Copyright 1996 Linus Torvalds
- * Adapted for PowerPC by Gary Thomas and Paul Mackerras
+ * Swiped from asm-sparc/semaphore.h and modified
+ * -- Cort (cort@cs.nmt.edu)
  */
 
+#ifdef __KERNEL__
+
 #include <asm/atomic.h>
+#include <linux/wait.h>
 
 struct semaphore {
        atomic_t count;
        atomic_t waking;
        wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+       long __magic;
+#endif
 };
 
-#define sema_init(sem, val)    atomic_set(&((sem)->count), (val))
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+               , (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+       __SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+       __SEMAPHORE_INITIALIZER(name,1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+       struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+extern inline void sema_init (struct semaphore *sem, int val)
+{
+       atomic_set(&sem->count, val);
+       atomic_set(&sem->waking, 0);
+       init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+       sem->__magic = (long)&sem->__magic;
+#endif
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+       sema_init(sem, 1);
+}
 
-#define MUTEX          ((struct semaphore) \
-                        { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
-#define MUTEX_LOCKED   ((struct semaphore) \
-                        { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+       sema_init(sem, 0);
+}
 
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
@@ -65,4 +102,6 @@ extern inline void up(struct semaphore * sem)
                __up(sem);
 }      
 
-#endif /* !(_PPC_SEMAPHORE_H) */
+#endif /* __KERNEL__ */
+
+#endif /* !(_SPARC_SEMAPHORE_H) */
index 427bb5ddd01f5a0a0124e10eecad7c8863813dad..99a0a803870517f9ce5f318931efe77e6ecf062a 100644 (file)
@@ -58,7 +58,6 @@ extern void __cli(void);
 extern int _disable_interrupts(void);
 extern void _enable_interrupts(int);
 
-extern void instruction_dump(unsigned long *);
 extern void print_backtrace(unsigned long *);
 extern void show_regs(struct pt_regs * regs);
 extern void flush_instruction_cache(void);
index a79d587914a3cda1d63343fc8803608bf044e14b..5990bba5edfa4eb5efdfd385ae4ba7f6ae4c0be3 100644 (file)
@@ -7,6 +7,12 @@
 #ifndef __ASM_SPARC_PROCESSOR_H
 #define __ASM_SPARC_PROCESSOR_H
 
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
 #include <linux/a.out.h>
 
 #include <asm/psr.h>
index 0facbaf4f87f6d3eba33c509b9201b889e13c768..8bf687ec92c6fe3280b80b352753adcd0554c638 100644 (file)
@@ -7,6 +7,12 @@
 #ifndef __ASM_SPARC64_PROCESSOR_H
 #define __ASM_SPARC64_PROCESSOR_H
 
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
 #include <asm/asi.h>
 #include <asm/a.out.h>
 #include <asm/pstate.h>
index f249cd698957db87226901eeaaa9c60946c738e3..24da4e0942be5be7a48e842d8eccb06d4588ef32 100644 (file)
@@ -94,7 +94,8 @@ static inline void end_bh_atomic(void)
 static inline int softirq_trylock(int cpu)
 {
        if (spin_trylock(&global_bh_count)) {
-               if (atomic_read(&global_bh_lock) == 0) {
+               if (atomic_read(&global_bh_lock) == 0 &&
+                   cpu_data[cpu].bh_count == 0) {
                        ++(cpu_data[cpu].bh_count);
                        return 1;
                }
index 930e32f65edb2aaa18c4e9f3ba440fda3574e6d1..d0c25a965966ad43b9331b6eccfc399dd4194754 100644 (file)
@@ -20,6 +20,14 @@ typedef unsigned char spinlock_t;
 #define spin_unlock(lock)      do { } while(0)
 #define spin_lock_irq(lock)    cli()
 #define spin_unlock_irq(lock)  sti()
+#define spin_lock_bh(lock) \
+do {   local_bh_count++; \
+       barrier(); \
+} while(0)
+#define spin_unlock_bh(lock) \
+do {   barrier(); \
+       local_bh_count--; \
+} while(0)
 
 #define spin_lock_irqsave(lock, flags)         save_and_cli(flags)
 #define spin_unlock_irqrestore(lock, flags)    restore_flags(flags)
@@ -43,9 +51,28 @@ typedef unsigned long rwlock_t;
 #define write_unlock(lock)     do { } while(0)
 #define read_lock_irq(lock)    cli()
 #define read_unlock_irq(lock)  sti()
+#define read_lock_bh(lock) \
+do {   local_bh_count++; \
+       barrier(); \
+} while(0)
+#define read_unlock_bh(lock) \
+do {   barrier(); \
+       local_bh_count--; \
+} while(0)
+
 #define write_lock_irq(lock)   cli()
 #define write_unlock_irq(lock) sti()
 
+#define write_lock_bh(lock) \
+do {   local_bh_count++; \
+       barrier(); \
+} while(0)
+#define write_unlock_bh(lock) \
+do {   barrier(); \
+       local_bh_count--; \
+} while(0)
+
 #define read_lock_irqsave(lock, flags)         save_and_cli(flags)
 #define read_unlock_irqrestore(lock, flags)    restore_flags(flags)
 #define write_lock_irqsave(lock, flags)                save_and_cli(flags)
@@ -149,6 +176,16 @@ extern __inline__ void spin_unlock_irq(spinlock_t *lock)
        : "memory");
 }
 
+#define spin_lock_bh(__lock)   \
+do {   local_bh_count++;       \
+       spin_lock(__lock);      \
+} while(0)
+
+#define spin_unlock_bh(__lock)         \
+do {   spin_unlock(__lock);            \
+       local_bh_count--;               \
+} while(0)
+
 #define spin_lock_irqsave(__lock, flags)                       \
 do {   register spinlock_t *__lp asm("g1");                    \
        __lp = (__lock);                                        \
@@ -205,9 +242,11 @@ extern int _spin_trylock (spinlock_t *lock);
 #define spin_trylock(lp)       _spin_trylock(lp)
 #define spin_lock(lock)                _do_spin_lock(lock, "spin_lock")
 #define spin_lock_irq(lock)    do { __cli(); _do_spin_lock(lock, "spin_lock_irq"); } while(0)
+#define spin_lock_bh(lock)     do { local_bh_count++; _do_spin_lock(lock, "spin_lock_bh"); } while(0)
 #define spin_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_spin_lock(lock, "spin_lock_irqsave"); } while(0)
 #define spin_unlock(lock)      _do_spin_unlock(lock)
 #define spin_unlock_irq(lock)  do { _do_spin_unlock(lock); __sti(); } while(0)
+#define spin_unlock_bh(lock)   do { _do_spin_unlock(lock); local_bh_count--; } while(0)
 #define spin_unlock_irqrestore(lock, flags) do { _do_spin_unlock(lock); __restore_flags(flags); } while(0)
 
 #endif /* SPIN_LOCK_DEBUG */
@@ -303,8 +342,12 @@ extern __inline__ void write_unlock(rwlock_t *rw)
 
 #define read_lock_irq(lock)    do { __cli(); read_lock(lock); } while (0)
 #define read_unlock_irq(lock)  do { read_unlock(lock); __sti(); } while (0)
+#define read_lock_bh(lock)     do { local_bh_count++; read_lock(lock); } while (0)
+#define read_unlock_bh(lock)   do { read_unlock(lock); local_bh_count--; } while (0)
 #define write_lock_irq(lock)   do { __cli(); write_lock(lock); } while (0)
 #define write_unlock_irq(lock) do { write_unlock(lock); __sti(); } while (0)
+#define write_lock_bh(lock)    do { local_bh_count++; write_lock(lock); } while (0)
+#define write_unlock_bh(lock)  do { write_unlock(lock); local_bh_count--; } while (0)
 
 #define read_lock_irqsave(lock, flags) \
        do { __save_and_cli(flags); read_lock(lock); } while (0)
@@ -336,6 +379,7 @@ do {        unsigned long flags; \
        __restore_flags(flags); \
 } while(0)
 #define read_lock_irq(lock)    do { __cli(); _do_read_lock(lock, "read_lock_irq"); } while(0)
+#define read_lock_bh(lock)     do { local_bh_count++; _do_read_lock(lock, "read_lock_bh"); } while(0)
 #define read_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_read_lock(lock, "read_lock_irqsave"); } while(0)
 
 #define read_unlock(lock) \
@@ -345,6 +389,7 @@ do {        unsigned long flags; \
        __restore_flags(flags); \
 } while(0)
 #define read_unlock_irq(lock)  do { _do_read_unlock(lock, "read_unlock_irq"); __sti() } while(0)
+#define read_unlock_bh(lock)   do { _do_read_unlock(lock, "read_unlock_bh"); local_bh_count--; } while(0)
 #define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0)
 
 #define write_lock(lock) \
@@ -354,6 +399,7 @@ do {        unsigned long flags; \
        __restore_flags(flags); \
 } while(0)
 #define write_lock_irq(lock)   do { __cli(); _do_write_lock(lock, "write_lock_irq"); } while(0)
+#define write_lock_bh(lock)    do { local_bh_count++; _do_write_lock(lock, "write_lock_bh"); } while(0)
 #define write_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_write_lock(lock, "write_lock_irqsave"); } while(0)
 
 #define write_unlock(lock) \
@@ -363,6 +409,7 @@ do {        unsigned long flags; \
        __restore_flags(flags); \
 } while(0)
 #define write_unlock_irq(lock) do { _do_write_unlock(lock); __sti(); } while(0)
+#define write_unlock_bh(lock)  do { _do_write_unlock(lock); local_bh_count--; } while(0)
 #define write_unlock_irqrestore(lock, flags) do { _do_write_unlock(lock); __restore_flags(flags); } while(0)
 
 #endif /* SPIN_LOCK_DEBUG */
index f564ae89884dd3af26bef69a276a0a5e5b4f710d..71ad74f6ec275387fbc75b1f670e407f9476de43 100644 (file)
@@ -1,11 +1,33 @@
 /*
- * $Id: b1lli.h,v 1.3 1998/01/31 10:54:37 calle Exp $
+ * $Id: b1lli.h,v 1.6 1999/04/15 19:49:36 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.6  1999/04/15 19:49:36  calle
+ * fix fuer die B1-PCI. Jetzt geht z.B. auch IRQ 17 ...
+ *
+ * Revision 1.5  1998/10/25 14:50:28  fritz
+ * Backported from MIPS (Cobalt).
+ *
+ * Revision 1.4  1998/03/29 16:05:02  calle
+ * changes from 2.0 tree merged.
+ *
+ * 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.3  1998/01/31 10:54:37  calle
  * include changes for PCMCIA cards from 2.0 version
  *
@@ -70,15 +92,17 @@ typedef struct avmb1_carddef {
        int irq;
 } avmb1_carddef;
 
-#define AVM_CARDTYPE_B1        0
-#define AVM_CARDTYPE_T1        1
-#define AVM_CARDTYPE_M1        2
-#define AVM_CARDTYPE_M2        3
+#define AVM_CARDTYPE_B1                0
+#define AVM_CARDTYPE_T1                1
+#define AVM_CARDTYPE_M1                2
+#define AVM_CARDTYPE_M2                3
+#define AVM_CARDTYPE_B1PCI     4
 
 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 */
@@ -87,6 +111,7 @@ typedef struct avmb1_extcarddef {
 #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) */
 
 
 
@@ -103,14 +128,12 @@ typedef struct avmb1_extcarddef {
 
 #ifdef __KERNEL__
 
-#define        AVMB1_PORTLEN   0x1f
+#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
@@ -119,9 +142,10 @@ typedef struct avmb1_extcarddef {
 typedef struct avmb1_card {
        struct avmb1_card *next;
        int cnr;
-       unsigned short port;
+       unsigned int port;
        unsigned irq;
        int cardtype;
+       int cardnr; /* for T1-HEMA */
        volatile unsigned short cardstate;
        int interrupt;
        int blocked;
@@ -149,23 +173,26 @@ typedef struct avmb1_card {
 
 
 /* b1lli.c */
-int B1_detect(unsigned short base, int cardtype);
-void B1_reset(unsigned short base);
-int B1_load_t4file(unsigned short base, avmb1_t4file * t4file);
-int B1_load_config(unsigned short base, avmb1_t4file * config);
-int B1_loaded(unsigned short base);
-unsigned char B1_assign_irq(unsigned short base, unsigned irq, int cardtype);
-unsigned char B1_enable_irq(unsigned short base);
-unsigned char B1_disable_irq(unsigned short base);
+int B1_detect(unsigned int base, int cardtype);
+int T1_detectandinit(unsigned int base, unsigned irq, int cardnr);
+void B1_reset(unsigned int base);
+void T1_reset(unsigned int base);
+int B1_load_t4file(unsigned int base, avmb1_t4file * t4file);
+int B1_load_config(unsigned int base, avmb1_t4file * config);
+int B1_loaded(unsigned int base);
+void B1_setinterrupt(unsigned int base, unsigned irq, int cardtype);
+unsigned char B1_disable_irq(unsigned int base);
+void T1_disable_irq(unsigned int 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,
+void B1_send_init(unsigned int port,
            unsigned int napps, unsigned int nncci, unsigned int cardnr);
-void B1_send_register(unsigned short port,
+void B1_send_register(unsigned int port,
                      __u16 appid, __u32 nmsg,
                      __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize);
-void B1_send_release(unsigned short port, __u16 appid);
-void B1_send_message(unsigned short port, struct sk_buff *skb);
+void B1_send_release(unsigned int port, __u16 appid);
+void B1_send_message(unsigned int port, struct sk_buff *skb);
 
 /* b1capi.c */
 void avmb1_handle_new_ncci(avmb1_card * card,
index dd4283a609cded47c90fe13c926cd4c8fec031a4..2a5e4fb82b90bd4fa18550609f0ac4456dfcd0d7 100644 (file)
@@ -34,7 +34,7 @@ struct blkpg_ioctl_arg {
         int flags;
         int datalen;
         void *data;
-} *p;
+};
 
 /* The subfunctions (for the op field) */
 #define BLKPG_ADD_PARTITION    1
index be558dc96164a82a012d5871b13e39f4439f04bd..2c127526cd35a517576bc18bd17db64041437dba 100644 (file)
@@ -557,7 +557,8 @@ struct cyclades_port {
        unsigned long           event;
        unsigned long           last_active;
        int                     count;  /* # of fd on device */
-       int                     x_break;
+       int                     breakon;
+       int                     breakoff;
        int                     blocked_open; /* # of blocked opens */
        long                    session; /* Session of opening process */
        long                    pgrp; /* pgrp of opening process */
index 129e1ed58ccc3a71bc7aed0da563aa34a25c288f..29e9766ea92d923a1e1ed39200d4fccead911557 100644 (file)
@@ -22,6 +22,8 @@
  *
  */
 
+#include <linux/version.h>
+
 #define I2C_BUS_MAX       4    /* max # of bus drivers  */
 #define I2C_DRIVER_MAX    8    /* max # of chip drivers */
 #define I2C_DEVICE_MAX    8    /* max # if devices per bus/driver */
@@ -35,6 +37,7 @@ struct i2c_device;
 #define I2C_DRIVERID_VIDEOTEXT  3
 
 #define I2C_BUSID_BT848                1       /* I2C bus on a BT848 */
+#define I2C_BUSID_PARPORT      2       /* Bit banging on a parallel port */
 
 /*
  * struct for a driver for a i2c chip (tuner, soundprocessor,
index f504bbde8e48b7bebc94feb97f7a10c80e4ad883..c0a3ba3094586b468ccf1beceaf8a5cea26b26e7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.37 1998/02/22 19:45:24 fritz Exp $
+/* $Id: isdn.h,v 1.64 1999/04/18 14:57:14 fritz Exp $
  *
  * Main header for the Linux ISDN subsystem (linklevel).
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * Note: This file differs from the corresponding revision as present in the
- * isdn4linux CVS repository because some later bug fixes have been extracted
- * from the repository and merged into this file. -- Henner Eisen
- *
  * $Log: isdn.h,v $
+ * Revision 1.64  1999/04/18 14:57:14  fritz
+ * Removed TIMRU stuff
+ *
+ * Revision 1.63  1999/04/18 14:07:18  fritz
+ * Removed TIMRU stuff.
+ *
+ * Revision 1.62  1999/04/12 13:16:54  fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.61  1999/03/02 11:43:21  armin
+ * Added variable to store connect-message of Modem.
+ * Added Timer-define for RegS7 (Wait for Carrier).
+ *
+ * Revision 1.60  1998/10/25 14:50:29  fritz
+ * Backported from MIPS (Cobalt).
+ *
+ * Revision 1.59  1998/10/23 10:18:55  paul
+ * Implementation of "dialmode" (successor of "status")
+ * You also need current isdnctrl for this!
+ *
+ * Revision 1.58  1998/10/23 10:10:06  fritz
+ * Test-Checkin
+ *
+ * Revision 1.57  1998/08/31 21:10:01  he
+ * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface'
+ *     peer phone number)
+ *
+ * Revision 1.56  1998/07/26 18:46:52  armin
+ * Added silence detection in voice receive mode.
+ *
+ * Revision 1.55  1998/06/26 15:13:17  fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 1.54  1998/06/18 23:32:01  fritz
+ * Replaced cli()/restore_flags() in isdn_tty_write() by locking.
+ * Removed direct-senddown feature in isdn_tty_write because it will
+ * never succeed with locking and is useless anyway.
+ *
+ * Revision 1.53  1998/06/17 19:51:51  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.52  1998/06/12 11:42:18  detabc
+ * cleanup abc
+ *
+ * Revision 1.51  1998/06/02 12:10:30  detabc
+ * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
+ * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
+ *
+ * Revision 1.50  1998/05/05 23:11:51  detabc
+ * add Item to stop icmp-unreach (max. 6 times of dialwait delay)
+ *
+ * Revision 1.49  1998/05/03 17:45:00  detabc
+ * Add Item to send icmp-host-unreach to all packets
+ *
+ * Revision 1.48  1998/04/26 19:58:14  detabc
+ * include the new abc-extension-items from 2.0.xx kernels
+ * remove some unused code
+ *
+ * Revision 1.47  1998/04/21 18:00:25  detabc
+ * Add items for secure-callback (abc-extension only)
+ *
+ * Revision 1.46  1998/04/14 16:28:59  he
+ * Fixed user space access with interrupts off and remaining
+ * copy_{to,from}_user() -> -EFAULT return codes
+ *
+ * Revision 1.45  1998/03/24 16:33:12  hipp
+ * More CCP changes. BSD compression now "works" on a local loopback link.
+ * Moved some isdn_ppp stuff from isdn.h to isdn_ppp.h
+ *
+ * Revision 1.44  1998/03/22 18:50:56  hipp
+ * Added BSD Compression for syncPPP .. UNTESTED at the moment
+ *
+ * Revision 1.43  1998/03/09 17:46:44  he
+ * merged in 2.1.89 changes
+ *
+ * Revision 1.42  1998/03/08 13:53:46  detabc
+ * add ABC-variables in structur isdn_devt
+ *
+ * Revision 1.41  1998/03/08 13:14:37  detabc
+ * abc-extension support for kernels > 2.1.x
+ * first try (sorry experimental)
+ *
+ * Revision 1.40  1998/03/08 01:08:29  fritz
+ * Increased NET_DV because of TIMRU
+ *
+ * Revision 1.39  1998/03/07 22:42:49  fritz
+ * Starting generic module support (Nothing usable yet).
+ *
+ * Revision 1.38  1998/03/07 18:21:29  cal
+ * Dynamic Timeout-Rule-Handling vs. 971110 included
+ *
  * Revision 1.37  1998/02/22 19:45:24  fritz
  * Some changes regarding V.110
  *
 #ifndef isdn_h
 #define isdn_h
 
+#include <linux/config.h>
 #include <linux/ioctl.h>
 
 #define ISDN_TTY_MAJOR    43
  * the correspondent code in isdn.c
  */
 
+#ifdef CONFIG_COBALT_MICRO_SERVER
+/* Save memory */
+#define ISDN_MAX_DRIVERS    2
+#define ISDN_MAX_CHANNELS   8
+#else
 #define ISDN_MAX_DRIVERS    32
 #define ISDN_MAX_CHANNELS   64
+#endif
 #define ISDN_MINOR_B        0
 #define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
-#define ISDN_MINOR_CTRL     ISDN_MAX_CHANNELS
-#define ISDN_MINOR_CTRLMAX  (2*ISDN_MAX_CHANNELS-1)
-#define ISDN_MINOR_PPP      (2*ISDN_MAX_CHANNELS)
-#define ISDN_MINOR_PPPMAX   (3*ISDN_MAX_CHANNELS-1)
+#define ISDN_MINOR_CTRL     64
+#define ISDN_MINOR_CTRLMAX  (64 + (ISDN_MAX_CHANNELS-1))
+#define ISDN_MINOR_PPP      128
+#define ISDN_MINOR_PPPMAX   (128 + (ISDN_MAX_CHANNELS-1))
 #define ISDN_MINOR_STATUS   255
 
 /* New ioctl-codes */
 #define IIOCNETANM  _IO('I',5)
 #define IIOCNETDNM  _IO('I',6)
 #define IIOCNETGNM  _IO('I',7)
-#define IIOCGETSET  _IO('I',8)
-#define IIOCSETSET  _IO('I',9)
+#define IIOCGETSET  _IO('I',8) /* no longer supported */
+#define IIOCSETSET  _IO('I',9) /* no longer supported */
 #define IIOCSETVER  _IO('I',10)
 #define IIOCNETHUP  _IO('I',11)
 #define IIOCSETGST  _IO('I',12)
 #define IIOCNETALN  _IO('I',32)
 #define IIOCNETDLN  _IO('I',33)
 
+#define IIOCNETGPN  _IO('I',34)
+
 #define IIOCDBGVAR  _IO('I',127)
 
 #define IIOCDRVCTL  _IO('I',128)
 
 #define ISDN_MODEM_ANZREG    23        /* Number of Modem-Registers        */
 #define ISDN_MSNLEN          20
+#define ISDN_LMSNLEN         255 /* Length of tty's Listen-MSN string */
+#define ISDN_CMSGLEN        50  /* Length of CONNECT-Message to add for Modem */
 
 typedef struct {
   char drvid[25];
@@ -256,8 +358,9 @@ typedef struct {
   int  outgoing;
 } isdn_net_ioctl_phone;
 
-#define NET_DV 0x04 /* Data version for net_cfg     */
-#define TTY_DV 0x04 /* Data version for iprofd etc. */
+#define NET_DV 0x05 /* Data version for net_cfg       */
+#define TTY_DV 0x05 /* Data version for iprofd etc.   */
+#define INF_DV 0x01 /* Data version for /dev/isdninfo */
 
 typedef struct {
   char name[10];     /* Name of interface                     */
@@ -282,8 +385,17 @@ 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  dialmode;     /* Flag: off / on / auto                 */
 } isdn_net_ioctl_cfg;
 
+#define ISDN_NET_DIALMODE_MASK 0xC0  /* bits for status                   */
+#define  ISDN_NET_DM_OFF       0x00    /* this interface is stopped      */
+#define  ISDN_NET_DM_MANUAL    0x40    /* this interface is on (manual)  */
+#define  ISDN_NET_DM_AUTO      0x80    /* this interface is autodial     */
+#define ISDN_NET_DIALMODE(x) ((&(x))->flags & ISDN_NET_DIALMODE_MASK)
+
 #ifdef __KERNEL__
 
 #ifndef STANDALONE
@@ -331,6 +443,7 @@ typedef struct {
 
 #include <linux/isdnif.h>
 
+
 #define ISDN_DRVIOCTL_MASK       0x7f  /* Mask for Device-ioctl */
 
 /* Until now unused */
@@ -372,14 +485,17 @@ typedef struct {
 #define ISDN_TIMER_NETHANGUP  32
 #define ISDN_TIMER_IPPP       64 
 #define ISDN_TIMER_KEEPALIVE 128 /* Cisco-Keepalive */
+#define ISDN_TIMER_CARRIER   256 /* Wait for Carrier */
 #define ISDN_TIMER_FAST      (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
                               ISDN_TIMER_MODEMXMIT)
 #define ISDN_TIMER_SLOW      (ISDN_TIMER_MODEMRING | ISDN_TIMER_NETHANGUP | \
-                              ISDN_TIMER_NETDIAL | ISDN_TIMER_KEEPALIVE)
+                              ISDN_TIMER_NETDIAL | ISDN_TIMER_KEEPALIVE | \
+                              ISDN_TIMER_CARRIER)
 
 /* Timeout-Values for isdn_net_dial() */
 #define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
 #define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
+#define ISDN_TIMER_DTIMEOUT60 (60*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1)))
 
 /* GLOBAL_FLAGS */
 #define ISDN_GLOBAL_STOPPED 1
@@ -398,6 +514,7 @@ 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_MAGIC      0x49344C02 /* for paranoia-checking             */
 
 /* Phone-list-element */
@@ -488,6 +605,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) */
 #ifdef CONFIG_ISDN_X25
   struct concap_device_ops *dops;      /* callbacks used by encapsulator   */
 #endif
@@ -496,18 +618,6 @@ typedef struct isdn_net_local_s {
   ulong cisco_yourseq;                 /* Remote keepalive seq. for Cisco  */
 } isdn_net_local;
 
-#ifdef CONFIG_ISDN_PPP
-struct ippp_bundle {
-  int mp_mrru;                        /* unused                             */
-  struct mpqueue *last;               /* currently defined in isdn_net_dev  */
-  int min;                            /* currently calculated 'on the fly'  */
-  long next_num;                      /* we wanna see this seq.-number next */
-  struct sqqueue *sq;
-  int modify:1;                       /* set to 1 while modifying sqqueue   */
-  int bundled:1;                      /* bundle active ?                    */
-};
-#endif
-
 /* the interface itself */
 typedef struct isdn_net_dev_s {
   isdn_net_local *local;
@@ -567,6 +677,10 @@ typedef struct atemu {
        u_char       mdmreg[ISDN_MODEM_ANZREG];  /* Modem-Registers                    */
        char         pmsn[ISDN_MSNLEN];          /* EAZ/MSNs Profile 0                 */
        char         msn[ISDN_MSNLEN];           /* EAZ/MSN                            */
+       char         plmsn[ISDN_LMSNLEN];        /* Listening MSNs Profile 0           */
+       char         lmsn[ISDN_LMSNLEN];         /* Listening MSNs                     */
+       char         cpn[ISDN_MSNLEN];           /* CalledPartyNumber on incoming call */
+       char         connmsg[ISDN_CMSGLEN];      /* CONNECT-Msg from HL-Driver         */
 #ifdef CONFIG_ISDN_AUDIO
        u_char       vpar[10];                   /* Voice-parameters                   */
        int          lastDLE;                    /* Flag for voice-coding: DLE seen    */
@@ -574,6 +688,7 @@ typedef struct atemu {
        int          mdmcmdl;                    /* Length of Modem-Commandbuffer      */
        int          pluscount;                  /* Counter for +++ sequence           */
        int          lastplus;                   /* Timestamp of last +                */
+       int          carrierwait;                /* Seconds of carrier waiting         */
        char         mdmcmd[255];                /* Modem-Commandbuffer                */
        unsigned int charge;                     /* Charge units of current connection */
 } atemu;
@@ -593,7 +708,7 @@ typedef struct modem_info {
   long                 pgrp;            /* pgrp of opening process        */
   int                   online;          /* 1 = B-Channel is up, drop data */
                                         /* 2 = B-Channel is up, deliver d.*/
-  int                   dialing;         /* Dial in progress               */
+  int                   dialing;         /* Dial in progress or ATA        */
   int                   rcvsched;        /* Receive needs schedule         */
   int                   isdn_driver;    /* Index to isdn-driver           */
   int                   isdn_channel;    /* Index to isdn-channel          */
@@ -612,6 +727,7 @@ typedef struct modem_info {
   int                   xmit_count;      /* # of chars in xmit_buf         */
   unsigned char         *xmit_buf;       /* transmit buffer                */
   struct sk_buff_head   xmit_queue;      /* transmit queue                 */
+  atomic_t              xmit_lock;       /* Semaphore for isdn_tty_write   */
 #ifdef CONFIG_ISDN_AUDIO
   int                   vonline;         /* Voice-channel status           */
                                         /* Bit 0 = recording              */
@@ -621,12 +737,19 @@ typedef struct modem_info {
   void                  *adpcms;         /* state for adpcm decompression  */
   void                  *adpcmr;         /* state for adpcm compression    */
   void                  *dtmf_state;     /* state for dtmf decoder         */
+  void                  *silence_state;  /* state for silence detection    */
 #endif
   struct tty_struct    *tty;            /* Pointer to corresponding tty   */
   atemu                 emu;             /* AT-emulator data               */
   struct termios       normal_termios;  /* For saving termios structs     */
   struct termios       callout_termios;
-  wait_queue_head_t    open_wait, close_wait;
+#if LINUX_VERSION_CODE < 131841
+  struct wait_queue    *open_wait;
+  struct wait_queue    *close_wait;
+#else
+  wait_queue_head_t    open_wait, close_wait;
+#endif
+  struct semaphore      write_sem;
 } modem_info;
 
 #define ISDN_MODEM_WINSIZE 8
@@ -644,72 +767,6 @@ typedef struct {
 
 /*======================= End of ISDN-tty stuff ============================*/
 
-/*======================= Start of sync-ppp stuff ==========================*/
-
-
-#define NUM_RCV_BUFFS     64
-#define PPP_HARD_HDR_LEN 4
-
-#ifdef CONFIG_ISDN_PPP
-
-struct sqqueue {
-  struct sqqueue *next;
-  long sqno_start;
-  long sqno_end;
-  struct sk_buff *skb;
-  long timer;
-};
-  
-struct mpqueue {
-  struct mpqueue *next;
-  struct mpqueue *last;
-  long sqno;
-  struct sk_buff *skb;
-  int BEbyte;
-  unsigned long time;
-}; 
-
-struct ippp_buf_queue {
-  struct ippp_buf_queue *next;
-  struct ippp_buf_queue *last;
-  char *buf;                 /* NULL here indicates end of queue */
-  int len;
-};
-
-struct ippp_struct {
-  struct ippp_struct *next_link;
-  int state;
-  struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
-  struct ippp_buf_queue *first;  /* pointer to (current) first packet */
-  struct ippp_buf_queue *last;   /* pointer to (current) last used packet in queue */
-  wait_queue_head_t wq;
-  wait_queue_head_t wql;
-  struct task_struct *tk;
-  unsigned int mpppcfg;
-  unsigned int pppcfg;
-  unsigned int mru;
-  unsigned int mpmru;
-  unsigned int mpmtu;
-  unsigned int maxcid;
-  isdn_net_local *lp;
-  int unit; 
-  int minor;
-  long last_link_seqno;
-  long mp_seqno;
-  long range;
-#ifdef CONFIG_ISDN_PPP_VJ
-  unsigned char *cbuf;
-  struct slcompress *slcomp;
-#endif
-  unsigned long debug;
-  struct isdn_ppp_compressor *compressor,*link_compressor;
-  void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
-};
-
-#endif
-
-/*======================== End of sync-ppp stuff ===========================*/
-
 /*======================== Start of V.110 stuff ============================*/
 #define V110_BUFSIZE 1024
 
@@ -742,69 +799,103 @@ typedef struct {
        char *private;
 } infostruct;
 
+typedef struct isdn_module {
+       struct isdn_module *prev;
+       struct isdn_module *next;
+       char *name;
+       int (*get_free_channel)(int, int, int, int, int);
+       int (*free_channel)(int, int, int);
+       int (*status_callback)(isdn_ctrl *);
+       int (*command)(isdn_ctrl *);
+       int (*receive_callback)(int, int, struct sk_buff *);
+       int (*writebuf_skb)(int, int, int, struct sk_buff *);
+       int (*net_start_xmit)(struct sk_buff *, struct device *);
+       int (*net_receive)(struct device *, struct sk_buff *);
+       int (*net_open)(struct device *);
+       int (*net_close)(struct device *);
+       int priority;
+} isdn_module;
+
+#define DRV_FLAG_RUNNING 1
+#define DRV_FLAG_REJBUS  2
+#define DRV_FLAG_LOADED  4
+
 /* Description of hardware-level-driver */
 typedef struct {
-  ulong               flags;            /* Flags                            */
-  int                 channels;         /* Number of channels               */
-  int                 reject_bus;       /* Flag: Reject rejected call on bus*/
-  wait_queue_head_t   st_waitq;         /* Wait-Queue for status-read's     */
-  int                 maxbufsize;       /* Maximum Buffersize supported     */
-  unsigned long       pktcount;         /* Until now: unused                */
-  int                 running;          /* Flag: Protocolcode running       */
-  int                 loaded;           /* Flag: Driver loaded              */
-  int                 stavail;          /* Chars avail on Status-device     */
-  isdn_if            *interface;        /* Interface to driver              */
-  int                *rcverr;           /* Error-counters for B-Ch.-receive */
-  int                *rcvcount;         /* Byte-counters for B-Ch.-receive  */
+       ulong               online;           /* Channel-Online flags             */
+       ulong               flags;            /* Misc driver Flags                */
+       int                 locks;            /* Number of locks for this driver  */
+       int                 channels;         /* Number of channels               */
+#if LINUX_VERSION_CODE < 131841
+       struct wait_queue  *st_waitq;         /* Wait-Queue for status-read's     */
+#else
+       wait_queue_head_t   st_waitq;         /* Wait-Queue for status-read's     */
+#endif
+       int                 maxbufsize;       /* Maximum Buffersize supported     */
+       unsigned long       pktcount;         /* Until now: unused                */
+       int                 stavail;          /* Chars avail on Status-device     */
+       isdn_if            *interface;        /* Interface to driver              */
+       int                *rcverr;           /* Error-counters for B-Ch.-receive */
+       int                *rcvcount;         /* Byte-counters for B-Ch.-receive  */
 #ifdef CONFIG_ISDN_AUDIO
-  unsigned long      DLEflag;           /* Flags: Insert DLE at next read   */
+       unsigned long      DLEflag;           /* Flags: Insert DLE at next read   */
+#endif
+       struct sk_buff_head *rpqueue;         /* Pointers to start of Rcv-Queue   */
+#if LINUX_VERSION_CODE < 131841
+       struct wait_queue  **rcv_waitq;       /* Wait-Queues for B-Channel-Reads  */
+       struct wait_queue  **snd_waitq;       /* Wait-Queue for B-Channel-Send's  */
+#else
+       wait_queue_head_t  *rcv_waitq;       /* Wait-Queues for B-Channel-Reads  */
+       wait_queue_head_t  *snd_waitq;       /* Wait-Queue for B-Channel-Send's  */
 #endif
-  struct sk_buff_head *rpqueue;         /* Pointers to start of Rcv-Queue   */
-  wait_queue_head_t  *rcv_waitq;  /* array of Wait-Queues for B-Channel-Reads  */
-  wait_queue_head_t  *snd_waitq;  /* array of Wait-Queue for B-Channel-Sends  */
-  char               msn2eaz[10][ISDN_MSNLEN];  /* Mapping-Table MSN->EAZ   */
+       char               msn2eaz[10][ISDN_MSNLEN];  /* Mapping-Table MSN->EAZ   */
 } driver;
 
 /* Main driver-data */
 typedef struct isdn_devt {
-  unsigned short    flags;                    /* Bitmapped Flags:           */
-                                              /*                            */
-  int               drivers;                  /* Current number of drivers  */
-  int               channels;                 /* Current number of channels */
-  int               net_verbose;               /* Verbose-Flag               */
-  int               modempoll;                /* Flag: tty-read active      */
-  int               tflags;                    /* Timer-Flags:               */
-                                              /*  see ISDN_TIMER_..defines  */
-  int               global_flags;
-  infostruct        *infochain;                /* List of open info-devs.    */
-  wait_queue_head_t info_waitq;               /* Wait-Queue for isdninfo    */
-  struct timer_list timer;                    /* Misc.-function Timer       */
-  int               chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel  */
-  int               drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index    */
-  int               usage[ISDN_MAX_CHANNELS];  /* Used by tty/ip/voice       */
-  char              num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
-                                               /* Remote number of active ch.*/
-  int               m_idx[ISDN_MAX_CHANNELS];  /* Index for mdm....          */
-  driver            *drv[ISDN_MAX_DRIVERS];    /* Array of drivers           */
-  isdn_net_dev      *netdev;                  /* Linked list of net-if's    */
-  char              drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID                 */
-  struct task_struct *profd;                   /* For iprofd                 */
-  modem             mdm;                      /* tty-driver-data            */
-  isdn_net_dev      *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers     */
-  isdn_net_dev      *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers   */
-  ulong             ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes  */
-  ulong             obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes  */
-  int               v110emu[ISDN_MAX_CHANNELS];/* V.110 emulator-mode 0=none */
-  atomic_t          v110use[ISDN_MAX_CHANNELS];/* Usage-Semaphore for stream */
-  isdn_v110_stream  *v110[ISDN_MAX_CHANNELS];  /* V.110 private data         */
-  struct semaphore  sem;                       /* serialize list access*/
+       unsigned short    flags;                       /* Bitmapped Flags:           */
+       /*                            */
+       int               drivers;                     /* Current number of drivers  */
+       int               channels;                    /* Current number of channels */
+       int               net_verbose;               /* Verbose-Flag               */
+       int               modempoll;                   /* Flag: tty-read active      */
+       int               tflags;                    /* Timer-Flags:               */
+       /*  see ISDN_TIMER_..defines  */
+       int               global_flags;
+       infostruct        *infochain;                /* List of open info-devs.    */
+#if LINUX_VERSION_CODE < 131841
+       struct wait_queue *info_waitq;               /* Wait-Queue for isdninfo    */
+#else
+       wait_queue_head_t info_waitq;               /* Wait-Queue for isdninfo    */
+#endif
+       struct timer_list timer;                       /* Misc.-function Timer       */
+       int               chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel  */
+       int               drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index    */
+       int               usage[ISDN_MAX_CHANNELS];  /* Used by tty/ip/voice       */
+       char              num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
+       /* Remote number of active ch.*/
+       int               m_idx[ISDN_MAX_CHANNELS];  /* Index for mdm....          */
+       driver            *drv[ISDN_MAX_DRIVERS];    /* Array of drivers           */
+       isdn_net_dev      *netdev;                     /* Linked list of net-if's    */
+       char              drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID                 */
+       struct task_struct *profd;                   /* For iprofd                 */
+       modem             mdm;                 /* tty-driver-data            */
+       isdn_net_dev      *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers     */
+       isdn_net_dev      *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers   */
+       ulong             ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes  */
+       ulong             obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes  */
+       int               v110emu[ISDN_MAX_CHANNELS];/* V.110 emulator-mode 0=none */
+       atomic_t          v110use[ISDN_MAX_CHANNELS];/* Usage-Semaphore for stream */
+       isdn_v110_stream  *v110[ISDN_MAX_CHANNELS];  /* V.110 private data         */
+       struct semaphore  sem;                       /* serialize list access*/
+       isdn_module       *modules;
 } isdn_dev;
 
 extern isdn_dev *dev;
 
+
 /* Utility-Macros */
 #define MIN(a,b) ((a<b)?a:b)
 #define MAX(a,b) ((a>b)?a:b)
-
 #endif /* __KERNEL__ */
 #endif /* isdn_h */
diff --git a/include/linux/isdn_budget.h b/include/linux/isdn_budget.h
new file mode 100644 (file)
index 0000000..2eaccea
--- /dev/null
@@ -0,0 +1,62 @@
+/* isdn_budget.h
+ *
+ * Linux ISDN subsystem, budget-accounting for network interfaces.
+ *
+ * Copyright 1997       by Christian Lademann <cal@zls.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. 
+ *
+ */
+
+/*
+30.06.97:cal:angelegt
+04.11.97:cal:budget.period: int --> time_t
+*/
+
+#ifndef __isdn_budget_h__
+#define __isdn_budget_h__
+
+#include       <linux/types.h>
+
+#define        ISDN_BUDGET_DIAL                0
+#define        ISDN_BUDGET_CHARGE              1
+#define        ISDN_BUDGET_ONLINE              2
+#define        ISDN_BUDGET_NUM_BUDGET          3
+
+#define        ISDN_BUDGET_INIT                0
+#define        ISDN_BUDGET_CHECK_DIAL          1
+#define        ISDN_BUDGET_CHECK_CHARGE        2
+#define        ISDN_BUDGET_CHECK_ONLINE        3
+#define        ISDN_BUDGET_START_ONLINE        10
+
+#define        ISDN_BUDGET_SET_BUDGET  0
+#define        ISDN_BUDGET_GET_BUDGET  1
+
+typedef struct {
+       char    name [9];               /* Interface */
+       int     command,                /* subcommand */
+               budget,                 /* budget-nr. */
+               amount,                 /* set/get budget-amount */
+               used;                   /* set/get used amount */
+       time_t  period,                 /* set/get length of period */
+               period_started;         /* set/get startpoint of period */
+}      isdn_ioctl_budget;
+
+#ifdef __KERNEL__
+extern int     isdn_net_budget(int, struct device *);
+extern int     isdn_budget_ioctl(isdn_ioctl_budget *);
+#endif /* __KERNEL__ */
+
+#endif /* __isdn_budget_h__ */
diff --git a/include/linux/isdn_lzscomp.h b/include/linux/isdn_lzscomp.h
new file mode 100644 (file)
index 0000000..8f64bfa
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * $Id: isdn_lzscomp.h,v 1.1 1998/07/08 16:52:33 hipp Exp $
+ *
+ * Header for isdn_lzscomp.c
+ * Concentrated here to not mess up half a dozen kernel headers with code
+ * snippets
+ *
+ */
+
+#define CI_LZS_COMPRESS                17
+#define CILEN_LZS_COMPRESS     5
+
+#define LZS_CMODE_NONE         0
+#define LZS_CMODE_LCB          1
+#define LZS_CMODE_CRC          2
+#define LZS_CMODE_SEQNO                3       /* MUST be implemented (default) */
+#define LZS_CMODE_EXT          4       /* Seems to be what Win0.95 uses */
+
+#define LZS_COMP_MAX_HISTS     1       /* Don't waste peers ressources */
+#define LZS_COMP_DEF_HISTS     1       /* Most likely to negotiate */
+#define LZS_DECOMP_MAX_HISTS   32      /* More is really nonsense */
+#define LZS_DECOMP_DEF_HISTS   8       /* If we get it, this may be optimal */
+
+#define LZS_HIST_BYTE1(word)           (word>>8)       /* Just for better reading */
+#define LZS_HIST_BYTE2(word)   (word&0xff)     /* of this big endian stuff */
+#define LZS_HIST_WORD(b1,b2)   ((b1<<8)|b2)    /* (network byte order rulez) */
index 177646520470eea38c33e9c4da7021f7365b4319..50b59f428da3861f257b9bfc165fdc8c5c10afaf 100644 (file)
@@ -1,19 +1,21 @@
+/* -*- mode: c; c-basic-offset: 2 -*- */
+
 #ifndef _LINUX_ISDN_PPP_H
 #define _LINUX_ISDN_PPP_H
 
-extern int isdn_ppp_dial_slave(char *);
-extern int isdn_ppp_hangup_slave(char *);
 
 #define CALLTYPE_INCOMING 0x1
 #define CALLTYPE_OUTGOING 0x2
 #define CALLTYPE_CALLBACK 0x4
 
+#define IPPP_VERSION    "2.2.0"
+
 struct pppcallinfo
 {
-       int calltype;
-       unsigned char local_num[64];
-       unsigned char remote_num[64];
-       int charge_units;
+  int calltype;
+  unsigned char local_num[64];
+  unsigned char remote_num[64];
+  int charge_units;
 };
 
 #define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo)
@@ -22,48 +24,216 @@ struct pppcallinfo
 #define PPPIOCSMPFLAGS _IOW('t',131,int)
 #define PPPIOCSMPMTU   _IOW('t',132,int)
 #define PPPIOCSMPMRU   _IOW('t',133,int)
-#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long)
+#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long [8])
 #define PPPIOCSCOMPRESSOR _IOW('t',135,int)
+#define PPPIOCGIFNAME      _IOR('t',136, char [IFNAMSIZ] )
 
 #define PPP_MP          0x003d
 #define PPP_LINK_COMP   0x00fb
+#define PPP_LINK_CCP    0x80fb
 
 #define SC_MP_PROT       0x00000200
 #define SC_REJ_MP_PROT   0x00000400
 #define SC_OUT_SHORT_SEQ 0x00000800
 #define SC_IN_SHORT_SEQ  0x00004000
 
+#define SC_DECOMP_ON           0x01
+#define SC_COMP_ON             0x02
+#define SC_DECOMP_DISCARD      0x04
+#define SC_COMP_DISCARD                0x08
+#define SC_LINK_DECOMP_ON      0x10
+#define SC_LINK_COMP_ON                0x20
+#define SC_LINK_DECOMP_DISCARD 0x40
+#define SC_LINK_COMP_DISCARD   0x80
+
+#define DECOMP_ERR_NOMEM       (-10)
+
 #define MP_END_FRAG    0x40
 #define MP_BEGIN_FRAG  0x80
 
+#define ISDN_PPP_COMP_MAX_OPTIONS 16
+
+#define IPPP_COMP_FLAG_XMIT 0x1
+#define IPPP_COMP_FLAG_LINK 0x2
+
+struct isdn_ppp_comp_data {
+  int num;
+  unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS];
+  int optlen;
+  int flags;
+};
+
 #ifdef __KERNEL__
+
+/*
+ * We need a way for the decompressor to influence the generation of CCP
+ * Reset-Requests in a variety of ways. The decompressor is already returning
+ * a lot of information (generated skb length, error conditions) so we use
+ * another parameter. This parameter is a pointer to a structure which is
+ * to be marked valid by the decompressor and only in this case is ever used.
+ * Furthermore, the only case where this data is used is when the decom-
+ * pressor returns DECOMP_ERROR.
+ *
+ * We use this same struct for the reset entry of the compressor to commu-
+ * nicate to its caller how to deal with sending of a Reset Ack. In this
+ * case, expra is not used, but other options still apply (supressing
+ * sending with rsend, appending arbitrary data, etc).
+ */
+
+#define IPPP_RESET_MAXDATABYTES        32
+
+struct isdn_ppp_resetparams {
+  unsigned char valid:1;       /* rw Is this structure filled at all ? */
+  unsigned char rsend:1;       /* rw Should we send one at all ? */
+  unsigned char idval:1;       /* rw Is the id field valid ? */
+  unsigned char dtval:1;       /* rw Is the data field valid ? */
+  unsigned char expra:1;       /* rw Is an Ack expected for this Req ? */
+  unsigned char id;            /* wo Send CCP ResetReq with this id */
+  unsigned short maxdlen;      /* ro Max bytes to be stored in data field */
+  unsigned short dlen;         /* rw Bytes stored in data field */
+  unsigned char *data;         /* wo Data for ResetReq info field */
+};
+
 /*
  * this is an 'old friend' from ppp-comp.h under a new name 
  * check the original include for more information
  */
 struct isdn_ppp_compressor {
-       struct isdn_ppp_compressor *next,*prev;
-       int num; /* CCP compression protocol number */
-       void *(*comp_alloc) (unsigned char *options, int opt_len);
-       void (*comp_free) (void *state);
-       int  (*comp_init) (void *state, unsigned char *options, int opt_len,
-                int unit, int opthdr, int debug);
-       void (*comp_reset) (void *state);
-       int  (*compress) (void *state,struct sk_buff *in, struct sk_buff *skb_out,
-                int proto);
-       void (*comp_stat) (void *state, struct compstat *stats);
-       void *(*decomp_alloc) (unsigned char *options, int opt_len);
-       void (*decomp_free) (void *state);
-       int  (*decomp_init) (void *state, unsigned char *options,
-                       int opt_len, int unit, int opthdr, int mru, int debug);
-       void (*decomp_reset) (void *state);
-       int  (*decompress) (void *state, unsigned char *ibuf, int isize, unsigned char *obuf, int osize);
-       void (*incomp) (void *state, unsigned char *ibuf, int icnt);
-       void (*decomp_stat) (void *state, struct compstat *stats);
+  struct isdn_ppp_compressor *next, *prev;
+  int num; /* CCP compression protocol number */
+  
+  void *(*alloc) (struct isdn_ppp_comp_data *);
+  void (*free) (void *state);
+  int  (*init) (void *state, struct isdn_ppp_comp_data *,
+               int unit,int debug);
+  
+  /* The reset entry needs to get more exact information about the
+     ResetReq or ResetAck it was called with. The parameters are
+     obvious. If reset is called without a Req or Ack frame which
+     could be handed into it, code MUST be set to 0. Using rsparm,
+     the reset entry can control if and how a ResetAck is returned. */
+  
+  void (*reset) (void *state, unsigned char code, unsigned char id,
+                unsigned char *data, unsigned len,
+                struct isdn_ppp_resetparams *rsparm);
+  
+  int  (*compress) (void *state, struct sk_buff *in,
+                   struct sk_buff *skb_out, int proto);
+  
+       int  (*decompress) (void *state,struct sk_buff *in,
+                           struct sk_buff *skb_out,
+                           struct isdn_ppp_resetparams *rsparm);
+  
+  void (*incomp) (void *state, struct sk_buff *in,int proto);
+  void (*stat) (void *state, struct compstat *stats);
 };
 
 extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
 extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
+extern int isdn_ppp_dial_slave(char *);
+extern int isdn_ppp_hangup_slave(char *);
+
+struct ippp_bundle {
+  int mp_mrru;                        /* unused                             */
+  struct mpqueue *last;               /* currently defined in isdn_net_dev  */
+  int min;                            /* currently calculated 'on the fly'  */
+  long next_num;                      /* we wanna see this seq.-number next */
+  struct sqqueue *sq;
+  int modify:1;                       /* set to 1 while modifying sqqueue   */
+  int bundled:1;                      /* bundle active ?                    */
+};
+
+#define NUM_RCV_BUFFS     64
+
+struct sqqueue {
+  struct sqqueue *next;
+  long sqno_start;
+  long sqno_end;
+  struct sk_buff *skb;
+  long timer;
+};
+
+struct mpqueue {
+  struct mpqueue *next;
+  struct mpqueue *last;
+  long sqno;
+  struct sk_buff *skb;
+  int BEbyte;
+  unsigned long time;
+};
+
+struct ippp_buf_queue {
+  struct ippp_buf_queue *next;
+  struct ippp_buf_queue *last;
+  char *buf;                 /* NULL here indicates end of queue */
+  int len;
+};
+
+/* The data structure for one CCP reset transaction */
+enum ippp_ccp_reset_states {
+  CCPResetIdle,
+  CCPResetSentReq,
+  CCPResetRcvdReq,
+  CCPResetSentAck,
+  CCPResetRcvdAck
+};
+
+struct ippp_ccp_reset_state {
+  enum ippp_ccp_reset_states state;    /* State of this transaction */
+  struct ippp_struct *is;              /* Backlink to device stuff */
+  unsigned char id;                    /* Backlink id index */
+  unsigned char ta:1;                  /* The timer is active (flag) */
+  unsigned char expra:1;               /* We expect a ResetAck at all */
+  int dlen;                            /* Databytes stored in data */
+  struct timer_list timer;             /* For timeouts/retries */
+  /* This is a hack but seems sufficient for the moment. We do not want
+     to have this be yet another allocation for some bytes, it is more
+     memory management overhead than the whole mess is worth. */
+  unsigned char data[IPPP_RESET_MAXDATABYTES];
+};
+
+/* The data structure keeping track of the currently outstanding CCP Reset
+   transactions. */
+struct ippp_ccp_reset {
+  struct ippp_ccp_reset_state *rs[256];        /* One per possible id */
+  unsigned char lastid;                        /* Last id allocated by the engine */
+};
+
+struct ippp_struct {
+  struct ippp_struct *next_link;
+  int state;
+  struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
+  struct ippp_buf_queue *first;  /* pointer to (current) first packet */
+  struct ippp_buf_queue *last;   /* pointer to (current) last used packet in queue */
+#if LINUX_VERSION_CODE < 131841
+  struct wait_queue *wq;
+#else
+  wait_queue_head_t wq;
+#endif
+  struct task_struct *tk;
+  unsigned int mpppcfg;
+  unsigned int pppcfg;
+  unsigned int mru;
+  unsigned int mpmru;
+  unsigned int mpmtu;
+  unsigned int maxcid;
+  struct isdn_net_local_s *lp;
+  int unit;
+  int minor;
+  long last_link_seqno;
+  long mp_seqno;
+  long range;
+#ifdef CONFIG_ISDN_PPP_VJ
+  unsigned char *cbuf;
+  struct slcompress *slcomp;
+#endif
+  unsigned long debug;
+  struct isdn_ppp_compressor *compressor,*decompressor;
+  struct isdn_ppp_compressor *link_compressor,*link_decompressor;
+  void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
+  struct ippp_ccp_reset *reset;        /* Allocated on demand, may never be needed */
+  unsigned long compflags;
+};
 
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/isdn_timru.h b/include/linux/isdn_timru.h
new file mode 100644 (file)
index 0000000..361dbbe
--- /dev/null
@@ -0,0 +1,119 @@
+/* isdn_timru.h
+ *
+ * Linux ISDN subsystem, timeout-rules for network interfaces.
+ *
+ * Copyright 1997       by Christian Lademann <cal@zls.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. 
+ *
+ */
+
+/*
+02.06.97:cal:ISDN_TIMRU_PACKET_NONE def., ISDN_TIMRU_PACKET_* inkr.
+*/
+
+#ifndef __isdn_timru_h__
+#define __isdn_timru_h__
+
+#define        ISDN_TIMRU_PACKET_NONE          0
+#define        ISDN_TIMRU_PACKET_SKB           1
+#define        ISDN_TIMRU_PACKET_PPP           2
+#define        ISDN_TIMRU_PACKET_PPP_NO_HEADER 3
+
+#define        ISDN_TIMRU_BRINGUP              0
+#define        ISDN_TIMRU_KEEPUP_IN            1
+#define        ISDN_TIMRU_KEEPUP_OUT           2
+#define        ISDN_TIMRU_BRINGDOWN            3
+#define        ISDN_TIMRU_NUM_CHECK            4
+
+#define        ISDN_TIMRU_PROTFAM_WILDCARD     0
+#define        ISDN_TIMRU_PROTFAM_IP           1
+#define        ISDN_TIMRU_PROTFAM_PPP          2
+#define        ISDN_TIMRU_PROTFAM_IPX          3
+#define        ISDN_TIMRU_NUM_PROTFAM          4
+
+#define        ISDN_TIMRU_IP_WILDCARD          0
+#define        ISDN_TIMRU_IP_ICMP              1
+#define        ISDN_TIMRU_IP_TCP               2
+#define        ISDN_TIMRU_IP_UDP               3
+
+#define        ISDN_TIMRU_PPP_WILDCARD         0
+#define        ISDN_TIMRU_PPP_IPCP             1
+#define        ISDN_TIMRU_PPP_IPXCP            2
+#define        ISDN_TIMRU_PPP_CCP              3
+#define        ISDN_TIMRU_PPP_LCP              4
+#define        ISDN_TIMRU_PPP_PAP              5
+#define        ISDN_TIMRU_PPP_LQR              6
+#define        ISDN_TIMRU_PPP_CHAP             7
+
+typedef struct {
+       struct in_addr  saddr,          /* Source Address */
+                       smask,          /* Source Subnetmask */
+                       daddr,          /* Dest. Address */
+                       dmask;          /* Dest. Subnetmask */
+       ushort          protocol;       /* TCP, UDP, ... */
+       union {
+               struct {
+                       __u16   s_from, /* Source Port */
+                               s_to,
+                               d_from,
+                               d_to;
+               }               port;
+               struct {
+                       __u8    from,   /* ICMP-Type */
+                               to;
+               }               type;
+       }               pt;
+}      isdn_timeout_rule_ip;
+
+
+typedef struct {
+       ushort          protocol;       /* IPCP, LCP, ... */
+}      isdn_timeout_rule_ppp;
+
+
+typedef struct isdn_timeout_rule_s {
+       struct isdn_timeout_rule_s      *next,          /* Pointer to next rule */
+                                       *prev;          /* Pointer to previous rule */
+       ushort                          type,           /* BRINGUP, KEEPUP_*, ... */
+                                       neg;
+       int                             timeout;        /* Timeout value */
+       ushort                          protfam;        /* IP, IPX, PPP, ... */
+       union {
+               isdn_timeout_rule_ip    ip;     /* IP-Rule */
+               isdn_timeout_rule_ppp   ppp;    /* PPP-Rule */
+       }                               rule;   /* Prot.-specific rule */
+}      isdn_timeout_rule;
+
+
+typedef struct {
+       char                    name [9];       /* Interface */
+       int                     where,          /* 0/1: add to start/end of list, -1: handle default */
+                               type,
+                               protfam,
+                               index,
+                               defval;
+       isdn_timeout_rule       rule;           /* Rule */
+}      isdn_ioctl_timeout_rule;
+
+#ifdef __KERNEL__
+extern int     isdn_net_recalc_timeout(int, int, struct device *, void *, ulong);
+extern int     isdn_timru_alloc_timeout_rules(struct device *);
+extern int     isdn_timru_ioctl_add_rule(isdn_ioctl_timeout_rule *);
+extern int     isdn_timru_ioctl_del_rule(isdn_ioctl_timeout_rule *);
+extern int     isdn_timru_ioctl_get_rule(isdn_ioctl_timeout_rule *);
+#endif /* __KERNEL__ */
+
+#endif /* __isdn_timru_h__ */
index e7a7f247c08668122c322b0dcaacc62f3fdb6652..5f1fcacaa17cb867910fe46b7c3e5202e2903143 100644 (file)
@@ -1,8 +1,4 @@
-/* X25 changes:
-   Added constants ISDN_PROTO_L2_X25DTE/DCE and corresponding ISDN_FEATURE_..
-   */
-
-/* $Id: isdnif.h,v 1.23 1998/02/20 17:36:52 fritz Exp $
+/* $Id: isdnif.h,v 1.25 1998/06/17 19:51:55 he Exp $
  *
  * Linux ISDN subsystem
  *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  * $Log: isdnif.h,v $
+ * Revision 1.25  1998/06/17 19:51:55  he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.24  1998/03/19 13:18:57  keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
  * Revision 1.23  1998/02/20 17:36:52  fritz
  * Added L2-protocols for V.110, changed FEATURE-Flag-constants.
  *
 #define ISDN_PROTO_L2_V11096 7   /* V.110 bitrate adaption 9600 Baud  */
 #define ISDN_PROTO_L2_V11019 8   /* V.110 bitrate adaption 19200 Baud */
 #define ISDN_PROTO_L2_V11038 9   /* V.110 bitrate adaption 38400 Baud */
+#define ISDN_PROTO_L2_MODEM  10  /* Analog Modem on Board */
 #define ISDN_PROTO_L2_MAX    15  /* Max. 16 Protocols                 */
 
 /*
 #define ISDN_CMD_UNLOCK  15       /* Release usage-lock                    */
 #define ISDN_CMD_SUSPEND 16       /* Suspend connection                    */
 #define ISDN_CMD_RESUME  17       /* Resume connection                     */
+#define CAPI_PUT_MESSAGE 18       /* CAPI message send down or up          */
 
 /*
  * Status-Values delivered from lowlevel to linklevel via
 #define ISDN_FEATURE_L2_V11096  (0x0001 << ISDN_PROTO_L2_V11096)
 #define ISDN_FEATURE_L2_V11019  (0x0001 << ISDN_PROTO_L2_V11019)
 #define ISDN_FEATURE_L2_V11038  (0x0001 << ISDN_PROTO_L2_V11038)
+#define ISDN_FEATURE_L2_MODEM   (0x0001 << ISDN_PROTO_L2_MODEM)
 
 #define ISDN_FEATURE_L2_MASK    (0x0FFFF) /* Max. 16 protocols */
 #define ISDN_FEATURE_L2_SHIFT   (0)
 #define ISDN_FEATURE_P_SHIFT    (24)
 
 typedef struct setup_parm {
-    char phone[32];         /* Remote Phone-Number */
-    char eazmsn[32];        /* Local EAZ or MSN    */
+    unsigned char phone[32];   /* Remote Phone-Number */
+    unsigned char eazmsn[32];  /* Local EAZ or MSN    */
     unsigned char si1;      /* Service Indicator 1 */
     unsigned char si2;      /* Service Indicator 2 */
     unsigned char plan;     /* Numbering plan      */
     unsigned char screen;   /* Screening info      */
 } setup_parm;
 
+/* CAPI structs */
+
+/* this is compatible to the old union size */
+#define MAX_CAPI_PARA_LEN 50
+
+typedef struct {
+       /* Header */
+       __u16 Length;
+       __u16 ApplId;
+       __u8 Command;
+       __u8 Subcommand;
+       __u16 Messagenumber;
+
+       /* Parameter */
+       union {
+               __u32 Controller;
+               __u32 PLCI;
+               __u32 NCCI;
+       } adr;
+       __u8 para[MAX_CAPI_PARA_LEN];
+} capi_msg;
+
+
 /*
  * Structure for exchanging above infos
  *
@@ -255,8 +286,9 @@ typedef struct {
   union {
        ulong errcode;               /* Type of error with STAT_L1ERR         */
        int   length;                /* Amount of bytes sent with STAT_BSENT  */
-       char  num[50];               /* Additional Data                       */
-       setup_parm setup;
+       u_char  num[50];        /* Additional Data                      */
+       setup_parm      setup;  /* For SETUP msg                        */
+       capi_msg        cmsg;   /* For CAPI like messages               */
   } parm;
 } isdn_ctrl;
 
index 07219a5a5b4a8bc9ddf626449c9346439f498d7b..83e4d7739203abd6f2a8f4e021722e4bdb95f7d6 100644 (file)
@@ -7,12 +7,6 @@
  * Interrupt support added 1993 Nigel Gamble
  */
 
-/* Magic numbers for defining port-device mappings */
-#define LP_PARPORT_UNSPEC -4
-#define LP_PARPORT_AUTO -3
-#define LP_PARPORT_OFF -2
-#define LP_PARPORT_NONE -1
-
 /*
  * Per POSIX guidelines, this module reserves the LP and lp prefixes
  * These are the lp_table[minor].flags flags...
 #define LP_TIMEOUT_INTERRUPT   (60 * HZ)
 #define LP_TIMEOUT_POLLED      (10 * HZ)
 
+#ifdef __KERNEL__
+
+/* Magic numbers for defining port-device mappings */
+#define LP_PARPORT_UNSPEC -4
+#define LP_PARPORT_AUTO -3
+#define LP_PARPORT_OFF -2
+#define LP_PARPORT_NONE -1
+
 #define LP_F(minor)    lp_table[(minor)].flags         /* flags for busy, etc. */
 #define LP_CHAR(minor) lp_table[(minor)].chars         /* busy timeout */
 #define LP_TIME(minor) lp_table[(minor)].time          /* wait time */
@@ -182,3 +184,5 @@ struct lp_struct {
 extern int lp_init(void);
 
 #endif
+
+#endif
index f2ef43b2934980aeaddce886da81b4335c2a41aa..3a256a89c7c1fd216cd0538596e63c77f74fe308 100644 (file)
@@ -266,6 +266,9 @@ struct device
        struct Qdisc            *qdisc_list;
        unsigned long           tx_queue_len;   /* Max frames per queue allowed */
 
+       /* hard_start_xmit synchronizer */
+       spinlock_t              xmit_lock;
+
        /* Pointers to interface service routines.      */
        int                     (*open)(struct device *dev);
        int                     (*stop)(struct device *dev);
@@ -331,6 +334,7 @@ struct packet_type
 
 extern struct device           loopback_dev;           /* The loopback */
 extern struct device           *dev_base;              /* All devices */
+extern rwlock_t                        dev_base_lock;          /* Device list lock */
 extern struct packet_type      *ptype_base[16];        /* Hashed types */
 extern int                     netdev_dropping;
 extern int                     net_cpu_congestion;
index 3e1e89b44daadfaa2504d3f5271456a84992e953..660ea0e1b103c50a8812b0e57ff46bc26a11fa69 100644 (file)
@@ -14,7 +14,7 @@
 
 static inline unsigned long page_address(struct page * page)
 {
-       return PAGE_OFFSET + PAGE_SIZE * (page - mem_map);
+       return PAGE_OFFSET + ((page - mem_map) << PAGE_SHIFT);
 }
 
 /*
index 493cd11270c20abc6438e730df4fb04a4b198f86..2fc126d6de3d7c5f555f12f7b582cd809e26b756 100644 (file)
@@ -212,6 +212,13 @@ struct parport {
        rwlock_t cad_lock;
 };
 
+struct parport_driver {
+       const char *name;
+       void (*attach) (struct parport *);
+       void (*detach) (struct parport *);
+       struct parport_driver *next;
+};
+
 /* parport_register_port registers a new parallel port at the given address (if
  * one does not already exist) and returns a pointer to it.  This entails
  * claiming the I/O region, IRQ and DMA.
@@ -220,6 +227,13 @@ struct parport {
 struct parport *parport_register_port(unsigned long base, int irq, int dma,
                                      struct parport_operations *ops);
 
+/* Once a registered port is ready for high-level drivers to use, the
+   low-level driver that registered it should announce it.  This will
+   call the high-level drivers' attach() functions (after things like
+   determining the IEEE 1284.3 topology of the port and collecting
+   DeviceIDs). */
+void parport_announce_port (struct parport *port);
+
 /* Unregister a port. */
 extern void parport_unregister_port(struct parport *port);
 
@@ -235,6 +249,12 @@ extern void parport_quiesce(struct parport *);
  */
 struct parport *parport_enumerate(void);
 
+/* Register a new high-level driver. */
+extern int parport_register_driver (struct parport_driver *);
+
+/* Unregister a high-level driver. */
+extern void parport_unregister_driver (struct parport_driver *);
+
 /* parport_register_device declares that a device is connected to a port, and 
  * tells the kernel all it needs to know.  
  * pf is the preemption function (may be NULL for no callback)
@@ -322,7 +342,8 @@ extern __inline__ void parport_generic_irq(int irq, struct parport *port,
 #define PARPORT_FLAG_COMA              (1<<0)
 #define PARPORT_FLAG_EXCL              (1<<1)  /* EXCL driver registered. */
 
-extern void parport_parse_irqs(int, const char *[], int irqval[]);
+extern int parport_parse_irqs(int, const char *[], int irqval[]);
+extern int parport_parse_dmas(int, const char *[], int irqval[]);
 extern int parport_ieee1284_nibble_mode_ok(struct parport *, unsigned char);
 extern int parport_wait_peripheral(struct parport *, unsigned char, unsigned
                                   char);
index 383fa36f048bf82f842310a02a8652cbec957f08..9a742ed8a336d395c2740106acaf3e2c7097e89e 100644 (file)
@@ -16,6 +16,7 @@ extern unsigned long event;
 #include <asm/system.h>
 #include <asm/semaphore.h>
 #include <asm/page.h>
+#include <asm/ptrace.h>
 
 #include <linux/smp.h>
 #include <linux/tty.h>
@@ -381,9 +382,13 @@ struct task_struct {
 /* signals */  SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
 }
 
+#ifndef INIT_TASK_SIZE
+# define INIT_TASK_SIZE        2048*sizeof(long)
+#endif
+
 union task_union {
        struct task_struct task;
-       unsigned long stack[2048];
+       unsigned long stack[INIT_TASK_SIZE/sizeof(long)];
 };
 
 extern union task_union init_task_union;
@@ -538,8 +543,7 @@ static inline void recalc_sigpending(struct task_struct *t)
 
 static inline int on_sig_stack(unsigned long sp)
 {
-       return (sp >= current->sas_ss_sp
-               && sp < current->sas_ss_sp + current->sas_ss_size);
+       return (sp - current->sas_ss_sp < current->sas_ss_size);
 }
 
 static inline int sas_ss_flags(unsigned long sp)
index 82d5da6e9685a52bdb91cb4595fe843385e3b5ec..8b65d75977801f96381b996d83287726bd75490f 100644 (file)
@@ -15,6 +15,8 @@
 #define _LINUX_SKBUFF_H
 
 #include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/time.h>
 
 #include <asm/atomic.h>
@@ -462,11 +464,8 @@ extern __inline__ unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
        unsigned char *tmp=skb->tail;
        skb->tail+=len;
        skb->len+=len;
-       if(skb->tail>skb->end)
-       {
-               __label__ here; 
-               skb_over_panic(skb, len, &&here); 
-here:          ;
+       if(skb->tail>skb->end) {
+               skb_over_panic(skb, len, current_text_addr());
        }
        return tmp;
 }
@@ -482,11 +481,8 @@ extern __inline__ unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
 {
        skb->data-=len;
        skb->len+=len;
-       if(skb->data<skb->head)
-       {
-               __label__ here;
-               skb_under_panic(skb, len, &&here);
-here:          ;
+       if(skb->data<skb->head) {
+               skb_under_panic(skb, len, current_text_addr());
        }
        return skb->data;
 }
index 54e30712a79f9710d8a72dba2f1c9613795e3d28..79fae935640b3fc325787a454f3b7b8eb7492e03 100644 (file)
@@ -8,11 +8,14 @@
 
 #ifdef __KERNEL__
 
-#include <asm/page.h>
-#include <asm/spinlock.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/stddef.h>
 
+#include <asm/page.h>
+#include <asm/spinlock.h>
+#include <asm/processor.h>
+
 /*
  * Temporary debugging help until all code is converted to the new
  * waitqueue usage.
@@ -118,7 +121,6 @@ typedef struct __wait_queue_head wait_queue_head_t;
 static inline void init_waitqueue_head(wait_queue_head_t *q)
 {
 #if WAITQUEUE_DEBUG
-       __label__ __x;
        if (!q)
                WQ_BUG();
 #endif
@@ -126,7 +128,7 @@ static inline void init_waitqueue_head(wait_queue_head_t *q)
        INIT_LIST_HEAD(&q->task_list);
 #if WAITQUEUE_DEBUG
        q->__magic = (long)&q->__magic;
-       __x: q->__creator = (long)&&__x;
+       q->__creator = (long)current_text_addr();
 #endif
 }
 
index 66df471228746b67437411472fe6d1ecb024c488..643898ced9b33653e69d615bfb0beda19f808bd9 100644 (file)
@@ -94,8 +94,6 @@ struct rtable
 #endif
 };
 
-extern struct rtable   *rt_hash_table[RT_HASH_DIVISOR];
-
 struct ip_rt_acct
 {
        __u32   o_bytes;
index 23d23c39af7695e8d0edd8226b3061f3ebc0b1ee..9f547de3d1186f71de08897c9c815d189f7058ca 100644 (file)
@@ -105,6 +105,7 @@ struct unix_opt {
        struct sock **          list;
        struct sock *           gc_tree;
        int                     inflight;
+       atomic_t                user_count;
 };
 
 #ifdef CONFIG_NETLINK
@@ -353,6 +354,22 @@ struct tcp_opt {
 #define SOCK_DEBUG(sk, msg...) do { } while (0)
 #endif
 
+/* This is the per-socket lock.  The spinlock provides a synchronization
+ * between user contexts and software interrupt processing, whereas the
+ * mini-semaphore synchronizes multiple users amongst themselves.
+ */
+typedef struct {
+       spinlock_t              slock;
+       unsigned int            users;
+       wait_queue_head_t       wq;
+} socket_lock_t;
+
+#define sock_lock_init(__sk) \
+do {   spin_lock_init(&((__sk)->lock.slock)); \
+       (__sk)->lock.users = 0; \
+       init_waitqueue_head(&((__sk)->lock.wq)); \
+} while(0);
+
 struct sock {
        /* This must be first. */
        struct sock             *sklist_next;
@@ -381,7 +398,7 @@ struct sock {
        unsigned char           reuse,          /* SO_REUSEADDR setting                 */
                                nonagle;        /* Disable Nagle algorithm?             */
 
-       atomic_t                sock_readers;   /* User count                           */
+       socket_lock_t           lock;           /* Synchronizer...                      */
        int                     rcvbuf;         /* Size of receive buffer in bytes      */
 
        wait_queue_head_t       *sleep; /* Sock wait queue                      */
@@ -415,9 +432,17 @@ struct sock {
        int                     hashent;
        struct sock             *pair;
 
-       /* Error and backlog packet queues, rarely used. */
-       struct sk_buff_head     back_log,
-                               error_queue;
+       /* The backlog queue is special, it is always used with
+        * the per-socket spinlock held and requires low latency
+        * access.  Therefore we special case it's implementation.
+        */
+       struct {
+               struct sk_buff *head;
+               struct sk_buff *tail;
+       } backlog;
+
+       /* Error queue, rarely used. */
+       struct sk_buff_head     error_queue;
 
        struct proto            *prot;
 
@@ -537,6 +562,18 @@ struct sock {
        void                    (*destruct)(struct sock *sk);
 };
 
+/* The per-socket spinlock must be held here. */
+#define sk_add_backlog(__sk, __skb)                    \
+do {   if((__sk)->backlog.tail == NULL) {              \
+               (__sk)->backlog.head =                  \
+                    (__sk)->backlog.tail = (__skb);    \
+       } else {                                        \
+               ((__sk)->backlog.tail)->next = (__skb); \
+               (__sk)->backlog.tail = (__skb);         \
+       }                                               \
+       (__skb)->next = NULL;                           \
+} while(0)
+
 /* IP protocol blocks we attach to sockets.
  * socket layer -> transport layer interface
  * transport -> network interface is defined by struct inet_proto
@@ -616,15 +653,26 @@ struct proto {
 /* Per-protocol hash table implementations use this to make sure
  * nothing changes.
  */
-#define SOCKHASH_LOCK()                start_bh_atomic()
-#define SOCKHASH_UNLOCK()      end_bh_atomic()
+extern rwlock_t sockhash_lock;
+#define SOCKHASH_LOCK_READ()           read_lock_bh(&sockhash_lock)
+#define SOCKHASH_UNLOCK_READ()         read_unlock_bh(&sockhash_lock)
+#define SOCKHASH_LOCK_WRITE()          write_lock_bh(&sockhash_lock)
+#define SOCKHASH_UNLOCK_WRITE()                write_unlock_bh(&sockhash_lock)
+
+/* The following variants must _only_ be used when you know you
+ * can only be executing in a BH context.
+ */
+#define SOCKHASH_LOCK_READ_BH()                read_lock(&sockhash_lock)
+#define SOCKHASH_UNLOCK_READ_BH()      read_unlock(&sockhash_lock)
+#define SOCKHASH_LOCK_WRITE_BH()       write_lock(&sockhash_lock)
+#define SOCKHASH_UNLOCK_WRITE_BH()     write_unlock(&sockhash_lock)
 
 /* Some things in the kernel just want to get at a protocols
  * entire socket list commensurate, thus...
  */
 static __inline__ void add_to_prot_sklist(struct sock *sk)
 {
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        if(!sk->sklist_next) {
                struct proto *p = sk->prot;
 
@@ -638,54 +686,37 @@ static __inline__ void add_to_prot_sklist(struct sock *sk)
                if(sk->prot->highestinuse < sk->prot->inuse)
                        sk->prot->highestinuse = sk->prot->inuse;
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static __inline__ void del_from_prot_sklist(struct sock *sk)
 {
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        if(sk->sklist_next) {
                sk->sklist_next->sklist_prev = sk->sklist_prev;
                sk->sklist_prev->sklist_next = sk->sklist_next;
                sk->sklist_next = NULL;
                sk->prot->inuse--;
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
-/*
- * Used by processes to "lock" a socket state, so that
+/* Used by processes to "lock" a socket state, so that
  * interrupts and bottom half handlers won't change it
  * from under us. It essentially blocks any incoming
  * packets, so that we won't get any new data or any
  * packets that change the state of the socket.
  *
- * Note the 'barrier()' calls: gcc may not move a lock
- * "downwards" or a unlock "upwards" when optimizing.
+ * While locked, BH processing will add new packets to
+ * the backlog queue.  This queue is processed by the
+ * owner of the socket lock right before it is released.
  */
-extern void __release_sock(struct sock *sk);
+extern void lock_sock(struct sock *sk);
+extern void release_sock(struct sock *sk);
 
-static inline void lock_sock(struct sock *sk)
-{
-#if 0
-/* debugging code: the test isn't even 100% correct, but it can catch bugs */
-/* Note that a double lock is ok in theory - it's just _usually_ a bug */
-       if (atomic_read(&sk->sock_readers)) {
-               __label__ here;
-               printk("double lock on socket at %p\n", &&here);
-here:
-       }
-#endif
-       atomic_inc(&sk->sock_readers);
-       synchronize_bh();
-}
-
-static inline void release_sock(struct sock *sk)
-{
-       barrier();
-       if (atomic_dec_and_test(&sk->sock_readers))
-               __release_sock(sk);
-}
+/* BH context may only use the following locking interface. */
+#define bh_lock_sock(__sk)     spin_lock(&((__sk)->lock.slock))
+#define bh_unlock_sock(__sk)   spin_unlock(&((__sk)->lock.slock))
 
 /*
  *     This might not be the most appropriate place for this two        
index 6d7dc75dc13253c0f028c2c1b6e4bf20b8e2b36b..385e635344c9d061252923b1b9af794f9fae2c6e 100644 (file)
  * New scheme, half the table is for TIME_WAIT, the other half is
  * for the rest.  I'll experiment with dynamic table growth later.
  */
-#define TCP_HTABLE_SIZE                512
+extern int tcp_ehash_size;
+extern struct sock **tcp_ehash;
 
 /* This is for listening sockets, thus all sockets which possess wildcards. */
 #define TCP_LHTABLE_SIZE       32      /* Yes, really, this is all you need. */
 
-/* This is for all sockets, to keep track of the local port allocations. */
-#define TCP_BHTABLE_SIZE       512
-
 /* tcp_ipv4.c: These need to be shared by v4 and v6 because the lookup
  *             and hashing code needs to work with different AF's yet
  *             the port space is shared.
  */
-extern struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
 extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
 
 /* There are a few simple rules, which allow for local port reuse by
@@ -85,7 +82,9 @@ struct tcp_bind_bucket {
        struct tcp_bind_bucket  **pprev;
 };
 
-extern struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+extern struct tcp_bind_bucket **tcp_bhash;
+extern int tcp_bhash_size;
+
 extern kmem_cache_t *tcp_bucket_cachep;
 extern struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum);
 extern void tcp_bucket_unlock(struct sock *sk);
@@ -113,7 +112,7 @@ static __inline__ void tcp_reg_zap(struct sock *sk)
 /* These are AF independent. */
 static __inline__ int tcp_bhashfn(__u16 lport)
 {
-       return (lport & (TCP_BHTABLE_SIZE - 1));
+       return (lport & (tcp_bhash_size - 1));
 }
 
 static __inline__ void tcp_sk_bindify(struct sock *sk)
@@ -121,7 +120,7 @@ static __inline__ void tcp_sk_bindify(struct sock *sk)
        struct tcp_bind_bucket *tb;
        unsigned short snum = sk->num;
 
-       for(tb = tcp_bound_hash[tcp_bhashfn(snum)]; tb->port != snum; tb = tb->next)
+       for(tb = tcp_bhash[tcp_bhashfn(snum)]; tb->port != snum; tb = tb->next)
                ;
        /* Update bucket flags. */
        if(tb->owners == NULL) {
index d97242df26c6ee82dfdfda76e68237e4e72447c9..b7b86e2d62996570e80a9a3ff2fa7206bf185557 100644 (file)
@@ -203,6 +203,7 @@ EXPORT_SYMBOL(tty_unregister_driver);
 EXPORT_SYMBOL(tty_std_termios);
 
 /* block device driver support */
+EXPORT_SYMBOL(blk_ioctl);
 EXPORT_SYMBOL(block_read);
 EXPORT_SYMBOL(block_write);
 EXPORT_SYMBOL(block_fsync);
index c30da74022c9bdbc5b2e3ce2b0b5bf4a165b2d3b..ff7066886100227f4e24519ac42715d85101975b 100644 (file)
@@ -1039,7 +1039,7 @@ out:
 #endif /* __sparc__ */
 #endif
 
-#if !defined(__alpha__)
+#if !defined(__alpha__) && !defined(__ia64__)
 /*
  * For backwards compatibility.  Functionality superseded by sigprocmask.
  */
@@ -1082,4 +1082,4 @@ sys_signal(int sig, __sighandler_t handler)
 
        return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
 }
-#endif /* !alpha */
+#endif /* !alpha && !__ia64__ */
index 9fe12559c9f9c8ef47a438546381b2e4be53174e..911442dad460c4c0a032b2f835288a4c41cfa1ca 100644 (file)
@@ -54,13 +54,15 @@ void get_fast_time(struct timeval * t)
        do_get_fast_time(t);
 }
 
-#ifndef __alpha__
+#if !defined(__alpha__) && !defined(__ia64__)
 
 /*
  * sys_time() can be implemented in user-level using
  * sys_gettimeofday().  Is this for backwards compatibility?  If so,
  * why not move it into the appropriate arch directory (for those
  * architectures that need it).
+ *
+ * XXX This function is NOT 64-bit clean!
  */
 asmlinkage int sys_time(int * tloc)
 {
index 97ccc92d2dbf10b9202a50f134c5851a3e6b5bd1..049cf90dab45050bcc52c02d4b03eda8827713be 100644 (file)
@@ -1311,18 +1311,9 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
        struct vm_operations_struct * ops;
        struct inode *inode = file->f_dentry->d_inode;
 
-       if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) {
+       ops = &file_private_mmap;
+       if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
                ops = &file_shared_mmap;
-               /* share_page() can only guarantee proper page sharing if
-                * the offsets are all page aligned. */
-               if (vma->vm_offset & (PAGE_SIZE - 1))
-                       return -EINVAL;
-       } else {
-               ops = &file_private_mmap;
-               if (inode->i_op && inode->i_op->bmap &&
-                   (vma->vm_offset & (inode->i_sb->s_blocksize - 1)))
-                       return -EINVAL;
-       }
        if (!inode->i_sb || !S_ISREG(inode->i_mode))
                return -EACCES;
        if (!inode->i_op || !inode->i_op->readpage)
index 9f7d3285183c5dfcb43e4a150a52f276477c6ec5..80fe4454578cc231e874d3ef7190d3b4ab100788 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -185,6 +185,9 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
        if (len > TASK_SIZE || addr > TASK_SIZE-len)
                return -EINVAL;
 
+       if (off & ~PAGE_MASK)
+               return -EINVAL;
+
        /* offset overflow? */
        if (off + len < off)
                return -EINVAL;
index 921f05470faaddd70eeab118ee3a388280367f54..6e8735751c4b10dc44f7b0411de53aeb023bf84c 100644 (file)
@@ -258,37 +258,43 @@ struct device *dev_get(const char *name)
 {
        struct device *dev;
 
-       for (dev = dev_base; dev != NULL; dev = dev->next) 
-       {
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                if (strcmp(dev->name, name) == 0)
-                       return(dev);
+                       goto out;
        }
-       return NULL;
+out:
+       read_unlock_bh(&dev_base_lock);
+       return dev;
 }
 
 struct device * dev_get_by_index(int ifindex)
 {
        struct device *dev;
 
-       for (dev = dev_base; dev != NULL; dev = dev->next) 
-       {
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                if (dev->ifindex == ifindex)
-                       return(dev);
+                       goto out;
        }
-       return NULL;
+out:
+       read_unlock_bh(&dev_base_lock);
+       return dev;
 }
 
 struct device *dev_getbyhwaddr(unsigned short type, char *ha)
 {
        struct device *dev;
 
-       for (dev = dev_base; dev != NULL; dev = dev->next) 
-       {
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                if (dev->type == type &&
                    memcmp(dev->dev_addr, ha, dev->addr_len) == 0)
-                       return(dev);
+                       goto out;
        }
-       return(NULL);
+out:
+       read_unlock_bh(&dev_base_lock);
+       return dev;
 }
 
 /*
@@ -376,6 +382,9 @@ int dev_open(struct device *dev)
        if (dev->flags&IFF_UP)
                return 0;
 
+       /* Setup the lock before we open the faucet. */
+       spin_lock_init(&dev->xmit_lock);
+
        /*
         *      Call device private open method
         */
@@ -438,8 +447,13 @@ void dev_clear_fastroute(struct device *dev)
        if (dev) {
                dev_do_clear_fastroute(dev);
        } else {
-               for (dev = dev_base; dev; dev = dev->next)
+               read_lock_bh(&dev_base_lock);
+               for (dev = dev_base; dev; dev = dev->next) {
+                       read_unlock_bh(&dev_base_lock);
                        dev_do_clear_fastroute(dev);
+                       read_lock_bh(&dev_base_lock);
+               }
+               read_unlock_bh(&dev_base_lock);
        }
 }
 #endif
@@ -583,12 +597,12 @@ int dev_queue_xmit(struct sk_buff *skb)
        NET_PROFILE_ENTER(dev_queue_xmit);
 #endif
 
-       start_bh_atomic();
+       spin_lock_bh(&dev->xmit_lock);
        q = dev->qdisc;
        if (q->enqueue) {
                q->enqueue(skb, q);
                qdisc_wakeup(dev);
-               end_bh_atomic();
+               spin_unlock_bh(&dev->xmit_lock);
 
 #ifdef CONFIG_NET_PROFILE
                NET_PROFILE_LEAVE(dev_queue_xmit);
@@ -610,7 +624,7 @@ int dev_queue_xmit(struct sk_buff *skb)
                if (netdev_nit) 
                        dev_queue_xmit_nit(skb,dev);
                if (dev->hard_start_xmit(skb, dev) == 0) {
-                       end_bh_atomic();
+                       spin_unlock_bh(&dev->xmit_lock);
 
 #ifdef CONFIG_NET_PROFILE
                        NET_PROFILE_LEAVE(dev_queue_xmit);
@@ -622,7 +636,7 @@ int dev_queue_xmit(struct sk_buff *skb)
                if (net_ratelimit())
                        printk(KERN_DEBUG "Virtual device %s asks to queue packet!\n", dev->name);
        }
-       end_bh_atomic();
+       spin_unlock_bh(&dev->xmit_lock);
 
        kfree_skb(skb);
 
@@ -1113,7 +1127,9 @@ static int dev_ifconf(char *arg)
         */
 
        total = 0;
+       read_lock_bh(&dev_base_lock);
        for (dev = dev_base; dev != NULL; dev = dev->next) {
+               read_unlock_bh(&dev_base_lock);
                for (i=0; i<NPROTO; i++) {
                        if (gifconf_list[i]) {
                                int done;
@@ -1122,12 +1138,15 @@ static int dev_ifconf(char *arg)
                                } else {
                                        done = gifconf_list[i](dev, pos+total, len-total);
                                }
-                               if (done<0)
+                               if (done<0) {
                                        return -EFAULT;
+                               }
                                total += done;
                        }
                }
+               read_lock_bh(&dev_base_lock);
        }
+       read_unlock_bh(&dev_base_lock);
 
        /*
         *      All done.  Write the updated control block back to the caller. 
@@ -1199,20 +1218,20 @@ int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy
        len+=size;
        
 
-       for (dev = dev_base; dev != NULL; dev = dev->next) 
-       {
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                size = sprintf_stats(buffer+len, dev);
                len+=size;
                pos=begin+len;
                                
-               if(pos<offset)
-               {
+               if(pos<offset) {
                        len=0;
                        begin=pos;
                }
                if(pos>offset+length)
                        break;
        }
+       read_unlock_bh(&dev_base_lock);
        
        *start=buffer+(offset-begin);   /* Start of wanted data */
        len-=(offset-begin);            /* Start slop */
@@ -1314,20 +1333,20 @@ int dev_get_wireless_info(char * buffer, char **start, off_t offset,
        pos+=size;
        len+=size;
 
-       for(dev = dev_base; dev != NULL; dev = dev->next) 
-       {
+       read_lock_bh(&dev_base_lock);
+       for(dev = dev_base; dev != NULL; dev = dev->next) {
                size = sprintf_wireless_stats(buffer+len, dev);
                len+=size;
                pos=begin+len;
 
-               if(pos < offset)
-               {
+               if(pos < offset) {
                        len=0;
                        begin=pos;
                }
                if(pos > offset + length)
                        break;
        }
+       read_unlock_bh(&dev_base_lock);
 
        *start = buffer + (offset - begin);     /* Start of wanted data */
        len -= (offset - begin);                /* Start slop */
@@ -1751,12 +1770,16 @@ int register_netdevice(struct device *dev)
                printk(KERN_INFO "early initialization of device %s is deferred\n", dev->name);
 
                /* Check for existence, and append to tail of chain */
+               write_lock_bh(&dev_base_lock);
                for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
-                       if (d == dev || strcmp(d->name, dev->name) == 0)
+                       if (d == dev || strcmp(d->name, dev->name) == 0) {
+                               write_unlock_bh(&dev_base_lock);
                                return -EEXIST;
+                       }
                }
                dev->next = NULL;
                *dp = dev;
+               write_unlock_bh(&dev_base_lock);
                return 0;
        }
 
@@ -1767,16 +1790,22 @@ int register_netdevice(struct device *dev)
                return -EIO;
 
        /* Check for existence, and append to tail of chain */
+       write_lock_bh(&dev_base_lock);
        for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
-               if (d == dev || strcmp(d->name, dev->name) == 0)
+               if (d == dev || strcmp(d->name, dev->name) == 0) {
+                       write_unlock_bh(&dev_base_lock);
                        return -EEXIST;
+               }
        }
        dev->next = NULL;
        dev_init_scheduler(dev);
+       *dp = dev;
+       write_unlock_bh(&dev_base_lock);
+
+       dev->ifindex = -1;
        dev->ifindex = dev_new_index();
        if (dev->iflink == -1)
                dev->iflink = dev->ifindex;
-       *dp = dev;
 
        /* Notify protocols, that a new device appeared. */
        notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
@@ -1820,17 +1849,19 @@ int unregister_netdevice(struct device *dev)
        }
 
        /* And unlink it from device chain. */
+       write_lock_bh(&dev_base_lock);
        for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) {
                if (d == dev) {
                        *dp = d->next;
-                       synchronize_bh();
                        d->next = NULL;
+                       write_unlock_bh(&dev_base_lock);
 
                        if (dev->destructor)
                                dev->destructor(dev);
                        return 0;
                }
        }
+       write_unlock_bh(&dev_base_lock);
        return -ENODEV;
 }
 
@@ -1976,26 +2007,25 @@ __initfunc(int net_dev_init(void))
         */
 
        dp = &dev_base;
-       while ((dev = *dp) != NULL)
-       {
+       write_lock_bh(&dev_base_lock);
+       while ((dev = *dp) != NULL) {
                dev->iflink = -1;
-               if (dev->init && dev->init(dev)) 
-               {
+               if (dev->init && dev->init(dev)) {
                        /*
                         *      It failed to come up. Unhook it.
                         */
                        *dp = dev->next;
-                       synchronize_bh();
-               } 
-               else
-               {
+               } else {
                        dp = &dev->next;
+                       write_unlock_bh(&dev_base_lock);
                        dev->ifindex = dev_new_index();
+                       write_lock_bh(&dev_base_lock);
                        if (dev->iflink == -1)
                                dev->iflink = dev->ifindex;
                        dev_init_scheduler(dev);
                }
        }
+       write_unlock_bh(&dev_base_lock);
 
 #ifdef CONFIG_PROC_FS
        proc_net_register(&proc_net_dev);
index bce3f4a4a2659b8fcd0f2c7e9ae5fb2fb4692e4a..3a27a7f786f7b41f078e55e0bd99cc70fbf56d7b 100644 (file)
@@ -203,8 +203,7 @@ static int dev_mc_read_proc(char *buffer, char **start, off_t offset,
        int len=0;
        struct device *dev;
 
-       start_bh_atomic();
-
+       read_lock_bh(&dev_base_lock);
        for (dev = dev_base; dev; dev = dev->next) {
                for (m = dev->mc_list; m; m = m->next) {
                        int i;
@@ -229,7 +228,7 @@ static int dev_mc_read_proc(char *buffer, char **start, off_t offset,
        *eof = 1;
 
 done:
-       end_bh_atomic();
+       read_unlock_bh(&dev_base_lock);
        *start=buffer+(offset-begin);
        len-=(offset-begin);
        if(len>length)
index b5aa3b640b56c97e35f54bee9cf22e52b6880816..187a484cb4630edb2969370db5fb759d8be2cdf9 100644 (file)
@@ -189,12 +189,14 @@ int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        int s_idx = cb->args[0];
        struct device *dev;
 
+       read_lock_bh(&dev_base_lock);
        for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
                if (idx < s_idx)
                        continue;
                if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0)
                        break;
        }
+       read_unlock_bh(&dev_base_lock);
        cb->args[0] = idx;
 
        return skb->len;
index 1473de7a3a83d527d6ab8f300e2f4e5e0498e036..7a1e42fc3b7d2fbb2e45ee1694f59090a310ad44 100644 (file)
@@ -487,10 +487,10 @@ struct sock *sk_alloc(int family, int priority, int zero_it)
 {
        struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
 
-       if(sk) {
-               if (zero_it) 
-                       memset(sk, 0, sizeof(struct sock));
+       if(sk && zero_it) {
+               memset(sk, 0, sizeof(struct sock));
                sk->family = family;
+               sock_lock_init(sk);
        }
 
        return sk;
@@ -736,24 +736,44 @@ failure:
        return NULL;
 }
 
-
-void __release_sock(struct sock *sk)
+void lock_sock(struct sock *sk)
 {
-#ifdef CONFIG_INET
-       if (!sk->prot || !sk->backlog_rcv)
-               return;
-               
-       /* See if we have any packets built up. */
-       start_bh_atomic();
-       while (!skb_queue_empty(&sk->back_log)) {
-               struct sk_buff * skb = sk->back_log.next;
-               __skb_unlink(skb, &sk->back_log);
-               sk->backlog_rcv(sk, skb);
+       spin_lock_bh(&sk->lock.slock);
+       if(sk->lock.users != 0) {
+               DECLARE_WAITQUEUE(wait, current);
+
+               add_wait_queue_exclusive(&sk->lock.wq, &wait);
+               for(;;) {
+                       current->state = TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE;
+                       spin_unlock_bh(&sk->lock.slock);
+                       schedule();
+                       spin_lock_bh(&sk->lock.slock);
+                       if(!sk->lock.users)
+                               break;
+               }
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&sk->lock.wq, &wait);
        }
-       end_bh_atomic();
-#endif  
+       sk->lock.users = 1;
+       spin_unlock_bh(&sk->lock.slock);
 }
 
+void release_sock(struct sock *sk)
+{
+       spin_lock_bh(&sk->lock.slock);
+       sk->lock.users = 0;
+       if(sk->backlog.tail != NULL) {
+               struct sk_buff *skb = sk->backlog.head;
+               do {    struct sk_buff *next = skb->next;
+                       skb->next = NULL;
+                       sk->backlog_rcv(sk, skb);
+                       skb = next;
+               } while(skb != NULL);
+               sk->backlog.head = sk->backlog.tail = NULL;
+       }
+       wake_up(&sk->lock.wq);
+       spin_unlock_bh(&sk->lock.slock);
+}
 
 /*
  *     Generic socket manager library. Most simpler socket families
@@ -1019,7 +1039,6 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 {
        skb_queue_head_init(&sk->receive_queue);
        skb_queue_head_init(&sk->write_queue);
-       skb_queue_head_init(&sk->back_log);
        skb_queue_head_init(&sk->error_queue);
        
        init_timer(&sk->timer);
index bce35d484cf1b550df1808f2c85684f9ecfba9bc..e3392749a7fb5e67ffd07f52c8e27b5f7c3fd628 100644 (file)
 
 __initfunc(void eth_setup(char *str, int *ints))
 {
-       struct device *d = dev_base;
+       struct device *d;
 
        if (!str || !*str)
                return;
+       read_lock_bh(&dev_base_lock);
+       d = dev_base;
        while (d) 
        {
                if (!strcmp(str,d->name)) 
@@ -83,6 +85,7 @@ __initfunc(void eth_setup(char *str, int *ints))
                }
                d=d->next;
        }
+       read_unlock_bh(&dev_base_lock);
 }
 
 
index f1f78200759550e4d89a1b783f5f23156cecebd9..a34ed8a9e411d1fa00b106befb206305bd34c36a 100644 (file)
@@ -160,9 +160,10 @@ static __inline__ void kill_sk_queues(struct sock *sk)
        while((skb = skb_dequeue(&sk->error_queue)) != NULL)
                kfree_skb(skb);
 
-       /* Now the backlog. */
-       while((skb=skb_dequeue(&sk->back_log)) != NULL)
-               kfree_skb(skb);
+       /* It is _impossible_ for the backlog to contain anything
+        * when we get here.  All user references to this socket
+        * have gone away, only the net layer knows can touch it.
+        */
 }
 
 static __inline__ void kill_sk_now(struct sock *sk)
@@ -195,14 +196,19 @@ static __inline__ void kill_sk_later(struct sock *sk)
 
        sk->destroy = 1;
        sk->ack_backlog = 0;
-       release_sock(sk);
+       bh_unlock_sock(sk);
        net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
 }
 
+/* Callers must hold the BH spinlock.
+ *
+ * At this point, there should be no process reference to this
+ * socket, and thus no user references at all.  Therefore we
+ * can assume the socket waitqueue is inactive and nobody will
+ * try to jump onto it.
+ */
 void destroy_sock(struct sock *sk)
 {
-       lock_sock(sk);                  /* just to be safe. */
-
        /* Now we can no longer get new packets or once the
         * timers are killed, send them.
         */
index c8b0fbbc80c4ab209aa5352a88335f1b95b9389e..e4e73ff7736d3a1c4b56df98ba4be22166715179 100644 (file)
@@ -661,15 +661,19 @@ u32 inet_select_addr(struct device *dev, u32 dst, int scope)
           in this case. It is importnat that lo is the first interface
           in dev_base list.
         */
+       read_lock_bh(&dev_base_lock);
        for (dev=dev_base; dev; dev=dev->next) {
                if ((in_dev=dev->ip_ptr) == NULL)
                        continue;
 
                for_primary_ifa(in_dev) {
-                       if (ifa->ifa_scope <= scope)
+                       if (ifa->ifa_scope <= scope) {
+                               read_unlock_bh(&dev_base_lock);
                                return ifa->ifa_local;
+                       }
                } endfor_ifa(in_dev);
        }
+       read_unlock_bh(&dev_base_lock);
 
        return 0;
 }
@@ -790,6 +794,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 
        s_idx = cb->args[0];
        s_ip_idx = ip_idx = cb->args[1];
+       read_lock_bh(&dev_base_lock);
        for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
                if (idx < s_idx)
                        continue;
@@ -807,6 +812,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
                }
        }
 done:
+       read_unlock_bh(&dev_base_lock);
        cb->args[0] = idx;
        cb->args[1] = ip_idx;
 
@@ -881,11 +887,13 @@ void inet_forward_change()
        ipv4_devconf.accept_redirects = !on;
        ipv4_devconf_dflt.forwarding = on;
 
+       read_lock_bh(&dev_base_lock);
        for (dev = dev_base; dev; dev = dev->next) {
                struct in_device *in_dev = dev->ip_ptr;
                if (in_dev)
                        in_dev->cnf.forwarding = on;
        }
+       read_unlock_bh(&dev_base_lock);
 
        rt_cache_flush(0);
 
index 868c44c31cec49957874baee8a4ebadfa13d1bc9..bb533faff6a81e5e383f3ecf368e88d80613b3b4 100644 (file)
@@ -79,13 +79,16 @@ static struct fib_rule main_rule = { &default_rule, 0x7FFE, RT_TABLE_MAIN, RTN_U
 static struct fib_rule local_rule = { &main_rule, 0, RT_TABLE_LOCAL, RTN_UNICAST, };
 
 static struct fib_rule *fib_rules = &local_rule;
+static rwlock_t fib_rules_lock = RW_LOCK_UNLOCKED;
 
 int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
        struct rtattr **rta = arg;
        struct rtmsg *rtm = NLMSG_DATA(nlh);
        struct fib_rule *r, **rp;
+       int err = -ESRCH;
 
+       write_lock_bh(&fib_rules_lock);
        for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) {
                if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) &&
                    rtm->rtm_src_len == r->r_src_len &&
@@ -99,18 +102,19 @@ int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
                    (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
                    (!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) &&
                    (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
+                       err = -EPERM;
                        if (r == &local_rule)
-                               return -EPERM;
+                               break;
 
                        *rp = r->r_next;
-                       synchronize_bh();
-
                        if (r != &default_rule && r != &main_rule)
                                kfree(r);
-                       return 0;
+                       err = 0;
+                       break;
                }
        }
-       return -ESRCH;
+       write_unlock_bh(&fib_rules_lock);
+       return err;
 }
 
 /* Allocate new unique table id */
@@ -188,6 +192,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
                memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4);
 #endif
 
+       write_lock_bh(&fib_rules_lock);
        rp = &fib_rules;
        if (!new_r->r_preference) {
                r = fib_rules;
@@ -206,6 +211,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 
        new_r->r_next = r;
        *rp = new_r;
+       write_unlock_bh(&fib_rules_lock);
        return 0;
 }
 
@@ -249,20 +255,24 @@ static void fib_rules_detach(struct device *dev)
 {
        struct fib_rule *r;
 
+       write_lock_bh(&fib_rules_lock);
        for (r=fib_rules; r; r=r->r_next) {
                if (r->r_ifindex == dev->ifindex)
                        r->r_ifindex = -1;
        }
+       write_unlock_bh(&fib_rules_lock);
 }
 
 static void fib_rules_attach(struct device *dev)
 {
        struct fib_rule *r;
 
+       write_lock_bh(&fib_rules_lock);
        for (r=fib_rules; r; r=r->r_next) {
                if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
                        r->r_ifindex = dev->ifindex;
        }
+       write_unlock_bh(&fib_rules_lock);
 }
 
 int fib_lookup(const struct rt_key *key, struct fib_result *res)
@@ -275,6 +285,7 @@ int fib_lookup(const struct rt_key *key, struct fib_result *res)
        u32 saddr = key->src;
 
 FRprintk("Lookup: %08x <- %08x ", key->dst, key->src);
+       read_lock_bh(&fib_rules_lock);
        for (r = fib_rules; r; r=r->r_next) {
                if (((saddr^r->r_src) & r->r_srcmask) ||
                    ((daddr^r->r_dst) & r->r_dstmask) ||
@@ -294,11 +305,14 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
                        policy = r;
                        break;
                case RTN_UNREACHABLE:
+                       read_unlock_bh(&fib_rules_lock);
                        return -ENETUNREACH;
                default:
                case RTN_BLACKHOLE:
+                       read_unlock_bh(&fib_rules_lock);
                        return -EINVAL;
                case RTN_PROHIBIT:
+                       read_unlock_bh(&fib_rules_lock);
                        return -EACCES;
                }
 
@@ -308,12 +322,16 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
                if (err == 0) {
 FRprintk("ok\n");
                        res->r = policy;
+                       read_unlock_bh(&fib_rules_lock);
                        return 0;
                }
-               if (err < 0 && err != -EAGAIN)
+               if (err < 0 && err != -EAGAIN) {
+                       read_unlock_bh(&fib_rules_lock);
                        return err;
+               }
        }
 FRprintk("FAILURE\n");
+       read_unlock_bh(&fib_rules_lock);
        return -ENETUNREACH;
 }
 
@@ -400,12 +418,14 @@ int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
        int s_idx = cb->args[0];
        struct fib_rule *r;
 
+       read_lock_bh(&fib_rules_lock);
        for (r=fib_rules, idx=0; r; r = r->r_next, idx++) {
                if (idx < s_idx)
                        continue;
                if (inet_fill_rule(skb, r, cb) < 0)
                        break;
        }
+       read_unlock_bh(&fib_rules_lock);
        cb->args[0] = idx;
 
        return skb->len;
index 68e52633eb25f4fa82d0054afd7d0c7c4f6d196b..0c7ac7324bcf53486e0617eac3e12c90984b3a86 100644 (file)
@@ -656,8 +656,8 @@ int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length, int dum
        
        len=sprintf(buffer,"Idx\tDevice    : Count Querier\tGroup    Users Timer\tReporter\n");  
        
-       for(dev = dev_base; dev; dev = dev->next)
-       {
+       read_lock_bh(&dev_base_lock);
+       for(dev = dev_base; dev; dev = dev->next) {
                struct in_device *in_dev = dev->ip_ptr;
                char   *querier = "NONE";
                
@@ -686,6 +686,8 @@ int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length, int dum
                }
        }
 done:
+       read_unlock_bh(&dev_base_lock);
+
        *start=buffer+(offset-begin);
        len-=(offset-begin);
        if(len>length)
index abe93ec2776e669aca8d028d9fd69bd45465506e..846d54b8ec57d737927868dab0c1f1c74da8fa8a 100644 (file)
@@ -112,7 +112,8 @@ static int __init ic_open_devs(void)
        unsigned short oflags;
 
        last = &ic_first_dev;
-       for (dev = dev_base; dev; dev = dev->next)
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev; dev = dev->next) {
                if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
                    (!(dev->flags & IFF_LOOPBACK) &&
                     (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) &&
@@ -142,6 +143,9 @@ static int __init ic_open_devs(void)
                        ic_proto_have_if |= able;
                        DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able));
                }
+       }
+       read_unlock_bh(&dev_base_lock);
+
        *last = NULL;
 
        if (!ic_first_dev) {
index 1640a05607527eb57bf58a468e1d6de563b98703..4c05059f8ea4f11f01966b991c21557f723f7738 100644 (file)
@@ -114,10 +114,8 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
                        slot_dist = tcp_tw_death_row_slot - slot_dist;
                timer_expires   = jiffies + (slot_dist * TCP_TWKILL_PERIOD);
        } else {
-               timer_active1 = del_timer(&tp->retransmit_timer);
-               timer_active2 = del_timer(&sp->timer);
-               if (!timer_active1) tp->retransmit_timer.expires=0;
-               if (!timer_active2) sp->timer.expires=0;
+               timer_active1 = tp->retransmit_timer.prev != NULL;
+               timer_active2 = sp->timer.prev != NULL;
                timer_active    = 0;
                timer_expires   = (unsigned) -1;
        }
@@ -147,9 +145,6 @@ static inline void get__sock(struct sock *sp, char *tmpbuf, int i, int format)
                (!tw_bucket && sp->socket) ? sp->socket->inode->i_uid : 0,
                (!tw_bucket && timer_active) ? sp->timeout : 0,
                (!tw_bucket && sp->socket) ? sp->socket->inode->i_ino : 0);
-       
-       if (timer_active1) add_timer(&tp->retransmit_timer);
-       if (timer_active2) add_timer(&sp->timer);       
 }
 
 /*
@@ -176,7 +171,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                               "  sl  local_address rem_address   st tx_queue "
                               "rx_queue tr tm->when retrnsmt   uid  timeout inode");
        pos = 128;
-       SOCKHASH_LOCK(); 
+       SOCKHASH_LOCK_READ();
        sp = pro->sklist_next;
        while(sp != (struct sock *)pro) {
                if (format == 0 && sp->state == TCP_LISTEN) {
@@ -211,7 +206,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                i++;
        }
 out: 
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
        
        begin = len - (pos - offset);
        *start = buffer + begin;
index fc6b1f2ee7f6be164b46f77b9176bd34be904a0a..a34057b6b3a72b68cb63b2d82229f08f2fd6270d 100644 (file)
@@ -75,11 +75,11 @@ static void raw_v4_hash(struct sock *sk)
 
        num &= (RAWV4_HTABLE_SIZE - 1);
        skp = &raw_v4_htable[num];
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        sk->next = *skp;
        *skp = sk;
        sk->hashent = num;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void raw_v4_unhash(struct sock *sk)
@@ -90,7 +90,7 @@ static void raw_v4_unhash(struct sock *sk)
        num &= (RAWV4_HTABLE_SIZE - 1);
        skp = &raw_v4_htable[num];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        while(*skp != NULL) {
                if(*skp == sk) {
                        *skp = sk->next;
@@ -98,7 +98,7 @@ static void raw_v4_unhash(struct sock *sk)
                }
                skp = &((*skp)->next);
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void raw_v4_rehash(struct sock *sk)
@@ -110,7 +110,7 @@ static void raw_v4_rehash(struct sock *sk)
        num &= (RAWV4_HTABLE_SIZE - 1);
        skp = &raw_v4_htable[oldnum];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        while(*skp != NULL) {
                if(*skp == sk) {
                        *skp = sk->next;
@@ -121,7 +121,7 @@ static void raw_v4_rehash(struct sock *sk)
        sk->next = raw_v4_htable[num];
        raw_v4_htable[num] = sk;
        sk->hashent = num;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 /* Grumble... icmp and ip_input want to get at this... */
@@ -130,7 +130,7 @@ struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
 {
        struct sock *s = sk;
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_READ();
        for(s = sk; s; s = s->next) {
                if((s->num == num)                              &&
                   !(s->dead && (s->state == TCP_CLOSE))        &&
@@ -139,7 +139,7 @@ struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
                   !(s->bound_dev_if && s->bound_dev_if != dif))
                        break; /* gotcha */
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
        return s;
 }
 
@@ -402,6 +402,8 @@ done:
 
 static void raw_close(struct sock *sk, long timeout)
 {
+       bh_lock_sock(sk);
+
        /* Observation: when raw_close is called, processes have
           no access to socket anymore. But net still has.
           Step one, detach it from networking:
index dbde97b70fca04c30ce0a4456f450800168b7f0c..2589f457d67b69ca1df5e2ab45a32a9abdf8e5fd 100644 (file)
@@ -174,7 +174,8 @@ __u8 ip_tos2prio[16] = {
  * Route cache.
  */
 
-struct rtable  *rt_hash_table[RT_HASH_DIVISOR];
+static struct rtable   *rt_hash_table[RT_HASH_DIVISOR];
+static rwlock_t                 rt_hash_lock = RW_LOCK_UNLOCKED;
 
 static int rt_intern_hash(unsigned hash, struct rtable * rth, struct rtable ** res);
 
@@ -204,7 +205,7 @@ static int rt_cache_get_info(char *buffer, char **start, off_t offset, int lengt
        }
        
        
-       start_bh_atomic();
+       read_lock_bh(&rt_hash_lock);
 
        for (i = 0; i<RT_HASH_DIVISOR; i++) {
                for (r = rt_hash_table[i]; r; r = r->u.rt_next) {
@@ -239,7 +240,7 @@ static int rt_cache_get_info(char *buffer, char **start, off_t offset, int lengt
         }
 
 done:
-       end_bh_atomic();
+       read_unlock_bh(&rt_hash_lock);
        
        *start = buffer+len-(pos-offset);
        len = pos-offset;
@@ -305,6 +306,7 @@ static void rt_check_expire(unsigned long dummy)
                rover = (rover + 1) & (RT_HASH_DIVISOR-1);
                rthp = &rt_hash_table[rover];
 
+               write_lock_bh(&rt_hash_lock);
                while ((rth = *rthp) != NULL) {
                        if (rth->u.dst.expires) {
                                /* Entrie is expired even if it is in use */
@@ -325,6 +327,7 @@ static void rt_check_expire(unsigned long dummy)
                        *rthp = rth->u.rt_next;
                        rt_free(rth);
                }
+               write_unlock_bh(&rt_hash_lock);
 
                /* Fallback loop breaker. */
                if ((jiffies - now) > 0)
@@ -341,11 +344,13 @@ static void rt_run_flush(unsigned long dummy)
 
        rt_deadline = 0;
 
-       start_bh_atomic();
+       write_lock_bh(&rt_hash_lock);
        for (i=0; i<RT_HASH_DIVISOR; i++) {
-               if ((rth = xchg(&rt_hash_table[i], NULL)) == NULL)
+               rth = rt_hash_table[i];
+               if(rth == NULL)
                        continue;
-               end_bh_atomic();
+               rt_hash_table[i] = NULL;
+               write_unlock_bh(&rt_hash_lock);
 
                for (; rth; rth=next) {
                        next = rth->u.rt_next;
@@ -353,11 +358,13 @@ static void rt_run_flush(unsigned long dummy)
                        rt_free(rth);
                }
 
-               start_bh_atomic();
+               write_lock_bh(&rt_hash_lock);
        }
-       end_bh_atomic();
+       write_unlock_bh(&rt_hash_lock);
 }
   
+static spinlock_t rt_flush_lock = SPIN_LOCK_UNLOCKED;
+
 void rt_cache_flush(int delay)
 {
        unsigned long now = jiffies;
@@ -366,7 +373,7 @@ void rt_cache_flush(int delay)
        if (delay < 0)
                delay = ip_rt_min_delay;
 
-       start_bh_atomic();
+       spin_lock_bh(&rt_flush_lock);
 
        if (del_timer(&rt_flush_timer) && delay > 0 && rt_deadline) {
                long tmo = (long)(rt_deadline - now);
@@ -386,7 +393,7 @@ void rt_cache_flush(int delay)
        }
 
        if (delay <= 0) {
-               end_bh_atomic();
+               spin_unlock_bh(&rt_flush_lock);
                rt_run_flush(0);
                return;
        }
@@ -396,7 +403,7 @@ void rt_cache_flush(int delay)
 
        rt_flush_timer.expires = now + delay;
        add_timer(&rt_flush_timer);
-       end_bh_atomic();
+       spin_unlock_bh(&rt_flush_lock);
 }
 
 /*
@@ -459,7 +466,7 @@ static int rt_garbage_collect(void)
        do {
                int i, k;
 
-               start_bh_atomic();
+               write_lock_bh(&rt_hash_lock);
                for (i=0, k=rover; i<RT_HASH_DIVISOR; i++) {
                        unsigned tmo = expire;
 
@@ -480,7 +487,7 @@ static int rt_garbage_collect(void)
                                break;
                }
                rover = k;
-               end_bh_atomic();
+               write_unlock_bh(&rt_hash_lock);
 
                if (goal <= 0)
                        goto work_done;
@@ -530,10 +537,9 @@ static int rt_intern_hash(unsigned hash, struct rtable * rt, struct rtable ** rp
        int attempts = !in_interrupt();
 
 restart:
-       start_bh_atomic();
-
        rthp = &rt_hash_table[hash];
 
+       write_lock_bh(&rt_hash_lock);
        while ((rth = *rthp) != NULL) {
                if (memcmp(&rth->key, &rt->key, sizeof(rt->key)) == 0) {
                        /* Put it first */
@@ -544,7 +550,7 @@ restart:
                        atomic_inc(&rth->u.dst.refcnt);
                        atomic_inc(&rth->u.dst.use);
                        rth->u.dst.lastuse = now;
-                       end_bh_atomic();
+                       write_unlock_bh(&rt_hash_lock);
 
                        rt_drop(rt);
                        *rp = rth;
@@ -559,7 +565,7 @@ restart:
         */
        if (rt->rt_type == RTN_UNICAST || rt->key.iif == 0) {
                if (!arp_bind_neighbour(&rt->u.dst)) {
-                       end_bh_atomic();
+                       write_unlock_bh(&rt_hash_lock);
 
                        /* Neighbour tables are full and nothing
                           can be released. Try to shrink route cache,
@@ -594,8 +600,8 @@ restart:
        }
 #endif
        rt_hash_table[hash] = rt;
-       end_bh_atomic();
        *rp = rt;
+       write_unlock_bh(&rt_hash_lock);
        return 0;
 }
 
@@ -633,6 +639,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
 
                        rthp=&rt_hash_table[hash];
 
+                       write_lock_bh(&rt_hash_lock);
                        while ( (rth = *rthp) != NULL) {
                                struct rtable *rt;
 
@@ -657,6 +664,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
                                rt = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
                                if (rt == NULL) {
                                        ip_rt_put(rth);
+                                       write_unlock_bh(&rt_hash_lock);
                                        return;
                                }
 
@@ -693,6 +701,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
                                rt_drop(rth);
                                break;
                        }
+                       write_unlock_bh(&rt_hash_lock);
                }
        }
        return;
@@ -722,8 +731,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 #if RT_CACHE_DEBUG >= 1
                        printk(KERN_DEBUG "ip_rt_advice: redirect to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos);
 #endif
-                       start_bh_atomic();
                        ip_rt_put(rt);
+                       write_lock_bh(&rt_hash_lock);
                        for (rthp = &rt_hash_table[hash]; *rthp; rthp = &(*rthp)->u.rt_next) {
                                if (*rthp == rt) {
                                        *rthp = rt->u.rt_next;
@@ -731,7 +740,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
                                        break;
                                }
                        }
-                       end_bh_atomic();
+                       write_unlock_bh(&rt_hash_lock);
                        return NULL;
                }
        }
@@ -861,6 +870,7 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
        for (i=0; i<2; i++) {
                unsigned hash = rt_hash_code(daddr, skeys[i], tos);
 
+               read_lock_bh(&rt_hash_lock);
                for (rth = rt_hash_table[hash]; rth; rth = rth->u.rt_next) {
                        if (rth->key.dst == daddr &&
                            rth->key.src == skeys[i] &&
@@ -890,6 +900,7 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
                                }
                        }
                }
+               read_unlock_bh(&rt_hash_lock);
        }
        return est_mtu ? : new_mtu;
 }
@@ -1362,6 +1373,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
        tos &= IPTOS_TOS_MASK;
        hash = rt_hash_code(daddr, saddr^(iif<<5), tos);
 
+       read_lock_bh(&rt_hash_lock);
        for (rth=rt_hash_table[hash]; rth; rth=rth->u.rt_next) {
                if (rth->key.dst == daddr &&
                    rth->key.src == saddr &&
@@ -1374,10 +1386,12 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
                        rth->u.dst.lastuse = jiffies;
                        atomic_inc(&rth->u.dst.use);
                        atomic_inc(&rth->u.dst.refcnt);
+                       read_unlock_bh(&rt_hash_lock);
                        skb->dst = (struct dst_entry*)rth;
                        return 0;
                }
        }
+       read_unlock_bh(&rt_hash_lock);
 
        /* Multicast recognition logic is moved from route cache to here.
           The problem was that too many Ethernet cards have broken/missing
@@ -1657,7 +1671,7 @@ int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif)
 
        hash = rt_hash_code(daddr, saddr^(oif<<5), tos);
 
-       start_bh_atomic();
+       read_lock_bh(&rt_hash_lock);
        for (rth=rt_hash_table[hash]; rth; rth=rth->u.rt_next) {
                if (rth->key.dst == daddr &&
                    rth->key.src == saddr &&
@@ -1673,12 +1687,12 @@ int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif)
                        rth->u.dst.lastuse = jiffies;
                        atomic_inc(&rth->u.dst.use);
                        atomic_inc(&rth->u.dst.refcnt);
-                       end_bh_atomic();
+                       read_unlock_bh(&rt_hash_lock);
                        *rp = rth;
                        return 0;
                }
        }
-       end_bh_atomic();
+       read_unlock_bh(&rt_hash_lock);
 
        return ip_route_output_slow(rp, daddr, saddr, tos, oif);
 }
@@ -1869,7 +1883,7 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
                if (h < s_h) continue;
                if (h > s_h)
                        s_idx = 0;
-               start_bh_atomic();
+               read_lock_bh(&rt_hash_lock);
                for (rt = rt_hash_table[h], idx = 0; rt; rt = rt->u.rt_next, idx++) {
                        if (idx < s_idx)
                                continue;
@@ -1877,12 +1891,12 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
                        if (rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
                                         cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1) <= 0) {
                                dst_release(xchg(&skb->dst, NULL));
-                               end_bh_atomic();
+                               read_unlock_bh(&rt_hash_lock);
                                goto done;
                        }
                        dst_release(xchg(&skb->dst, NULL));
                }
-               end_bh_atomic();
+               read_unlock_bh(&rt_hash_lock);
        }
 
 done:
index 5c31b63a0275e7b27df3312282240011cb6d7088..8c3637e6a0b3ba97a9bba9f431446a0929b1a2f6 100644 (file)
 #include <linux/fcntl.h>
 #include <linux/poll.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -655,7 +656,8 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 /*
  *     Wait for a socket to get into the connected state
  *
- *     Note: must be called with the socket locked.
+ *     Note: Must be called with the socket locked, and it
+ *           runs with the kernel fully unlocked.
  */
 static int wait_for_tcp_connect(struct sock * sk, int flags)
 {
@@ -698,6 +700,8 @@ static inline int tcp_memory_free(struct sock *sk)
 
 /*
  *     Wait for more memory for a socket
+ *
+ * NOTE: This runs with the kernel fully unlocked.
  */
 static void wait_for_tcp_memory(struct sock * sk)
 {
@@ -744,6 +748,7 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg)
        int mss_now;
        int err, copied;
 
+       unlock_kernel();
        lock_sock(sk);
 
        err = 0;
@@ -896,6 +901,7 @@ int tcp_do_sendmsg(struct sock *sk, struct msghdr *msg)
                                        err = -ERESTARTSYS;
                                        goto do_interrupted;
                                }
+                               tcp_push_pending_frames(sk, tp);
                                wait_for_tcp_memory(sk);
 
                                /* If SACK's were formed or PMTU events happened,
@@ -969,6 +975,7 @@ do_fault2:
 out:
        tcp_push_pending_frames(sk, tp);
        release_sock(sk);
+       lock_kernel();
        return err;
 }
 
@@ -1148,6 +1155,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
        if (flags & MSG_WAITALL)
                target=len;
 
+       unlock_kernel();
        add_wait_queue(sk->sleep, &wait);
        lock_sock(sk);
        
@@ -1300,6 +1308,8 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                /*      We now will not sleep again until we are finished
                 *      with skb. Sorry if you are doing the SMP port
                 *      but you'll just have to fix it neatly ;)
+                *
+                *      Very funny Alan... -DaveM
                 */
                atomic_dec(&skb->users);
 
@@ -1344,6 +1354,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
        /* Clean up data we have read: This will do ACK frames. */
        cleanup_rbuf(sk, copied);
        release_sock(sk);
+       lock_kernel();
        return copied;
 }
 
@@ -1471,22 +1482,17 @@ void tcp_close(struct sock *sk, long timeout)
        struct sk_buff *skb;
        int data_was_unread = 0;
 
-       /*
-        * Check whether the socket is locked ... supposedly
-        * it's impossible to tcp_close() a locked socket.
-        */
-       if (atomic_read(&sk->sock_readers))
-               printk("tcp_close: socket already locked!\n");
-
        /* We need to grab some memory, and put together a FIN,
         * and then put it into the queue to be sent.
         */
+       unlock_kernel();
        lock_sock(sk);
        if(sk->state == TCP_LISTEN) {
                /* Special case. */
                tcp_set_state(sk, TCP_CLOSE);
                tcp_close_pending(sk);
                release_sock(sk);
+               lock_kernel();
                sk->dead = 1;
                return;
        }
@@ -1560,12 +1566,14 @@ void tcp_close(struct sock *sk, long timeout)
        tcp_check_fin_timer(sk);
 
        release_sock(sk);
+       lock_kernel();
        sk->dead = 1;
 }
 
 /*
  *     Wait for an incoming connection, avoid race
- *     conditions. This must be called with the socket locked.
+ *     conditions. This must be called with the socket locked,
+ *     and without the kernel lock held.
  */
 static struct open_request * wait_for_connect(struct sock * sk,
                                              struct open_request **pprev)
@@ -1620,6 +1628,7 @@ struct sock *tcp_accept(struct sock *sk, int flags)
        struct sock *newsk = NULL;
        int error;
 
+       unlock_kernel();
        lock_sock(sk); 
 
        /* We need to make sure that this socket is listening,
@@ -1652,6 +1661,7 @@ struct sock *tcp_accept(struct sock *sk, int flags)
                tcp_inc_slow_timer(TCP_SLT_KEEPALIVE);
 
        release_sock(sk);
+       lock_kernel();
        return newsk;
 
 out:
@@ -1660,6 +1670,7 @@ out:
         */ 
        sk->err = error; 
        release_sock(sk);
+       lock_kernel();
        return newsk;
 }
 
@@ -1782,6 +1793,8 @@ extern void __skb_cb_too_small_for_tcp(int, int);
 void __init tcp_init(void)
 {
        struct sk_buff *skb = NULL;
+       unsigned long goal;
+       int order;
 
        if(sizeof(struct tcp_skb_cb) > sizeof(skb->cb))
                __skb_cb_too_small_for_tcp(sizeof(struct tcp_skb_cb),
@@ -1807,4 +1820,37 @@ void __init tcp_init(void)
                                                NULL, NULL);
        if(!tcp_timewait_cachep)
                panic("tcp_init: Cannot alloc tcp_tw_bucket cache.");
+
+       /* Size and allocate the main established and bind bucket
+        * hash tables.
+        *
+        * The methodology is similar to that of the buffer cache.
+        */
+       goal = num_physpages >> (20 - PAGE_SHIFT);
+       for(order = 5; (1UL << order) < goal; order++)
+               ;
+       do {
+               tcp_ehash_size = (1UL << order) * PAGE_SIZE /
+                       sizeof(struct sock *);
+               tcp_ehash = (struct sock **)
+                       __get_free_pages(GFP_ATOMIC, order);
+       } while (tcp_ehash == NULL && --order > 4);
+
+       if (!tcp_ehash)
+               panic("Failed to allocate TCP established hash table\n");
+       memset(tcp_ehash, 0, tcp_ehash_size * sizeof(struct sock *));
+
+       do {
+               tcp_bhash_size = (1UL << order) * PAGE_SIZE /
+                       sizeof(struct tcp_bind_bucket *);
+               tcp_bhash = (struct tcp_bind_bucket **)
+                       __get_free_pages(GFP_ATOMIC, order);
+       } while (tcp_bhash == NULL && --order > 4);
+
+       if (!tcp_bhash)
+               panic("Failed to allocate TCP bind hash table\n");
+       memset(tcp_bhash, 0, tcp_bhash_size * sizeof(struct tcp_bind_bucket *));
+
+       printk("TCP: Hash tables configured (established %d bind %d)\n",
+              tcp_ehash_size, tcp_bhash_size);
 }
index 9b4fecd6f1f88b551fee91f571c349d210d67b04..1ebcf7f48de7d4f82d7398fd9ac0e6fb50b94531 100644 (file)
@@ -914,8 +914,11 @@ extern void tcp_tw_schedule(struct tcp_tw_bucket *tw);
 extern void tcp_tw_reschedule(struct tcp_tw_bucket *tw);
 extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw);
 
+/* Must be called only from BH context. */
 void tcp_timewait_kill(struct tcp_tw_bucket *tw)
 {
+       SOCKHASH_LOCK_WRITE_BH();
+
        /* Unlink from various places. */
        if(tw->bind_next)
                tw->bind_next->bind_pprev = tw->bind_pprev;
@@ -933,6 +936,8 @@ void tcp_timewait_kill(struct tcp_tw_bucket *tw)
        tw->sklist_next->sklist_prev = tw->sklist_prev;
        tw->sklist_prev->sklist_next = tw->sklist_next;
 
+       SOCKHASH_UNLOCK_WRITE_BH();
+
        /* Ok, now free it up. */
        kmem_cache_free(tcp_timewait_cachep, tw);
 }
@@ -963,6 +968,7 @@ int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
                struct sock *sk;
                struct tcp_func *af_specific = tw->af_specific;
                __u32 isn;
+               int ret;
 
                isn = tw->rcv_nxt + 128000;
                if(isn == 0)
@@ -971,14 +977,25 @@ int tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
                tcp_timewait_kill(tw);
                sk = af_specific->get_sock(skb, th);
                if(sk == NULL ||
-                  !ipsec_sk_policy(sk,skb) ||
-                  atomic_read(&sk->sock_readers) != 0)
+                  !ipsec_sk_policy(sk,skb))
                        return 0;
+
+               bh_lock_sock(sk);
+
+               /* Default is to discard the frame. */
+               ret = 0;
+
+               if(sk->lock.users)
+                       goto out_unlock;
+
                skb_set_owner_r(skb, sk);
                af_specific = sk->tp_pinfo.af_tcp.af_specific;
+
                if(af_specific->conn_request(sk, skb, isn) < 0)
-                       return 1; /* Toss a reset back. */
-               return 0; /* Discard the frame. */
+                       ret = 1; /* Toss a reset back. */
+       out_unlock:
+               bh_unlock_sock(sk);
+               return ret;
        }
 
        /* Check RST or SYN */
@@ -1031,7 +1048,7 @@ static __inline__ void tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *t
        sk->prot->inuse--;
 
        /* Step 4: Hash TW into TIMEWAIT half of established hash table. */
-       head = &tcp_established_hash[sk->hashent + (TCP_HTABLE_SIZE/2)];
+       head = &tcp_ehash[sk->hashent + (tcp_ehash_size >> 1)];
        sktw = (struct sock *)tw;
        if((sktw->next = *head) != NULL)
                (*head)->pprev = &sktw->next;
@@ -1069,7 +1086,9 @@ void tcp_time_wait(struct sock *sk)
                }
 #endif
                /* Linkage updates. */
+               SOCKHASH_LOCK_WRITE();
                tcp_tw_hashdance(sk, tw);
+               SOCKHASH_UNLOCK_WRITE();
 
                /* Get the TIME_WAIT timeout firing. */
                tcp_tw_schedule(tw);
index 66be537c16333d2b2ca96d6b7efbf09d1d0be410..30aed245e134482d83b9e87e74f8aa0b7bbcea58 100644 (file)
@@ -90,12 +90,14 @@ void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
  * First half of the table is for sockets not in TIME_WAIT, second half
  * is for TIME_WAIT sockets only.
  */
-struct sock *tcp_established_hash[TCP_HTABLE_SIZE];
+struct sock **tcp_ehash;
+int tcp_ehash_size;
 
 /* Ok, let's try this, I give up, we do need a local binding
  * TCP hash as well as the others for fast bind/connect.
  */
-struct tcp_bind_bucket *tcp_bound_hash[TCP_BHTABLE_SIZE];
+struct tcp_bind_bucket **tcp_bhash;
+int tcp_bhash_size;
 
 /* All sockets in TCP_LISTEN state will be in here.  This is the only table
  * where wildcard'd TCP sockets can exist.  Hash function here is just local
@@ -117,7 +119,7 @@ int tcp_port_rover = (1024 - 1);
 static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport,
                                 __u32 faddr, __u16 fport)
 {
-       return ((laddr ^ lport) ^ (faddr ^ fport)) & ((TCP_HTABLE_SIZE/2) - 1);
+       return ((laddr ^ lport) ^ (faddr ^ fport)) & ((tcp_ehash_size >> 1) - 1);
 }
 
 static __inline__ int tcp_sk_hashfn(struct sock *sk)
@@ -136,8 +138,8 @@ void tcp_bucket_unlock(struct sock *sk)
        struct tcp_bind_bucket *tb;
        unsigned short snum = sk->num;
 
-       SOCKHASH_LOCK();
-       for(tb = tcp_bound_hash[tcp_bhashfn(snum)]; tb; tb = tb->next) {
+       SOCKHASH_LOCK_WRITE();
+       for(tb = tcp_bhash[tcp_bhashfn(snum)]; tb; tb = tb->next) {
                if(tb->port == snum) {
                        if(tb->owners == NULL &&
                           (tb->flags & TCPB_FLAG_LOCKED)) {
@@ -148,9 +150,10 @@ void tcp_bucket_unlock(struct sock *sk)
                        break;
                }
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
+/* The sockhash lock must be held as a writer here. */
 struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum)
 {
        struct tcp_bind_bucket *tb;
@@ -158,7 +161,7 @@ struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum)
        tb = kmem_cache_alloc(tcp_bucket_cachep, SLAB_ATOMIC);
        if(tb != NULL) {
                struct tcp_bind_bucket **head =
-                       &tcp_bound_hash[tcp_bhashfn(snum)];
+                       &tcp_bhash[tcp_bhashfn(snum)];
                tb->port = snum;
                tb->flags = TCPB_FLAG_LOCKED;
                tb->owners = NULL;
@@ -176,13 +179,18 @@ struct tcp_bind_bucket *tcp_bucket_create(unsigned short snum)
  */
 static __inline__ int tcp_bucket_check(unsigned short snum)
 {
-       struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(snum)];
+       struct tcp_bind_bucket *tb;
+       int ret = 0;
+
+       SOCKHASH_LOCK_WRITE();
+       tb = tcp_bhash[tcp_bhashfn(snum)];
        for( ; (tb && (tb->port != snum)); tb = tb->next)
                ;
        if(tb == NULL && tcp_bucket_create(snum) == NULL)
-               return 1;
-       else
-               return 0;
+               ret = 1;
+       SOCKHASH_UNLOCK_WRITE();
+
+       return ret;
 }
 #endif
 
@@ -191,8 +199,8 @@ static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
        struct tcp_bind_bucket *tb;
        int result = 0;
 
-       SOCKHASH_LOCK();
-       for(tb = tcp_bound_hash[tcp_bhashfn(snum)];
+       SOCKHASH_LOCK_WRITE();
+       for(tb = tcp_bhash[tcp_bhashfn(snum)];
            (tb && (tb->port != snum));
            tb = tb->next)
                ;
@@ -256,7 +264,7 @@ static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
                }
        }
 go_like_smoke:
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
        return result;
 }
 
@@ -268,13 +276,13 @@ unsigned short tcp_good_socknum(void)
        int remaining = (high - low) + 1;
        int rover;
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        rover = tcp_port_rover;
        do {
                rover += 1;
                if((rover < low) || (rover > high))
                        rover = low;
-               tb = tcp_bound_hash[tcp_bhashfn(rover)];
+               tb = tcp_bhash[tcp_bhashfn(rover)];
                for( ; tb; tb = tb->next) {
                        if(tb->port == rover)
                                goto next;
@@ -288,7 +296,7 @@ unsigned short tcp_good_socknum(void)
                rover = 0;
        if (tb != NULL)
                tb->flags |= TCPB_FLAG_GOODSOCKNUM;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 
        return rover;
 }
@@ -298,20 +306,20 @@ static void tcp_v4_hash(struct sock *sk)
        if (sk->state != TCP_CLOSE) {
                struct sock **skp;
 
-               SOCKHASH_LOCK();
-               skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
+               SOCKHASH_LOCK_WRITE();
+               skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
                if((sk->next = *skp) != NULL)
                        (*skp)->pprev = &sk->next;
                *skp = sk;
                sk->pprev = skp;
                tcp_sk_bindify(sk);
-               SOCKHASH_UNLOCK();
+               SOCKHASH_UNLOCK_WRITE();
        }
 }
 
 static void tcp_v4_unhash(struct sock *sk)
 {
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        if(sk->pprev) {
                if(sk->next)
                        sk->next->pprev = sk->pprev;
@@ -320,14 +328,14 @@ static void tcp_v4_unhash(struct sock *sk)
                tcp_reg_zap(sk);
                tcp_sk_unbindify(sk);
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void tcp_v4_rehash(struct sock *sk)
 {
        unsigned char state;
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        state = sk->state;
        if(sk->pprev != NULL) {
                if(sk->next)
@@ -342,7 +350,7 @@ static void tcp_v4_rehash(struct sock *sk)
                if(state == TCP_LISTEN)
                        skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
                else
-                       skp = &tcp_established_hash[(sk->hashent = tcp_sk_hashfn(sk))];
+                       skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
 
                if((sk->next = *skp) != NULL)
                        (*skp)->pprev = &sk->next;
@@ -351,7 +359,7 @@ static void tcp_v4_rehash(struct sock *sk)
                if(state == TCP_LISTEN)
                        tcp_sk_bindify(sk);
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 /* Don't inline this cruft.  Here are some nice properties to
@@ -395,10 +403,10 @@ static struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int d
 
 /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
- * It is assumed that this code only gets called from within NET_BH.
+ *
+ * The sockhash lock must be held as a reader here.
  */
-static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
-                                          u32 saddr, u16 sport,
+static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport,
                                           u32 daddr, u16 dport, int dif)
 {
        TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
@@ -416,7 +424,7 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
         * have wildcards anyways.
         */
        hash = tcp_hashfn(daddr, hnum, saddr, sport);
-       for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
+       for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
                if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) {
                        if (sk->state == TCP_ESTABLISHED)
                                TCP_RHASH(sport) = sk;
@@ -424,7 +432,7 @@ static inline struct sock *__tcp_v4_lookup(struct tcphdr *th,
                }
        }
        /* Must check for a TIME_WAIT'er before going to listener hash. */
-       for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next)
+       for(sk = tcp_ehash[hash+(tcp_ehash_size >> 1)]; sk; sk = sk->next)
                if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
                        goto hit;
        sk = tcp_v4_lookup_listener(daddr, hnum, dif);
@@ -434,7 +442,13 @@ hit:
 
 __inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
 {
-       return __tcp_v4_lookup(0, saddr, sport, daddr, dport, dif);
+       struct sock *sk;
+
+       SOCKHASH_LOCK_READ();
+       sk = __tcp_v4_lookup(saddr, sport, daddr, dport, dif);
+       SOCKHASH_UNLOCK_READ();
+
+       return sk;
 }
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
@@ -462,9 +476,12 @@ static struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
                        paddr = idev->ifa_list->ifa_local;
        }
 
-       /* This code must run only from NET_BH. */
+       /* We must obtain the sockhash lock here, we are always
+        * in BH context.
+        */
+       SOCKHASH_LOCK_READ_BH();
        {
-               struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hnum)];
+               struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hnum)];
                for( ; (tb && tb->port != hnum); tb = tb->next)
                        ;
                if(tb == NULL)
@@ -505,7 +522,7 @@ pass2:
        }
 next:
        if(firstpass--) {
-               struct tcp_bind_bucket *tb = tcp_bound_hash[tcp_bhashfn(hpnum)];
+               struct tcp_bind_bucket *tb = tcp_bhash[tcp_bhashfn(hpnum)];
                for( ; (tb && tb->port != hpnum); tb = tb->next)
                        ;
                if(tb) {
@@ -514,6 +531,7 @@ next:
                }
        }
 gotit:
+       SOCKHASH_UNLOCK_READ_BH();
        return result;
 }
 #endif /* CONFIG_IP_TRANSPARENT_PROXY */
@@ -540,21 +558,23 @@ static int tcp_v4_unique_address(struct sock *sk)
        int retval = 1;
 
        /* Freeze the hash while we snoop around. */
-       SOCKHASH_LOCK();
-       tb = tcp_bound_hash[tcp_bhashfn(snum)];
+       SOCKHASH_LOCK_READ();
+       tb = tcp_bhash[tcp_bhashfn(snum)];
        for(; tb; tb = tb->next) {
                if(tb->port == snum && tb->owners != NULL) {
                        /* Almost certainly the re-use port case, search the real hashes
                         * so it actually scales.
                         */
-                       sk = __tcp_v4_lookup(NULL, sk->daddr, sk->dport,
+                       sk = __tcp_v4_lookup(sk->daddr, sk->dport,
                                             sk->rcv_saddr, snum, sk->bound_dev_if);
+                       SOCKHASH_UNLOCK_READ();
+
                        if((sk != NULL) && (sk->state != TCP_LISTEN))
                                retval = 0;
-                       break;
+                       return retval;
                }
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
        return retval;
 }
 
@@ -727,16 +747,17 @@ static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip, unsigned
 {
        struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 
-       if (atomic_read(&sk->sock_readers))
-               return;
-
-       /* Don't interested in TCP_LISTEN and open_requests (SYN-ACKs
+       /* We are not interested in TCP_LISTEN and open_requests (SYN-ACKs
         * send out by Linux are always <576bytes so they should go through
         * unfragmented).
         */
        if (sk->state == TCP_LISTEN)
                return; 
 
+       bh_lock_sock(sk);
+       if(sk->lock.users != 0)
+               goto out;
+
        /* We don't check in the destentry if pmtu discovery is forbidden
         * on this route. We just assume that no packet_to_big packets
         * are send back when pmtu discovery is not active.
@@ -744,7 +765,8 @@ static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip, unsigned
         * route, but I think that's acceptable.
         */
        if (sk->dst_cache == NULL)
-               return;
+               goto out;
+
        ip_rt_update_pmtu(sk->dst_cache, mtu);
        if (sk->ip_pmtudisc != IP_PMTUDISC_DONT &&
            tp->pmtu_cookie > sk->dst_cache->pmtu) {
@@ -757,6 +779,8 @@ static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip, unsigned
                 */
                tcp_simple_retransmit(sk);
        } /* else let the usual retransmit timer handle it */
+out:
+       bh_unlock_sock(sk);
 }
 
 /*
@@ -849,17 +873,6 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
        switch (sk->state) {
                struct open_request *req, *prev;
        case TCP_LISTEN:
-               /* Prevent race conditions with accept() - 
-                * ICMP is unreliable. 
-                */
-               if (atomic_read(&sk->sock_readers)) {
-                       net_statistics.LockDroppedIcmps++;
-                        /* If too many ICMPs get dropped on busy
-                         * servers this needs to be solved differently.
-                         */
-                       return;
-               }
-
                /* The final ACK of the handshake should be already 
                 * handled in the new socket context, not here.
                 * Strictly speaking - an ICMP error for the final
@@ -869,12 +882,24 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
                if (!no_flags && !th->syn && !th->ack)
                        return;
 
+               /* Prevent race conditions with accept() - 
+                * ICMP is unreliable. 
+                */
+               bh_lock_sock(sk);
+               if (sk->lock.users != 0) {
+                       net_statistics.LockDroppedIcmps++;
+                        /* If too many ICMPs get dropped on busy
+                         * servers this needs to be solved differently.
+                         */
+                       goto out_unlock;
+               }
+
                req = tcp_v4_search_req(tp, iph, th, &prev); 
                if (!req)
-                       return;
+                       goto out_unlock;
                if (seq != req->snt_isn) {
                        net_statistics.OutOfWindowIcmps++;
-                       return;
+                       goto out_unlock;
                }
                if (req->sk) {  
                        /* 
@@ -884,6 +909,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
                         * but only with the next operation on the socket after
                         * accept. 
                         */
+                       bh_unlock_sock(sk);
                        sk = req->sk;
                } else {
                        /* 
@@ -896,6 +922,8 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
                        tcp_synq_unlink(tp, req, prev);
                        req->class->destructor(req);
                        tcp_openreq_free(req);
+       out_unlock:
+                       bh_unlock_sock(sk);
                        return; 
                }
                break;
@@ -1025,9 +1053,10 @@ static struct sock *tcp_v4_search_proxy_openreq(struct sk_buff *skb)
 {
        struct iphdr *iph = skb->nh.iph;
        struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);
-       struct sock *sk;
+       struct sock *sk = NULL;
        int i;
 
+       SOCKHASH_LOCK_READ();
        for (i=0; i<TCP_LHTABLE_SIZE; i++) {
                for(sk = tcp_listening_hash[i]; sk; sk = sk->next) {
                        struct open_request *dummy;
@@ -1035,10 +1064,12 @@ static struct sock *tcp_v4_search_proxy_openreq(struct sk_buff *skb)
                                              th, &dummy) &&
                            (!sk->bound_dev_if ||
                             sk->bound_dev_if == skb->dev->ifindex))
-                               return sk;
+                               goto out;
                }
        }
-       return NULL;
+out:
+       SOCKHASH_UNLOCK_READ();
+       return sk;
 }
 
 /*
@@ -1319,7 +1350,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
                /* Clone the TCP header template */
                newsk->dport = req->rmt_port;
 
-               atomic_set(&newsk->sock_readers, 0);
+               sock_lock_init(newsk);
+
                atomic_set(&newsk->rmem_alloc, 0);
                skb_queue_head_init(&newsk->receive_queue);
                atomic_set(&newsk->wmem_alloc, 0);
@@ -1329,7 +1361,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
                newsk->done = 0;
                newsk->proc = 0;
                newsk->pair = NULL;
-               skb_queue_head_init(&newsk->back_log);
+               newsk->backlog.head = newsk->backlog.tail = NULL;
                skb_queue_head_init(&newsk->error_queue);
 #ifdef CONFIG_FILTER
                if ((filter = newsk->filter) != NULL)
@@ -1570,8 +1602,17 @@ static inline struct sock *tcp_v4_hnd_req(struct sock *sk,struct sk_buff *skb)
        return sk; 
 }
 
+/* The socket must have it's spinlock held when we get
+ * here.
+ *
+ * We have a potential double-lock case here, so even when
+ * doing backlog processing we use the BH locking scheme.
+ * This is because we cannot sleep with the original spinlock
+ * held.
+ */
 int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
+       int need_unlock = 0;
 #ifdef CONFIG_FILTER
        struct sk_filter *filter = sk->filter;
        if (filter && sk_filter(skb, filter))
@@ -1591,7 +1632,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
                return 0; 
        } 
 
-
        if (sk->state == TCP_LISTEN) { 
                struct sock *nsk;
                
@@ -1604,17 +1644,22 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
                 * otherwise we just shortcircuit this and continue with
                 * the new socket..
                 */
-               if (atomic_read(&nsk->sock_readers)) {
-                       skb_orphan(skb);
-                       __skb_queue_tail(&nsk->back_log, skb);
-                       return 0;
+               if (nsk != sk) {
+                       bh_lock_sock(nsk);
+                       if (nsk->lock.users != 0) {
+                               skb_orphan(skb);
+                               sk_add_backlog(nsk, skb);
+                               bh_unlock_sock(nsk);
+                               return 0;
+                       }
+                       need_unlock = 1;
+                       sk = nsk;
                }
-               sk = nsk;
        }
        
        if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
                goto reset;
-       return 0;
+       goto out_maybe_unlock;
 
 reset:
        tcp_v4_send_reset(skb);
@@ -1625,6 +1670,9 @@ discard:
         * might be destroyed here. This current version compiles correctly,
         * but you have been warned.
         */
+out_maybe_unlock:
+       if(need_unlock)
+               bh_unlock_sock(sk);
        return 0;
 }
 
@@ -1636,6 +1684,7 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
 {
        struct tcphdr *th;
        struct sock *sk;
+       int ret;
 
        if (skb->pkt_type!=PACKET_HOST)
                goto discard_it;
@@ -1681,8 +1730,10 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
                                         IPCB(skb)->redirport, skb->dev->ifindex);
        else {
 #endif
-               sk = __tcp_v4_lookup(th, skb->nh.iph->saddr, th->source,
+               SOCKHASH_LOCK_READ_BH();
+               sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source,
                                     skb->nh.iph->daddr, th->dest, skb->dev->ifindex);
+               SOCKHASH_UNLOCK_READ_BH();
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
                if (!sk)
                        sk = tcp_v4_search_proxy_openreq(skb);
@@ -1702,11 +1753,16 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
 
        if (sk->state == TCP_TIME_WAIT)
                goto do_time_wait;
-       if (!atomic_read(&sk->sock_readers))
-               return tcp_v4_do_rcv(sk, skb);
 
-       __skb_queue_tail(&sk->back_log, skb);
-       return 0;
+       bh_lock_sock(sk);
+       ret = 0;
+       if (!sk->lock.users)
+               ret = tcp_v4_do_rcv(sk, skb);
+       else
+               sk_add_backlog(sk, skb);
+       bh_unlock_sock(sk);
+
+       return ret;
 
 no_tcp_socket:
        tcp_v4_send_reset(skb);
index 0aa868a667c0b7c16d52a8c12787e754f714acc8..4d0a4164dd82c06fd743b9badac42b91bf0a7955 100644 (file)
@@ -36,6 +36,8 @@
 
 #include <net/tcp.h>
 
+#include <linux/smp_lock.h>
+
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_sack;
@@ -966,6 +968,7 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mtu)
        /* Ok, now lock the socket before we make it visible to
         * the incoming packet engine.
         */
+       unlock_kernel();
        lock_sock(sk);
 
        /* Socket identity change complete, no longer
@@ -993,6 +996,7 @@ void tcp_connect(struct sock *sk, struct sk_buff *buff, int mtu)
 
        /* Now, it is safe to release the socket. */
        release_sock(sk);
+       lock_kernel();
 }
 
 /* Send out a delayed ack, the caller does the policy checking
index 123676fa54d6eba1677c62a9a6ab283b63353a21..41f2770a1d3e5c335b79daba79e14e17e3061686 100644 (file)
@@ -171,11 +171,12 @@ void tcp_delack_timer(unsigned long data)
        if(!sk->zapped &&
           sk->tp_pinfo.af_tcp.delayed_acks &&
           sk->state != TCP_CLOSE) {
-               /* If socket is currently locked, defer the ACK. */
-               if (!atomic_read(&sk->sock_readers))
+               bh_lock_sock(sk);
+               if (!sk->lock.users)
                        tcp_send_ack(sk);
                else
                        tcp_send_delayed_ack(&(sk->tp_pinfo.af_tcp), HZ/10);
+               bh_unlock_sock(sk);
        }
 }
 
@@ -187,9 +188,11 @@ void tcp_probe_timer(unsigned long data)
        if(sk->zapped) 
                return;
        
-       if (atomic_read(&sk->sock_readers)) {
+       bh_lock_sock(sk);
+       if (sk->lock.users) {
                /* Try again later. */
                tcp_reset_xmit_timer(sk, TIME_PROBE0, HZ/5);
+               bh_unlock_sock(sk);
                return;
        }
 
@@ -216,6 +219,7 @@ void tcp_probe_timer(unsigned long data)
                /* Only send another probe if we didn't close things up. */
                tcp_send_probe0(sk);
        }
+       bh_unlock_sock(sk);
 }
 
 static __inline__ int tcp_keepopen_proc(struct sock *sk)
@@ -253,8 +257,9 @@ static void tcp_bucketgc(unsigned long data)
 {
        int i, reaped = 0;;
 
-       for(i = 0; i < TCP_BHTABLE_SIZE; i++) {
-               struct tcp_bind_bucket *tb = tcp_bound_hash[i];
+       SOCKHASH_LOCK_WRITE_BH();
+       for(i = 0; i < tcp_bhash_size; i++) {
+               struct tcp_bind_bucket *tb = tcp_bhash[i];
 
                while(tb) {
                        struct tcp_bind_bucket *next = tb->next;
@@ -274,6 +279,8 @@ static void tcp_bucketgc(unsigned long data)
                        tb = next;
                }
        }
+       SOCKHASH_UNLOCK_WRITE_BH();
+
        if(reaped != 0) {
                struct tcp_sl_timer *slt = (struct tcp_sl_timer *)data;
 
@@ -294,8 +301,14 @@ static void tcp_twkill(unsigned long data)
        struct tcp_tw_bucket *tw;
        int killed = 0;
 
+       /* The death-row tw chains are only ever touched
+        * in BH context so no locking is needed.
+        */
        tw = tcp_tw_death_row[tcp_tw_death_row_slot];
        tcp_tw_death_row[tcp_tw_death_row_slot] = NULL;
+       tcp_tw_death_row_slot =
+         ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1));
+
        while(tw != NULL) {
                struct tcp_tw_bucket *next = tw->next_death;
 
@@ -307,8 +320,6 @@ static void tcp_twkill(unsigned long data)
                struct tcp_sl_timer *slt = (struct tcp_sl_timer *)data;
                atomic_sub(killed, &slt->count);
        }
-       tcp_tw_death_row_slot =
-         ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1));
 }
 
 /* These are always called from BH context.  See callers in
@@ -319,12 +330,14 @@ void tcp_tw_schedule(struct tcp_tw_bucket *tw)
        int slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
        struct tcp_tw_bucket **tpp = &tcp_tw_death_row[slot];
 
+       SOCKHASH_LOCK_WRITE_BH();
        if((tw->next_death = *tpp) != NULL)
                (*tpp)->pprev_death = &tw->next_death;
        *tpp = tw;
        tw->pprev_death = tpp;
 
        tw->death_slot = slot;
+       SOCKHASH_UNLOCK_WRITE_BH();
 
        tcp_inc_slow_timer(TCP_SLT_TWKILL);
 }
@@ -335,6 +348,7 @@ void tcp_tw_reschedule(struct tcp_tw_bucket *tw)
        struct tcp_tw_bucket **tpp;
        int slot;
 
+       SOCKHASH_LOCK_WRITE_BH();
        if(tw->next_death)
                tw->next_death->pprev_death = tw->pprev_death;
        *tw->pprev_death = tw->next_death;
@@ -348,16 +362,21 @@ void tcp_tw_reschedule(struct tcp_tw_bucket *tw)
        tw->pprev_death = tpp;
 
        tw->death_slot = slot;
+       SOCKHASH_UNLOCK_WRITE_BH();
+
        /* Timer was incremented when we first entered the table. */
 }
 
 /* This is for handling early-kills of TIME_WAIT sockets. */
 void tcp_tw_deschedule(struct tcp_tw_bucket *tw)
 {
+       SOCKHASH_LOCK_WRITE_BH();
        if(tw->next_death)
                tw->next_death->pprev_death = tw->pprev_death;
        *tw->pprev_death = tw->next_death;
        tw->pprev_death = NULL;
+       SOCKHASH_UNLOCK_WRITE_BH();
+
        tcp_dec_slow_timer(TCP_SLT_TWKILL);
 }
 
@@ -399,20 +418,30 @@ static void tcp_keepalive(unsigned long data)
        int count = 0;
        int i;
        
-       for(i = chain_start; i < (chain_start + ((TCP_HTABLE_SIZE/2) >> 2)); i++) {
-               struct sock *sk = tcp_established_hash[i];
+       SOCKHASH_LOCK_READ_BH();
+       for(i = chain_start; i < (chain_start + ((tcp_ehash_size >> 1) >> 2)); i++) {
+               struct sock *sk;
+
+               sk = tcp_ehash[i];
                while(sk) {
-                       if(!atomic_read(&sk->sock_readers) && sk->keepopen) {
+                       struct sock *next = sk->next;
+
+                       bh_lock_sock(sk);
+                       if (sk->keepopen && !sk->lock.users) {
+                               SOCKHASH_UNLOCK_READ_BH();
                                count += tcp_keepopen_proc(sk);
-                               if(count == sysctl_tcp_max_ka_probes)
-                                       goto out;
+                               SOCKHASH_LOCK_READ_BH();
                        }
-                       sk = sk->next;
+                       bh_unlock_sock(sk);
+                       if(count == sysctl_tcp_max_ka_probes)
+                               goto out;
+                       sk = next;
                }
        }
 out:
-       chain_start = ((chain_start + ((TCP_HTABLE_SIZE/2)>>2)) &
-                      ((TCP_HTABLE_SIZE/2) - 1));
+       SOCKHASH_UNLOCK_READ_BH();
+       chain_start = ((chain_start + ((tcp_ehash_size >> 1)>>2)) &
+                      ((tcp_ehash_size >> 1) - 1));
 }
 
 /*
@@ -439,9 +468,11 @@ void tcp_retransmit_timer(unsigned long data)
                return;
        }
 
-       if (atomic_read(&sk->sock_readers)) {
+       bh_lock_sock(sk);
+       if (sk->lock.users) {
                /* Try again later */  
                tcp_reset_xmit_timer(sk, TIME_RETRANS, HZ/20);
+               bh_unlock_sock(sk);
                return;
        }
 
@@ -508,12 +539,51 @@ void tcp_retransmit_timer(unsigned long data)
        tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
 
        tcp_write_timeout(sk);
+
+       bh_unlock_sock(sk);
 }
 
 /*
  *     Slow timer for SYN-RECV sockets
  */
 
+static void tcp_do_syn_queue(struct sock *sk, struct tcp_opt *tp, unsigned long now)
+{
+       struct open_request *prev, *req;
+
+       prev = (struct open_request *) &tp->syn_wait_queue;
+       for(req = tp->syn_wait_queue; req; ) {
+               struct open_request *next = req->dl_next;
+
+               if (! req->sk) {
+                       tcp_synq_unlink(tp, req, prev);
+                       if(req->retrans >= sysctl_tcp_retries1) {
+                               (*req->class->destructor)(req);
+                               tcp_dec_slow_timer(TCP_SLT_SYNACK);
+                               tp->syn_backlog--;
+                               tcp_openreq_free(req);
+                               if (! tp->syn_wait_queue)
+                                       break;
+                       } else {
+                               unsigned long timeo;
+                               struct open_request *rp;
+
+                               (*req->class->rtx_syn_ack)(sk, req);
+                               req->retrans++;
+                               timeo = min((TCP_TIMEOUT_INIT << req->retrans),
+                                           (120 * HZ));
+                               req->expires = now + timeo;
+                               rp = prev->dl_next;
+                               tcp_synq_queue(tp, req);
+                               if(rp != prev->dl_next)
+                                       prev = prev->dl_next;
+                       }
+               } else
+                       prev = req;
+               req = next;
+       }
+}
+
 /* This now scales very nicely. -DaveM */
 static void tcp_syn_recv_timer(unsigned long data)
 {
@@ -521,66 +591,21 @@ static void tcp_syn_recv_timer(unsigned long data)
        unsigned long now = jiffies;
        int i;
 
+       SOCKHASH_LOCK_READ_BH();
        for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
                sk = tcp_listening_hash[i];
-
                while(sk) {
                        struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
                        
                        /* TCP_LISTEN is implied. */
-                       if (!atomic_read(&sk->sock_readers) && tp->syn_wait_queue) {
-                               struct open_request *prev = (struct open_request *)(&tp->syn_wait_queue);
-                               struct open_request *req = tp->syn_wait_queue;
-                               do {
-                                       struct open_request *conn;
-                                 
-                                       conn = req;
-                                       req = req->dl_next;
-
-                                       if (conn->sk) {
-                                               prev = conn; 
-                                               continue; 
-                                       }
-
-                                       tcp_synq_unlink(tp, conn, prev);
-                                       if (conn->retrans >= sysctl_tcp_retries1) {
-#ifdef TCP_DEBUG
-                                               printk(KERN_DEBUG "syn_recv: "
-                                                      "too many retransmits\n");
-#endif
-                                               (*conn->class->destructor)(conn);
-                                               tcp_dec_slow_timer(TCP_SLT_SYNACK);
-                                               tp->syn_backlog--;
-                                               tcp_openreq_free(conn);
-
-                                               if (!tp->syn_wait_queue)
-                                                       break;
-                                       } else {
-                                               unsigned long timeo;
-                                               struct open_request *op; 
-
-                                               (*conn->class->rtx_syn_ack)(sk, conn);
-
-                                               conn->retrans++;
-#ifdef TCP_DEBUG
-                                               printk(KERN_DEBUG "syn_ack rtx %d\n",
-                                                      conn->retrans);
-#endif
-                                               timeo = min((TCP_TIMEOUT_INIT 
-                                                            << conn->retrans),
-                                                           120*HZ);
-                                               conn->expires = now + timeo;
-                                               op = prev->dl_next; 
-                                               tcp_synq_queue(tp, conn);
-                                               if (op != prev->dl_next)
-                                                       prev = prev->dl_next;
-                                       }
-                                       /* old prev still valid here */
-                               } while (req);
-                       }
+                       bh_lock_sock(sk);
+                       if (!sk->lock.users && tp->syn_wait_queue)
+                               tcp_do_syn_queue(sk, tp, now);
+                       bh_unlock_sock(sk);
                        sk = sk->next;
                }
        }
+       SOCKHASH_UNLOCK_READ_BH();
 }
 
 void tcp_sltimer_handler(unsigned long data)
index 3821a7c4cf2186f3c03c5fa36a0baf1a6934d8dc..088a44650cf806eeb673092cf17c2656deb73f78 100644 (file)
@@ -69,13 +69,15 @@ void net_reset_timer (struct sock *t, int timeout, unsigned long len)
  */
 void net_timer (unsigned long data)
 {
-       struct sock *sk = (struct sock*)data;
+       struct sock *sk = (struct sock *) data;
        int why = sk->timeout;
 
        /* Only process if socket is not in use. */
-       if (atomic_read(&sk->sock_readers)) {
+       bh_lock_sock(sk);
+       if (sk->lock.users) {
                /* Try again later. */ 
                mod_timer(&sk->timer, jiffies+HZ/20);
+               bh_unlock_sock(sk);
                return;
        }
 
@@ -99,15 +101,15 @@ void net_timer (unsigned long data)
                                printk (KERN_DEBUG "non CLOSE socket in time_done\n");
                                break;
                        }
-                       destroy_sock (sk);
-                       break;
+                       destroy_sock(sk);
+                       return;
 
                case TIME_DESTROY:
                        /* We've waited for a while for all the memory associated with
                         * the socket to be freed.
                         */
                        destroy_sock(sk);
-                       break;
+                       return;
 
                case TIME_CLOSE:
                        /* We've waited long enough, close the socket. */
@@ -123,5 +125,8 @@ void net_timer (unsigned long data)
                        printk ("net_timer: timer expired - reason %d is unknown\n", why);
                        break;
        }
+
+       /* We only need to unlock if the socket was not destroyed. */
+       bh_unlock_sock(sk);
 }
 
index 5fcec9cf3db07ed75d7d78fdc3cb016ef88a6061..fdf3760139b38ec1b38ba1bf2bf0b39c847023c2 100644 (file)
@@ -128,7 +128,7 @@ static int udp_v4_verify_bind(struct sock *sk, unsigned short snum)
        struct sock *sk2;
        int retval = 0, sk_reuse = sk->reuse;
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_READ();
        for(sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; sk2 != NULL; sk2 = sk2->next) {
                if((sk2->num == snum) && (sk2 != sk)) {
                        unsigned char state = sk2->state;
@@ -158,7 +158,7 @@ static int udp_v4_verify_bind(struct sock *sk, unsigned short snum)
                        }
                }
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
        return retval;
 }
 
@@ -180,7 +180,7 @@ unsigned short udp_good_socknum(void)
        static int start = 0;
        int i, best, best_size_so_far;
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_READ();
         if (start > sysctl_local_port_range[1] || start < sysctl_local_port_range[0])
                 start = sysctl_local_port_range[0];
 
@@ -223,15 +223,10 @@ unsigned short udp_good_socknum(void)
         }
 out:
        start = result;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
        return result;
 }
 
-/* Last hit UDP socket cache, this is ipv4 specific so make it static. */
-static u32 uh_cache_saddr, uh_cache_daddr;
-static u16 uh_cache_dport, uh_cache_sport;
-static struct sock *uh_cache_sk = NULL;
-
 static void udp_v4_hash(struct sock *sk)
 {
        struct sock **skp;
@@ -240,11 +235,11 @@ static void udp_v4_hash(struct sock *sk)
        num &= (UDP_HTABLE_SIZE - 1);
        skp = &udp_hash[num];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        sk->next = *skp;
        *skp = sk;
        sk->hashent = num;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void udp_v4_unhash(struct sock *sk)
@@ -255,7 +250,7 @@ static void udp_v4_unhash(struct sock *sk)
        num &= (UDP_HTABLE_SIZE - 1);
        skp = &udp_hash[num];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        while(*skp != NULL) {
                if(*skp == sk) {
                        *skp = sk->next;
@@ -263,9 +258,7 @@ static void udp_v4_unhash(struct sock *sk)
                }
                skp = &((*skp)->next);
        }
-       if(uh_cache_sk == sk)
-               uh_cache_sk = NULL;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void udp_v4_rehash(struct sock *sk)
@@ -277,7 +270,7 @@ static void udp_v4_rehash(struct sock *sk)
        num &= (UDP_HTABLE_SIZE - 1);
        skp = &udp_hash[oldnum];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        while(*skp != NULL) {
                if(*skp == sk) {
                        *skp = sk->next;
@@ -288,13 +281,11 @@ static void udp_v4_rehash(struct sock *sk)
        sk->next = udp_hash[num];
        udp_hash[num] = sk;
        sk->hashent = num;
-       if(uh_cache_sk == sk)
-               uh_cache_sk = NULL;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
- * harder than this here plus the last hit cache. -DaveM
+ * harder than this. -DaveM
  */
 struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
 {
@@ -341,21 +332,9 @@ __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport
 {
        struct sock *sk;
 
-       if(!dif && uh_cache_sk          &&
-          uh_cache_saddr == saddr      &&
-          uh_cache_sport == sport      &&
-          uh_cache_dport == dport      &&
-          uh_cache_daddr == daddr)
-               return uh_cache_sk;
-
+       SOCKHASH_LOCK_READ();
        sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif);
-       if(!dif) {
-               uh_cache_sk     = sk;
-               uh_cache_saddr  = saddr;
-               uh_cache_daddr  = daddr;
-               uh_cache_sport  = sport;
-               uh_cache_dport  = dport;
-       }
+       SOCKHASH_UNLOCK_READ();
        return sk;
 }
 
@@ -393,7 +372,7 @@ static struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
                        paddr = idev->ifa_list->ifa_local;
        }
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_READ();
        for(s = udp_v4_proxy_loop_init(hnum, hpnum, s, firstpass);
            s != NULL;
            s = udp_v4_proxy_loop_next(hnum, hpnum, s, firstpass)) {
@@ -431,7 +410,7 @@ static struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
                        }
                }
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
        return result;
 }
 
@@ -979,8 +958,6 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                sk->rcv_saddr=INADDR_ANY;
                sk->daddr=INADDR_ANY;
                sk->state = TCP_CLOSE;
-               if(uh_cache_sk == sk)
-                       uh_cache_sk = NULL;
                return 0;
        }
 
@@ -1005,9 +982,6 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        sk->dport = usin->sin_port;
        sk->state = TCP_ESTABLISHED;
 
-       if(uh_cache_sk == sk)
-               uh_cache_sk = NULL;
-
        sk->dst_cache = &rt->u.dst;
        return(0);
 }
@@ -1015,6 +989,8 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
 static void udp_close(struct sock *sk, long timeout)
 {
+       bh_lock_sock(sk);
+
        /* See for explanation: raw_close in ipv4/raw.c */
        sk->state = TCP_CLOSE;
        udp_v4_unhash(sk);
index f349750766d2f427090720c6890406c16fed95c0..7bf7fd3b8db8eea5a2d4473d18319382d7bf3789 100644 (file)
@@ -982,6 +982,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
                return;
        }
 
+       read_lock_bh(&dev_base_lock);
         for (dev = dev_base; dev != NULL; dev = dev->next) {
                if (dev->ip_ptr && (dev->flags & IFF_UP)) {
                        struct in_device * in_dev = dev->ip_ptr;
@@ -1000,6 +1001,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
                                        flag |= IFA_HOST;
                                }
 
+                               read_unlock_bh(&dev_base_lock);
                                addrconf_lock();
                                ifp = ipv6_add_addr(idev, &addr, flag);
                                if (ifp) {
@@ -1011,9 +1013,11 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
                                        ipv6_ifa_notify(RTM_NEWADDR, ifp);
                                }
                                addrconf_unlock();
+                               read_lock_bh(&dev_base_lock);
                        }
                }
         }
+       read_unlock_bh(&dev_base_lock);
 }
 
 static void init_loopback(struct device *dev)
@@ -1842,11 +1846,12 @@ __initfunc(void addrconf_init(void))
        struct device *dev;
 
        /* This takes sense only during module load. */
-
+       read_lock_bh(&dev_base_lock);
        for (dev = dev_base; dev; dev = dev->next) {
                if (!(dev->flags&IFF_UP))
                        continue;
 
+               read_unlock_bh(&dev_base_lock);
                switch (dev->type) {
                case ARPHRD_LOOPBACK:   
                        init_loopback(dev);
@@ -1857,7 +1862,9 @@ __initfunc(void addrconf_init(void))
                default:
                        /* Ignore all other */
                }
+               read_lock_bh(&dev_base_lock);
        }
+       read_unlock_bh(&dev_base_lock);
 #endif
        
 #ifdef CONFIG_PROC_FS
index 939d268da3e5c0508da938811ecf0d344893a949..650a38cda9e16d40d9facb2be6da25eea1db58e9 100644 (file)
@@ -615,6 +615,7 @@ static int igmp6_read_proc(char *buffer, char **start, off_t offset,
        int len=0;
        struct device *dev;
        
+       read_lock_bh(&dev_base_lock);
        for (dev = dev_base; dev; dev = dev->next) {
                struct inet6_dev *idev;
 
@@ -647,6 +648,8 @@ static int igmp6_read_proc(char *buffer, char **start, off_t offset,
        *eof = 1;
 
 done:
+       read_unlock_bh(&dev_base_lock);
+
        *start=buffer+(offset-begin);
        len-=(offset-begin);
        if(len>length)
index 31f6a2f5571650d16acfa19f7d89599de08a2551..358213816dc7c74a775c9cff3690307881c8f77e 100644 (file)
@@ -52,7 +52,7 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
                                                                                /*144 */
 
        pos = 149;
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_READ();
        sp = pro->sklist_next;
        while(sp != (struct sock *)pro) {
                struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sp;
@@ -72,6 +72,7 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
                }
                destp = ntohs(sp->dport);
                srcp  = ntohs(sp->sport);
+
                if((format == 0) && (sp->state == TCP_TIME_WAIT)) {
                        extern int tcp_tw_death_row_slot;
                        int slot_dist;
@@ -85,10 +86,8 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
                                slot_dist = tcp_tw_death_row_slot - slot_dist;
                        timer_expires   = jiffies + (slot_dist * TCP_TWKILL_PERIOD);
                } else {
-                       timer_active1 = del_timer(&tp->retransmit_timer);
-                       timer_active2 = del_timer(&sp->timer);
-                       if(!timer_active1) tp->retransmit_timer.expires = 0;
-                       if(!timer_active2) sp->timer.expires = 0;
+                       timer_active1 = tp->retransmit_timer.prev != NULL;
+                       timer_active2 = sp->timer.prev != NULL;
                        timer_active = 0;
                        timer_expires = (unsigned) -1;
                }
@@ -128,8 +127,6 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
                        ((!tw_bucket && sp->socket) ?
                         sp->socket->inode->i_ino : 0));
 
-               if(timer_active1) add_timer(&tp->retransmit_timer);
-               if(timer_active2) add_timer(&sp->timer);
                len += sprintf(buffer+len, "%-148s\n", tmpbuf);
                if(len >= length)
                        break;
@@ -137,7 +134,7 @@ static int get__netinfo6(struct proto *pro, char *buffer, int format, char **sta
                sp = sp->sklist_next;
                i++;
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
 
        begin = len - (pos - offset);
        *start = buffer + begin;
index f82ac33dbfb20e443d71617374bda849c4f61017..c472d8f1f69dad4c7f03e638b6086a3762e462eb 100644 (file)
@@ -50,11 +50,11 @@ static void raw_v6_hash(struct sock *sk)
 
        num &= (RAWV6_HTABLE_SIZE - 1);
        skp = &raw_v6_htable[num];
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        sk->next = *skp;
        *skp = sk;
        sk->hashent = num;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void raw_v6_unhash(struct sock *sk)
@@ -65,7 +65,7 @@ static void raw_v6_unhash(struct sock *sk)
        num &= (RAWV6_HTABLE_SIZE - 1);
        skp = &raw_v6_htable[num];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        while(*skp != NULL) {
                if(*skp == sk) {
                        *skp = sk->next;
@@ -73,7 +73,7 @@ static void raw_v6_unhash(struct sock *sk)
                }
                skp = &((*skp)->next);
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void raw_v6_rehash(struct sock *sk)
@@ -85,7 +85,7 @@ static void raw_v6_rehash(struct sock *sk)
        num &= (RAWV6_HTABLE_SIZE - 1);
        skp = &raw_v6_htable[oldnum];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        while(*skp != NULL) {
                if(*skp == sk) {
                        *skp = sk->next;
@@ -96,7 +96,7 @@ static void raw_v6_rehash(struct sock *sk)
        sk->next = raw_v6_htable[num];
        raw_v6_htable[num] = sk;
        sk->hashent = num;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static __inline__ int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
@@ -631,6 +631,8 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
 
 static void rawv6_close(struct sock *sk, long timeout)
 {
+       bh_lock_sock(sk);
+
        /* See for explanation: raw_close in ipv4/raw.c */
        sk->state = TCP_CLOSE;
        raw_v6_unhash(sk);
index f1ef74de8a4d85e3a37ca9ddc7805a278b5155af..e6da2d859a80b5d0c7131a7b419e4063020101fd 100644 (file)
@@ -67,7 +67,7 @@ static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport,
        int hashent = (lport ^ fport);
 
        hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
-       return (hashent & ((TCP_HTABLE_SIZE/2) - 1));
+       return (hashent & ((tcp_ehash_size >> 1) - 1));
 }
 
 static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
@@ -89,8 +89,8 @@ static int tcp_v6_verify_bind(struct sock *sk, unsigned short snum)
        struct tcp_bind_bucket *tb;
        int result = 0;
 
-       SOCKHASH_LOCK();
-       for(tb = tcp_bound_hash[tcp_bhashfn(snum)];
+       SOCKHASH_LOCK_WRITE();
+       for(tb = tcp_bhash[tcp_bhashfn(snum)];
            (tb && (tb->port != snum));
            tb = tb->next)
                ;
@@ -156,7 +156,7 @@ static int tcp_v6_verify_bind(struct sock *sk, unsigned short snum)
                }
        }
 go_like_smoke:
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
        return result;
 }
 
@@ -172,20 +172,20 @@ static void tcp_v6_hash(struct sock *sk)
        if(sk->state != TCP_CLOSE) {
                struct sock **skp;
 
-               SOCKHASH_LOCK();
-               skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
+               SOCKHASH_LOCK_WRITE();
+               skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
                if((sk->next = *skp) != NULL)
                        (*skp)->pprev = &sk->next;
                *skp = sk;
                sk->pprev = skp;
                tcp_sk_bindify(sk);
-               SOCKHASH_UNLOCK();
+               SOCKHASH_UNLOCK_WRITE();
        }
 }
 
 static void tcp_v6_unhash(struct sock *sk)
 {
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        if(sk->pprev) {
                if(sk->next)
                        sk->next->pprev = sk->pprev;
@@ -194,14 +194,14 @@ static void tcp_v6_unhash(struct sock *sk)
                tcp_sk_unbindify(sk);
                tcp_reg_zap(sk);
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void tcp_v6_rehash(struct sock *sk)
 {
        unsigned char state;
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        state = sk->state;
        if(sk->pprev != NULL) {
                if(sk->next)
@@ -216,7 +216,7 @@ static void tcp_v6_rehash(struct sock *sk)
                if(state == TCP_LISTEN)
                        skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
                else
-                       skp = &tcp_established_hash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
+                       skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))];
 
                if((sk->next = *skp) != NULL)
                        (*skp)->pprev = &sk->next;
@@ -225,7 +225,7 @@ static void tcp_v6_rehash(struct sock *sk)
                if(state == TCP_LISTEN)
                        tcp_sk_bindify(sk);
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned short hnum, int dif)
@@ -264,10 +264,10 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor
 
 /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
  * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
- * It is assumed that this code only gets called from within NET_BH.
+ *
+ * The sockhash lock must be held as a reader here.
  */
-static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
-                                          struct in6_addr *saddr, u16 sport,
+static inline struct sock *__tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
                                           struct in6_addr *daddr, u16 dport,
                                           int dif)
 {
@@ -285,7 +285,7 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
         * have wildcards anyways.
         */
        hash = tcp_v6_hashfn(daddr, hnum, saddr, sport);
-       for(sk = tcp_established_hash[hash]; sk; sk = sk->next) {
+       for(sk = tcp_ehash[hash]; sk; sk = sk->next) {
                /* For IPV6 do the cheaper port and family tests first. */
                if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) {
                        if (sk->state == TCP_ESTABLISHED)
@@ -294,7 +294,7 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th,
                }
        }
        /* Must check for a TIME_WAIT'er before going to listener hash. */
-       for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next) {
+       for(sk = tcp_ehash[hash+(tcp_ehash_size >> 1)]; sk; sk = sk->next) {
                if(*((__u32 *)&(sk->dport))     == ports        &&
                   sk->family                   == PF_INET6) {
                        struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
@@ -309,7 +309,13 @@ hit:
        return sk;
 }
 
-#define tcp_v6_lookup(sa, sp, da, dp, dif) __tcp_v6_lookup((0),(sa),(sp),(da),(dp),(dif))
+#define tcp_v6_lookup(sa, sp, da, dp, dif) \
+({     struct sock *___sk; \
+       SOCKHASH_LOCK_READ(); \
+       ___sk = __tcp_v6_lookup((sa),(sp),(da),(dp),(dif)); \
+       SOCKHASH_UNLOCK_READ(); \
+       ___sk; \
+})
 
 static __inline__ u16 tcp_v6_check(struct tcphdr *th, int len,
                                   struct in6_addr *saddr, 
@@ -344,24 +350,26 @@ static int tcp_v6_unique_address(struct sock *sk)
        int retval = 1;
 
        /* Freeze the hash while we snoop around. */
-       SOCKHASH_LOCK();
-       tb = tcp_bound_hash[tcp_bhashfn(snum)];
+       SOCKHASH_LOCK_READ();
+       tb = tcp_bhash[tcp_bhashfn(snum)];
        for(; tb; tb = tb->next) {
                if(tb->port == snum && tb->owners != NULL) {
                        /* Almost certainly the re-use port case, search the real hashes
                         * so it actually scales.  (we hope that all ipv6 ftp servers will
                         * use passive ftp, I just cover this case for completeness)
                         */
-                       sk = __tcp_v6_lookup(NULL, &sk->net_pinfo.af_inet6.daddr,
+                       sk = __tcp_v6_lookup(&sk->net_pinfo.af_inet6.daddr,
                                             sk->dport,
                                             &sk->net_pinfo.af_inet6.rcv_saddr, snum,
                                             sk->bound_dev_if);
+                       SOCKHASH_UNLOCK_READ();
+
                        if((sk != NULL) && (sk->state != TCP_LISTEN))
                                retval = 0;
-                       break;
+                       return retval;
                }
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
        return retval;
 }
 
@@ -551,7 +559,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
 failure:
        dst_release(xchg(&sk->dst_cache, NULL));
-       memcpy(&np->daddr, 0, sizeof(struct in6_addr));
+       memset(&np->daddr, 0, sizeof(struct in6_addr));
        sk->daddr = 0;
        return err;
 }
@@ -628,11 +636,14 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
        if (type == ICMPV6_PKT_TOOBIG) {
                struct dst_entry *dst = NULL;
 
-               if (atomic_read(&sk->sock_readers))
+               if (sk->state == TCP_LISTEN)
                        return;
 
-               if (sk->state == TCP_LISTEN)
+               bh_lock_sock(sk);
+               if(sk->lock.users) {
+                       bh_unlock_sock(sk);
                        return;
+               }
 
                /* icmp should have updated the destination cache entry */
                if (sk->dst_cache)
@@ -664,7 +675,7 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
                        tcp_simple_retransmit(sk);
                } /* else let the usual retransmit timer handle it */
                dst_release(dst);
-               return;
+               bh_unlock_sock(sk);
        }
 
        icmpv6_err_convert(type, code, &err);
@@ -674,11 +685,13 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
                struct open_request *req, *prev;
                struct ipv6hdr hd;
        case TCP_LISTEN:
-               if (atomic_read(&sk->sock_readers)) {
+               bh_lock_sock(sk);
+               if (sk->lock.users) {
                        net_statistics.LockDroppedIcmps++;
                         /* If too many ICMPs get dropped on busy
                          * servers this needs to be solved differently.
                          */
+                       bh_unlock_sock(sk);
                        return;
                }
 
@@ -686,20 +699,22 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
                ipv6_addr_copy(&hd.saddr, saddr);
                ipv6_addr_copy(&hd.daddr, daddr); 
                req = tcp_v6_search_req(tp, &hd, th, tcp_v6_iif(skb), &prev);
-               if (!req)
-                       return;
-               if (seq != req->snt_isn) {
+               if (!req || (seq != req->snt_isn)) {
                        net_statistics.OutOfWindowIcmps++;
+                       bh_unlock_sock(sk);
                        return;
                }
                if (req->sk) {
+                       bh_unlock_sock(sk);
                        sk = req->sk; /* report error in accept */
                } else {
                        tp->syn_backlog--;
                        tcp_synq_unlink(tp, req, prev);
                        req->class->destructor(req);
                        tcp_openreq_free(req);
+                       bh_unlock_sock(sk);
                }
+
                /* FALL THROUGH */ 
        case TCP_SYN_SENT:
        case TCP_SYN_RECV:  /* Cannot happen */ 
@@ -1210,12 +1225,20 @@ static inline struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
        return sk;
 }
 
+/* The socket must have it's spinlock held when we get
+ * here.
+ *
+ * We have a potential double-lock case here, so even when
+ * doing backlog processing we use the BH locking scheme.
+ * This is because we cannot sleep with the original spinlock
+ * held.
+ */
 static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
 #ifdef CONFIG_FILTER
        struct sk_filter *filter;
 #endif
-       int users = 0;
+       int users = 0, need_unlock = 0;
 
        /* Imagine: socket is IPv6. IPv4 packet arrives,
           goes to IPv4 receive handler and backlogged.
@@ -1286,19 +1309,24 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                 * otherwise we just shortcircuit this and continue with
                 * the new socket..
                 */
-               if (atomic_read(&nsk->sock_readers)) {
-                       skb_orphan(skb);
-                       __skb_queue_tail(&nsk->back_log, skb);
-                       return 0;
+               if(nsk != sk) {
+                       bh_lock_sock(nsk);
+                       if (nsk->lock.users) {
+                               skb_orphan(skb);
+                               sk_add_backlog(nsk, skb);
+                               bh_unlock_sock(nsk);
+                               return 0;
+                       }
+                       need_unlock = 1;
+                       sk = nsk;
                }
-               sk = nsk;
        }
 
        if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
                goto reset;
        if (users)
                goto ipv6_pktoptions;
-       return 0;
+       goto out_maybe_unlock;
 
 reset:
        tcp_v6_send_reset(skb);
@@ -1306,7 +1334,7 @@ discard:
        if (users)
                kfree_skb(skb);
        kfree_skb(skb);
-       return 0;
+       goto out_maybe_unlock;
 
 ipv6_pktoptions:
        /* Do you ask, what is it?
@@ -1335,6 +1363,9 @@ ipv6_pktoptions:
 
        if (skb)
                kfree_skb(skb);
+out_maybe_unlock:
+       if (need_unlock)
+               bh_unlock_sock(sk);
        return 0;
 }
 
@@ -1344,6 +1375,7 @@ int tcp_v6_rcv(struct sk_buff *skb, unsigned long len)
        struct sock *sk;
        struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
        struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+       int ret;
 
        th = skb->h.th;
 
@@ -1383,7 +1415,9 @@ int tcp_v6_rcv(struct sk_buff *skb, unsigned long len)
                /* CHECKSUM_UNNECESSARY */
        };
 
-       sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
+       SOCKHASH_LOCK_READ_BH();
+       sk = __tcp_v6_lookup(saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
+       SOCKHASH_UNLOCK_READ_BH();
 
        if (!sk)
                goto no_tcp_socket;
@@ -1396,11 +1430,15 @@ int tcp_v6_rcv(struct sk_buff *skb, unsigned long len)
        if(sk->state == TCP_TIME_WAIT)
                goto do_time_wait;
 
-       if (!atomic_read(&sk->sock_readers))
-               return tcp_v6_do_rcv(sk, skb);
+       bh_lock_sock(sk);
+       ret = 0;
+       if (!sk->lock.users)
+               ret = tcp_v6_do_rcv(sk, skb);
+       else
+               sk_add_backlog(sk, skb);
+       bh_unlock_sock(sk);
 
-       __skb_queue_tail(&sk->back_log, skb);
-       return(0);
+       return ret;
 
 no_tcp_socket:
        tcp_v6_send_reset(skb);
index 5b4d55f9e4c8b1c40bf1f7af9b34646725deda46..4d74b5608caf95713d1e35b82b15f169657241eb 100644 (file)
@@ -55,7 +55,7 @@ static int udp_v6_verify_bind(struct sock *sk, unsigned short snum)
        int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
        int retval = 0, sk_reuse = sk->reuse;
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_READ();
        for(sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; sk2 != NULL; sk2 = sk2->next) {
                if((sk2->num == snum) && (sk2 != sk)) {
                        unsigned char state = sk2->state;
@@ -86,7 +86,7 @@ static int udp_v6_verify_bind(struct sock *sk, unsigned short snum)
                        }
                }
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_READ();
        return retval;
 }
 
@@ -98,11 +98,11 @@ static void udp_v6_hash(struct sock *sk)
        num &= (UDP_HTABLE_SIZE - 1);
        skp = &udp_hash[num];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        sk->next = *skp;
        *skp = sk;
        sk->hashent = num;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void udp_v6_unhash(struct sock *sk)
@@ -113,7 +113,7 @@ static void udp_v6_unhash(struct sock *sk)
        num &= (UDP_HTABLE_SIZE - 1);
        skp = &udp_hash[num];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        while(*skp != NULL) {
                if(*skp == sk) {
                        *skp = sk->next;
@@ -121,7 +121,7 @@ static void udp_v6_unhash(struct sock *sk)
                }
                skp = &((*skp)->next);
        }
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static void udp_v6_rehash(struct sock *sk)
@@ -133,7 +133,7 @@ static void udp_v6_rehash(struct sock *sk)
        num &= (UDP_HTABLE_SIZE - 1);
        skp = &udp_hash[oldnum];
 
-       SOCKHASH_LOCK();
+       SOCKHASH_LOCK_WRITE();
        while(*skp != NULL) {
                if(*skp == sk) {
                        *skp = sk->next;
@@ -144,7 +144,7 @@ static void udp_v6_rehash(struct sock *sk)
        sk->next = udp_hash[num];
        udp_hash[num] = sk;
        sk->hashent = num;
-       SOCKHASH_UNLOCK();
+       SOCKHASH_UNLOCK_WRITE();
 }
 
 static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
@@ -154,6 +154,7 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
        unsigned short hnum = ntohs(dport);
        int badness = -1;
 
+       SOCKHASH_LOCK_READ();
        for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
                if((sk->num == hnum)            &&
                   (sk->family == PF_INET6)     &&
@@ -189,6 +190,7 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
                        }
                }
        }
+       SOCKHASH_UNLOCK_READ();
        return result;
 }
 
@@ -331,6 +333,8 @@ ipv4_connected:
 
 static void udpv6_close(struct sock *sk, long timeout)
 {
+       bh_lock_sock(sk);
+
        /* See for explanation: raw_close in ipv4/raw.c */
        sk->state = TCP_CLOSE;
        udp_v6_unhash(sk);
index d46e45eb664c73eb00c732dc32eebf16b3748db8..4041967db4ba050e27435b04cf4b8a72de5254c3 100644 (file)
@@ -564,10 +564,13 @@ struct device *nr_dev_first(void)
 {
        struct device *dev, *first = NULL;
 
-       for (dev = dev_base; dev != NULL; dev = dev->next)
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
                        if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
                                first = dev;
+       }
+       read_unlock_bh(&dev_base_lock);
 
        return first;
 }
@@ -579,11 +582,14 @@ struct device *nr_dev_get(ax25_address *addr)
 {
        struct device *dev;
 
-       for (dev = dev_base; dev != NULL; dev = dev->next)
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
-                       return dev;
-
-       return NULL;
+                       goto out;
+       }
+out:
+       read_unlock_bh(&dev_base_lock);
+       return dev;
 }
 
 static ax25_digi *nr_call_to_digi(int ndigis, ax25_address *digipeaters)
index 764900d50f74a8c5ab551dfd3e3769068fb240ab..17910f1ac9b7e4adf7df6aefee950ef24a0bdadb 100644 (file)
@@ -106,10 +106,17 @@ EXPORT_SYMBOL(dev_lockct);
 EXPORT_SYMBOL(skb_over_panic);
 EXPORT_SYMBOL(skb_under_panic);
 
+/* Socket layer global data */
+EXPORT_SYMBOL(sockhash_lock);
+
 /* Socket layer registration */
 EXPORT_SYMBOL(sock_register);
 EXPORT_SYMBOL(sock_unregister);
 
+/* Socket locking */
+EXPORT_SYMBOL(lock_sock);
+EXPORT_SYMBOL(release_sock);
+
 /* Socket layer support routines */
 EXPORT_SYMBOL(memcpy_fromiovec);
 EXPORT_SYMBOL(memcpy_tokerneliovec);
@@ -243,7 +250,6 @@ EXPORT_SYMBOL(ip_mc_dec_group);
 EXPORT_SYMBOL(__ip_finish_output);
 EXPORT_SYMBOL(inet_dgram_ops);
 EXPORT_SYMBOL(ip_cmsg_recv);
-EXPORT_SYMBOL(__release_sock);
 
 /* Route manipulation */
 EXPORT_SYMBOL(ip_rt_ioctl);
@@ -279,9 +285,11 @@ EXPORT_SYMBOL(inet_recvmsg);
 
 /* Socket demultiplexing. */
 EXPORT_SYMBOL(tcp_good_socknum);
-EXPORT_SYMBOL(tcp_established_hash);
+EXPORT_SYMBOL(tcp_ehash);
+EXPORT_SYMBOL(tcp_ehash_size);
 EXPORT_SYMBOL(tcp_listening_hash);
-EXPORT_SYMBOL(tcp_bound_hash);
+EXPORT_SYMBOL(tcp_bhash);
+EXPORT_SYMBOL(tcp_bhash_size);
 EXPORT_SYMBOL(udp_good_socknum);
 EXPORT_SYMBOL(udp_hash);
 
@@ -470,6 +478,7 @@ EXPORT_SYMBOL(netdev_unregister_fc);
 EXPORT_SYMBOL(netdev_fc_xoff);
 #endif
 EXPORT_SYMBOL(dev_base);
+EXPORT_SYMBOL(dev_base_lock);
 EXPORT_SYMBOL(dev_close);
 EXPORT_SYMBOL(dev_mc_add);
 EXPORT_SYMBOL(dev_mc_delete);
index 1fad6b7cc92683c8547d59e68d9cec8eea568735..668015246466a5b4d54ec0da279b94459cb321ab 100644 (file)
@@ -543,10 +543,13 @@ struct device *rose_dev_first(void)
 {
        struct device *dev, *first = NULL;
 
-       for (dev = dev_base; dev != NULL; dev = dev->next)
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
                        if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
                                first = dev;
+       }
+       read_unlock_bh(&dev_base_lock);
 
        return first;
 }
@@ -558,11 +561,14 @@ struct device *rose_dev_get(rose_address *addr)
 {
        struct device *dev;
 
-       for (dev = dev_base; dev != NULL; dev = dev->next)
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
-                       return dev;
-
-       return NULL;
+                       goto out;
+       }
+out:
+       read_unlock_bh(&dev_base_lock);
+       return dev;
 }
 
 struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neigh)
index 0ced70bbcd08895ce9c0d674e12db36db5b0d397..bb1bc418298a4c86b6f75ad61fdd13d161ff7114 100644 (file)
@@ -713,6 +713,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
 
        s_idx = cb->args[0];
        s_q_idx = q_idx = cb->args[1];
+       read_lock_bh(&dev_base_lock);
        for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
                if (idx < s_idx)
                        continue;
@@ -729,6 +730,8 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
        }
 
 done:
+       read_unlock_bh(&dev_base_lock);
+
        cb->args[0] = idx;
        cb->args[1] = q_idx;
 
index ba40033e5bf20559b81bb73c45f759aaed296c3f..9d199cbdc9a33c86b4f8f843f087b966fc69aaeb 100644 (file)
@@ -96,8 +96,10 @@ void qdisc_run_queues(void)
                struct Qdisc *q = (struct Qdisc*)h;
                struct device *dev = q->dev;
 
+               spin_lock_bh(&dev->xmit_lock);
                while (!dev->tbusy && (res = qdisc_restart(dev)) < 0)
                        /* NOTHING */;
+               spin_unlock_bh(&dev->xmit_lock);
 
                /* An explanation is necessary here.
                   qdisc_restart called dev->hard_start_xmit,
@@ -131,8 +133,11 @@ static void dev_do_watchdog(unsigned long dummy)
        for (h = qdisc_head.forw; h != &qdisc_head; h = h->forw) {
                struct Qdisc *q = (struct Qdisc*)h;
                struct device *dev = q->dev;
+
+               spin_lock_bh(&dev->xmit_lock);
                if (dev->tbusy && jiffies - q->tx_last > q->tx_timeo)
                        qdisc_restart(dev);
+               spin_unlock_bh(&dev->xmit_lock);
        }
        dev_watchdog.expires = jiffies + 5*HZ;
        add_timer(&dev_watchdog);
index 1322d29599c8eabc42bbacf7c6584b3480e5cc55..8402e0480d19071a1408a71d68ca8230de376b35 100644 (file)
@@ -130,6 +130,11 @@ struct net_proto_family *net_families[NPROTO];
 
 static int sockets_in_use  = 0;
 
+/*
+ *     Socket hashing lock.
+ */
+rwlock_t sockhash_lock = RW_LOCK_UNLOCKED;
+
 /*
  *     Support routines. Move socket addresses back and forth across the kernel/user
  *     divide and look after the messy bits.
@@ -561,7 +566,8 @@ int sock_wake_async(struct socket *sock, int how)
                /* fall through */
        case 0:
        call_kill:
-               kill_fasync(sock->fasync_list, SIGIO);
+               if(sock->fasync_list != NULL)
+                       kill_fasync(sock->fasync_list, SIGIO);
                break;
        }
        return 0;
index 1d2b14787352c1d373081137d95eafc4778e1dee..4f67268c7eaeb7376cd082557d7a9eaf50930e74 100644 (file)
@@ -144,19 +144,21 @@ extern __inline__ int unix_may_send(unix_socket *sk, unix_socket *osk)
        return (unix_peer(osk) == NULL || unix_our_peer(sk, osk));
 }
 
+#define ulock(sk)      (&(sk->protinfo.af_unix.user_count))
+
 extern __inline__ void unix_lock(unix_socket *sk)
 {
-       atomic_inc(&sk->sock_readers);
+       atomic_inc(ulock(sk));
 }
 
 extern __inline__ void unix_unlock(unix_socket *sk)
 {
-       atomic_dec(&sk->sock_readers);
+       atomic_dec(ulock(sk));
 }
 
 extern __inline__ int unix_locked(unix_socket *sk)
 {
-       return atomic_read(&sk->sock_readers);
+       return (atomic_read(ulock(sk)) != 0);
 }
 
 extern __inline__ void unix_release_addr(struct unix_address *addr)
@@ -1511,7 +1513,7 @@ static int unix_read_proc(char *buffer, char **start, off_t offset,
        {
                len+=sprintf(buffer+len,"%p: %08X %08X %08lX %04X %02X %5ld",
                        s,
-                       atomic_read(&s->sock_readers),
+                       atomic_read(ulock(s)),
                        0,
                        s->socket ? s->socket->flags : 0,
                        s->type,
index e7f894e8ecf36ba72b2b8bde23672b07edcceef6..b2e802c0d993ed78949633754db1794633001ba4 100644 (file)
@@ -1336,14 +1336,20 @@ int init_module(void)
        /*
         *      Register any pre existing devices.
         */
-       for (dev = dev_base; dev != NULL; dev = dev->next)
+       read_lock_bh(&dev_base_lock);
+       for (dev = dev_base; dev != NULL; dev = dev->next) {
                if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25
 #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
                                           || dev->type == ARPHRD_ETHER
 #endif
-                                                                       ))
-               x25_link_device_up(dev);
-       
+                       )) {
+                       read_unlock_bh(&dev_base_lock);
+                       x25_link_device_up(dev);
+                       read_lock_bh(&dev_base_lock);
+               }
+       }
+       read_unlock_bh(&dev_base_lock);
+
        return 0;
 }