isdn: i4l: move active-isdn drivers to staging
authorArnd Bergmann <arnd@arndb.de>
Wed, 2 Mar 2016 19:06:46 +0000 (20:06 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 5 Mar 2016 23:00:38 +0000 (15:00 -0800)
The icn, act2000 and pcbit drivers are all for very old hardware,
and it is highly unlikely that anyone is actually still using them
on modern kernels, if at all.

All three drivers apparently are for hardware that predates PCI
being the common connector, as they are ISA-only and active
PCI ISDN cards were widely available in the 1990s.

Looking through the git logs, it I cannot find any indication of a
patch to any of these drivers that has been tested on real hardware,
only cleanups or global API changes.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Karsten Keil <isdn@linux-pingi.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
66 files changed:
Documentation/isdn/00-INDEX
Documentation/isdn/README.act2000 [deleted file]
Documentation/isdn/README.icn [deleted file]
Documentation/isdn/README.pcbit [deleted file]
Documentation/isdn/README.sc [deleted file]
drivers/isdn/Makefile
drivers/isdn/act2000/Kconfig [deleted file]
drivers/isdn/act2000/Makefile [deleted file]
drivers/isdn/act2000/act2000.h [deleted file]
drivers/isdn/act2000/act2000_isa.c [deleted file]
drivers/isdn/act2000/act2000_isa.h [deleted file]
drivers/isdn/act2000/capi.c [deleted file]
drivers/isdn/act2000/capi.h [deleted file]
drivers/isdn/act2000/module.c [deleted file]
drivers/isdn/i4l/Kconfig
drivers/isdn/icn/Kconfig [deleted file]
drivers/isdn/icn/Makefile [deleted file]
drivers/isdn/icn/icn.c [deleted file]
drivers/isdn/icn/icn.h [deleted file]
drivers/isdn/pcbit/Kconfig [deleted file]
drivers/isdn/pcbit/Makefile [deleted file]
drivers/isdn/pcbit/callbacks.c [deleted file]
drivers/isdn/pcbit/callbacks.h [deleted file]
drivers/isdn/pcbit/capi.c [deleted file]
drivers/isdn/pcbit/capi.h [deleted file]
drivers/isdn/pcbit/drv.c [deleted file]
drivers/isdn/pcbit/edss1.c [deleted file]
drivers/isdn/pcbit/edss1.h [deleted file]
drivers/isdn/pcbit/layer2.c [deleted file]
drivers/isdn/pcbit/layer2.h [deleted file]
drivers/isdn/pcbit/module.c [deleted file]
drivers/isdn/pcbit/pcbit.h [deleted file]
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/i4l/Documentation/README.act2000 [new file with mode: 0644]
drivers/staging/i4l/Documentation/README.icn [new file with mode: 0644]
drivers/staging/i4l/Documentation/README.pcbit [new file with mode: 0644]
drivers/staging/i4l/Documentation/README.sc [new file with mode: 0644]
drivers/staging/i4l/Kconfig [new file with mode: 0644]
drivers/staging/i4l/Makefile [new file with mode: 0644]
drivers/staging/i4l/TODO [new file with mode: 0644]
drivers/staging/i4l/act2000/Kconfig [new file with mode: 0644]
drivers/staging/i4l/act2000/Makefile [new file with mode: 0644]
drivers/staging/i4l/act2000/act2000.h [new file with mode: 0644]
drivers/staging/i4l/act2000/act2000_isa.c [new file with mode: 0644]
drivers/staging/i4l/act2000/act2000_isa.h [new file with mode: 0644]
drivers/staging/i4l/act2000/capi.c [new file with mode: 0644]
drivers/staging/i4l/act2000/capi.h [new file with mode: 0644]
drivers/staging/i4l/act2000/module.c [new file with mode: 0644]
drivers/staging/i4l/icn/Kconfig [new file with mode: 0644]
drivers/staging/i4l/icn/Makefile [new file with mode: 0644]
drivers/staging/i4l/icn/icn.c [new file with mode: 0644]
drivers/staging/i4l/icn/icn.h [new file with mode: 0644]
drivers/staging/i4l/pcbit/Kconfig [new file with mode: 0644]
drivers/staging/i4l/pcbit/Makefile [new file with mode: 0644]
drivers/staging/i4l/pcbit/callbacks.c [new file with mode: 0644]
drivers/staging/i4l/pcbit/callbacks.h [new file with mode: 0644]
drivers/staging/i4l/pcbit/capi.c [new file with mode: 0644]
drivers/staging/i4l/pcbit/capi.h [new file with mode: 0644]
drivers/staging/i4l/pcbit/drv.c [new file with mode: 0644]
drivers/staging/i4l/pcbit/edss1.c [new file with mode: 0644]
drivers/staging/i4l/pcbit/edss1.h [new file with mode: 0644]
drivers/staging/i4l/pcbit/layer2.c [new file with mode: 0644]
drivers/staging/i4l/pcbit/layer2.h [new file with mode: 0644]
drivers/staging/i4l/pcbit/module.c [new file with mode: 0644]
drivers/staging/i4l/pcbit/pcbit.h [new file with mode: 0644]

index e87e336f590ef256bb2a2e446a1222328261f700..2d1889b6c1fa8127fdf386042aec1ab5b2a8ab4d 100644 (file)
@@ -16,8 +16,6 @@ README.FAQ
        - general info for FAQ.
 README.HiSax
        - info on the HiSax driver which replaces the old teles.
-README.act2000
-       - info on driver for IBM ACT-2000 card.
 README.audio
        - info for running audio over ISDN.
 README.avmb1
@@ -34,14 +32,8 @@ README.hfc-pci
        - info on hfc-pci based cards.
 README.hysdn
         - info on driver for Hypercope active HYSDN cards
-README.icn
-       - info on the ICN-ISDN-card and its driver.
 README.mISDN
        - info on the Modular ISDN subsystem (mISDN)
-README.pcbit
-       - info on the PCBIT-D ISDN adapter and driver.
-README.sc
-       - info on driver for Spellcaster cards.
 README.syncppp
        - info on running Sync PPP over ISDN.
 README.x25
diff --git a/Documentation/isdn/README.act2000 b/Documentation/isdn/README.act2000
deleted file mode 100644 (file)
index ce7115e..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-$Id: README.act2000,v 1.3 2000/08/06 09:22:51 armin Exp $
-
-This document describes the ACT2000 driver for the
-IBM Active 2000 ISDN card.
-
-There are 3 Types of this card available. A ISA-, MCA-, and PCMCIA-Bus
-Version. Currently, only the ISA-Bus version of the card is supported.
-However MCA and PCMCIA will follow soon.
-
-The ISA-Bus Version uses 8 IO-ports. The base port address has to be set
-manually using the DIP switches.
-
-Setting up the DIP switches for the IBM Active 2000 ISDN card:
-
-        Note: S5 and S6 always set off!
-
-     S1  S2  S3  S4  Base-port
-     on  on  on  on  0x0200 (Factory default)
-     off on  on  on  0x0240 
-     on  off on  on  0x0280 
-     off off on  on  0x02c0 
-     on  on  off on  0x0300 
-     off on  off on  0x0340 
-     on  off off on  0x0380 
-     on  on  on  off 0xcfe0
-     off on  on  off 0xcfa0 
-     on  off on  off 0xcf60 
-     off off on  off 0xcf20 
-     on  on  off off 0xcee0 
-     off on  off off 0xcea0 
-     on  off off off 0xce60 
-     off off off off Card disabled 
-
-IRQ is configured by software. Possible values are:
-
-  3, 5, 7, 10, 11, 12, 15 and none (polled mode)
-
-
-The ACT2000 driver may either be built into the kernel or as a module.
-Initialization depends on how the driver is built:
-
-Driver built into the kernel:
-
-  The ACT2000 driver can be configured using the commandline-feature while
-  loading the kernel with LILO or LOADLIN. It accepts the following syntax:
-
-  act2000=b,p,i[,idstring]
-
-  where
-
-    b = Bus-Type      (1=ISA, 2=MCA, 3=PCMCIA)
-    p = portbase      (-1 means autoprobe)
-    i = Interrupt     (-1 means use next free IRQ, 0 means polled mode)
-
-  The idstring is an arbitrary string used for referencing the card
-  by the actctrl tool later.
-
-  Defaults used, when no parameters given at all:
-
-    1,-1,-1,""
-
-  which means: Autoprobe for an ISA card, use next free IRQ, let the
-  ISDN linklevel fill the IdString (usually "line0" for the first card).
-  If you like to use more than one card, you can use the program
-  "actctrl" from the utility-package to configure additional cards.
-
-  Using the "actctrl"-utility, portbase and irq can also be changed
-  during runtime. The D-channel protocol is configured by the "dproto"
-  option of the "actctrl"-utility after loading the firmware into the
-  card's memory using the "actctrl"-utility.
-
-Driver built as module:
-
-  The module act2000.o can be configured during modprobe (insmod) by
-  appending its parameters to the modprobe resp. insmod commandline.
-  The following syntax is accepted:
-
-    act_bus=b act_port=p act_irq=i act_id=idstring
-
-  where b, p, i and idstring have the same meanings as the parameters
-  described for the builtin version above.
-
-  Using the "actctrl"-utility, the same features apply to the modularized
-  version as to the kernel-builtin one. (i.e. loading of firmware and
-  configuring the D-channel protocol)
-
-Loading the firmware into the card:
-
-  The firmware is supplied together with the isdn4k-utils package. It
-  can be found in the subdirectory act2000/firmware/
-
-  Assuming you have installed the utility-package correctly, the firmware
-  will be downloaded into the card using the following command:
-
-    actctrl -d idstring load /etc/isdn/bip11.btl
-
-  where idstring is the Name of the card, given during insmod-time or
-  (for kernel-builtin driver) on the kernel commandline. If only one
-  ISDN card is used, the -d isdstrin may be omitted.
-
-  For further documentation (adding more IBM Active 2000 cards), refer to
-  the manpage actctrl.8 which is included in the isdn4k-utils package.
-
diff --git a/Documentation/isdn/README.icn b/Documentation/isdn/README.icn
deleted file mode 100644 (file)
index 13f833d..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-$Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $
-
-You can get the ICN-ISDN-card from:
-
-Thinking Objects Software GmbH
-Versbacher Röthe 159
-97078 Würzburg
-Tel: +49 931 2877950
-Fax: +49 931 2877951
-
-email info@think.de
-WWW   http:/www.think.de
-
-
-The card communicates with the PC by two interfaces:
-  1. A range of 4 successive port-addresses, whose base address can be 
-     configured with the switches.
-  2. A memory window with 16KB-256KB size, which can be setup in 16k steps
-     over the whole range of 16MB. Isdn4linux only uses a 16k window.
-     The base address of the window can be configured when loading
-     the lowlevel-module (see README). If using more than one card,
-     all cards are mapped to the same window and activated as needed.
-
-Setting up the IO-address dipswitches for the ICN-ISDN-card:
-
-  Two types of cards exist, one with dip-switches and one with
-  hook-switches.
-
-  1. Setting for the card with hook-switches:
-
-     (0 = switch closed, 1 = switch open)
-
-     S3 S2 S1  Base-address
-      0  0  0  0x300
-      0  0  1  0x310
-      0  1  0  0x320 (Default for isdn4linux)
-      0  1  1  0x330
-      1  0  0  0x340
-      1  0  1  0x350
-      1  1  0  0x360
-      1  1  1  NOT ALLOWED!
-    
-  2. Setting for the card with dip-switches:
-
-     (0 = switch closed, 1 = switch open)
-
-     S1 S2 S3 S4  Base-Address
-      0  0  0  0  0x300
-      0  0  0  1  0x310
-      0  0  1  0  0x320 (Default for isdn4linux)
-      0  0  1  1  0x330
-      0  1  0  0  0x340
-      0  1  0  1  0x350
-      0  1  1  0  0x360
-      0  1  1  1  NOT ALLOWED!
-      1  0  0  0  0x308
-      1  0  0  1  0x318
-      1  0  1  0  0x328
-      1  0  1  1  0x338
-      1  1  0  0  0x348
-      1  1  0  1  0x358
-      1  1  1  0  0x368
-      1  1  1  1  NOT ALLOWED!
-
-The ICN driver may be built into the kernel or as a module. Initialization
-depends on how the driver is built:
-
-Driver built into the kernel:
-
-  The ICN driver can be configured using the commandline-feature while
-  loading the kernel with LILO or LOADLIN. It accepts the following syntax:
-
-  icn=p,m[,idstring1[,idstring2]]
-
-  where
-
-    p = portbase      (default: 0x320)
-    m = shared memory (default: 0xd0000)
-
-  When using the ICN double card (4B), you MUST define TWO idstrings.
-  idstring must start with a character! There is no way for the driver
-  to distinguish between a 2B and 4B type card. Therefore, by supplying
-  TWO idstrings, you tell the driver that you have a 4B installed.
-  
-  If you like to use more than one card, you can use the program
-  "icnctrl" from the utility-package to configure additional cards.
-  You need to configure shared memory only once, since the icn-driver
-  maps all cards into the same address-space.
-
-  Using the "icnctrl"-utility, portbase and shared memory can also be
-  changed during runtime.
-
-  The D-channel protocol is configured by loading different firmware
-  into the card's memory using the "icnctrl"-utility.
-
-
-Driver built as module:
-
-  The module icn.o can be configured during "insmod'ing" it by
-  appending its parameters to the insmod-commandline. The following
-  syntax is accepted:
-
-    portbase=p membase=m icn_id=idstring [icn_id2=idstring2]
-
-  where p, m, idstring1 and idstring2 have the same meanings as the
-  parameters described for the kernel-version above.
-      
-  When using the ICN double card (4B), you MUST define TWO idstrings.
-  idstring must start with a character! There is no way for the driver
-  to distinguish between a 2B and 4B type card. Therefore, by supplying
-  TWO idstrings, you tell the driver that you have a 4B installed.
-  
-  Using the "icnctrl"-utility, the same features apply to the modularized
-  version like to the kernel-builtin one.
-
-  The D-channel protocol is configured by loading different firmware
-  into the card's memory using the "icnctrl"-utility.
-
-Loading the firmware into the card:
-
-  The firmware is supplied together with the isdn4k-utils package. It
-  can be found in the subdirectory icnctrl/firmware/
-
-  There are 3 files:
-
-    loadpg.bin   - Image of the bootstrap loader.
-    pc_1t_ca.bin - Image of firmware for german 1TR6 protocol.
-    pc_eu_ca.bin - Image if firmware for EDSS1 (Euro-ISDN) protocol.
-
-  Assuming you have installed the utility-package correctly, the firmware
-  will be downloaded into the 2B-card using the following command:
-
-    icnctrl -d Idstring load /etc/isdn/loadpg.bin /etc/isdn/pc_XX_ca.bin
-
-  where XX is either "1t" or "eu", depending on the D-Channel protocol
-  used on your S0-bus and Idstring is the Name of the card, given during
-  insmod-time or (for kernel-builtin driver) on the kernel commandline.
-
-  To load a 4B-card, the same command is used, except a second firmware
-  file is appended to the commandline of icnctrl.
-
-  -> After downloading firmware, the two LEDs at the back cover of the card
-     (ICN-4B: 4 LEDs) must be blinking intermittently now. If a connection
-     is up, the corresponding led is lit continuously.
-
-  For further documentation (adding more ICN-cards), refer to the manpage
-  icnctrl.8 which is included in the isdn4k-utils package.
-
diff --git a/Documentation/isdn/README.pcbit b/Documentation/isdn/README.pcbit
deleted file mode 100644 (file)
index 5125002..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-------------------------------------------------------------------------------
- README file for the PCBIT-D Device Driver.
-------------------------------------------------------------------------------
-
-The PCBIT is a Euro ISDN adapter manufactured in Portugal by Octal and
-developed in cooperation with Portugal Telecom and Inesc.
-The driver interfaces with the standard kernel isdn facilities
-originally developed by Fritz Elfert in the isdn4linux project.
-
-The common versions of the pcbit board require a firmware that is 
-distributed (and copyrighted) by the manufacturer. To load this
-firmware you need "pcbitctl" available on the standard isdn4k-utils
-package or in the pcbit package available in:
-
-ftp://ftp.di.fc.ul.pt/pub/systems/Linux/isdn
-
-Known Limitations:
-
-- The board reset procedure is at the moment incorrect and will only
-allow you to load the firmware after a hard reset.
-
-- Only HDLC in B-channels is supported at the moment. There is no
-current support for X.25 in B or D channels nor LAPD in B
-channels. The main reason is that these two other protocol modes have,
-to my knowledge, very little use. If you want to see them implemented
-*do* send me a mail.
-
-- The driver often triggers errors in the board that I and the
-manufacturer believe to be caused by bugs in the firmware. The current
-version includes several procedures for error recovery that should
-allow normal operation. Plans for the future include cooperation with
-the manufacturer in order to solve this problem.
-
-Information/hints/help can be obtained in the linux isdn
-mailing list (isdn4linux@listserv.isdn4linux.de) or directly from me.
-
-regards,
-  Pedro.
-               
-<roque@di.fc.ul.pt>
diff --git a/Documentation/isdn/README.sc b/Documentation/isdn/README.sc
deleted file mode 100644 (file)
index 1153cd9..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-Welcome to Beta Release 2 of the combination ISDN driver for SpellCaster's
-ISA ISDN adapters. Please note this release 2 includes support for the
-DataCommute/BRI and TeleCommute/BRI adapters only and any other use is 
-guaranteed to fail. If you have a DataCommute/PRI installed in the test
-computer, we recommend removing it as it will be detected but will not
-be usable.  To see what we have done to Beta Release 2, see section 3.
-
-Speaking of guarantees, THIS IS BETA SOFTWARE and as such contains
-bugs and defects either known or unknown. Use this software at your own
-risk. There is NO SUPPORT for this software. Some help may be available
-through the web site or the mailing list but such support is totally at
-our own option and without warranty. If you choose to assume all and
-total risk by using this driver, we encourage you to join the beta
-mailing list.
-
-To join the Linux beta mailing list, send a message to:
-majordomo@spellcast.com with the words "subscribe linux-beta" as the only
-contents of the message. Do not include a signature. If you choose to
-remove yourself from this list at a later date, send another message to
-the same address with the words "unsubscribe linux-beta" as its only
-contents.
-
-TABLE OF CONTENTS
------------------
-       1. Introduction
-        1.1 What is ISDN4Linux?
-        1.2 What is different between this driver and previous drivers?
-        1.3 How do I setup my system with the correct software to use
-            this driver release?
-       
-       2. Basic Operations
-        2.1 Unpacking and installing the driver
-        2.2 Read the man pages!!!
-        2.3 Installing the driver
-        2.4 Removing the driver
-        2.5 What to do if it doesn't load
-        2.6 How to setup ISDN4Linux with the driver
-
-       3. Beta Change Summaries and Miscellaneous Notes
-
-1. Introduction
----------------
-
-The revision 2 Linux driver for SpellCaster ISA ISDN adapters is built
-upon ISDN4Linux available separately or as included in Linux 2.0 and later.
-The driver will support a maximum of 4 adapters in any one system of any
-type including DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI for a
-maximum of 92 channels for host. The driver is supplied as a module in
-source form and needs to be complied before it can be used. It has been
-tested on Linux 2.0.20.
-
-1.1 What Is ISDN4Linux
-
-ISDN4Linux is a driver and set of tools used to access and use ISDN devices
-on a Linux platform in a common and standard way. It supports HDLC and PPP
-protocols and offers channel bundling and MLPPP support. To use ISDN4Linux
-you need to configure your kernel for ISDN support and get the ISDN4Linux
-tool kit from our web site.
-
-ISDN4Linux creates a channel pool from all of the available ISDN channels
-and therefore can function across adapters. When an ISDN4Linux compliant
-driver (such as ours) is loaded, all of the channels go into a pool and
-are used on a first-come first-served basis. In addition, individual
-channels can be specifically bound to particular interfaces.
-
-1.2 What is different between this driver and previous drivers?
-
-The revision 2 driver besides adopting the ISDN4Linux architecture has many
-subtle and not so subtle functional differences from previous releases. These
-include:
-       - More efficient shared memory management combined with a simpler
-         configuration. All adapters now use only 16Kbytes of shared RAM
-         versus between 16K and 64K. New methods for using the shared RAM
-         allow us to utilize all of the available RAM on the adapter through
-         only one 16K page.
-       - Better detection of available upper memory. The probing routines
-         have been improved to better detect available shared RAM pages and
-         used pages are now locked.
-       - Decreased loading time and a wider range of I/O ports probed.
-         We have significantly reduced the amount of time it takes to load
-         the driver and at the same time doubled the number of I/O ports
-         probed increasing the likelihood of finding an adapter.
-       - We now support all ISA adapter models with a single driver instead
-         of separate drivers for each model. The revision 2 driver supports
-         the DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI in any
-         combination up to a maximum of four adapters per system.
-       - On board PPP protocol support has been removed in favour of the
-         sync-PPP support used in ISDN4Linux. This means more control of
-         the protocol parameters, faster negotiation time and a more
-         familiar interface.
-
-1.3 How do I setup my system with the correct software to use
-    this driver release?
-
-Before you can compile, install and use the SpellCaster ISA ISDN driver, you
-must ensure that the following software is installed, configured and running:
-
-       - Linux kernel 2.0.20 or later with the required init and ps
-         versions. Please see your distribution vendor for the correct
-         utility packages. The latest kernel is available from
-         ftp://sunsite.unc.edu/pub/Linux/kernel/v2.0/
-
-       - The latest modules package (modules-2.0.0.tar.gz) from
-         ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
-
-       - The ISDN4Linux tools available from 
-         ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz
-         This package may fail to compile for you so you can alternatively
-         get a pre-compiled version from
-         ftp://ftp.spellcast.com/pub/drivers/isdn4linux/isdn4k-bin-2.0.tar.gz
-
-
-2. Basic Operations
--------------------
-
-2.1 Unpacking and installing the driver
-
-       1. As root, create a directory in a convenient place. We suggest
-          /usr/src/spellcaster.
-       
-       2. Unpack the archive with :
-               tar xzf sc-n.nn.tar.gz -C /usr/src/spellcaster
-       
-       3. Change directory to /usr/src/spellcaster
-
-       4. Read the README and RELNOTES files.
-
-       5. Run 'make' and if all goes well, run 'make install'.
-
-2.2 Read the man pages!!!
-
-Make sure you read the scctrl(8) and sc(4) manual pages before continuing
-any further. Type 'man 8 scctrl' and 'man 4 sc'.
-
-2.3 Installing the driver
-
-To install the driver, type '/sbin/insmod sc' as root. sc(4) details options
-you can specify but you shouldn't need to use any unless this doesn't work.
-
-Make sure the driver loaded and detected all of the adapters by typing
-'dmesg'.
-
-The driver can be configured so that it is loaded upon startup.  To do this, 
-edit the file "/etc/modules/'uname -f'/'uname -v'" and insert the driver name
-"sc" into this file.
-
-2.4 Removing the driver
-
-To remove the driver, delete any interfaces that may exist (see isdnctrl(8)
-for more on this) and then type '/sbin/rmmod sc'.
-
-2.5 What to do if it doesn't load
-
-If, when you try to install the driver, you get a message mentioning
-'register_isdn' then you do not have the ISDN4Linux system installed. Please
-make sure that ISDN support is configured in the kernel.
-
-If you get a message that says 'initialization of sc failed', then the
-driver failed to detect an adapter or failed to find resources needed such
-as a free IRQ line or shared memory segment. If you are sure there are free
-resources available, use the insmod options detailed in sc(4) to override
-the probing function.  
-
-Upon testing, the following problem was noted, the driver would load without
-problems, but the board would not respond beyond that point.  When a check was 
-done with 'cat /proc/interrupts' the interrupt count for sc was 0.  In the event 
-of this problem, change the BIOS settings so that the interrupts in question are
-reserved for ISA use only.   
-
-
-2.6 How to setup ISDN4Linux with the driver
-
-There are three main configurations which you can use with the driver:
-
-A)     Basic HDLC connection
-B)     PPP connection
-C)     MLPPP connection
-
-It should be mentioned here that you may also use a tty connection if you
-desire. The Documentation directory of the isdn4linux subsystem offers good
-documentation on this feature.
-
-A) 10 steps to the establishment of a basic HDLC connection
------------------------------------------------------------
-
-- please open the isdn-hdlc file in the examples directory and follow along...
-       
-       This file is a script used to configure a BRI ISDN TA to establish a 
-       basic HDLC connection between its two channels.  Two network 
-       interfaces are created and two routes added between the channels.
-
-       i)   using the isdnctrl utility, add an interface with "addif" and 
-            name it "isdn0"
-       ii)  add the outgoing and inbound telephone numbers
-       iii) set the Layer 2 protocol to hdlc
-       iv)  set the eaz of the interface to be the phone number of that 
-            specific channel
-       v)   to turn the callback features off, set the callback to "off" and
-            the callback delay (cbdelay) to 0.
-       vi)  the hangup timeout can be set to a specified number of seconds
-       vii) the hangup upon incoming call can be set on or off 
-       viii) use the ifconfig command to bring up the network interface with 
-             a specific IP address and point to point address
-       ix)  add a route to the IP address through the isdn0 interface
-       x)   a ping should result in the establishment of the connection
-
-       
-B) Establishment of a PPP connection
-------------------------------------
-
-- please open the isdn-ppp file in the examples directory and follow along...
-       
-       This file is a script used to configure a BRI ISDN TA to establish a 
-       PPP connection  between the two channels.  The file is almost 
-       identical to the HDLC connection example except that the packet 
-       encapsulation type has to be set.
-       
-       use the same procedure as in the HDLC connection from steps i) to 
-       iii) then, after the Layer 2 protocol is set, set the encapsulation 
-       "encap" to syncppp. With this done, the rest of the steps, iv) to x) 
-       can be followed from above.
-
-       Then, the ipppd (ippp daemon) must be setup:
-       
-       xi)   use the ipppd function found in /sbin/ipppd to set the following:
-       xii)  take out (minus) VJ compression and bsd compression
-       xiii) set the mru size to 2000
-       xiv)  link the two /dev interfaces to the daemon
-
-NOTE:  A "*" in the inbound telephone number specifies that a call can be 
-accepted on any number.
-
-C) Establishment of a MLPPP connection
---------------------------------------
-
-- please open the isdn-mppp file in the examples directory and follow along...
-       
-       This file is a script used to configure a BRI ISDN TA to accept a 
-       Multi Link PPP connection. 
-       
-       i)   using the isdnctrl utility, add an interface with "addif" and 
-            name it "ippp0"
-       ii)  add the inbound telephone number
-       iii) set the Layer 2 protocol to hdlc and the Layer 3 protocol to 
-            trans (transparent)
-       iv)  set the packet encapsulation to syncppp
-       v)   set the eaz of the interface to be the phone number of that 
-            specific channel
-       vi)  to turn the callback features off, set the callback to "off" and
-            the callback delay (cbdelay) to 0.
-       vi)  the hangup timeout can be set to a specified number of seconds
-       vii) the hangup upon incoming call can be set on or off 
-       viii) add a slave interface and name it "ippp32" for example
-       ix)  set the similar parameters for the ippp32 interface
-       x)   use the ifconfig command to bring-up the ippp0 interface with a 
-            specific IP address and point to point address
-       xi)  add a route to the IP address through the ippp0 interface
-       xii) use the ipppd function found in /sbin/ipppd to set the following:
-       xiii) take out (minus) bsd compression
-       xiv) set the mru size to 2000
-       xv)  add (+) the multi-link function "+mp"
-       xvi)  link the two /dev interfaces to the daemon
-
-NOTE:  To use the MLPPP connection to dial OUT to a MLPPP connection, change 
-the inbound telephone numbers to the outgoing telephone numbers of the MLPPP 
-host.
-
-       
-3. Beta Change Summaries and Miscellaneous Notes
-------------------------------------------------
-When using the "scctrl" utility to upload firmware revisions on the board,
-please note that the byte count displayed at the end of the operation may be
-different from the total number of bytes in the "dcbfwn.nn.sr" file. Please
-disregard the displayed byte count.
-
-It was noted that in Beta Release 1, the module would fail to load and result
-in a segmentation fault when 'insmod'ed. This problem was created when one of
-the isdn4linux parameters, (isdn_ctrl, data field) was filled in. In some
-cases, this data field was NULL, and was left unchecked, so when it was
-referenced... segv. The bug has been fixed around line 63-68 of event.c.
-
index 91c81965e7ca2772b3d362509f40b5afda59e3ce..c32e45826c2c36d2ae379db2a12dce0f2d34c616 100644 (file)
@@ -8,9 +8,6 @@ obj-$(CONFIG_MISDN)                     += mISDN/
 obj-$(CONFIG_ISDN)                     += hardware/
 obj-$(CONFIG_ISDN_DIVERSION)           += divert/
 obj-$(CONFIG_ISDN_DRV_HISAX)           += hisax/
-obj-$(CONFIG_ISDN_DRV_ICN)             += icn/
-obj-$(CONFIG_ISDN_DRV_PCBIT)           += pcbit/
 obj-$(CONFIG_ISDN_DRV_LOOP)            += isdnloop/
-obj-$(CONFIG_ISDN_DRV_ACT2000)         += act2000/
 obj-$(CONFIG_HYSDN)                    += hysdn/
 obj-$(CONFIG_ISDN_DRV_GIGASET)         += gigaset/
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
deleted file mode 100644 (file)
index fa2673f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-config ISDN_DRV_ACT2000
-       tristate "IBM Active 2000 support"
-       depends on ISA
-       help
-         Say Y here if you have an IBM Active 2000 ISDN card. In order to use
-         this card, additional firmware is necessary, which has to be loaded
-         into the card using a utility which is part of the latest
-         isdn4k-utils package. Please read the file
-         <file:Documentation/isdn/README.act2000> for more information.
diff --git a/drivers/isdn/act2000/Makefile b/drivers/isdn/act2000/Makefile
deleted file mode 100644 (file)
index 05e582f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# Makefile for the act2000 ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o
-
-# Multipart objects.
-
-act2000-y                      := module.o capi.o act2000_isa.o
diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h
deleted file mode 100644 (file)
index 321d437..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/* $Id: act2000.h,v 1.8.6.3 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
- *
- * Author       Fritz Elfert
- * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#ifndef act2000_h
-#define act2000_h
-
-#include <linux/compiler.h>
-
-#define ACT2000_IOCTL_SETPORT    1
-#define ACT2000_IOCTL_GETPORT    2
-#define ACT2000_IOCTL_SETIRQ     3
-#define ACT2000_IOCTL_GETIRQ     4
-#define ACT2000_IOCTL_SETBUS     5
-#define ACT2000_IOCTL_GETBUS     6
-#define ACT2000_IOCTL_SETPROTO   7
-#define ACT2000_IOCTL_GETPROTO   8
-#define ACT2000_IOCTL_SETMSN     9
-#define ACT2000_IOCTL_GETMSN    10
-#define ACT2000_IOCTL_LOADBOOT  11
-#define ACT2000_IOCTL_ADDCARD   12
-
-#define ACT2000_IOCTL_TEST      98
-#define ACT2000_IOCTL_DEBUGVAR  99
-
-#define ACT2000_BUS_ISA          1
-#define ACT2000_BUS_MCA          2
-#define ACT2000_BUS_PCMCIA       3
-
-/* Struct for adding new cards */
-typedef struct act2000_cdef {
-       int bus;
-       int port;
-       int irq;
-       char id[10];
-} act2000_cdef;
-
-/* Struct for downloading firmware */
-typedef struct act2000_ddef {
-       int length;             /* Length of code */
-       char __user *buffer;    /* Ptr. to code   */
-} act2000_ddef;
-
-typedef struct act2000_fwid {
-       char isdn[4];
-       char revlen[2];
-       char revision[504];
-} act2000_fwid;
-
-#if defined(__KERNEL__) || defined(__DEBUGVAR__)
-
-#ifdef __KERNEL__
-/* Kernel includes */
-
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/skbuff.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/ctype.h>
-#include <linux/isdnif.h>
-
-#endif                           /* __KERNEL__ */
-
-#define ACT2000_PORTLEN        8
-
-#define ACT2000_FLAGS_RUNNING  1 /* Cards driver activated */
-#define ACT2000_FLAGS_PVALID   2 /* Cards port is valid    */
-#define ACT2000_FLAGS_IVALID   4 /* Cards irq is valid     */
-#define ACT2000_FLAGS_LOADED   8 /* Firmware loaded        */
-
-#define ACT2000_BCH            2 /* # of channels per card */
-
-/* D-Channel states */
-#define ACT2000_STATE_NULL     0
-#define ACT2000_STATE_ICALL    1
-#define ACT2000_STATE_OCALL    2
-#define ACT2000_STATE_IWAIT    3
-#define ACT2000_STATE_OWAIT    4
-#define ACT2000_STATE_IBWAIT   5
-#define ACT2000_STATE_OBWAIT   6
-#define ACT2000_STATE_BWAIT    7
-#define ACT2000_STATE_BHWAIT   8
-#define ACT2000_STATE_BHWAIT2  9
-#define ACT2000_STATE_DHWAIT  10
-#define ACT2000_STATE_DHWAIT2 11
-#define ACT2000_STATE_BSETUP  12
-#define ACT2000_STATE_ACTIVE  13
-
-#define ACT2000_MAX_QUEUED  8000 /* 2 * maxbuff */
-
-#define ACT2000_LOCK_TX 0
-#define ACT2000_LOCK_RX 1
-
-typedef struct act2000_chan {
-       unsigned short callref;          /* Call Reference              */
-       unsigned short fsm_state;        /* Current D-Channel state     */
-       unsigned short eazmask;          /* EAZ-Mask for this Channel   */
-       short queued;                    /* User-Data Bytes in TX queue */
-       unsigned short plci;
-       unsigned short ncci;
-       unsigned char  l2prot;           /* Layer 2 protocol            */
-       unsigned char  l3prot;           /* Layer 3 protocol            */
-} act2000_chan;
-
-typedef struct msn_entry {
-       char eaz;
-       char msn[16];
-       struct msn_entry *next;
-} msn_entry;
-
-typedef struct irq_data_isa {
-       __u8           *rcvptr;
-       __u16           rcvidx;
-       __u16           rcvlen;
-       struct sk_buff *rcvskb;
-       __u8            rcvignore;
-       __u8            rcvhdr[8];
-} irq_data_isa;
-
-typedef union act2000_irq_data {
-       irq_data_isa isa;
-} act2000_irq_data;
-
-/*
- * Per card driver data
- */
-typedef struct act2000_card {
-       unsigned short port;            /* Base-port-address                */
-       unsigned short irq;             /* Interrupt                        */
-       u_char ptype;                   /* Protocol type (1TR6 or Euro)     */
-       u_char bus;                     /* Cardtype (ISA, MCA, PCMCIA)      */
-       struct act2000_card *next;      /* Pointer to next device struct    */
-       spinlock_t lock;                /* protect critical operations      */
-       int myid;                       /* Driver-Nr. assigned by linklevel */
-       unsigned long flags;            /* Statusflags                      */
-       unsigned long ilock;            /* Semaphores for IRQ-Routines      */
-       struct sk_buff_head rcvq;       /* Receive-Message queue            */
-       struct sk_buff_head sndq;       /* Send-Message queue               */
-       struct sk_buff_head ackq;       /* Data-Ack-Message queue           */
-       u_char *ack_msg;                /* Ptr to User Data in User skb     */
-       __u16 need_b3ack;               /* Flag: Need ACK for current skb   */
-       struct sk_buff *sbuf;           /* skb which is currently sent      */
-       struct timer_list ptimer;       /* Poll timer                       */
-       struct work_struct snd_tq;      /* Task struct for xmit bh          */
-       struct work_struct rcv_tq;      /* Task struct for rcv bh           */
-       struct work_struct poll_tq;     /* Task struct for polled rcv bh    */
-       msn_entry *msn_list;
-       unsigned short msgnum;          /* Message number for sending       */
-       spinlock_t mnlock;              /* lock for msgnum                  */
-       act2000_chan bch[ACT2000_BCH];  /* B-Channel status/control         */
-       char   status_buf[256];         /* Buffer for status messages       */
-       char   *status_buf_read;
-       char   *status_buf_write;
-       char   *status_buf_end;
-       act2000_irq_data idat;          /* Data used for IRQ handler        */
-       isdn_if interface;              /* Interface to upper layer         */
-       char regname[35];               /* Name used for request_region     */
-} act2000_card;
-
-static inline void act2000_schedule_tx(act2000_card *card)
-{
-       schedule_work(&card->snd_tq);
-}
-
-static inline void act2000_schedule_rx(act2000_card *card)
-{
-       schedule_work(&card->rcv_tq);
-}
-
-static inline void act2000_schedule_poll(act2000_card *card)
-{
-       schedule_work(&card->poll_tq);
-}
-
-extern char *act2000_find_eaz(act2000_card *, char);
-
-#endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif                          /* act2000_h */
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
deleted file mode 100644 (file)
index b5fad29..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-/* $Id: act2000_isa.c,v 1.11.6.3 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
- *
- * Author       Fritz Elfert
- * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#include "act2000.h"
-#include "act2000_isa.h"
-#include "capi.h"
-
-/*
- * Reset Controller, then try to read the Card's signature.
- + Return:
- *   1 = Signature found.
- *   0 = Signature not found.
- */
-static int
-act2000_isa_reset(unsigned short portbase)
-{
-       unsigned char reg;
-       int i;
-       int found;
-       int serial = 0;
-
-       found = 0;
-       if ((reg = inb(portbase + ISA_COR)) != 0xff) {
-               outb(reg | ISA_COR_RESET, portbase + ISA_COR);
-               mdelay(10);
-               outb(reg, portbase + ISA_COR);
-               mdelay(10);
-
-               for (i = 0; i < 16; i++) {
-                       if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
-                               serial |= 0x10000;
-                       serial >>= 1;
-               }
-               if (serial == ISA_SER_ID)
-                       found++;
-       }
-       return found;
-}
-
-int
-act2000_isa_detect(unsigned short portbase)
-{
-       int ret = 0;
-
-       if (request_region(portbase, ACT2000_PORTLEN, "act2000isa")) {
-               ret = act2000_isa_reset(portbase);
-               release_region(portbase, ISA_REGION);
-       }
-       return ret;
-}
-
-static irqreturn_t
-act2000_isa_interrupt(int dummy, void *dev_id)
-{
-       act2000_card *card = dev_id;
-       u_char istatus;
-
-       istatus = (inb(ISA_PORT_ISR) & 0x07);
-       if (istatus & ISA_ISR_OUT) {
-               /* RX fifo has data */
-               istatus &= ISA_ISR_OUT_MASK;
-               outb(0, ISA_PORT_SIS);
-               act2000_isa_receive(card);
-               outb(ISA_SIS_INT, ISA_PORT_SIS);
-       }
-       if (istatus & ISA_ISR_ERR) {
-               /* Error Interrupt */
-               istatus &= ISA_ISR_ERR_MASK;
-               printk(KERN_WARNING "act2000: errIRQ\n");
-       }
-       if (istatus)
-               printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", card->irq, istatus);
-       return IRQ_HANDLED;
-}
-
-static void
-act2000_isa_select_irq(act2000_card *card)
-{
-       unsigned char reg;
-
-       reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
-       switch (card->irq) {
-       case 3:
-               reg = ISA_COR_IRQ03;
-               break;
-       case 5:
-               reg = ISA_COR_IRQ05;
-               break;
-       case 7:
-               reg = ISA_COR_IRQ07;
-               break;
-       case 10:
-               reg = ISA_COR_IRQ10;
-               break;
-       case 11:
-               reg = ISA_COR_IRQ11;
-               break;
-       case 12:
-               reg = ISA_COR_IRQ12;
-               break;
-       case 15:
-               reg = ISA_COR_IRQ15;
-               break;
-       }
-       outb(reg, ISA_PORT_COR);
-}
-
-static void
-act2000_isa_enable_irq(act2000_card *card)
-{
-       act2000_isa_select_irq(card);
-       /* Enable READ irq */
-       outb(ISA_SIS_INT, ISA_PORT_SIS);
-}
-
-/*
- * Install interrupt handler, enable irq on card.
- * If irq is -1, choose next free irq, else irq is given explicitly.
- */
-int
-act2000_isa_config_irq(act2000_card *card, short irq)
-{
-       int old_irq;
-
-       if (card->flags & ACT2000_FLAGS_IVALID) {
-               free_irq(card->irq, card);
-       }
-       card->flags &= ~ACT2000_FLAGS_IVALID;
-       outb(ISA_COR_IRQOFF, ISA_PORT_COR);
-       if (!irq)
-               return 0;
-
-       old_irq = card->irq;
-       card->irq = irq;
-       if (request_irq(irq, &act2000_isa_interrupt, 0, card->regname, card)) {
-               card->irq = old_irq;
-               card->flags |= ACT2000_FLAGS_IVALID;
-               printk(KERN_WARNING
-                      "act2000: Could not request irq %d\n", irq);
-               return -EBUSY;
-       } else {
-               act2000_isa_select_irq(card);
-               /* Disable READ and WRITE irq */
-               outb(0, ISA_PORT_SIS);
-               outb(0, ISA_PORT_SOS);
-       }
-       return 0;
-}
-
-int
-act2000_isa_config_port(act2000_card *card, unsigned short portbase)
-{
-       if (card->flags & ACT2000_FLAGS_PVALID) {
-               release_region(card->port, ISA_REGION);
-               card->flags &= ~ACT2000_FLAGS_PVALID;
-       }
-       if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
-               return -EBUSY;
-       else {
-               card->port = portbase;
-               card->flags |= ACT2000_FLAGS_PVALID;
-               return 0;
-       }
-}
-
-/*
- * Release ressources, used by an adaptor.
- */
-void
-act2000_isa_release(act2000_card *card)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       if (card->flags & ACT2000_FLAGS_IVALID)
-               free_irq(card->irq, card);
-
-       card->flags &= ~ACT2000_FLAGS_IVALID;
-       if (card->flags & ACT2000_FLAGS_PVALID)
-               release_region(card->port, ISA_REGION);
-       card->flags &= ~ACT2000_FLAGS_PVALID;
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static int
-act2000_isa_writeb(act2000_card *card, u_char data)
-{
-       u_char timeout = 40;
-
-       while (timeout) {
-               if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
-                       outb(data, ISA_PORT_SDO);
-                       return 0;
-               } else {
-                       timeout--;
-                       udelay(10);
-               }
-       }
-       return 1;
-}
-
-static int
-act2000_isa_readb(act2000_card *card, u_char *data)
-{
-       u_char timeout = 40;
-
-       while (timeout) {
-               if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
-                       *data = inb(ISA_PORT_SDI);
-                       return 0;
-               } else {
-                       timeout--;
-                       udelay(10);
-               }
-       }
-       return 1;
-}
-
-void
-act2000_isa_receive(act2000_card *card)
-{
-       u_char c;
-
-       if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
-               return;
-       while (!act2000_isa_readb(card, &c)) {
-               if (card->idat.isa.rcvidx < 8) {
-                       card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
-                       if (card->idat.isa.rcvidx == 8) {
-                               int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
-
-                               if (valid) {
-                                       card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
-                                       card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
-                                       if (card->idat.isa.rcvskb == NULL) {
-                                               card->idat.isa.rcvignore = 1;
-                                               printk(KERN_WARNING
-                                                      "act2000_isa_receive: no memory\n");
-                                               test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
-                                               return;
-                                       }
-                                       memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
-                                       card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
-                               } else {
-                                       card->idat.isa.rcvidx = 0;
-                                       printk(KERN_WARNING
-                                              "act2000_isa_receive: Invalid CAPI msg\n");
-                                       {
-                                               int i; __u8 *p; __u8 *t; __u8 tmp[30];
-                                               for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, t = tmp; i < 8; i++)
-                                                       t += sprintf(t, "%02x ", *(p++));
-                                               printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
-                                       }
-                               }
-                       }
-               } else {
-                       if (!card->idat.isa.rcvignore)
-                               *card->idat.isa.rcvptr++ = c;
-                       if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
-                               if (!card->idat.isa.rcvignore) {
-                                       skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
-                                       act2000_schedule_rx(card);
-                               }
-                               card->idat.isa.rcvidx = 0;
-                               card->idat.isa.rcvlen = 8;
-                               card->idat.isa.rcvignore = 0;
-                               card->idat.isa.rcvskb = NULL;
-                               card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
-                       }
-               }
-       }
-       if (!(card->flags & ACT2000_FLAGS_IVALID)) {
-               /* In polling mode, schedule myself */
-               if ((card->idat.isa.rcvidx) &&
-                   (card->idat.isa.rcvignore ||
-                    (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
-                       act2000_schedule_poll(card);
-       }
-       test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
-}
-
-void
-act2000_isa_send(act2000_card *card)
-{
-       unsigned long flags;
-       struct sk_buff *skb;
-       actcapi_msg *msg;
-       int l;
-
-       if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
-               return;
-       while (1) {
-               spin_lock_irqsave(&card->lock, flags);
-               if (!(card->sbuf)) {
-                       if ((card->sbuf = skb_dequeue(&card->sndq))) {
-                               card->ack_msg = card->sbuf->data;
-                               msg = (actcapi_msg *)card->sbuf->data;
-                               if ((msg->hdr.cmd.cmd == 0x86) &&
-                                   (msg->hdr.cmd.subcmd == 0)) {
-                                       /* Save flags in message */
-                                       card->need_b3ack = msg->msg.data_b3_req.flags;
-                                       msg->msg.data_b3_req.flags = 0;
-                               }
-                       }
-               }
-               spin_unlock_irqrestore(&card->lock, flags);
-               if (!(card->sbuf)) {
-                       /* No more data to send */
-                       test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
-                       return;
-               }
-               skb = card->sbuf;
-               l = 0;
-               while (skb->len) {
-                       if (act2000_isa_writeb(card, *(skb->data))) {
-                               /* Fifo is full, but more data to send */
-                               test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
-                               /* Schedule myself */
-                               act2000_schedule_tx(card);
-                               return;
-                       }
-                       skb_pull(skb, 1);
-                       l++;
-               }
-               msg = (actcapi_msg *)card->ack_msg;
-               if ((msg->hdr.cmd.cmd == 0x86) &&
-                   (msg->hdr.cmd.subcmd == 0)) {
-                       /*
-                        * If it's user data, reset data-ptr
-                        * and put skb into ackq.
-                        */
-                       skb->data = card->ack_msg;
-                       /* Restore flags in message */
-                       msg->msg.data_b3_req.flags = card->need_b3ack;
-                       skb_queue_tail(&card->ackq, skb);
-               } else
-                       dev_kfree_skb(skb);
-               card->sbuf = NULL;
-       }
-}
-
-/*
- * Get firmware ID, check for 'ISDN' signature.
- */
-static int
-act2000_isa_getid(act2000_card *card)
-{
-
-       act2000_fwid fid;
-       u_char *p = (u_char *)&fid;
-       int count = 0;
-
-       while (1) {
-               if (count > 510)
-                       return -EPROTO;
-               if (act2000_isa_readb(card, p++))
-                       break;
-               count++;
-       }
-       if (count <= 20) {
-               printk(KERN_WARNING "act2000: No Firmware-ID!\n");
-               return -ETIME;
-       }
-       *p = '\0';
-       fid.revlen[0] = '\0';
-       if (strcmp(fid.isdn, "ISDN")) {
-               printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
-               return -EPROTO;
-       }
-       if ((p = strchr(fid.revision, '\n')))
-               *p = '\0';
-       printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
-       if (card->flags & ACT2000_FLAGS_IVALID) {
-               printk(KERN_DEBUG "Enabling Interrupts ...\n");
-               act2000_isa_enable_irq(card);
-       }
-       return 0;
-}
-
-/*
- * Download microcode into card, check Firmware signature.
- */
-int
-act2000_isa_download(act2000_card *card, act2000_ddef __user *cb)
-{
-       unsigned int length;
-       int l;
-       int c;
-       long timeout;
-       u_char *b;
-       u_char __user *p;
-       u_char *buf;
-       act2000_ddef cblock;
-
-       if (!act2000_isa_reset(card->port))
-               return -ENXIO;
-       msleep_interruptible(500);
-       if (copy_from_user(&cblock, cb, sizeof(cblock)))
-               return -EFAULT;
-       length = cblock.length;
-       p = cblock.buffer;
-       if (!access_ok(VERIFY_READ, p, length))
-               return -EFAULT;
-       buf = kmalloc(1024, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       timeout = 0;
-       while (length) {
-               l = (length > 1024) ? 1024 : length;
-               c = 0;
-               b = buf;
-               if (copy_from_user(buf, p, l)) {
-                       kfree(buf);
-                       return -EFAULT;
-               }
-               while (c < l) {
-                       if (act2000_isa_writeb(card, *b++)) {
-                               printk(KERN_WARNING
-                                      "act2000: loader timed out"
-                                      " len=%d c=%d\n", length, c);
-                               kfree(buf);
-                               return -ETIME;
-                       }
-                       c++;
-               }
-               length -= l;
-               p += l;
-       }
-       kfree(buf);
-       msleep_interruptible(500);
-       return (act2000_isa_getid(card));
-}
diff --git a/drivers/isdn/act2000/act2000_isa.h b/drivers/isdn/act2000/act2000_isa.h
deleted file mode 100644 (file)
index 1a72898..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* $Id: act2000_isa.h,v 1.4.6.1 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
- *
- * Author       Fritz Elfert
- * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#ifndef act2000_isa_h
-#define act2000_isa_h
-
-#define ISA_POLL_LOOP 40        /* Try to read-write before give up */
-
-typedef enum {
-       INT_NO_CHANGE = 0,      /* Do not change the Mask */
-       INT_ON = 1,             /* Set to Enable */
-       INT_OFF = 2,            /* Set to Disable */
-} ISA_INT_T;
-
-/**************************************************************************/
-/*      Configuration Register COR (RW)                                   */
-/**************************************************************************/
-/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
-/* Soft Res|  IRQM  |        IRQ Select        |   N/A  |  WAIT  |Proc err */
-/**************************************************************************/
-#define        ISA_COR             0   /* Offset for ISA config register */
-#define        ISA_COR_PERR     0x01   /* Processor Error Enabled        */
-#define        ISA_COR_WS       0x02   /* Insert Wait State if 1         */
-#define        ISA_COR_IRQOFF   0x38   /* No Interrupt                   */
-#define        ISA_COR_IRQ07    0x30   /* IRQ 7 Enable                   */
-#define        ISA_COR_IRQ05    0x28   /* IRQ 5 Enable                   */
-#define        ISA_COR_IRQ03    0x20   /* IRQ 3 Enable                   */
-#define        ISA_COR_IRQ10    0x18   /* IRQ 10 Enable                  */
-#define        ISA_COR_IRQ11    0x10   /* IRQ 11 Enable                  */
-#define        ISA_COR_IRQ12    0x08   /* IRQ 12 Enable                  */
-#define        ISA_COR_IRQ15    0x00   /* IRQ 15 Enable                  */
-#define        ISA_COR_IRQPULSE 0x40   /* 0 = Level 1 = Pulse Interrupt  */
-#define        ISA_COR_RESET    0x80   /* Soft Reset for Transputer      */
-
-/**************************************************************************/
-/*      Interrupt Source Register ISR (RO)                                */
-/**************************************************************************/
-/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
-/*   N/A   |  N/A   |   N/A  |Err sig |Ser ID  |IN Intr |Out Intr| Error  */
-/**************************************************************************/
-#define        ISA_ISR             1   /* Offset for Interrupt Register  */
-#define        ISA_ISR_ERR      0x01   /* Error Interrupt                */
-#define        ISA_ISR_OUT      0x02   /* Output Interrupt               */
-#define        ISA_ISR_INP      0x04   /* Input Interrupt                */
-#define        ISA_ISR_SERIAL   0x08   /* Read out Serial ID after Reset */
-#define        ISA_ISR_ERRSIG   0x10   /* Error Signal Input             */
-#define        ISA_ISR_ERR_MASK 0xfe    /* Mask Error Interrupt           */
-#define        ISA_ISR_OUT_MASK 0xfd    /* Mask Output Interrupt          */
-#define        ISA_ISR_INP_MASK 0xfb    /* Mask Input Interrupt           */
-
-/* Signature delivered after Reset at ISA_ISR_SERIAL (LSB first)          */
-#define        ISA_SER_ID     0x0201   /* ID for ISA Card                */
-
-/**************************************************************************/
-/*      EEPROM Register EPR (RW)                                          */
-/**************************************************************************/
-/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
-/*   N/A   |  N/A   |   N/A  |ROM Hold| ROM CS |ROM CLK | ROM IN |ROM Out */
-/**************************************************************************/
-#define        ISA_EPR             2   /* Offset for this Register       */
-#define        ISA_EPR_OUT      0x01   /* Rome Register Out (RO)         */
-#define        ISA_EPR_IN       0x02   /* Rom Register In (WR)           */
-#define        ISA_EPR_CLK      0x04   /* Rom Clock (WR)                 */
-#define        ISA_EPR_CS       0x08   /* Rom Cip Select (WR)            */
-#define        ISA_EPR_HOLD     0x10   /* Rom Hold Signal (WR)           */
-
-/**************************************************************************/
-/*      EEPROM enable Register EER (unused)                               */
-/**************************************************************************/
-#define        ISA_EER             3   /* Offset for this Register       */
-
-/**************************************************************************/
-/*      SLC Data Input SDI (RO)                                           */
-/**************************************************************************/
-#define        ISA_SDI             4   /* Offset for this Register       */
-
-/**************************************************************************/
-/*      SLC Data Output SDO (WO)                                          */
-/**************************************************************************/
-#define        ISA_SDO             5   /* Offset for this Register       */
-
-/**************************************************************************/
-/*      IMS C011 Mode 2 Input Status Register for INMOS CPU SIS (RW)      */
-/**************************************************************************/
-/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
-/*   N/A   |  N/A   |   N/A  |  N/A   |   N/A  |   N/A  |Int Ena |Data Pre */
-/**************************************************************************/
-#define        ISA_SIS             6   /* Offset for this Register       */
-#define        ISA_SIS_READY    0x01   /* If 1 : data is available       */
-#define        ISA_SIS_INT      0x02   /* Enable Interrupt for READ      */
-
-/**************************************************************************/
-/*      IMS C011 Mode 2 Output Status Register from INMOS CPU SOS (RW)    */
-/**************************************************************************/
-/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
-/*   N/A   |  N/A   |   N/A  |  N/A   |   N/A  |   N/A  |Int Ena |Out Rdy */
-/**************************************************************************/
-#define        ISA_SOS             7   /* Offset for this Register       */
-#define        ISA_SOS_READY    0x01   /* If 1 : we can write Data       */
-#define        ISA_SOS_INT      0x02   /* Enable Interrupt for WRITE     */
-
-#define        ISA_REGION          8   /* Number of Registers            */
-
-
-/* Macros for accessing ports */
-#define ISA_PORT_COR (card->port + ISA_COR)
-#define ISA_PORT_ISR (card->port + ISA_ISR)
-#define ISA_PORT_EPR (card->port + ISA_EPR)
-#define ISA_PORT_EER (card->port + ISA_EER)
-#define ISA_PORT_SDI (card->port + ISA_SDI)
-#define ISA_PORT_SDO (card->port + ISA_SDO)
-#define ISA_PORT_SIS (card->port + ISA_SIS)
-#define ISA_PORT_SOS (card->port + ISA_SOS)
-
-/* Prototypes */
-
-extern int act2000_isa_detect(unsigned short portbase);
-extern int act2000_isa_config_irq(act2000_card *card, short irq);
-extern int act2000_isa_config_port(act2000_card *card, unsigned short portbase);
-extern int act2000_isa_download(act2000_card *card, act2000_ddef __user *cb);
-extern void act2000_isa_release(act2000_card *card);
-extern void act2000_isa_receive(act2000_card *card);
-extern void act2000_isa_send(act2000_card *card);
-
-#endif                          /* act2000_isa_h */
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
deleted file mode 100644 (file)
index 3f66ca2..0000000
+++ /dev/null
@@ -1,1180 +0,0 @@
-/* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
- * CAPI encoder/decoder
- *
- * Author       Fritz Elfert
- * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#include "act2000.h"
-#include "capi.h"
-
-static actcapi_msgdsc valid_msg[] = {
-       {{ 0x86, 0x02}, "DATA_B3_IND"},       /* DATA_B3_IND/CONF must be first because of speed!!! */
-       {{ 0x86, 0x01}, "DATA_B3_CONF"},
-       {{ 0x02, 0x01}, "CONNECT_CONF"},
-       {{ 0x02, 0x02}, "CONNECT_IND"},
-       {{ 0x09, 0x01}, "CONNECT_INFO_CONF"},
-       {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"},
-       {{ 0x04, 0x01}, "DISCONNECT_CONF"},
-       {{ 0x04, 0x02}, "DISCONNECT_IND"},
-       {{ 0x05, 0x01}, "LISTEN_CONF"},
-       {{ 0x06, 0x01}, "GET_PARAMS_CONF"},
-       {{ 0x07, 0x01}, "INFO_CONF"},
-       {{ 0x07, 0x02}, "INFO_IND"},
-       {{ 0x08, 0x01}, "DATA_CONF"},
-       {{ 0x08, 0x02}, "DATA_IND"},
-       {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"},
-       {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"},
-       {{ 0x81, 0x01}, "LISTEN_B3_CONF"},
-       {{ 0x82, 0x01}, "CONNECT_B3_CONF"},
-       {{ 0x82, 0x02}, "CONNECT_B3_IND"},
-       {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"},
-       {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"},
-       {{ 0x84, 0x02}, "DISCONNECT_B3_IND"},
-       {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"},
-       {{ 0x01, 0x01}, "RESET_B3_CONF"},
-       {{ 0x01, 0x02}, "RESET_B3_IND"},
-       /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */
-       {{ 0xff, 0x01}, "MANUFACTURER_CONF"},
-       {{ 0xff, 0x02}, "MANUFACTURER_IND"},
-#ifdef DEBUG_MSG
-       /* Requests */
-       {{ 0x01, 0x00}, "RESET_B3_REQ"},
-       {{ 0x02, 0x00}, "CONNECT_REQ"},
-       {{ 0x04, 0x00}, "DISCONNECT_REQ"},
-       {{ 0x05, 0x00}, "LISTEN_REQ"},
-       {{ 0x06, 0x00}, "GET_PARAMS_REQ"},
-       {{ 0x07, 0x00}, "INFO_REQ"},
-       {{ 0x08, 0x00}, "DATA_REQ"},
-       {{ 0x09, 0x00}, "CONNECT_INFO_REQ"},
-       {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"},
-       {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"},
-       {{ 0x81, 0x00}, "LISTEN_B3_REQ"},
-       {{ 0x82, 0x00}, "CONNECT_B3_REQ"},
-       {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"},
-       {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"},
-       {{ 0x86, 0x00}, "DATA_B3_REQ"},
-       {{ 0xff, 0x00}, "MANUFACTURER_REQ"},
-       /* Responses */
-       {{ 0x01, 0x03}, "RESET_B3_RESP"},
-       {{ 0x02, 0x03}, "CONNECT_RESP"},
-       {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"},
-       {{ 0x04, 0x03}, "DISCONNECT_RESP"},
-       {{ 0x07, 0x03}, "INFO_RESP"},
-       {{ 0x08, 0x03}, "DATA_RESP"},
-       {{ 0x82, 0x03}, "CONNECT_B3_RESP"},
-       {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"},
-       {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
-       {{ 0x86, 0x03}, "DATA_B3_RESP"},
-       {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
-#endif
-       {{ 0x00, 0x00}, NULL},
-};
-#define num_valid_imsg 27 /* MANUFACTURER_IND */
-
-/*
- * Check for a valid incoming CAPI message.
- * Return:
- *   0 = Invalid message
- *   1 = Valid message, no B-Channel-data
- *   2 = Valid message, B-Channel-data
- */
-int
-actcapi_chkhdr(act2000_card *card, actcapi_msghdr *hdr)
-{
-       int i;
-
-       if (hdr->applicationID != 1)
-               return 0;
-       if (hdr->len < 9)
-               return 0;
-       for (i = 0; i < num_valid_imsg; i++)
-               if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) &&
-                   (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) {
-                       return (i ? 1 : 2);
-               }
-       return 0;
-}
-
-#define ACTCAPI_MKHDR(l, c, s) {                               \
-               skb = alloc_skb(l + 8, GFP_ATOMIC);             \
-               if (skb) {                                      \
-                       m = (actcapi_msg *)skb_put(skb, l + 8); \
-                       m->hdr.len = l + 8;                     \
-                       m->hdr.applicationID = 1;               \
-                       m->hdr.cmd.cmd = c;                     \
-                       m->hdr.cmd.subcmd = s;                  \
-                       m->hdr.msgnum = actcapi_nextsmsg(card); \
-               } else m = NULL;                                \
-       }
-
-#define ACTCAPI_CHKSKB if (!skb) {                                     \
-               printk(KERN_WARNING "actcapi: alloc_skb failed\n");     \
-               return;                                                 \
-       }
-
-#define ACTCAPI_QUEUE_TX {                             \
-               actcapi_debug_msg(skb, 1);              \
-               skb_queue_tail(&card->sndq, skb);       \
-               act2000_schedule_tx(card);              \
-       }
-
-int
-actcapi_listen_req(act2000_card *card)
-{
-       __u16 eazmask = 0;
-       int i;
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       for (i = 0; i < ACT2000_BCH; i++)
-               eazmask |= card->bch[i].eazmask;
-       ACTCAPI_MKHDR(9, 0x05, 0x00);
-       if (!skb) {
-               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
-               return -ENOMEM;
-       }
-       m->msg.listen_req.controller = 0;
-       m->msg.listen_req.infomask = 0x3f; /* All information */
-       m->msg.listen_req.eazmask = eazmask;
-       m->msg.listen_req.simask = (eazmask) ? 0x86 : 0; /* All SI's  */
-       ACTCAPI_QUEUE_TX;
-       return 0;
-}
-
-int
-actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
-                   char eaz, int si1, int si2)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00);
-       if (!skb) {
-               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
-               chan->fsm_state = ACT2000_STATE_NULL;
-               return -ENOMEM;
-       }
-       m->msg.connect_req.controller = 0;
-       m->msg.connect_req.bchan = 0x83;
-       m->msg.connect_req.infomask = 0x3f;
-       m->msg.connect_req.si1 = si1;
-       m->msg.connect_req.si2 = si2;
-       m->msg.connect_req.eaz = eaz ? eaz : '0';
-       m->msg.connect_req.addr.len = strlen(phone) + 1;
-       m->msg.connect_req.addr.tnp = 0x81;
-       memcpy(m->msg.connect_req.addr.num, phone, strlen(phone));
-       chan->callref = m->hdr.msgnum;
-       ACTCAPI_QUEUE_TX;
-       return 0;
-}
-
-static void
-actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(17, 0x82, 0x00);
-       ACTCAPI_CHKSKB;
-       m->msg.connect_b3_req.plci = chan->plci;
-       memset(&m->msg.connect_b3_req.ncpi, 0,
-              sizeof(m->msg.connect_b3_req.ncpi));
-       m->msg.connect_b3_req.ncpi.len = 13;
-       m->msg.connect_b3_req.ncpi.modulo = 8;
-       ACTCAPI_QUEUE_TX;
-}
-
-/*
- * Set net type (1TR6) or (EDSS1)
- */
-int
-actcapi_manufacturer_req_net(act2000_card *card)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(5, 0xff, 0x00);
-       if (!skb) {
-               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
-               return -ENOMEM;
-       }
-       m->msg.manufacturer_req_net.manuf_msg = 0x11;
-       m->msg.manufacturer_req_net.controller = 1;
-       m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO) ? 1 : 0;
-       ACTCAPI_QUEUE_TX;
-       printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n",
-              card->interface.id, (card->ptype == ISDN_PTYPE_EURO) ? "euro" : "1tr6");
-       card->interface.features &=
-               ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6);
-       card->interface.features |=
-               ((card->ptype == ISDN_PTYPE_EURO) ? ISDN_FEATURE_P_EURO : ISDN_FEATURE_P_1TR6);
-       return 0;
-}
-
-/*
- * Switch V.42 on or off
- */
-#if 0
-int
-actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(8, 0xff, 0x00);
-       if (!skb) {
-
-               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
-               return -ENOMEM;
-       }
-       m->msg.manufacturer_req_v42.manuf_msg = 0x10;
-       m->msg.manufacturer_req_v42.controller = 0;
-       m->msg.manufacturer_req_v42.v42control = (arg ? 1 : 0);
-       ACTCAPI_QUEUE_TX;
-       return 0;
-}
-#endif  /*  0  */
-
-/*
- * Set error-handler
- */
-int
-actcapi_manufacturer_req_errh(act2000_card *card)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(4, 0xff, 0x00);
-       if (!skb) {
-
-               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
-               return -ENOMEM;
-       }
-       m->msg.manufacturer_req_err.manuf_msg = 0x03;
-       m->msg.manufacturer_req_err.controller = 0;
-       ACTCAPI_QUEUE_TX;
-       return 0;
-}
-
-/*
- * Set MSN-Mapping.
- */
-int
-actcapi_manufacturer_req_msn(act2000_card *card)
-{
-       msn_entry *p = card->msn_list;
-       actcapi_msg *m;
-       struct sk_buff *skb;
-       int len;
-
-       while (p) {
-               int i;
-
-               len = strlen(p->msn);
-               for (i = 0; i < 2; i++) {
-                       ACTCAPI_MKHDR(6 + len, 0xff, 0x00);
-                       if (!skb) {
-                               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
-                               return -ENOMEM;
-                       }
-                       m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i;
-                       m->msg.manufacturer_req_msn.controller = 0;
-                       m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz;
-                       m->msg.manufacturer_req_msn.msnmap.len = len;
-                       memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len);
-                       ACTCAPI_QUEUE_TX;
-               }
-               p = p->next;
-       }
-       return 0;
-}
-
-void
-actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(10, 0x40, 0x00);
-       ACTCAPI_CHKSKB;
-       m->msg.select_b2_protocol_req.plci = chan->plci;
-       memset(&m->msg.select_b2_protocol_req.dlpd, 0,
-              sizeof(m->msg.select_b2_protocol_req.dlpd));
-       m->msg.select_b2_protocol_req.dlpd.len = 6;
-       switch (chan->l2prot) {
-       case ISDN_PROTO_L2_TRANS:
-               m->msg.select_b2_protocol_req.protocol = 0x03;
-               m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
-               break;
-       case ISDN_PROTO_L2_HDLC:
-               m->msg.select_b2_protocol_req.protocol = 0x02;
-               m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
-               break;
-       case ISDN_PROTO_L2_X75I:
-       case ISDN_PROTO_L2_X75UI:
-       case ISDN_PROTO_L2_X75BUI:
-               m->msg.select_b2_protocol_req.protocol = 0x01;
-               m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
-               m->msg.select_b2_protocol_req.dlpd.laa = 3;
-               m->msg.select_b2_protocol_req.dlpd.lab = 1;
-               m->msg.select_b2_protocol_req.dlpd.win = 7;
-               m->msg.select_b2_protocol_req.dlpd.modulo = 8;
-               break;
-       }
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(17, 0x80, 0x00);
-       ACTCAPI_CHKSKB;
-       m->msg.select_b3_protocol_req.plci = chan->plci;
-       memset(&m->msg.select_b3_protocol_req.ncpd, 0,
-              sizeof(m->msg.select_b3_protocol_req.ncpd));
-       switch (chan->l3prot) {
-       case ISDN_PROTO_L3_TRANS:
-               m->msg.select_b3_protocol_req.protocol = 0x04;
-               m->msg.select_b3_protocol_req.ncpd.len = 13;
-               m->msg.select_b3_protocol_req.ncpd.modulo = 8;
-               break;
-       }
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(2, 0x81, 0x00);
-       ACTCAPI_CHKSKB;
-       m->msg.listen_b3_req.plci = chan->plci;
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(3, 0x04, 0x00);
-       ACTCAPI_CHKSKB;
-       m->msg.disconnect_req.plci = chan->plci;
-       m->msg.disconnect_req.cause = 0;
-       ACTCAPI_QUEUE_TX;
-}
-
-void
-actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(17, 0x84, 0x00);
-       ACTCAPI_CHKSKB;
-       m->msg.disconnect_b3_req.ncci = chan->ncci;
-       memset(&m->msg.disconnect_b3_req.ncpi, 0,
-              sizeof(m->msg.disconnect_b3_req.ncpi));
-       m->msg.disconnect_b3_req.ncpi.len = 13;
-       m->msg.disconnect_b3_req.ncpi.modulo = 8;
-       chan->fsm_state = ACT2000_STATE_BHWAIT;
-       ACTCAPI_QUEUE_TX;
-}
-
-void
-actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(3, 0x02, 0x03);
-       ACTCAPI_CHKSKB;
-       m->msg.connect_resp.plci = chan->plci;
-       m->msg.connect_resp.rejectcause = cause;
-       if (cause) {
-               chan->fsm_state = ACT2000_STATE_NULL;
-               chan->plci = 0x8000;
-       } else
-               chan->fsm_state = ACT2000_STATE_IWAIT;
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(2, 0x03, 0x03);
-       ACTCAPI_CHKSKB;
-       m->msg.connect_resp.plci = chan->plci;
-       if (chan->fsm_state == ACT2000_STATE_IWAIT)
-               chan->fsm_state = ACT2000_STATE_IBWAIT;
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR((rejectcause ? 3 : 17), 0x82, 0x03);
-       ACTCAPI_CHKSKB;
-       m->msg.connect_b3_resp.ncci = chan->ncci;
-       m->msg.connect_b3_resp.rejectcause = rejectcause;
-       if (!rejectcause) {
-               memset(&m->msg.connect_b3_resp.ncpi, 0,
-                      sizeof(m->msg.connect_b3_resp.ncpi));
-               m->msg.connect_b3_resp.ncpi.len = 13;
-               m->msg.connect_b3_resp.ncpi.modulo = 8;
-               chan->fsm_state = ACT2000_STATE_BWAIT;
-       }
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(2, 0x83, 0x03);
-       ACTCAPI_CHKSKB;
-       m->msg.connect_b3_active_resp.ncci = chan->ncci;
-       chan->fsm_state = ACT2000_STATE_ACTIVE;
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_info_resp(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(2, 0x07, 0x03);
-       ACTCAPI_CHKSKB;
-       m->msg.info_resp.plci = chan->plci;
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(2, 0x84, 0x03);
-       ACTCAPI_CHKSKB;
-       m->msg.disconnect_b3_resp.ncci = chan->ncci;
-       chan->ncci = 0x8000;
-       chan->queued = 0;
-       ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
-{
-       actcapi_msg *m;
-       struct sk_buff *skb;
-
-       ACTCAPI_MKHDR(2, 0x04, 0x03);
-       ACTCAPI_CHKSKB;
-       m->msg.disconnect_resp.plci = chan->plci;
-       chan->plci = 0x8000;
-       ACTCAPI_QUEUE_TX;
-}
-
-static int
-new_plci(act2000_card *card, __u16 plci)
-{
-       int i;
-       for (i = 0; i < ACT2000_BCH; i++)
-               if (card->bch[i].plci == 0x8000) {
-                       card->bch[i].plci = plci;
-                       return i;
-               }
-       return -1;
-}
-
-static int
-find_plci(act2000_card *card, __u16 plci)
-{
-       int i;
-       for (i = 0; i < ACT2000_BCH; i++)
-               if (card->bch[i].plci == plci)
-                       return i;
-       return -1;
-}
-
-static int
-find_ncci(act2000_card *card, __u16 ncci)
-{
-       int i;
-       for (i = 0; i < ACT2000_BCH; i++)
-               if (card->bch[i].ncci == ncci)
-                       return i;
-       return -1;
-}
-
-static int
-find_dialing(act2000_card *card, __u16 callref)
-{
-       int i;
-       for (i = 0; i < ACT2000_BCH; i++)
-               if ((card->bch[i].callref == callref) &&
-                   (card->bch[i].fsm_state == ACT2000_STATE_OCALL))
-                       return i;
-       return -1;
-}
-
-static int
-actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) {
-       __u16 plci;
-       __u16 ncci;
-       __u16 controller;
-       __u8  blocknr;
-       int chan;
-       actcapi_msg *msg = (actcapi_msg *)skb->data;
-
-       EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, controller, ncci);
-       chan = find_ncci(card, ncci);
-       if (chan < 0)
-               return 0;
-       if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE)
-               return 0;
-       if (card->bch[chan].plci != plci)
-               return 0;
-       blocknr = msg->msg.data_b3_ind.blocknr;
-       skb_pull(skb, 19);
-       card->interface.rcvcallb_skb(card->myid, chan, skb);
-       if (!(skb = alloc_skb(11, GFP_ATOMIC))) {
-               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
-               return 1;
-       }
-       msg = (actcapi_msg *)skb_put(skb, 11);
-       msg->hdr.len = 11;
-       msg->hdr.applicationID = 1;
-       msg->hdr.cmd.cmd = 0x86;
-       msg->hdr.cmd.subcmd = 0x03;
-       msg->hdr.msgnum = actcapi_nextsmsg(card);
-       msg->msg.data_b3_resp.ncci = ncci;
-       msg->msg.data_b3_resp.blocknr = blocknr;
-       ACTCAPI_QUEUE_TX;
-       return 1;
-}
-
-/*
- * Walk over ackq, unlink DATA_B3_REQ from it, if
- * ncci and blocknr are matching.
- * Decrement queued-bytes counter.
- */
-static int
-handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
-       unsigned long flags;
-       struct sk_buff *skb;
-       struct sk_buff *tmp;
-       struct actcapi_msg *m;
-       int ret = 0;
-
-       spin_lock_irqsave(&card->lock, flags);
-       skb = skb_peek(&card->ackq);
-       spin_unlock_irqrestore(&card->lock, flags);
-       if (!skb) {
-               printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
-               return 0;
-       }
-       tmp = skb;
-       while (1) {
-               m = (actcapi_msg *)tmp->data;
-               if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
-                   (m->msg.data_b3_req.blocknr == blocknr)) {
-                       /* found corresponding DATA_B3_REQ */
-                       skb_unlink(tmp, &card->ackq);
-                       chan->queued -= m->msg.data_b3_req.datalen;
-                       if (m->msg.data_b3_req.flags)
-                               ret = m->msg.data_b3_req.datalen;
-                       dev_kfree_skb(tmp);
-                       if (chan->queued < 0)
-                               chan->queued = 0;
-                       return ret;
-               }
-               spin_lock_irqsave(&card->lock, flags);
-               tmp = skb_peek((struct sk_buff_head *)tmp);
-               spin_unlock_irqrestore(&card->lock, flags);
-               if ((tmp == skb) || (tmp == NULL)) {
-                       /* reached end of queue */
-                       printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
-                       return 0;
-               }
-       }
-}
-
-void
-actcapi_dispatch(struct work_struct *work)
-{
-       struct act2000_card *card =
-               container_of(work, struct act2000_card, rcv_tq);
-       struct sk_buff *skb;
-       actcapi_msg *msg;
-       __u16 ccmd;
-       int chan;
-       int len;
-       act2000_chan *ctmp;
-       isdn_ctrl cmd;
-       char tmp[170];
-
-       while ((skb = skb_dequeue(&card->rcvq))) {
-               actcapi_debug_msg(skb, 0);
-               msg = (actcapi_msg *)skb->data;
-               ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd);
-               switch (ccmd) {
-               case 0x8602:
-                       /* DATA_B3_IND */
-                       if (actcapi_data_b3_ind(card, skb))
-                               return;
-                       break;
-               case 0x8601:
-                       /* DATA_B3_CONF */
-                       chan = find_ncci(card, msg->msg.data_b3_conf.ncci);
-                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) {
-                               if (msg->msg.data_b3_conf.info != 0)
-                                       printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n",
-                                              msg->msg.data_b3_conf.info);
-                               len = handle_ack(card, &card->bch[chan],
-                                                msg->msg.data_b3_conf.blocknr);
-                               if (len) {
-                                       cmd.driver = card->myid;
-                                       cmd.command = ISDN_STAT_BSENT;
-                                       cmd.arg = chan;
-                                       cmd.parm.length = len;
-                                       card->interface.statcallb(&cmd);
-                               }
-                       }
-                       break;
-               case 0x0201:
-                       /* CONNECT_CONF */
-                       chan = find_dialing(card, msg->hdr.msgnum);
-                       if (chan >= 0) {
-                               if (msg->msg.connect_conf.info) {
-                                       card->bch[chan].fsm_state = ACT2000_STATE_NULL;
-                                       cmd.driver = card->myid;
-                                       cmd.command = ISDN_STAT_DHUP;
-                                       cmd.arg = chan;
-                                       card->interface.statcallb(&cmd);
-                               } else {
-                                       card->bch[chan].fsm_state = ACT2000_STATE_OWAIT;
-                                       card->bch[chan].plci = msg->msg.connect_conf.plci;
-                               }
-                       }
-                       break;
-               case 0x0202:
-                       /* CONNECT_IND */
-                       chan = new_plci(card, msg->msg.connect_ind.plci);
-                       if (chan < 0) {
-                               ctmp = (act2000_chan *)tmp;
-                               ctmp->plci = msg->msg.connect_ind.plci;
-                               actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
-                       } else {
-                               card->bch[chan].fsm_state = ACT2000_STATE_ICALL;
-                               cmd.driver = card->myid;
-                               cmd.command = ISDN_STAT_ICALL;
-                               cmd.arg = chan;
-                               cmd.parm.setup.si1 = msg->msg.connect_ind.si1;
-                               cmd.parm.setup.si2 = msg->msg.connect_ind.si2;
-                               if (card->ptype == ISDN_PTYPE_EURO)
-                                       strcpy(cmd.parm.setup.eazmsn,
-                                              act2000_find_eaz(card, msg->msg.connect_ind.eaz));
-                               else {
-                                       cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz;
-                                       cmd.parm.setup.eazmsn[1] = 0;
-                               }
-                               memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone));
-                               memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num,
-                                      msg->msg.connect_ind.addr.len - 1);
-                               cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp;
-                               cmd.parm.setup.screen = 0;
-                               if (card->interface.statcallb(&cmd) == 2)
-                                       actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */
-                       }
-                       break;
-               case 0x0302:
-                       /* CONNECT_ACTIVE_IND */
-                       chan = find_plci(card, msg->msg.connect_active_ind.plci);
-                       if (chan >= 0)
-                               switch (card->bch[chan].fsm_state) {
-                               case ACT2000_STATE_IWAIT:
-                                       actcapi_connect_active_resp(card, &card->bch[chan]);
-                                       break;
-                               case ACT2000_STATE_OWAIT:
-                                       actcapi_connect_active_resp(card, &card->bch[chan]);
-                                       actcapi_select_b2_protocol_req(card, &card->bch[chan]);
-                                       break;
-                               }
-                       break;
-               case 0x8202:
-                       /* CONNECT_B3_IND */
-                       chan = find_plci(card, msg->msg.connect_b3_ind.plci);
-                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) {
-                               card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci;
-                               actcapi_connect_b3_resp(card, &card->bch[chan], 0);
-                       } else {
-                               ctmp = (act2000_chan *)tmp;
-                               ctmp->ncci = msg->msg.connect_b3_ind.ncci;
-                               actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
-                       }
-                       break;
-               case 0x8302:
-                       /* CONNECT_B3_ACTIVE_IND */
-                       chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci);
-                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) {
-                               actcapi_connect_b3_active_resp(card, &card->bch[chan]);
-                               cmd.driver = card->myid;
-                               cmd.command = ISDN_STAT_BCONN;
-                               cmd.arg = chan;
-                               card->interface.statcallb(&cmd);
-                       }
-                       break;
-               case 0x8402:
-                       /* DISCONNECT_B3_IND */
-                       chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci);
-                       if (chan >= 0) {
-                               ctmp = &card->bch[chan];
-                               actcapi_disconnect_b3_resp(card, ctmp);
-                               switch (ctmp->fsm_state) {
-                               case ACT2000_STATE_ACTIVE:
-                                       ctmp->fsm_state = ACT2000_STATE_DHWAIT2;
-                                       cmd.driver = card->myid;
-                                       cmd.command = ISDN_STAT_BHUP;
-                                       cmd.arg = chan;
-                                       card->interface.statcallb(&cmd);
-                                       break;
-                               case ACT2000_STATE_BHWAIT2:
-                                       actcapi_disconnect_req(card, ctmp);
-                                       ctmp->fsm_state = ACT2000_STATE_DHWAIT;
-                                       cmd.driver = card->myid;
-                                       cmd.command = ISDN_STAT_BHUP;
-                                       cmd.arg = chan;
-                                       card->interface.statcallb(&cmd);
-                                       break;
-                               }
-                       }
-                       break;
-               case 0x0402:
-                       /* DISCONNECT_IND */
-                       chan = find_plci(card, msg->msg.disconnect_ind.plci);
-                       if (chan >= 0) {
-                               ctmp = &card->bch[chan];
-                               actcapi_disconnect_resp(card, ctmp);
-                               ctmp->fsm_state = ACT2000_STATE_NULL;
-                               cmd.driver = card->myid;
-                               cmd.command = ISDN_STAT_DHUP;
-                               cmd.arg = chan;
-                               card->interface.statcallb(&cmd);
-                       } else {
-                               ctmp = (act2000_chan *)tmp;
-                               ctmp->plci = msg->msg.disconnect_ind.plci;
-                               actcapi_disconnect_resp(card, ctmp);
-                       }
-                       break;
-               case 0x4001:
-                       /* SELECT_B2_PROTOCOL_CONF */
-                       chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci);
-                       if (chan >= 0)
-                               switch (card->bch[chan].fsm_state) {
-                               case ACT2000_STATE_ICALL:
-                               case ACT2000_STATE_OWAIT:
-                                       ctmp = &card->bch[chan];
-                                       if (msg->msg.select_b2_protocol_conf.info == 0)
-                                               actcapi_select_b3_protocol_req(card, ctmp);
-                                       else {
-                                               ctmp->fsm_state = ACT2000_STATE_NULL;
-                                               cmd.driver = card->myid;
-                                               cmd.command = ISDN_STAT_DHUP;
-                                               cmd.arg = chan;
-                                               card->interface.statcallb(&cmd);
-                                       }
-                                       break;
-                               }
-                       break;
-               case 0x8001:
-                       /* SELECT_B3_PROTOCOL_CONF */
-                       chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci);
-                       if (chan >= 0)
-                               switch (card->bch[chan].fsm_state) {
-                               case ACT2000_STATE_ICALL:
-                               case ACT2000_STATE_OWAIT:
-                                       ctmp = &card->bch[chan];
-                                       if (msg->msg.select_b3_protocol_conf.info == 0)
-                                               actcapi_listen_b3_req(card, ctmp);
-                                       else {
-                                               ctmp->fsm_state = ACT2000_STATE_NULL;
-                                               cmd.driver = card->myid;
-                                               cmd.command = ISDN_STAT_DHUP;
-                                               cmd.arg = chan;
-                                               card->interface.statcallb(&cmd);
-                                       }
-                               }
-                       break;
-               case 0x8101:
-                       /* LISTEN_B3_CONF */
-                       chan = find_plci(card, msg->msg.listen_b3_conf.plci);
-                       if (chan >= 0)
-                               switch (card->bch[chan].fsm_state) {
-                               case ACT2000_STATE_ICALL:
-                                       ctmp = &card->bch[chan];
-                                       if (msg->msg.listen_b3_conf.info == 0)
-                                               actcapi_connect_resp(card, ctmp, 0);
-                                       else {
-                                               ctmp->fsm_state = ACT2000_STATE_NULL;
-                                               cmd.driver = card->myid;
-                                               cmd.command = ISDN_STAT_DHUP;
-                                               cmd.arg = chan;
-                                               card->interface.statcallb(&cmd);
-                                       }
-                                       break;
-                               case ACT2000_STATE_OWAIT:
-                                       ctmp = &card->bch[chan];
-                                       if (msg->msg.listen_b3_conf.info == 0) {
-                                               actcapi_connect_b3_req(card, ctmp);
-                                               ctmp->fsm_state = ACT2000_STATE_OBWAIT;
-                                               cmd.driver = card->myid;
-                                               cmd.command = ISDN_STAT_DCONN;
-                                               cmd.arg = chan;
-                                               card->interface.statcallb(&cmd);
-                                       } else {
-                                               ctmp->fsm_state = ACT2000_STATE_NULL;
-                                               cmd.driver = card->myid;
-                                               cmd.command = ISDN_STAT_DHUP;
-                                               cmd.arg = chan;
-                                               card->interface.statcallb(&cmd);
-                                       }
-                                       break;
-                               }
-                       break;
-               case 0x8201:
-                       /* CONNECT_B3_CONF */
-                       chan = find_plci(card, msg->msg.connect_b3_conf.plci);
-                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) {
-                               ctmp = &card->bch[chan];
-                               if (msg->msg.connect_b3_conf.info) {
-                                       ctmp->fsm_state = ACT2000_STATE_NULL;
-                                       cmd.driver = card->myid;
-                                       cmd.command = ISDN_STAT_DHUP;
-                                       cmd.arg = chan;
-                                       card->interface.statcallb(&cmd);
-                               } else {
-                                       ctmp->ncci = msg->msg.connect_b3_conf.ncci;
-                                       ctmp->fsm_state = ACT2000_STATE_BWAIT;
-                               }
-                       }
-                       break;
-               case 0x8401:
-                       /* DISCONNECT_B3_CONF */
-                       chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci);
-                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT))
-                               card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2;
-                       break;
-               case 0x0702:
-                       /* INFO_IND */
-                       chan = find_plci(card, msg->msg.info_ind.plci);
-                       if (chan >= 0)
-                               /* TODO: Eval Charging info / cause */
-                               actcapi_info_resp(card, &card->bch[chan]);
-                       break;
-               case 0x0401:
-                       /* LISTEN_CONF */
-               case 0x0501:
-                       /* LISTEN_CONF */
-               case 0xff01:
-                       /* MANUFACTURER_CONF */
-                       break;
-               case 0xff02:
-                       /* MANUFACTURER_IND */
-                       if (msg->msg.manuf_msg == 3) {
-                               memset(tmp, 0, sizeof(tmp));
-                               strncpy(tmp,
-                                       &msg->msg.manufacturer_ind_err.errstring,
-                                       msg->hdr.len - 16);
-                               if (msg->msg.manufacturer_ind_err.errcode)
-                                       printk(KERN_WARNING "act2000: %s\n", tmp);
-                               else {
-                                       printk(KERN_DEBUG "act2000: %s\n", tmp);
-                                       if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) ||
-                                           (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) {
-                                               card->flags |= ACT2000_FLAGS_RUNNING;
-                                               cmd.command = ISDN_STAT_RUN;
-                                               cmd.driver = card->myid;
-                                               cmd.arg = 0;
-                                               actcapi_manufacturer_req_net(card);
-                                               actcapi_manufacturer_req_msn(card);
-                                               actcapi_listen_req(card);
-                                               card->interface.statcallb(&cmd);
-                                       }
-                               }
-                       }
-                       break;
-               default:
-                       printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
-                       break;
-               }
-               dev_kfree_skb(skb);
-       }
-}
-
-#ifdef DEBUG_MSG
-static void
-actcapi_debug_caddr(actcapi_addr *addr)
-{
-       char tmp[30];
-
-       printk(KERN_DEBUG " Alen  = %d\n", addr->len);
-       if (addr->len > 0)
-               printk(KERN_DEBUG " Atnp  = 0x%02x\n", addr->tnp);
-       if (addr->len > 1) {
-               memset(tmp, 0, 30);
-               memcpy(tmp, addr->num, addr->len - 1);
-               printk(KERN_DEBUG " Anum  = '%s'\n", tmp);
-       }
-}
-
-static void
-actcapi_debug_ncpi(actcapi_ncpi *ncpi)
-{
-       printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len);
-       if (ncpi->len >= 2)
-               printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic);
-       if (ncpi->len >= 4)
-               printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic);
-       if (ncpi->len >= 6)
-               printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc);
-       if (ncpi->len >= 8)
-               printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc);
-       if (ncpi->len >= 10)
-               printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc);
-       if (ncpi->len >= 12)
-               printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc);
-       if (ncpi->len >= 13)
-               printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo);
-}
-
-static void
-actcapi_debug_dlpd(actcapi_dlpd *dlpd)
-{
-       printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len);
-       if (dlpd->len >= 2)
-               printk(KERN_DEBUG " dlpd.dlen   = 0x%04x\n", dlpd->dlen);
-       if (dlpd->len >= 3)
-               printk(KERN_DEBUG " dlpd.laa    = 0x%02x\n", dlpd->laa);
-       if (dlpd->len >= 4)
-               printk(KERN_DEBUG " dlpd.lab    = 0x%02x\n", dlpd->lab);
-       if (dlpd->len >= 5)
-               printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo);
-       if (dlpd->len >= 6)
-               printk(KERN_DEBUG " dlpd.win    = %d\n", dlpd->win);
-}
-
-#ifdef DEBUG_DUMP_SKB
-static void dump_skb(struct sk_buff *skb) {
-       char tmp[80];
-       char *p = skb->data;
-       char *t = tmp;
-       int i;
-
-       for (i = 0; i < skb->len; i++) {
-               t += sprintf(t, "%02x ", *p++ & 0xff);
-               if ((i & 0x0f) == 8) {
-                       printk(KERN_DEBUG "dump: %s\n", tmp);
-                       t = tmp;
-               }
-       }
-       if (i & 0x07)
-               printk(KERN_DEBUG "dump: %s\n", tmp);
-}
-#endif
-
-void
-actcapi_debug_msg(struct sk_buff *skb, int direction)
-{
-       actcapi_msg *msg = (actcapi_msg *)skb->data;
-       char *descr;
-       int i;
-       char tmp[170];
-
-#ifndef DEBUG_DATA_MSG
-       if (msg->hdr.cmd.cmd == 0x86)
-               return;
-#endif
-       descr = "INVALID";
-#ifdef DEBUG_DUMP_SKB
-       dump_skb(skb);
-#endif
-       for (i = 0; i < ARRAY_SIZE(valid_msg); i++)
-               if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
-                   (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
-                       descr = valid_msg[i].description;
-                       break;
-               }
-       printk(KERN_DEBUG "%s %s msg\n", direction ? "Outgoing" : "Incoming", descr);
-       printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID);
-       printk(KERN_DEBUG " Len    = %d\n", msg->hdr.len);
-       printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum);
-       printk(KERN_DEBUG " Cmd    = 0x%02x\n", msg->hdr.cmd.cmd);
-       printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd);
-       switch (i) {
-       case 0:
-               /* DATA B3 IND */
-               printk(KERN_DEBUG " BLOCK = 0x%02x\n",
-                      msg->msg.data_b3_ind.blocknr);
-               break;
-       case 2:
-               /* CONNECT CONF */
-               printk(KERN_DEBUG " PLCI = 0x%04x\n",
-                      msg->msg.connect_conf.plci);
-               printk(KERN_DEBUG " Info = 0x%04x\n",
-                      msg->msg.connect_conf.info);
-               break;
-       case 3:
-               /* CONNECT IND */
-               printk(KERN_DEBUG " PLCI = 0x%04x\n",
-                      msg->msg.connect_ind.plci);
-               printk(KERN_DEBUG " Contr = %d\n",
-                      msg->msg.connect_ind.controller);
-               printk(KERN_DEBUG " SI1   = %d\n",
-                      msg->msg.connect_ind.si1);
-               printk(KERN_DEBUG " SI2   = %d\n",
-                      msg->msg.connect_ind.si2);
-               printk(KERN_DEBUG " EAZ   = '%c'\n",
-                      msg->msg.connect_ind.eaz);
-               actcapi_debug_caddr(&msg->msg.connect_ind.addr);
-               break;
-       case 5:
-               /* CONNECT ACTIVE IND */
-               printk(KERN_DEBUG " PLCI = 0x%04x\n",
-                      msg->msg.connect_active_ind.plci);
-               actcapi_debug_caddr(&msg->msg.connect_active_ind.addr);
-               break;
-       case 8:
-               /* LISTEN CONF */
-               printk(KERN_DEBUG " Contr = %d\n",
-                      msg->msg.listen_conf.controller);
-               printk(KERN_DEBUG " Info = 0x%04x\n",
-                      msg->msg.listen_conf.info);
-               break;
-       case 11:
-               /* INFO IND */
-               printk(KERN_DEBUG " PLCI = 0x%04x\n",
-                      msg->msg.info_ind.plci);
-               printk(KERN_DEBUG " Imsk = 0x%04x\n",
-                      msg->msg.info_ind.nr.mask);
-               if (msg->hdr.len > 12) {
-                       int l = msg->hdr.len - 12;
-                       int j;
-                       char *p = tmp;
-                       for (j = 0; j < l; j++)
-                               p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]);
-                       printk(KERN_DEBUG " D = '%s'\n", tmp);
-               }
-               break;
-       case 14:
-               /* SELECT B2 PROTOCOL CONF */
-               printk(KERN_DEBUG " PLCI = 0x%04x\n",
-                      msg->msg.select_b2_protocol_conf.plci);
-               printk(KERN_DEBUG " Info = 0x%04x\n",
-                      msg->msg.select_b2_protocol_conf.info);
-               break;
-       case 15:
-               /* SELECT B3 PROTOCOL CONF */
-               printk(KERN_DEBUG " PLCI = 0x%04x\n",
-                      msg->msg.select_b3_protocol_conf.plci);
-               printk(KERN_DEBUG " Info = 0x%04x\n",
-                      msg->msg.select_b3_protocol_conf.info);
-               break;
-       case 16:
-               /* LISTEN B3 CONF */
-               printk(KERN_DEBUG " PLCI = 0x%04x\n",
-                      msg->msg.listen_b3_conf.plci);
-               printk(KERN_DEBUG " Info = 0x%04x\n",
-                      msg->msg.listen_b3_conf.info);
-               break;
-       case 18:
-               /* CONNECT B3 IND */
-               printk(KERN_DEBUG " NCCI = 0x%04x\n",
-                      msg->msg.connect_b3_ind.ncci);
-               printk(KERN_DEBUG " PLCI = 0x%04x\n",
-                      msg->msg.connect_b3_ind.plci);
-               actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi);
-               break;
-       case 19:
-               /* CONNECT B3 ACTIVE IND */
-               printk(KERN_DEBUG " NCCI = 0x%04x\n",
-                      msg->msg.connect_b3_active_ind.ncci);
-               actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi);
-               break;
-       case 26:
-               /* MANUFACTURER IND */
-               printk(KERN_DEBUG " Mmsg = 0x%02x\n",
-                      msg->msg.manufacturer_ind_err.manuf_msg);
-               switch (msg->msg.manufacturer_ind_err.manuf_msg) {
-               case 3:
-                       printk(KERN_DEBUG " Contr = %d\n",
-                              msg->msg.manufacturer_ind_err.controller);
-                       printk(KERN_DEBUG " Code = 0x%08x\n",
-                              msg->msg.manufacturer_ind_err.errcode);
-                       memset(tmp, 0, sizeof(tmp));
-                       strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring,
-                               msg->hdr.len - 16);
-                       printk(KERN_DEBUG " Emsg = '%s'\n", tmp);
-                       break;
-               }
-               break;
-       case 30:
-               /* LISTEN REQ */
-               printk(KERN_DEBUG " Imsk = 0x%08x\n",
-                      msg->msg.listen_req.infomask);
-               printk(KERN_DEBUG " Emsk = 0x%04x\n",
-                      msg->msg.listen_req.eazmask);
-               printk(KERN_DEBUG " Smsk = 0x%04x\n",
-                      msg->msg.listen_req.simask);
-               break;
-       case 35:
-               /* SELECT_B2_PROTOCOL_REQ */
-               printk(KERN_DEBUG " PLCI  = 0x%04x\n",
-                      msg->msg.select_b2_protocol_req.plci);
-               printk(KERN_DEBUG " prot  = 0x%02x\n",
-                      msg->msg.select_b2_protocol_req.protocol);
-               if (msg->hdr.len >= 11)
-                       printk(KERN_DEBUG "No dlpd\n");
-               else
-                       actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd);
-               break;
-       case 44:
-               /* CONNECT RESP */
-               printk(KERN_DEBUG " PLCI  = 0x%04x\n",
-                      msg->msg.connect_resp.plci);
-               printk(KERN_DEBUG " CAUSE = 0x%02x\n",
-                      msg->msg.connect_resp.rejectcause);
-               break;
-       case 45:
-               /* CONNECT ACTIVE RESP */
-               printk(KERN_DEBUG " PLCI  = 0x%04x\n",
-                      msg->msg.connect_active_resp.plci);
-               break;
-       }
-}
-#endif
diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h
deleted file mode 100644 (file)
index 01ccdec..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/* $Id: capi.h,v 1.6.6.2 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
- *
- * Author       Fritz Elfert
- * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#ifndef CAPI_H
-#define CAPI_H
-
-/* Command-part of a CAPI message */
-typedef struct actcapi_msgcmd {
-       __u8 cmd;
-       __u8 subcmd;
-} actcapi_msgcmd;
-
-/* CAPI message header */
-typedef struct actcapi_msghdr {
-       __u16 len;
-       __u16 applicationID;
-       actcapi_msgcmd cmd;
-       __u16 msgnum;
-} actcapi_msghdr;
-
-/* CAPI message description (for debugging) */
-typedef struct actcapi_msgdsc {
-       actcapi_msgcmd cmd;
-       char *description;
-} actcapi_msgdsc;
-
-/* CAPI Address */
-typedef struct actcapi_addr {
-       __u8 len;                            /* Length of element            */
-       __u8 tnp;                            /* Type/Numbering Plan          */
-       __u8 num[20];                        /* Caller ID                    */
-} actcapi_addr;
-
-/* CAPI INFO element mask */
-typedef  union actcapi_infonr {              /* info number                  */
-       __u16 mask;                          /* info-mask field              */
-       struct bmask {                       /* bit definitions              */
-               unsigned  codes:3;           /* code set                     */
-               unsigned  rsvd:5;            /* reserved                     */
-               unsigned  svind:1;           /* single, variable length ind. */
-               unsigned  wtype:7;           /* W-element type               */
-       } bmask;
-} actcapi_infonr;
-
-/* CAPI INFO element */
-typedef union  actcapi_infoel {              /* info element                 */
-       __u8 len;                            /* length of info element       */
-       __u8 display[40];                    /* display contents             */
-       __u8 uuinfo[40];                     /* User-user info field         */
-       struct cause {                       /* Cause information            */
-               unsigned ext2:1;             /* extension                    */
-               unsigned cod:2;              /* coding standard              */
-               unsigned spare:1;            /* spare                        */
-               unsigned loc:4;              /* location                     */
-               unsigned ext1:1;             /* extension                    */
-               unsigned cval:7;             /* Cause value                  */
-       } cause;
-       struct charge {                      /* Charging information         */
-               __u8 toc;                    /* type of charging info        */
-               __u8 unit[10];               /* charging units               */
-       } charge;
-       __u8 date[20];                       /* date fields                  */
-       __u8 stat;                           /* state of remote party        */
-} actcapi_infoel;
-
-/* Message for EAZ<->MSN Mapping */
-typedef struct actcapi_msn {
-       __u8 eaz;
-       __u8 len;                            /* Length of MSN                */
-       __u8 msn[15];
-}  __attribute__((packed)) actcapi_msn;
-
-typedef struct actcapi_dlpd {
-       __u8 len;                            /* Length of structure          */
-       __u16 dlen;                          /* Data Length                  */
-       __u8 laa;                            /* Link Address A               */
-       __u8 lab;                            /* Link Address B               */
-       __u8 modulo;                         /* Modulo Mode                  */
-       __u8 win;                            /* Window size                  */
-       __u8 xid[100];                       /* XID Information              */
-} __attribute__((packed)) actcapi_dlpd;
-
-typedef struct actcapi_ncpd {
-       __u8   len;                          /* Length of structure          */
-       __u16  lic;
-       __u16  hic;
-       __u16  ltc;
-       __u16  htc;
-       __u16  loc;
-       __u16  hoc;
-       __u8   modulo;
-} __attribute__((packed)) actcapi_ncpd;
-#define actcapi_ncpi actcapi_ncpd
-
-/*
- * Layout of NCCI field in a B3 DATA CAPI message is different from
- * standard at act2000:
- *
- * Bit 0-4  = PLCI
- * Bit 5-7  = Controller
- * Bit 8-15 = NCCI
- */
-#define MAKE_NCCI(plci, contr, ncci)                                   \
-       ((plci & 0x1f) | ((contr & 0x7) << 5) | ((ncci & 0xff) << 8))
-
-#define EVAL_NCCI(fakencci, plci, contr, ncci) {       \
-               plci  = fakencci & 0x1f;                \
-               contr = (fakencci >> 5) & 0x7;          \
-               ncci  = (fakencci >> 8) & 0xff;         \
-       }
-
-/*
- * Layout of PLCI field in a B3 DATA CAPI message is different from
- * standard at act2000:
- *
- * Bit 0-4  = PLCI
- * Bit 5-7  = Controller
- * Bit 8-15 = reserved (must be 0)
- */
-#define MAKE_PLCI(plci, contr)                 \
-       ((plci & 0x1f) | ((contr & 0x7) << 5))
-
-#define EVAL_PLCI(fakeplci, plci, contr) {     \
-               plci  = fakeplci & 0x1f;        \
-               contr = (fakeplci >> 5) & 0x7;  \
-       }
-
-typedef struct actcapi_msg {
-       actcapi_msghdr hdr;
-       union {
-               __u16 manuf_msg;
-               struct manufacturer_req_net {
-                       __u16 manuf_msg;
-                       __u16 controller;
-                       __u8  nettype;
-               } manufacturer_req_net;
-               struct manufacturer_req_v42 {
-                       __u16 manuf_msg;
-                       __u16 controller;
-                       __u32 v42control;
-               } manufacturer_req_v42;
-               struct manufacturer_conf_v42 {
-                       __u16 manuf_msg;
-                       __u16 controller;
-               } manufacturer_conf_v42;
-               struct manufacturer_req_err {
-                       __u16 manuf_msg;
-                       __u16 controller;
-               } manufacturer_req_err;
-               struct manufacturer_ind_err {
-                       __u16 manuf_msg;
-                       __u16 controller;
-                       __u32 errcode;
-                       __u8  errstring; /* actually up to 160 */
-               } manufacturer_ind_err;
-               struct manufacturer_req_msn {
-                       __u16 manuf_msg;
-                       __u16 controller;
-                       actcapi_msn msnmap;
-               } __attribute ((packed)) manufacturer_req_msn;
-               /* TODO: TraceInit-req/conf/ind/resp and
-                *       TraceDump-req/conf/ind/resp
-                */
-               struct connect_req {
-                       __u8  controller;
-                       __u8  bchan;
-                       __u32 infomask;
-                       __u8  si1;
-                       __u8  si2;
-                       __u8  eaz;
-                       actcapi_addr addr;
-               } __attribute__ ((packed)) connect_req;
-               struct connect_conf {
-                       __u16 plci;
-                       __u16 info;
-               } connect_conf;
-               struct connect_ind {
-                       __u16 plci;
-                       __u8  controller;
-                       __u8  si1;
-                       __u8  si2;
-                       __u8  eaz;
-                       actcapi_addr addr;
-               } __attribute__ ((packed)) connect_ind;
-               struct connect_resp {
-                       __u16 plci;
-                       __u8  rejectcause;
-               } connect_resp;
-               struct connect_active_ind {
-                       __u16 plci;
-                       actcapi_addr addr;
-               } __attribute__ ((packed)) connect_active_ind;
-               struct connect_active_resp {
-                       __u16 plci;
-               } connect_active_resp;
-               struct connect_b3_req {
-                       __u16 plci;
-                       actcapi_ncpi ncpi;
-               } __attribute__ ((packed)) connect_b3_req;
-               struct connect_b3_conf {
-                       __u16 plci;
-                       __u16 ncci;
-                       __u16 info;
-               } connect_b3_conf;
-               struct connect_b3_ind {
-                       __u16 ncci;
-                       __u16 plci;
-                       actcapi_ncpi ncpi;
-               } __attribute__ ((packed)) connect_b3_ind;
-               struct connect_b3_resp {
-                       __u16 ncci;
-                       __u8  rejectcause;
-                       actcapi_ncpi ncpi;
-               } __attribute__ ((packed)) connect_b3_resp;
-               struct disconnect_req {
-                       __u16 plci;
-                       __u8  cause;
-               } disconnect_req;
-               struct disconnect_conf {
-                       __u16 plci;
-                       __u16 info;
-               } disconnect_conf;
-               struct disconnect_ind {
-                       __u16 plci;
-                       __u16 info;
-               } disconnect_ind;
-               struct disconnect_resp {
-                       __u16 plci;
-               } disconnect_resp;
-               struct connect_b3_active_ind {
-                       __u16 ncci;
-                       actcapi_ncpi ncpi;
-               } __attribute__ ((packed)) connect_b3_active_ind;
-               struct connect_b3_active_resp {
-                       __u16 ncci;
-               } connect_b3_active_resp;
-               struct disconnect_b3_req {
-                       __u16 ncci;
-                       actcapi_ncpi ncpi;
-               } __attribute__ ((packed)) disconnect_b3_req;
-               struct disconnect_b3_conf {
-                       __u16 ncci;
-                       __u16 info;
-               } disconnect_b3_conf;
-               struct disconnect_b3_ind {
-                       __u16 ncci;
-                       __u16 info;
-                       actcapi_ncpi ncpi;
-               } __attribute__ ((packed)) disconnect_b3_ind;
-               struct disconnect_b3_resp {
-                       __u16 ncci;
-               } disconnect_b3_resp;
-               struct info_ind {
-                       __u16 plci;
-                       actcapi_infonr nr;
-                       actcapi_infoel el;
-               } __attribute__ ((packed)) info_ind;
-               struct info_resp {
-                       __u16 plci;
-               } info_resp;
-               struct listen_b3_req {
-                       __u16 plci;
-               } listen_b3_req;
-               struct listen_b3_conf {
-                       __u16 plci;
-                       __u16 info;
-               } listen_b3_conf;
-               struct select_b2_protocol_req {
-                       __u16 plci;
-                       __u8  protocol;
-                       actcapi_dlpd dlpd;
-               } __attribute__ ((packed)) select_b2_protocol_req;
-               struct select_b2_protocol_conf {
-                       __u16 plci;
-                       __u16 info;
-               } select_b2_protocol_conf;
-               struct select_b3_protocol_req {
-                       __u16 plci;
-                       __u8  protocol;
-                       actcapi_ncpd ncpd;
-               } __attribute__ ((packed)) select_b3_protocol_req;
-               struct select_b3_protocol_conf {
-                       __u16 plci;
-                       __u16 info;
-               } select_b3_protocol_conf;
-               struct listen_req {
-                       __u8  controller;
-                       __u32 infomask;
-                       __u16 eazmask;
-                       __u16 simask;
-               } __attribute__ ((packed)) listen_req;
-               struct listen_conf {
-                       __u8  controller;
-                       __u16 info;
-               } __attribute__ ((packed)) listen_conf;
-               struct data_b3_req {
-                       __u16 fakencci;
-                       __u16 datalen;
-                       __u32 unused;
-                       __u8  blocknr;
-                       __u16 flags;
-               } __attribute ((packed)) data_b3_req;
-               struct data_b3_ind {
-                       __u16 fakencci;
-                       __u16 datalen;
-                       __u32 unused;
-                       __u8  blocknr;
-                       __u16 flags;
-               } __attribute__ ((packed)) data_b3_ind;
-               struct data_b3_resp {
-                       __u16 ncci;
-                       __u8  blocknr;
-               } __attribute__ ((packed)) data_b3_resp;
-               struct data_b3_conf {
-                       __u16 ncci;
-                       __u8  blocknr;
-                       __u16 info;
-               } __attribute__ ((packed)) data_b3_conf;
-       } msg;
-} __attribute__ ((packed)) actcapi_msg;
-
-static inline unsigned short
-actcapi_nextsmsg(act2000_card *card)
-{
-       unsigned long flags;
-       unsigned short n;
-
-       spin_lock_irqsave(&card->mnlock, flags);
-       n = card->msgnum;
-       card->msgnum++;
-       card->msgnum &= 0x7fff;
-       spin_unlock_irqrestore(&card->mnlock, flags);
-       return n;
-}
-#define DEBUG_MSG
-#undef DEBUG_DATA_MSG
-#undef DEBUG_DUMP_SKB
-
-extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
-extern int actcapi_listen_req(act2000_card *);
-extern int actcapi_manufacturer_req_net(act2000_card *);
-extern int actcapi_manufacturer_req_errh(act2000_card *);
-extern int actcapi_manufacturer_req_msn(act2000_card *);
-extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
-extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *);
-extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *);
-extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8);
-extern void actcapi_dispatch(struct work_struct *);
-#ifdef DEBUG_MSG
-extern void actcapi_debug_msg(struct sk_buff *skb, int);
-#else
-#define actcapi_debug_msg(skb, len)
-#endif
-#endif
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
deleted file mode 100644 (file)
index 68073d0..0000000
+++ /dev/null
@@ -1,813 +0,0 @@
-/* $Id: module.c,v 1.14.6.4 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
- *
- * Author       Fritz Elfert
- * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#include "act2000.h"
-#include "act2000_isa.h"
-#include "capi.h"
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-static unsigned short act2000_isa_ports[] =
-{
-       0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
-       0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
-};
-
-static act2000_card *cards = (act2000_card *) NULL;
-
-/* Parameters to be set by insmod */
-static int   act_bus  =  0;
-static int   act_port = -1;  /* -1 = Autoprobe  */
-static int   act_irq  = -1;
-static char *act_id   = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-
-MODULE_DESCRIPTION("ISDN4Linux: Driver for IBM Active 2000 ISDN card");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");
-MODULE_PARM_DESC(act_port, "Base port address of first card");
-MODULE_PARM_DESC(act_irq, "IRQ of first card");
-MODULE_PARM_DESC(act_id, "ID-String of first card");
-module_param(act_bus, int, 0);
-module_param(act_port, int, 0);
-module_param(act_irq, int, 0);
-module_param(act_id, charp, 0);
-
-static int act2000_addcard(int, int, int, char *);
-
-static act2000_chan *
-find_channel(act2000_card *card, int channel)
-{
-       if ((channel >= 0) && (channel < ACT2000_BCH))
-               return &(card->bch[channel]);
-       printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);
-       return NULL;
-}
-
-/*
- * Free MSN list
- */
-static void
-act2000_clear_msn(act2000_card *card)
-{
-       struct msn_entry *p = card->msn_list;
-       struct msn_entry *q;
-       unsigned long flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       card->msn_list = NULL;
-       spin_unlock_irqrestore(&card->lock, flags);
-       while (p) {
-               q  = p->next;
-               kfree(p);
-               p = q;
-       }
-}
-
-/*
- * Find an MSN entry in the list.
- * If ia5 != 0, return IA5-encoded EAZ, else
- * return a bitmask with corresponding bit set.
- */
-static __u16
-act2000_find_msn(act2000_card *card, char *msn, int ia5)
-{
-       struct msn_entry *p = card->msn_list;
-       __u8 eaz = '0';
-
-       while (p) {
-               if (!strcmp(p->msn, msn)) {
-                       eaz = p->eaz;
-                       break;
-               }
-               p = p->next;
-       }
-       if (!ia5)
-               return (1 << (eaz - '0'));
-       else
-               return eaz;
-}
-
-/*
- * Find an EAZ entry in the list.
- * return a string with corresponding msn.
- */
-char *
-act2000_find_eaz(act2000_card *card, char eaz)
-{
-       struct msn_entry *p = card->msn_list;
-
-       while (p) {
-               if (p->eaz == eaz)
-                       return (p->msn);
-               p = p->next;
-       }
-       return ("\0");
-}
-
-/*
- * Add or delete an MSN to the MSN list
- *
- * First character of msneaz is EAZ, rest is MSN.
- * If length of eazmsn is 1, delete that entry.
- */
-static int
-act2000_set_msn(act2000_card *card, char *eazmsn)
-{
-       struct msn_entry *p = card->msn_list;
-       struct msn_entry *q = NULL;
-       unsigned long flags;
-       int i;
-
-       if (!strlen(eazmsn))
-               return 0;
-       if (strlen(eazmsn) > 16)
-               return -EINVAL;
-       for (i = 0; i < strlen(eazmsn); i++)
-               if (!isdigit(eazmsn[i]))
-                       return -EINVAL;
-       if (strlen(eazmsn) == 1) {
-               /* Delete a single MSN */
-               while (p) {
-                       if (p->eaz == eazmsn[0]) {
-                               spin_lock_irqsave(&card->lock, flags);
-                               if (q)
-                                       q->next = p->next;
-                               else
-                                       card->msn_list = p->next;
-                               spin_unlock_irqrestore(&card->lock, flags);
-                               kfree(p);
-                               printk(KERN_DEBUG
-                                      "Mapping for EAZ %c deleted\n",
-                                      eazmsn[0]);
-                               return 0;
-                       }
-                       q = p;
-                       p = p->next;
-               }
-               return 0;
-       }
-       /* Add a single MSN */
-       while (p) {
-               /* Found in list, replace MSN */
-               if (p->eaz == eazmsn[0]) {
-                       spin_lock_irqsave(&card->lock, flags);
-                       strcpy(p->msn, &eazmsn[1]);
-                       spin_unlock_irqrestore(&card->lock, flags);
-                       printk(KERN_DEBUG
-                              "Mapping for EAZ %c changed to %s\n",
-                              eazmsn[0],
-                              &eazmsn[1]);
-                       return 0;
-               }
-               p = p->next;
-       }
-       /* Not found in list, add new entry */
-       p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-       p->eaz = eazmsn[0];
-       strcpy(p->msn, &eazmsn[1]);
-       p->next = card->msn_list;
-       spin_lock_irqsave(&card->lock, flags);
-       card->msn_list = p;
-       spin_unlock_irqrestore(&card->lock, flags);
-       printk(KERN_DEBUG
-              "Mapping %c -> %s added\n",
-              eazmsn[0],
-              &eazmsn[1]);
-       return 0;
-}
-
-static void
-act2000_transmit(struct work_struct *work)
-{
-       struct act2000_card *card =
-               container_of(work, struct act2000_card, snd_tq);
-
-       switch (card->bus) {
-       case ACT2000_BUS_ISA:
-               act2000_isa_send(card);
-               break;
-       case ACT2000_BUS_PCMCIA:
-       case ACT2000_BUS_MCA:
-       default:
-               printk(KERN_WARNING
-                      "act2000_transmit: Illegal bustype %d\n", card->bus);
-       }
-}
-
-static void
-act2000_receive(struct work_struct *work)
-{
-       struct act2000_card *card =
-               container_of(work, struct act2000_card, poll_tq);
-
-       switch (card->bus) {
-       case ACT2000_BUS_ISA:
-               act2000_isa_receive(card);
-               break;
-       case ACT2000_BUS_PCMCIA:
-       case ACT2000_BUS_MCA:
-       default:
-               printk(KERN_WARNING
-                      "act2000_receive: Illegal bustype %d\n", card->bus);
-       }
-}
-
-static void
-act2000_poll(unsigned long data)
-{
-       act2000_card *card = (act2000_card *)data;
-       unsigned long flags;
-
-       act2000_receive(&card->poll_tq);
-       spin_lock_irqsave(&card->lock, flags);
-       mod_timer(&card->ptimer, jiffies + 3);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static int
-act2000_command(act2000_card *card, isdn_ctrl *c)
-{
-       ulong a;
-       act2000_chan *chan;
-       act2000_cdef cdef;
-       isdn_ctrl cmd;
-       char tmp[17];
-       int ret;
-       unsigned long flags;
-       void __user *arg;
-
-       switch (c->command) {
-       case ISDN_CMD_IOCTL:
-               memcpy(&a, c->parm.num, sizeof(ulong));
-               arg = (void __user *)a;
-               switch (c->arg) {
-               case ACT2000_IOCTL_LOADBOOT:
-                       switch (card->bus) {
-                       case ACT2000_BUS_ISA:
-                               ret = act2000_isa_download(card,
-                                                          arg);
-                               if (!ret) {
-                                       card->flags |= ACT2000_FLAGS_LOADED;
-                                       if (!(card->flags & ACT2000_FLAGS_IVALID)) {
-                                               card->ptimer.expires = jiffies + 3;
-                                               card->ptimer.function = act2000_poll;
-                                               card->ptimer.data = (unsigned long)card;
-                                               add_timer(&card->ptimer);
-                                       }
-                                       actcapi_manufacturer_req_errh(card);
-                               }
-                               break;
-                       default:
-                               printk(KERN_WARNING
-                                      "act2000: Illegal BUS type %d\n",
-                                      card->bus);
-                               ret = -EIO;
-                       }
-                       return ret;
-               case ACT2000_IOCTL_SETPROTO:
-                       card->ptype = a ? ISDN_PTYPE_EURO : ISDN_PTYPE_1TR6;
-                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                               return 0;
-                       actcapi_manufacturer_req_net(card);
-                       return 0;
-               case ACT2000_IOCTL_SETMSN:
-                       if (copy_from_user(tmp, arg,
-                                          sizeof(tmp)))
-                               return -EFAULT;
-                       if ((ret = act2000_set_msn(card, tmp)))
-                               return ret;
-                       if (card->flags & ACT2000_FLAGS_RUNNING)
-                               return (actcapi_manufacturer_req_msn(card));
-                       return 0;
-               case ACT2000_IOCTL_ADDCARD:
-                       if (copy_from_user(&cdef, arg,
-                                          sizeof(cdef)))
-                               return -EFAULT;
-                       if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))
-                               return -EIO;
-                       return 0;
-               case ACT2000_IOCTL_TEST:
-                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                               return -ENODEV;
-                       return 0;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case ISDN_CMD_DIAL:
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (!(chan = find_channel(card, c->arg & 0x0f)))
-                       break;
-               spin_lock_irqsave(&card->lock, flags);
-               if (chan->fsm_state != ACT2000_STATE_NULL) {
-                       spin_unlock_irqrestore(&card->lock, flags);
-                       printk(KERN_WARNING "Dial on channel with state %d\n",
-                              chan->fsm_state);
-                       return -EBUSY;
-               }
-               if (card->ptype == ISDN_PTYPE_EURO)
-                       tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);
-               else
-                       tmp[0] = c->parm.setup.eazmsn[0];
-               chan->fsm_state = ACT2000_STATE_OCALL;
-               chan->callref = 0xffff;
-               spin_unlock_irqrestore(&card->lock, flags);
-               ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
-                                         tmp[0], c->parm.setup.si1,
-                                         c->parm.setup.si2);
-               if (ret) {
-                       cmd.driver = card->myid;
-                       cmd.command = ISDN_STAT_DHUP;
-                       cmd.arg &= 0x0f;
-                       card->interface.statcallb(&cmd);
-               }
-               return ret;
-       case ISDN_CMD_ACCEPTD:
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (!(chan = find_channel(card, c->arg & 0x0f)))
-                       break;
-               if (chan->fsm_state == ACT2000_STATE_ICALL)
-                       actcapi_select_b2_protocol_req(card, chan);
-               return 0;
-       case ISDN_CMD_ACCEPTB:
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               return 0;
-       case ISDN_CMD_HANGUP:
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (!(chan = find_channel(card, c->arg & 0x0f)))
-                       break;
-               switch (chan->fsm_state) {
-               case ACT2000_STATE_ICALL:
-               case ACT2000_STATE_BSETUP:
-                       actcapi_connect_resp(card, chan, 0x15);
-                       break;
-               case ACT2000_STATE_ACTIVE:
-                       actcapi_disconnect_b3_req(card, chan);
-                       break;
-               }
-               return 0;
-       case ISDN_CMD_SETEAZ:
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (!(chan = find_channel(card, c->arg & 0x0f)))
-                       break;
-               if (strlen(c->parm.num)) {
-                       if (card->ptype == ISDN_PTYPE_EURO) {
-                               chan->eazmask = act2000_find_msn(card, c->parm.num, 0);
-                       }
-                       if (card->ptype == ISDN_PTYPE_1TR6) {
-                               int i;
-                               chan->eazmask = 0;
-                               for (i = 0; i < strlen(c->parm.num); i++)
-                                       if (isdigit(c->parm.num[i]))
-                                               chan->eazmask |= (1 << (c->parm.num[i] - '0'));
-                       }
-               } else
-                       chan->eazmask = 0x3ff;
-               actcapi_listen_req(card);
-               return 0;
-       case ISDN_CMD_CLREAZ:
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (!(chan = find_channel(card, c->arg & 0x0f)))
-                       break;
-               chan->eazmask = 0;
-               actcapi_listen_req(card);
-               return 0;
-       case ISDN_CMD_SETL2:
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (!(chan = find_channel(card, c->arg & 0x0f)))
-                       break;
-               chan->l2prot = (c->arg >> 8);
-               return 0;
-       case ISDN_CMD_SETL3:
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
-                       printk(KERN_WARNING "L3 protocol unknown\n");
-                       return -1;
-               }
-               if (!(chan = find_channel(card, c->arg & 0x0f)))
-                       break;
-               chan->l3prot = (c->arg >> 8);
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int
-act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb)
-{
-       struct sk_buff *xmit_skb;
-       int len;
-       act2000_chan *chan;
-       actcapi_msg *msg;
-
-       if (!(chan = find_channel(card, channel)))
-               return -1;
-       if (chan->fsm_state != ACT2000_STATE_ACTIVE)
-               return -1;
-       len = skb->len;
-       if ((chan->queued + len) >= ACT2000_MAX_QUEUED)
-               return 0;
-       if (!len)
-               return 0;
-       if (skb_headroom(skb) < 19) {
-               printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n",
-                      skb_headroom(skb));
-               xmit_skb = alloc_skb(len + 19, GFP_ATOMIC);
-               if (!xmit_skb) {
-                       printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
-                       return 0;
-               }
-               skb_reserve(xmit_skb, 19);
-               skb_copy_from_linear_data(skb, skb_put(xmit_skb, len), len);
-       } else {
-               xmit_skb = skb_clone(skb, GFP_ATOMIC);
-               if (!xmit_skb) {
-                       printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
-                       return 0;
-               }
-       }
-       dev_kfree_skb(skb);
-       msg = (actcapi_msg *)skb_push(xmit_skb, 19);
-       msg->hdr.len = 19 + len;
-       msg->hdr.applicationID = 1;
-       msg->hdr.cmd.cmd = 0x86;
-       msg->hdr.cmd.subcmd = 0x00;
-       msg->hdr.msgnum = actcapi_nextsmsg(card);
-       msg->msg.data_b3_req.datalen = len;
-       msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff);
-       msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci);
-       msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */
-       actcapi_debug_msg(xmit_skb, 1);
-       chan->queued += len;
-       skb_queue_tail(&card->sndq, xmit_skb);
-       act2000_schedule_tx(card);
-       return len;
-}
-
-
-/* Read the Status-replies from the Interface */
-static int
-act2000_readstatus(u_char __user *buf, int len, act2000_card *card)
-{
-       int count;
-       u_char __user *p;
-
-       for (p = buf, count = 0; count < len; p++, count++) {
-               if (card->status_buf_read == card->status_buf_write)
-                       return count;
-               put_user(*card->status_buf_read++, p);
-               if (card->status_buf_read > card->status_buf_end)
-                       card->status_buf_read = card->status_buf;
-       }
-       return count;
-}
-
-/*
- * Find card with given driverId
- */
-static inline act2000_card *
-act2000_findcard(int driverid)
-{
-       act2000_card *p = cards;
-
-       while (p) {
-               if (p->myid == driverid)
-                       return p;
-               p = p->next;
-       }
-       return (act2000_card *) 0;
-}
-
-/*
- * Wrapper functions for interface to linklevel
- */
-static int
-if_command(isdn_ctrl *c)
-{
-       act2000_card *card = act2000_findcard(c->driver);
-
-       if (card)
-               return (act2000_command(card, c));
-       printk(KERN_ERR
-              "act2000: if_command %d called with invalid driverId %d!\n",
-              c->command, c->driver);
-       return -ENODEV;
-}
-
-static int
-if_writecmd(const u_char __user *buf, int len, int id, int channel)
-{
-       act2000_card *card = act2000_findcard(id);
-
-       if (card) {
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               return (len);
-       }
-       printk(KERN_ERR
-              "act2000: if_writecmd called with invalid driverId!\n");
-       return -ENODEV;
-}
-
-static int
-if_readstatus(u_char __user *buf, int len, int id, int channel)
-{
-       act2000_card *card = act2000_findcard(id);
-
-       if (card) {
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               return (act2000_readstatus(buf, len, card));
-       }
-       printk(KERN_ERR
-              "act2000: if_readstatus called with invalid driverId!\n");
-       return -ENODEV;
-}
-
-static int
-if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
-{
-       act2000_card *card = act2000_findcard(id);
-
-       if (card) {
-               if (!(card->flags & ACT2000_FLAGS_RUNNING))
-                       return -ENODEV;
-               return (act2000_sendbuf(card, channel, ack, skb));
-       }
-       printk(KERN_ERR
-              "act2000: if_sendbuf called with invalid driverId!\n");
-       return -ENODEV;
-}
-
-
-/*
- * Allocate a new card-struct, initialize it
- * link it into cards-list.
- */
-static void
-act2000_alloccard(int bus, int port, int irq, char *id)
-{
-       int i;
-       act2000_card *card;
-       if (!(card = kzalloc(sizeof(act2000_card), GFP_KERNEL))) {
-               printk(KERN_WARNING
-                      "act2000: (%s) Could not allocate card-struct.\n", id);
-               return;
-       }
-       spin_lock_init(&card->lock);
-       spin_lock_init(&card->mnlock);
-       skb_queue_head_init(&card->sndq);
-       skb_queue_head_init(&card->rcvq);
-       skb_queue_head_init(&card->ackq);
-       INIT_WORK(&card->snd_tq, act2000_transmit);
-       INIT_WORK(&card->rcv_tq, actcapi_dispatch);
-       INIT_WORK(&card->poll_tq, act2000_receive);
-       init_timer(&card->ptimer);
-       card->interface.owner = THIS_MODULE;
-       card->interface.channels = ACT2000_BCH;
-       card->interface.maxbufsize = 4000;
-       card->interface.command = if_command;
-       card->interface.writebuf_skb = if_sendbuf;
-       card->interface.writecmd = if_writecmd;
-       card->interface.readstat = if_readstatus;
-       card->interface.features =
-               ISDN_FEATURE_L2_X75I |
-               ISDN_FEATURE_L2_HDLC |
-               ISDN_FEATURE_L3_TRANS |
-               ISDN_FEATURE_P_UNKNOWN;
-       card->interface.hl_hdrlen = 20;
-       card->ptype = ISDN_PTYPE_EURO;
-       strlcpy(card->interface.id, id, sizeof(card->interface.id));
-       for (i = 0; i < ACT2000_BCH; i++) {
-               card->bch[i].plci = 0x8000;
-               card->bch[i].ncci = 0x8000;
-               card->bch[i].l2prot = ISDN_PROTO_L2_X75I;
-               card->bch[i].l3prot = ISDN_PROTO_L3_TRANS;
-       }
-       card->myid = -1;
-       card->bus = bus;
-       card->port = port;
-       card->irq = irq;
-       card->next = cards;
-       cards = card;
-}
-
-/*
- * register card at linklevel
- */
-static int
-act2000_registercard(act2000_card *card)
-{
-       switch (card->bus) {
-       case ACT2000_BUS_ISA:
-               break;
-       case ACT2000_BUS_MCA:
-       case ACT2000_BUS_PCMCIA:
-       default:
-               printk(KERN_WARNING
-                      "act2000: Illegal BUS type %d\n",
-                      card->bus);
-               return -1;
-       }
-       if (!register_isdn(&card->interface)) {
-               printk(KERN_WARNING
-                      "act2000: Unable to register %s\n",
-                      card->interface.id);
-               return -1;
-       }
-       card->myid = card->interface.channels;
-       sprintf(card->regname, "act2000-isdn (%s)", card->interface.id);
-       return 0;
-}
-
-static void
-unregister_card(act2000_card *card)
-{
-       isdn_ctrl cmd;
-
-       cmd.command = ISDN_STAT_UNLOAD;
-       cmd.driver = card->myid;
-       card->interface.statcallb(&cmd);
-       switch (card->bus) {
-       case ACT2000_BUS_ISA:
-               act2000_isa_release(card);
-               break;
-       case ACT2000_BUS_MCA:
-       case ACT2000_BUS_PCMCIA:
-       default:
-               printk(KERN_WARNING
-                      "act2000: Invalid BUS type %d\n",
-                      card->bus);
-               break;
-       }
-}
-
-static int
-act2000_addcard(int bus, int port, int irq, char *id)
-{
-       act2000_card *p;
-       act2000_card *q = NULL;
-       int initialized;
-       int added = 0;
-       int failed = 0;
-       int i;
-
-       if (!bus)
-               bus = ACT2000_BUS_ISA;
-       if (port != -1) {
-               /* Port defined, do fixed setup */
-               act2000_alloccard(bus, port, irq, id);
-       } else {
-               /* No port defined, perform autoprobing.
-                * This may result in more than one card detected.
-                */
-               switch (bus) {
-               case ACT2000_BUS_ISA:
-                       for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++)
-                               if (act2000_isa_detect(act2000_isa_ports[i])) {
-                                       printk(KERN_INFO "act2000: Detected "
-                                              "ISA card at port 0x%x\n",
-                                              act2000_isa_ports[i]);
-                                       act2000_alloccard(bus,
-                                                         act2000_isa_ports[i], irq, id);
-                               }
-                       break;
-               case ACT2000_BUS_MCA:
-               case ACT2000_BUS_PCMCIA:
-               default:
-                       printk(KERN_WARNING
-                              "act2000: addcard: Invalid BUS type %d\n", bus);
-               }
-       }
-       if (!cards)
-               return 1;
-       p = cards;
-       while (p) {
-               initialized = 0;
-               if (!p->interface.statcallb) {
-                       /* Not yet registered.
-                        * Try to register and activate it.
-                        */
-                       added++;
-                       switch (p->bus) {
-                       case ACT2000_BUS_ISA:
-                               if (act2000_isa_detect(p->port)) {
-                                       if (act2000_registercard(p))
-                                               break;
-                                       if (act2000_isa_config_port(p, p->port)) {
-                                               printk(KERN_WARNING
-                                                      "act2000: Could not request port 0x%04x\n",
-                                                      p->port);
-                                               unregister_card(p);
-                                               p->interface.statcallb = NULL;
-                                               break;
-                                       }
-                                       if (act2000_isa_config_irq(p, p->irq)) {
-                                               printk(KERN_INFO
-                                                      "act2000: No IRQ available, fallback to polling\n");
-                                               /* Fall back to polled operation */
-                                               p->irq = 0;
-                                       }
-                                       printk(KERN_INFO
-                                              "act2000: ISA"
-                                              "-type card at port "
-                                              "0x%04x ",
-                                              p->port);
-                                       if (p->irq)
-                                               printk("irq %d\n", p->irq);
-                                       else
-                                               printk("polled\n");
-                                       initialized = 1;
-                               }
-                               break;
-                       case ACT2000_BUS_MCA:
-                       case ACT2000_BUS_PCMCIA:
-                       default:
-                               printk(KERN_WARNING
-                                      "act2000: addcard: Invalid BUS type %d\n",
-                                      p->bus);
-                       }
-               } else
-                       /* Card already initialized */
-                       initialized = 1;
-               if (initialized) {
-                       /* Init OK, next card ... */
-                       q = p;
-                       p = p->next;
-               } else {
-                       /* Init failed, remove card from list, free memory */
-                       printk(KERN_WARNING
-                              "act2000: Initialization of %s failed\n",
-                              p->interface.id);
-                       if (q) {
-                               q->next = p->next;
-                               kfree(p);
-                               p = q->next;
-                       } else {
-                               cards = p->next;
-                               kfree(p);
-                               p = cards;
-                       }
-                       failed++;
-               }
-       }
-       return (added - failed);
-}
-
-#define DRIVERNAME "IBM Active 2000 ISDN driver"
-
-static int __init act2000_init(void)
-{
-       printk(KERN_INFO "%s\n", DRIVERNAME);
-       if (!cards)
-               act2000_addcard(act_bus, act_port, act_irq, act_id);
-       if (!cards)
-               printk(KERN_INFO "act2000: No cards defined yet\n");
-       return 0;
-}
-
-static void __exit act2000_exit(void)
-{
-       act2000_card *card = cards;
-       act2000_card *last;
-       while (card) {
-               unregister_card(card);
-               del_timer_sync(&card->ptimer);
-               card = card->next;
-       }
-       card = cards;
-       while (card) {
-               last = card;
-               card = card->next;
-               act2000_clear_msn(last);
-               kfree(last);
-       }
-       printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
-}
-
-module_init(act2000_init);
-module_exit(act2000_exit);
index f5b714cd761891117490d997e1b9df2e600535e3..68e54d9f2f53855a1cd65afe11d3c6dd24c504f6 100644 (file)
@@ -123,16 +123,6 @@ comment "ISDN4Linux hardware drivers"
 
 source "drivers/isdn/hisax/Kconfig"
 
-
-menu "Active cards"
-
-source "drivers/isdn/icn/Kconfig"
-
-source "drivers/isdn/pcbit/Kconfig"
-
-source "drivers/isdn/act2000/Kconfig"
-
-endmenu
 # end ISDN_I4L
 endif
 
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig
deleted file mode 100644 (file)
index 4534f21..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-config ISDN_DRV_ICN
-       tristate "ICN 2B and 4B support"
-       depends on ISA
-       help
-         This enables support for two kinds of ISDN-cards made by a German
-         company called ICN.  2B is the standard version for a single ISDN
-         line with two B-channels, 4B supports two ISDN lines.  For running
-         this card, additional firmware is necessary, which has to be
-         downloaded into the card using a utility which is distributed
-         separately.  See <file:Documentation/isdn/README> and
-         <file:Documentation/isdn/README.icn> for more
-         information.
diff --git a/drivers/isdn/icn/Makefile b/drivers/isdn/icn/Makefile
deleted file mode 100644 (file)
index d9b476f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# Makefile for the icn ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_ICN)     += icn.o
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
deleted file mode 100644 (file)
index 46d957c..0000000
+++ /dev/null
@@ -1,1693 +0,0 @@
-/* $Id: icn.c,v 1.65.6.8 2001/09/23 22:24:55 kai Exp $
- *
- * ISDN low-level module for the ICN active ISDN-Card.
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include "icn.h"
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-
-static int portbase = ICN_BASEADDR;
-static unsigned long membase = ICN_MEMADDR;
-static char *icn_id = "\0";
-static char *icn_id2 = "\0";
-
-MODULE_DESCRIPTION("ISDN4Linux: Driver for ICN active ISDN card");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-module_param(portbase, int, 0);
-MODULE_PARM_DESC(portbase, "Port address of first card");
-module_param(membase, ulong, 0);
-MODULE_PARM_DESC(membase, "Shared memory address of all cards");
-module_param(icn_id, charp, 0);
-MODULE_PARM_DESC(icn_id, "ID-String of first card");
-module_param(icn_id2, charp, 0);
-MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
-
-/*
- * Verbose bootcode- and protocol-downloading.
- */
-#undef BOOT_DEBUG
-
-/*
- * Verbose Shmem-Mapping.
- */
-#undef MAP_DEBUG
-
-static char
-*revision = "$Revision: 1.65.6.8 $";
-
-static int icn_addcard(int, char *, char *);
-
-/*
- * Free send-queue completely.
- * Parameter:
- *   card   = pointer to card struct
- *   channel = channel number
- */
-static void
-icn_free_queue(icn_card *card, int channel)
-{
-       struct sk_buff_head *queue = &card->spqueue[channel];
-       struct sk_buff *skb;
-
-       skb_queue_purge(queue);
-       card->xlen[channel] = 0;
-       card->sndcount[channel] = 0;
-       if ((skb = card->xskb[channel])) {
-               card->xskb[channel] = NULL;
-               dev_kfree_skb(skb);
-       }
-}
-
-/* Put a value into a shift-register, highest bit first.
- * Parameters:
- *            port     = port for output (bit 0 is significant)
- *            val      = value to be output
- *            firstbit = Bit-Number of highest bit
- *            bitcount = Number of bits to output
- */
-static inline void
-icn_shiftout(unsigned short port,
-            unsigned long val,
-            int firstbit,
-            int bitcount)
-{
-
-       register u_char s;
-       register u_char c;
-
-       for (s = firstbit, c = bitcount; c > 0; s--, c--)
-               OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
-}
-
-/*
- * disable a cards shared memory
- */
-static inline void
-icn_disable_ram(icn_card *card)
-{
-       OUTB_P(0, ICN_MAPRAM);
-}
-
-/*
- * enable a cards shared memory
- */
-static inline void
-icn_enable_ram(icn_card *card)
-{
-       OUTB_P(0xff, ICN_MAPRAM);
-}
-
-/*
- * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
- *
- * must called with holding the devlock
- */
-static inline void
-icn_map_channel(icn_card *card, int channel)
-{
-#ifdef MAP_DEBUG
-       printk(KERN_DEBUG "icn_map_channel %d %d\n", dev.channel, channel);
-#endif
-       if ((channel == dev.channel) && (card == dev.mcard))
-               return;
-       if (dev.mcard)
-               icn_disable_ram(dev.mcard);
-       icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4);       /* Select Bank          */
-       icn_enable_ram(card);
-       dev.mcard = card;
-       dev.channel = channel;
-#ifdef MAP_DEBUG
-       printk(KERN_DEBUG "icn_map_channel done\n");
-#endif
-}
-
-/*
- * Lock a cards channel.
- * Return 0 if requested card/channel is unmapped (failure).
- * Return 1 on success.
- *
- * must called with holding the devlock
- */
-static inline int
-icn_lock_channel(icn_card *card, int channel)
-{
-       register int retval;
-
-#ifdef MAP_DEBUG
-       printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
-#endif
-       if ((dev.channel == channel) && (card == dev.mcard)) {
-               dev.chanlock++;
-               retval = 1;
-#ifdef MAP_DEBUG
-               printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
-#endif
-       } else {
-               retval = 0;
-#ifdef MAP_DEBUG
-               printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev.channel);
-#endif
-       }
-       return retval;
-}
-
-/*
- * Release current card/channel lock
- *
- * must called with holding the devlock
- */
-static inline void
-__icn_release_channel(void)
-{
-#ifdef MAP_DEBUG
-       printk(KERN_DEBUG "icn_release_channel l=%d\n", dev.chanlock);
-#endif
-       if (dev.chanlock > 0)
-               dev.chanlock--;
-}
-
-/*
- * Release current card/channel lock
- */
-static inline void
-icn_release_channel(void)
-{
-       ulong flags;
-
-       spin_lock_irqsave(&dev.devlock, flags);
-       __icn_release_channel();
-       spin_unlock_irqrestore(&dev.devlock, flags);
-}
-
-/*
- * Try to map and lock a cards channel.
- * Return 1 on success, 0 on failure.
- */
-static inline int
-icn_trymaplock_channel(icn_card *card, int channel)
-{
-       ulong flags;
-
-#ifdef MAP_DEBUG
-       printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
-              dev.chanlock);
-#endif
-       spin_lock_irqsave(&dev.devlock, flags);
-       if ((!dev.chanlock) ||
-           ((dev.channel == channel) && (dev.mcard == card))) {
-               dev.chanlock++;
-               icn_map_channel(card, channel);
-               spin_unlock_irqrestore(&dev.devlock, flags);
-#ifdef MAP_DEBUG
-               printk(KERN_DEBUG "trymaplock %d OK\n", channel);
-#endif
-               return 1;
-       }
-       spin_unlock_irqrestore(&dev.devlock, flags);
-#ifdef MAP_DEBUG
-       printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
-#endif
-       return 0;
-}
-
-/*
- * Release current card/channel lock,
- * then map same or other channel without locking.
- */
-static inline void
-icn_maprelease_channel(icn_card *card, int channel)
-{
-       ulong flags;
-
-#ifdef MAP_DEBUG
-       printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
-#endif
-       spin_lock_irqsave(&dev.devlock, flags);
-       if (dev.chanlock > 0)
-               dev.chanlock--;
-       if (!dev.chanlock)
-               icn_map_channel(card, channel);
-       spin_unlock_irqrestore(&dev.devlock, flags);
-}
-
-/* Get Data from the B-Channel, assemble fragmented packets and put them
- * into receive-queue. Wake up any B-Channel-reading processes.
- * This routine is called via timer-callback from icn_pollbchan().
- */
-
-static void
-icn_pollbchan_receive(int channel, icn_card *card)
-{
-       int mch = channel + ((card->secondhalf) ? 2 : 0);
-       int eflag;
-       int cnt;
-       struct sk_buff *skb;
-
-       if (icn_trymaplock_channel(card, mch)) {
-               while (rbavl) {
-                       cnt = readb(&rbuf_l);
-                       if ((card->rcvidx[channel] + cnt) > 4000) {
-                               printk(KERN_WARNING
-                                      "icn: (%s) bogus packet on ch%d, dropping.\n",
-                                      CID,
-                                      channel + 1);
-                               card->rcvidx[channel] = 0;
-                               eflag = 0;
-                       } else {
-                               memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
-                                             &rbuf_d, cnt);
-                               card->rcvidx[channel] += cnt;
-                               eflag = readb(&rbuf_f);
-                       }
-                       rbnext;
-                       icn_maprelease_channel(card, mch & 2);
-                       if (!eflag) {
-                               if ((cnt = card->rcvidx[channel])) {
-                                       if (!(skb = dev_alloc_skb(cnt))) {
-                                               printk(KERN_WARNING "icn: receive out of memory\n");
-                                               break;
-                                       }
-                                       memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
-                                       card->rcvidx[channel] = 0;
-                                       card->interface.rcvcallb_skb(card->myid, channel, skb);
-                               }
-                       }
-                       if (!icn_trymaplock_channel(card, mch))
-                               break;
-               }
-               icn_maprelease_channel(card, mch & 2);
-       }
-}
-
-/* Send data-packet to B-Channel, split it up into fragments of
- * ICN_FRAGSIZE length. If last fragment is sent out, signal
- * success to upper layers via statcallb with ISDN_STAT_BSENT argument.
- * This routine is called via timer-callback from icn_pollbchan() or
- * directly from icn_sendbuf().
- */
-
-static void
-icn_pollbchan_send(int channel, icn_card *card)
-{
-       int mch = channel + ((card->secondhalf) ? 2 : 0);
-       int cnt;
-       unsigned long flags;
-       struct sk_buff *skb;
-       isdn_ctrl cmd;
-
-       if (!(card->sndcount[channel] || card->xskb[channel] ||
-             !skb_queue_empty(&card->spqueue[channel])))
-               return;
-       if (icn_trymaplock_channel(card, mch)) {
-               while (sbfree &&
-                      (card->sndcount[channel] ||
-                       !skb_queue_empty(&card->spqueue[channel]) ||
-                       card->xskb[channel])) {
-                       spin_lock_irqsave(&card->lock, flags);
-                       if (card->xmit_lock[channel]) {
-                               spin_unlock_irqrestore(&card->lock, flags);
-                               break;
-                       }
-                       card->xmit_lock[channel]++;
-                       spin_unlock_irqrestore(&card->lock, flags);
-                       skb = card->xskb[channel];
-                       if (!skb) {
-                               skb = skb_dequeue(&card->spqueue[channel]);
-                               if (skb) {
-                                       /* Pop ACK-flag off skb.
-                                        * Store length to xlen.
-                                        */
-                                       if (*(skb_pull(skb, 1)))
-                                               card->xlen[channel] = skb->len;
-                                       else
-                                               card->xlen[channel] = 0;
-                               }
-                       }
-                       if (!skb)
-                               break;
-                       if (skb->len > ICN_FRAGSIZE) {
-                               writeb(0xff, &sbuf_f);
-                               cnt = ICN_FRAGSIZE;
-                       } else {
-                               writeb(0x0, &sbuf_f);
-                               cnt = skb->len;
-                       }
-                       writeb(cnt, &sbuf_l);
-                       memcpy_toio(&sbuf_d, skb->data, cnt);
-                       skb_pull(skb, cnt);
-                       sbnext; /* switch to next buffer        */
-                       icn_maprelease_channel(card, mch & 2);
-                       spin_lock_irqsave(&card->lock, flags);
-                       card->sndcount[channel] -= cnt;
-                       if (!skb->len) {
-                               if (card->xskb[channel])
-                                       card->xskb[channel] = NULL;
-                               card->xmit_lock[channel] = 0;
-                               spin_unlock_irqrestore(&card->lock, flags);
-                               dev_kfree_skb(skb);
-                               if (card->xlen[channel]) {
-                                       cmd.command = ISDN_STAT_BSENT;
-                                       cmd.driver = card->myid;
-                                       cmd.arg = channel;
-                                       cmd.parm.length = card->xlen[channel];
-                                       card->interface.statcallb(&cmd);
-                               }
-                       } else {
-                               card->xskb[channel] = skb;
-                               card->xmit_lock[channel] = 0;
-                               spin_unlock_irqrestore(&card->lock, flags);
-                       }
-                       if (!icn_trymaplock_channel(card, mch))
-                               break;
-               }
-               icn_maprelease_channel(card, mch & 2);
-       }
-}
-
-/* Send/Receive Data to/from the B-Channel.
- * This routine is called via timer-callback.
- * It schedules itself while any B-Channel is open.
- */
-
-static void
-icn_pollbchan(unsigned long data)
-{
-       icn_card *card = (icn_card *) data;
-       unsigned long flags;
-
-       if (card->flags & ICN_FLAGS_B1ACTIVE) {
-               icn_pollbchan_receive(0, card);
-               icn_pollbchan_send(0, card);
-       }
-       if (card->flags & ICN_FLAGS_B2ACTIVE) {
-               icn_pollbchan_receive(1, card);
-               icn_pollbchan_send(1, card);
-       }
-       if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
-               /* schedule b-channel polling again */
-               spin_lock_irqsave(&card->lock, flags);
-               mod_timer(&card->rb_timer, jiffies + ICN_TIMER_BCREAD);
-               card->flags |= ICN_FLAGS_RBTIMER;
-               spin_unlock_irqrestore(&card->lock, flags);
-       } else
-               card->flags &= ~ICN_FLAGS_RBTIMER;
-}
-
-typedef struct icn_stat {
-       char *statstr;
-       int command;
-       int action;
-} icn_stat;
-/* *INDENT-OFF* */
-static icn_stat icn_stat_table[] =
-{
-       {"BCON_",          ISDN_STAT_BCONN, 1}, /* B-Channel connected        */
-       {"BDIS_",          ISDN_STAT_BHUP,  2}, /* B-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  */
-       {"CIF",            ISDN_STAT_CINF,  5}, /* Charge-info, 1TR6-type     */
-       {"AOC",            ISDN_STAT_CINF,  6}, /* Charge-info, DSS1-type     */
-       {"CAU",            ISDN_STAT_CAUSE, 7}, /* Cause code                 */
-       {"TEI OK",         ISDN_STAT_RUN,   0}, /* Card connected to wallplug */
-       {"E_L1: ACT FAIL", ISDN_STAT_BHUP,  8}, /* Layer-1 activation failed  */
-       {"E_L2: DATA LIN", ISDN_STAT_BHUP,  8}, /* Layer-2 data link lost     */
-       {"E_L1: ACTIVATION FAILED",
-        ISDN_STAT_BHUP,  8},   /* Layer-1 activation failed  */
-       {NULL, 0, -1}
-};
-/* *INDENT-ON* */
-
-
-/*
- * Check Statusqueue-Pointer from isdn-cards.
- * If there are new status-replies from the interface, check
- * them against B-Channel-connects/disconnects and set flags accordingly.
- * Wake-Up any processes, who are reading the status-device.
- * If there are B-Channels open, initiate a timer-callback to
- * icn_pollbchan().
- * This routine is called periodically via timer.
- */
-
-static void
-icn_parse_status(u_char *status, int channel, icn_card *card)
-{
-       icn_stat *s = icn_stat_table;
-       int action = -1;
-       unsigned long flags;
-       isdn_ctrl cmd;
-
-       while (s->statstr) {
-               if (!strncmp(status, s->statstr, strlen(s->statstr))) {
-                       cmd.command = s->command;
-                       action = s->action;
-                       break;
-               }
-               s++;
-       }
-       if (action == -1)
-               return;
-       cmd.driver = card->myid;
-       cmd.arg = channel;
-       switch (action) {
-       case 11:
-               spin_lock_irqsave(&card->lock, flags);
-               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;
-                       spin_unlock_irqrestore(&card->lock, flags);
-                       card->interface.statcallb(&cmd);
-               } else
-                       spin_unlock_irqrestore(&card->lock, flags);
-               break;
-       case 1:
-               spin_lock_irqsave(&card->lock, flags);
-               icn_free_queue(card, channel);
-               card->flags |= (channel) ?
-                       ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
-               spin_unlock_irqrestore(&card->lock, flags);
-               break;
-       case 2:
-               spin_lock_irqsave(&card->lock, flags);
-               card->flags &= ~((channel) ?
-                                ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
-               icn_free_queue(card, channel);
-               card->rcvidx[channel] = 0;
-               spin_unlock_irqrestore(&card->lock, flags);
-               break;
-       case 3:
-       {
-               char *t = status + 6;
-               char *s = strchr(t, ',');
-
-               *s++ = '\0';
-               strlcpy(cmd.parm.setup.phone, t,
-                       sizeof(cmd.parm.setup.phone));
-               s = strchr(t = s, ',');
-               *s++ = '\0';
-               if (!strlen(t))
-                       cmd.parm.setup.si1 = 0;
-               else
-                       cmd.parm.setup.si1 =
-                               simple_strtoul(t, NULL, 10);
-               s = strchr(t = s, ',');
-               *s++ = '\0';
-               if (!strlen(t))
-                       cmd.parm.setup.si2 = 0;
-               else
-                       cmd.parm.setup.si2 =
-                               simple_strtoul(t, NULL, 10);
-               strlcpy(cmd.parm.setup.eazmsn, s,
-                       sizeof(cmd.parm.setup.eazmsn));
-       }
-       cmd.parm.setup.plan = 0;
-       cmd.parm.setup.screen = 0;
-       break;
-       case 4:
-               sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
-               sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
-               cmd.parm.setup.si1 = 7;
-               cmd.parm.setup.si2 = 0;
-               cmd.parm.setup.plan = 0;
-               cmd.parm.setup.screen = 0;
-               break;
-       case 5:
-               strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
-               break;
-       case 6:
-               snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
-                        (int) simple_strtoul(status + 7, NULL, 16));
-               break;
-       case 7:
-               status += 3;
-               if (strlen(status) == 4)
-                       snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
-                                status + 2, *status, *(status + 1));
-               else
-                       strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
-               break;
-       case 8:
-               spin_lock_irqsave(&card->lock, flags);
-               card->flags &= ~ICN_FLAGS_B1ACTIVE;
-               icn_free_queue(card, 0);
-               card->rcvidx[0] = 0;
-               spin_unlock_irqrestore(&card->lock, flags);
-               cmd.arg = 0;
-               cmd.driver = card->myid;
-               card->interface.statcallb(&cmd);
-               cmd.command = ISDN_STAT_DHUP;
-               cmd.arg = 0;
-               cmd.driver = card->myid;
-               card->interface.statcallb(&cmd);
-               cmd.command = ISDN_STAT_BHUP;
-               spin_lock_irqsave(&card->lock, flags);
-               card->flags &= ~ICN_FLAGS_B2ACTIVE;
-               icn_free_queue(card, 1);
-               card->rcvidx[1] = 0;
-               spin_unlock_irqrestore(&card->lock, flags);
-               cmd.arg = 1;
-               cmd.driver = card->myid;
-               card->interface.statcallb(&cmd);
-               cmd.command = ISDN_STAT_DHUP;
-               cmd.arg = 1;
-               cmd.driver = card->myid;
-               break;
-       }
-       card->interface.statcallb(&cmd);
-       return;
-}
-
-static void
-icn_putmsg(icn_card *card, unsigned char c)
-{
-       ulong flags;
-
-       spin_lock_irqsave(&card->lock, flags);
-       *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
-       if (card->msg_buf_write == card->msg_buf_read) {
-               if (++card->msg_buf_read > card->msg_buf_end)
-                       card->msg_buf_read = card->msg_buf;
-       }
-       if (card->msg_buf_write > card->msg_buf_end)
-               card->msg_buf_write = card->msg_buf;
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void
-icn_polldchan(unsigned long data)
-{
-       icn_card *card = (icn_card *) data;
-       int mch = card->secondhalf ? 2 : 0;
-       int avail = 0;
-       int left;
-       u_char c;
-       int ch;
-       unsigned long flags;
-       int i;
-       u_char *p;
-       isdn_ctrl cmd;
-
-       if (icn_trymaplock_channel(card, mch)) {
-               avail = msg_avail;
-               for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
-                       c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
-                       icn_putmsg(card, c);
-                       if (c == 0xff) {
-                               card->imsg[card->iptr] = 0;
-                               card->iptr = 0;
-                               if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
-                                   card->imsg[1] <= '2' && card->imsg[2] == ';') {
-                                       ch = (card->imsg[1] - '0') - 1;
-                                       p = &card->imsg[3];
-                                       icn_parse_status(p, ch, card);
-                               } else {
-                                       p = card->imsg;
-                                       if (!strncmp(p, "DRV1.", 5)) {
-                                               u_char vstr[10];
-                                               u_char *q = vstr;
-
-                                               printk(KERN_INFO "icn: (%s) %s\n", CID, p);
-                                               if (!strncmp(p + 7, "TC", 2)) {
-                                                       card->ptype = ISDN_PTYPE_1TR6;
-                                                       card->interface.features |= ISDN_FEATURE_P_1TR6;
-                                                       printk(KERN_INFO
-                                                              "icn: (%s) 1TR6-Protocol loaded and running\n", CID);
-                                               }
-                                               if (!strncmp(p + 7, "EC", 2)) {
-                                                       card->ptype = ISDN_PTYPE_EURO;
-                                                       card->interface.features |= ISDN_FEATURE_P_EURO;
-                                                       printk(KERN_INFO
-                                                              "icn: (%s) Euro-Protocol loaded and running\n", CID);
-                                               }
-                                               p = strstr(card->imsg, "BRV") + 3;
-                                               while (*p) {
-                                                       if (*p >= '0' && *p <= '9')
-                                                               *q++ = *p;
-                                                       p++;
-                                               }
-                                               *q = '\0';
-                                               strcat(vstr, "000");
-                                               vstr[3] = '\0';
-                                               card->fw_rev = (int) simple_strtoul(vstr, NULL, 10);
-                                               continue;
-
-                                       }
-                               }
-                       } else {
-                               card->imsg[card->iptr] = c;
-                               if (card->iptr < 59)
-                                       card->iptr++;
-                       }
-               }
-               writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
-               icn_release_channel();
-       }
-       if (avail) {
-               cmd.command = ISDN_STAT_STAVAIL;
-               cmd.driver = card->myid;
-               cmd.arg = avail;
-               card->interface.statcallb(&cmd);
-       }
-       spin_lock_irqsave(&card->lock, flags);
-       if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
-               if (!(card->flags & ICN_FLAGS_RBTIMER)) {
-                       /* schedule b-channel polling */
-                       card->flags |= ICN_FLAGS_RBTIMER;
-                       del_timer(&card->rb_timer);
-                       card->rb_timer.function = icn_pollbchan;
-                       card->rb_timer.data = (unsigned long) card;
-                       card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
-                       add_timer(&card->rb_timer);
-               }
-       /* schedule again */
-       mod_timer(&card->st_timer, jiffies + ICN_TIMER_DCREAD);
-       spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* Append a packet to the transmit buffer-queue.
- * Parameters:
- *   channel = Number of B-channel
- *   skb     = pointer to sk_buff
- *   card    = pointer to card-struct
- * Return:
- *   Number of bytes transferred, -E??? on error
- */
-
-static int
-icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card *card)
-{
-       int len = skb->len;
-       unsigned long flags;
-       struct sk_buff *nskb;
-
-       if (len > 4000) {
-               printk(KERN_WARNING
-                      "icn: Send packet too large\n");
-               return -EINVAL;
-       }
-       if (len) {
-               if (!(card->flags & (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE))
-                       return 0;
-               if (card->sndcount[channel] > ICN_MAX_SQUEUE)
-                       return 0;
-               /* TODO test headroom or use skb->nb to flag ACK */
-               nskb = skb_clone(skb, GFP_ATOMIC);
-               if (nskb) {
-                       /* Push ACK flag as one
-                        * byte in front of data.
-                        */
-                       *(skb_push(nskb, 1)) = ack ? 1 : 0;
-                       skb_queue_tail(&card->spqueue[channel], nskb);
-                       dev_kfree_skb(skb);
-               } else
-                       len = 0;
-               spin_lock_irqsave(&card->lock, flags);
-               card->sndcount[channel] += len;
-               spin_unlock_irqrestore(&card->lock, flags);
-       }
-       return len;
-}
-
-/*
- * Check card's status after starting the bootstrap loader.
- * On entry, the card's shared memory has already to be mapped.
- * Return:
- *   0 on success (Boot loader ready)
- *   -EIO on failure (timeout)
- */
-static int
-icn_check_loader(int cardnumber)
-{
-       int timer = 0;
-
-       while (1) {
-#ifdef BOOT_DEBUG
-               printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
-#endif
-               if (readb(&dev.shmem->data_control.scns) ||
-                   readb(&dev.shmem->data_control.scnr)) {
-                       if (timer++ > 5) {
-                               printk(KERN_WARNING
-                                      "icn: Boot-Loader %d timed out.\n",
-                                      cardnumber);
-                               icn_release_channel();
-                               return -EIO;
-                       }
-#ifdef BOOT_DEBUG
-                       printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
-#endif
-                       msleep_interruptible(ICN_BOOT_TIMEOUT1);
-               } else {
-#ifdef BOOT_DEBUG
-                       printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
-#endif
-                       icn_release_channel();
-                       return 0;
-               }
-       }
-}
-
-/* Load the boot-code into the interface-card's memory and start it.
- * Always called from user-process.
- *
- * Parameters:
- *            buffer = pointer to packet
- * Return:
- *        0 if successfully loaded
- */
-
-#ifdef BOOT_DEBUG
-#define SLEEP(sec) {                                           \
-               int slsec = sec;                                \
-               printk(KERN_DEBUG "SLEEP(%d)\n", slsec);        \
-               while (slsec) {                                 \
-                       msleep_interruptible(1000);             \
-                       slsec--;                                \
-               }                                               \
-       }
-#else
-#define SLEEP(sec)
-#endif
-
-static int
-icn_loadboot(u_char __user *buffer, icn_card *card)
-{
-       int ret;
-       u_char *codebuf;
-       unsigned long flags;
-
-#ifdef BOOT_DEBUG
-       printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
-#endif
-       if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) {
-               printk(KERN_WARNING "icn: Could not allocate code buffer\n");
-               ret = -ENOMEM;
-               goto out;
-       }
-       if (copy_from_user(codebuf, buffer, ICN_CODE_STAGE1)) {
-               ret = -EFAULT;
-               goto out_kfree;
-       }
-       if (!card->rvalid) {
-               if (!request_region(card->port, ICN_PORTLEN, card->regname)) {
-                       printk(KERN_WARNING
-                              "icn: (%s) ports 0x%03x-0x%03x in use.\n",
-                              CID,
-                              card->port,
-                              card->port + ICN_PORTLEN);
-                       ret = -EBUSY;
-                       goto out_kfree;
-               }
-               card->rvalid = 1;
-               if (card->doubleS0)
-                       card->other->rvalid = 1;
-       }
-       if (!dev.mvalid) {
-               if (!request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)")) {
-                       printk(KERN_WARNING
-                              "icn: memory at 0x%08lx in use.\n", dev.memaddr);
-                       ret = -EBUSY;
-                       goto out_kfree;
-               }
-               dev.shmem = ioremap(dev.memaddr, 0x4000);
-               dev.mvalid = 1;
-       }
-       OUTB_P(0, ICN_RUN);     /* Reset Controller */
-       OUTB_P(0, ICN_MAPRAM);  /* Disable RAM      */
-       icn_shiftout(ICN_CFG, 0x0f, 3, 4);      /* Windowsize= 16k  */
-       icn_shiftout(ICN_CFG, dev.memaddr, 23, 10);     /* Set RAM-Addr.    */
-#ifdef BOOT_DEBUG
-       printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
-#endif
-       SLEEP(1);
-#ifdef BOOT_DEBUG
-       printk(KERN_DEBUG "Map Bank 0\n");
-#endif
-       spin_lock_irqsave(&dev.devlock, flags);
-       icn_map_channel(card, 0);       /* Select Bank 0    */
-       icn_lock_channel(card, 0);      /* Lock Bank 0      */
-       spin_unlock_irqrestore(&dev.devlock, flags);
-       SLEEP(1);
-       memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);       /* Copy code        */
-#ifdef BOOT_DEBUG
-       printk(KERN_DEBUG "Bootloader transferred\n");
-#endif
-       if (card->doubleS0) {
-               SLEEP(1);
-#ifdef BOOT_DEBUG
-               printk(KERN_DEBUG "Map Bank 8\n");
-#endif
-               spin_lock_irqsave(&dev.devlock, flags);
-               __icn_release_channel();
-               icn_map_channel(card, 2);       /* Select Bank 8   */
-               icn_lock_channel(card, 2);      /* Lock Bank 8     */
-               spin_unlock_irqrestore(&dev.devlock, flags);
-               SLEEP(1);
-               memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);       /* Copy code        */
-#ifdef BOOT_DEBUG
-               printk(KERN_DEBUG "Bootloader transferred\n");
-#endif
-       }
-       SLEEP(1);
-       OUTB_P(0xff, ICN_RUN);  /* Start Boot-Code */
-       if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) {
-               goto out_kfree;
-       }
-       if (!card->doubleS0) {
-               ret = 0;
-               goto out_kfree;
-       }
-       /* reached only, if we have a Double-S0-Card */
-#ifdef BOOT_DEBUG
-       printk(KERN_DEBUG "Map Bank 0\n");
-#endif
-       spin_lock_irqsave(&dev.devlock, flags);
-       icn_map_channel(card, 0);       /* Select Bank 0   */
-       icn_lock_channel(card, 0);      /* Lock Bank 0     */
-       spin_unlock_irqrestore(&dev.devlock, flags);
-       SLEEP(1);
-       ret = (icn_check_loader(1));
-
-out_kfree:
-       kfree(codebuf);
-out:
-       return ret;
-}
-
-static int
-icn_loadproto(u_char __user *buffer, icn_card *card)
-{
-       register u_char __user *p = buffer;
-       u_char codebuf[256];
-       uint left = ICN_CODE_STAGE2;
-       uint cnt;
-       int timer;
-       unsigned long flags;
-
-#ifdef BOOT_DEBUG
-       printk(KERN_DEBUG "icn_loadproto called\n");
-#endif
-       if (!access_ok(VERIFY_READ, buffer, ICN_CODE_STAGE2))
-               return -EFAULT;
-       timer = 0;
-       spin_lock_irqsave(&dev.devlock, flags);
-       if (card->secondhalf) {
-               icn_map_channel(card, 2);
-               icn_lock_channel(card, 2);
-       } else {
-               icn_map_channel(card, 0);
-               icn_lock_channel(card, 0);
-       }
-       spin_unlock_irqrestore(&dev.devlock, flags);
-       while (left) {
-               if (sbfree) {   /* If there is a free buffer...  */
-                       cnt = left;
-                       if (cnt > 256)
-                               cnt = 256;
-                       if (copy_from_user(codebuf, p, cnt)) {
-                               icn_maprelease_channel(card, 0);
-                               return -EFAULT;
-                       }
-                       memcpy_toio(&sbuf_l, codebuf, cnt);     /* copy data                     */
-                       sbnext; /* switch to next buffer         */
-                       p += cnt;
-                       left -= cnt;
-                       timer = 0;
-               } else {
-#ifdef BOOT_DEBUG
-                       printk(KERN_DEBUG "boot 2 !sbfree\n");
-#endif
-                       if (timer++ > 5) {
-                               icn_maprelease_channel(card, 0);
-                               return -EIO;
-                       }
-                       schedule_timeout_interruptible(10);
-               }
-       }
-       writeb(0x20, &sbuf_n);
-       timer = 0;
-       while (1) {
-               if (readb(&cmd_o) || readb(&cmd_i)) {
-#ifdef BOOT_DEBUG
-                       printk(KERN_DEBUG "Proto?\n");
-#endif
-                       if (timer++ > 5) {
-                               printk(KERN_WARNING
-                                      "icn: (%s) Protocol timed out.\n",
-                                      CID);
-#ifdef BOOT_DEBUG
-                               printk(KERN_DEBUG "Proto TO!\n");
-#endif
-                               icn_maprelease_channel(card, 0);
-                               return -EIO;
-                       }
-#ifdef BOOT_DEBUG
-                       printk(KERN_DEBUG "Proto TO?\n");
-#endif
-                       msleep_interruptible(ICN_BOOT_TIMEOUT1);
-               } else {
-                       if ((card->secondhalf) || (!card->doubleS0)) {
-#ifdef BOOT_DEBUG
-                               printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
-                                      card->secondhalf);
-#endif
-                               spin_lock_irqsave(&card->lock, flags);
-                               init_timer(&card->st_timer);
-                               card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-                               card->st_timer.function = icn_polldchan;
-                               card->st_timer.data = (unsigned long) card;
-                               add_timer(&card->st_timer);
-                               card->flags |= ICN_FLAGS_RUNNING;
-                               if (card->doubleS0) {
-                                       init_timer(&card->other->st_timer);
-                                       card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
-                                       card->other->st_timer.function = icn_polldchan;
-                                       card->other->st_timer.data = (unsigned long) card->other;
-                                       add_timer(&card->other->st_timer);
-                                       card->other->flags |= ICN_FLAGS_RUNNING;
-                               }
-                               spin_unlock_irqrestore(&card->lock, flags);
-                       }
-                       icn_maprelease_channel(card, 0);
-                       return 0;
-               }
-       }
-}
-
-/* Read the Status-replies from the Interface */
-static int
-icn_readstatus(u_char __user *buf, int len, icn_card *card)
-{
-       int count;
-       u_char __user *p;
-
-       for (p = buf, count = 0; count < len; p++, count++) {
-               if (card->msg_buf_read == card->msg_buf_write)
-                       return count;
-               if (put_user(*card->msg_buf_read++, p))
-                       return -EFAULT;
-               if (card->msg_buf_read > card->msg_buf_end)
-                       card->msg_buf_read = card->msg_buf;
-       }
-       return count;
-}
-
-/* Put command-strings into the command-queue of the Interface */
-static int
-icn_writecmd(const u_char *buf, int len, int user, icn_card *card)
-{
-       int mch = card->secondhalf ? 2 : 0;
-       int pp;
-       int i;
-       int count;
-       int xcount;
-       int ocount;
-       int loop;
-       unsigned long flags;
-       int lastmap_channel;
-       struct icn_card *lastmap_card;
-       u_char *p;
-       isdn_ctrl cmd;
-       u_char msg[0x100];
-
-       ocount = 1;
-       xcount = loop = 0;
-       while (len) {
-               count = cmd_free;
-               if (count > len)
-                       count = len;
-               if (user) {
-                       if (copy_from_user(msg, buf, count))
-                               return -EFAULT;
-               } else
-                       memcpy(msg, buf, count);
-
-               spin_lock_irqsave(&dev.devlock, flags);
-               lastmap_card = dev.mcard;
-               lastmap_channel = dev.channel;
-               icn_map_channel(card, mch);
-
-               icn_putmsg(card, '>');
-               for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
-                            ++) {
-                       writeb((*p == '\n') ? 0xff : *p,
-                              &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
-                       len--;
-                       xcount++;
-                       icn_putmsg(card, *p);
-                       if ((*p == '\n') && (i > 1)) {
-                               icn_putmsg(card, '>');
-                               ocount++;
-                       }
-                       ocount++;
-               }
-               writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
-               if (lastmap_card)
-                       icn_map_channel(lastmap_card, lastmap_channel);
-               spin_unlock_irqrestore(&dev.devlock, flags);
-               if (len) {
-                       mdelay(1);
-                       if (loop++ > 20)
-                               break;
-               } else
-                       break;
-       }
-       if (len && (!user))
-               printk(KERN_WARNING "icn: writemsg incomplete!\n");
-       cmd.command = ISDN_STAT_STAVAIL;
-       cmd.driver = card->myid;
-       cmd.arg = ocount;
-       card->interface.statcallb(&cmd);
-       return xcount;
-}
-
-/*
- * Delete card's pending timers, send STOP to linklevel
- */
-static void
-icn_stopcard(icn_card *card)
-{
-       unsigned long flags;
-       isdn_ctrl cmd;
-
-       spin_lock_irqsave(&card->lock, flags);
-       if (card->flags & ICN_FLAGS_RUNNING) {
-               card->flags &= ~ICN_FLAGS_RUNNING;
-               del_timer(&card->st_timer);
-               del_timer(&card->rb_timer);
-               spin_unlock_irqrestore(&card->lock, flags);
-               cmd.command = ISDN_STAT_STOP;
-               cmd.driver = card->myid;
-               card->interface.statcallb(&cmd);
-               if (card->doubleS0)
-                       icn_stopcard(card->other);
-       } else
-               spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void
-icn_stopallcards(void)
-{
-       icn_card *p = cards;
-
-       while (p) {
-               icn_stopcard(p);
-               p = p->next;
-       }
-}
-
-/*
- * Unmap all cards, because some of them may be mapped accidetly during
- * autoprobing of some network drivers (SMC-driver?)
- */
-static void
-icn_disable_cards(void)
-{
-       icn_card *card = cards;
-
-       while (card) {
-               if (!request_region(card->port, ICN_PORTLEN, "icn-isdn")) {
-                       printk(KERN_WARNING
-                              "icn: (%s) ports 0x%03x-0x%03x in use.\n",
-                              CID,
-                              card->port,
-                              card->port + ICN_PORTLEN);
-               } else {
-                       OUTB_P(0, ICN_RUN);     /* Reset Controller     */
-                       OUTB_P(0, ICN_MAPRAM);  /* Disable RAM          */
-                       release_region(card->port, ICN_PORTLEN);
-               }
-               card = card->next;
-       }
-}
-
-static int
-icn_command(isdn_ctrl *c, icn_card *card)
-{
-       ulong a;
-       ulong flags;
-       int i;
-       char cbuf[80];
-       isdn_ctrl cmd;
-       icn_cdef cdef;
-       char __user *arg;
-
-       switch (c->command) {
-       case ISDN_CMD_IOCTL:
-               memcpy(&a, c->parm.num, sizeof(ulong));
-               arg = (char __user *)a;
-               switch (c->arg) {
-               case ICN_IOCTL_SETMMIO:
-                       if (dev.memaddr != (a & 0x0ffc000)) {
-                               if (!request_mem_region(a & 0x0ffc000, 0x4000, "icn-isdn (all cards)")) {
-                                       printk(KERN_WARNING
-                                              "icn: memory at 0x%08lx in use.\n",
-                                              a & 0x0ffc000);
-                                       return -EINVAL;
-                               }
-                               release_mem_region(a & 0x0ffc000, 0x4000);
-                               icn_stopallcards();
-                               spin_lock_irqsave(&card->lock, flags);
-                               if (dev.mvalid) {
-                                       iounmap(dev.shmem);
-                                       release_mem_region(dev.memaddr, 0x4000);
-                               }
-                               dev.mvalid = 0;
-                               dev.memaddr = a & 0x0ffc000;
-                               spin_unlock_irqrestore(&card->lock, flags);
-                               printk(KERN_INFO
-                                      "icn: (%s) mmio set to 0x%08lx\n",
-                                      CID,
-                                      dev.memaddr);
-                       }
-                       break;
-               case ICN_IOCTL_GETMMIO:
-                       return (long) dev.memaddr;
-               case ICN_IOCTL_SETPORT:
-                       if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
-                           || a == 0x340 || a == 0x350 || a == 0x360 ||
-                           a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
-                           || a == 0x348 || a == 0x358 || a == 0x368) {
-                               if (card->port != (unsigned short) a) {
-                                       if (!request_region((unsigned short) a, ICN_PORTLEN, "icn-isdn")) {
-                                               printk(KERN_WARNING
-                                                      "icn: (%s) ports 0x%03x-0x%03x in use.\n",
-                                                      CID, (int) a, (int) a + ICN_PORTLEN);
-                                               return -EINVAL;
-                                       }
-                                       release_region((unsigned short) a, ICN_PORTLEN);
-                                       icn_stopcard(card);
-                                       spin_lock_irqsave(&card->lock, flags);
-                                       if (card->rvalid)
-                                               release_region(card->port, ICN_PORTLEN);
-                                       card->port = (unsigned short) a;
-                                       card->rvalid = 0;
-                                       if (card->doubleS0) {
-                                               card->other->port = (unsigned short) a;
-                                               card->other->rvalid = 0;
-                                       }
-                                       spin_unlock_irqrestore(&card->lock, flags);
-                                       printk(KERN_INFO
-                                              "icn: (%s) port set to 0x%03x\n",
-                                              CID, card->port);
-                               }
-                       } else
-                               return -EINVAL;
-                       break;
-               case ICN_IOCTL_GETPORT:
-                       return (int) card->port;
-               case ICN_IOCTL_GETDOUBLE:
-                       return (int) card->doubleS0;
-               case ICN_IOCTL_DEBUGVAR:
-                       if (copy_to_user(arg,
-                                        &card,
-                                        sizeof(ulong)))
-                               return -EFAULT;
-                       a += sizeof(ulong);
-                       {
-                               ulong l = (ulong)&dev;
-                               if (copy_to_user(arg,
-                                                &l,
-                                                sizeof(ulong)))
-                                       return -EFAULT;
-                       }
-                       return 0;
-               case ICN_IOCTL_LOADBOOT:
-                       if (dev.firstload) {
-                               icn_disable_cards();
-                               dev.firstload = 0;
-                       }
-                       icn_stopcard(card);
-                       return (icn_loadboot(arg, card));
-               case ICN_IOCTL_LOADPROTO:
-                       icn_stopcard(card);
-                       if ((i = (icn_loadproto(arg, card))))
-                               return i;
-                       if (card->doubleS0)
-                               i = icn_loadproto(arg + ICN_CODE_STAGE2, card->other);
-                       return i;
-                       break;
-               case ICN_IOCTL_ADDCARD:
-                       if (!dev.firstload)
-                               return -EBUSY;
-                       if (copy_from_user(&cdef,
-                                          arg,
-                                          sizeof(cdef)))
-                               return -EFAULT;
-                       return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
-                       break;
-               case ICN_IOCTL_LEASEDCFG:
-                       if (a) {
-                               if (!card->leased) {
-                                       card->leased = 1;
-                                       while (card->ptype == ISDN_PTYPE_UNKNOWN) {
-                                               msleep_interruptible(ICN_BOOT_TIMEOUT1);
-                                       }
-                                       msleep_interruptible(ICN_BOOT_TIMEOUT1);
-                                       sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
-                                               (a & 1) ? '1' : 'C', (a & 2) ? '2' : 'C');
-                                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                                       printk(KERN_INFO
-                                              "icn: (%s) Leased-line mode enabled\n",
-                                              CID);
-                                       cmd.command = ISDN_STAT_RUN;
-                                       cmd.driver = card->myid;
-                                       cmd.arg = 0;
-                                       card->interface.statcallb(&cmd);
-                               }
-                       } else {
-                               if (card->leased) {
-                                       card->leased = 0;
-                                       sprintf(cbuf, "00;FV2OFF\n");
-                                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                                       printk(KERN_INFO
-                                              "icn: (%s) Leased-line mode disabled\n",
-                                              CID);
-                                       cmd.command = ISDN_STAT_RUN;
-                                       cmd.driver = card->myid;
-                                       cmd.arg = 0;
-                                       card->interface.statcallb(&cmd);
-                               }
-                       }
-                       return 0;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case ISDN_CMD_DIAL:
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (card->leased)
-                       break;
-               if ((c->arg & 255) < ICN_BCH) {
-                       char *p;
-                       char dcode[4];
-
-                       a = c->arg;
-                       p = c->parm.setup.phone;
-                       if (*p == 's' || *p == 'S') {
-                               /* Dial for SPV */
-                               p++;
-                               strcpy(dcode, "SCA");
-                       } else
-                               /* Normal Dial */
-                               strcpy(dcode, "CAL");
-                       snprintf(cbuf, sizeof(cbuf),
-                                "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
-                                dcode, p, c->parm.setup.si1,
-                                c->parm.setup.si2, c->parm.setup.eazmsn);
-                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-               }
-               break;
-       case ISDN_CMD_ACCEPTD:
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (c->arg < ICN_BCH) {
-                       a = c->arg + 1;
-                       if (card->fw_rev >= 300) {
-                               switch (card->l2_proto[a - 1]) {
-                               case ISDN_PROTO_L2_X75I:
-                                       sprintf(cbuf, "%02d;BX75\n", (int) a);
-                                       break;
-                               case ISDN_PROTO_L2_HDLC:
-                                       sprintf(cbuf, "%02d;BTRA\n", (int) a);
-                                       break;
-                               }
-                               i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                       }
-                       sprintf(cbuf, "%02d;DCON_R\n", (int) a);
-                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-               }
-               break;
-       case ISDN_CMD_ACCEPTB:
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (c->arg < ICN_BCH) {
-                       a = c->arg + 1;
-                       if (card->fw_rev >= 300)
-                               switch (card->l2_proto[a - 1]) {
-                               case ISDN_PROTO_L2_X75I:
-                                       sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
-                                       break;
-                               case ISDN_PROTO_L2_HDLC:
-                                       sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
-                                       break;
-                               } else
-                               sprintf(cbuf, "%02d;BCON_R\n", (int) a);
-                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-               }
-               break;
-       case ISDN_CMD_HANGUP:
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (c->arg < ICN_BCH) {
-                       a = c->arg + 1;
-                       sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
-                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-               }
-               break;
-       case ISDN_CMD_SETEAZ:
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (card->leased)
-                       break;
-               if (c->arg < ICN_BCH) {
-                       a = c->arg + 1;
-                       if (card->ptype == ISDN_PTYPE_EURO) {
-                               sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
-                                       c->parm.num[0] ? "N" : "ALL", c->parm.num);
-                       } else
-                               sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
-                                       c->parm.num[0] ? (char *)(c->parm.num) : "0123456789");
-                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-               }
-               break;
-       case ISDN_CMD_CLREAZ:
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               if (card->leased)
-                       break;
-               if (c->arg < ICN_BCH) {
-                       a = c->arg + 1;
-                       if (card->ptype == ISDN_PTYPE_EURO)
-                               sprintf(cbuf, "%02d;MSNC\n", (int) a);
-                       else
-                               sprintf(cbuf, "%02d;EAZC\n", (int) a);
-                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-               }
-               break;
-       case ISDN_CMD_SETL2:
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               if ((c->arg & 255) < ICN_BCH) {
-                       a = c->arg;
-                       switch (a >> 8) {
-                       case ISDN_PROTO_L2_X75I:
-                               sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
-                               break;
-                       case ISDN_PROTO_L2_HDLC:
-                               sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
-                       card->l2_proto[a & 255] = (a >> 8);
-               }
-               break;
-       case ISDN_CMD_SETL3:
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/*
- * Find card with given driverId
- */
-static inline icn_card *
-icn_findcard(int driverid)
-{
-       icn_card *p = cards;
-
-       while (p) {
-               if (p->myid == driverid)
-                       return p;
-               p = p->next;
-       }
-       return (icn_card *) 0;
-}
-
-/*
- * Wrapper functions for interface to linklevel
- */
-static int
-if_command(isdn_ctrl *c)
-{
-       icn_card *card = icn_findcard(c->driver);
-
-       if (card)
-               return (icn_command(c, card));
-       printk(KERN_ERR
-              "icn: if_command %d called with invalid driverId %d!\n",
-              c->command, c->driver);
-       return -ENODEV;
-}
-
-static int
-if_writecmd(const u_char __user *buf, int len, int id, int channel)
-{
-       icn_card *card = icn_findcard(id);
-
-       if (card) {
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               return (icn_writecmd(buf, len, 1, card));
-       }
-       printk(KERN_ERR
-              "icn: if_writecmd called with invalid driverId!\n");
-       return -ENODEV;
-}
-
-static int
-if_readstatus(u_char __user *buf, int len, int id, int channel)
-{
-       icn_card *card = icn_findcard(id);
-
-       if (card) {
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               return (icn_readstatus(buf, len, card));
-       }
-       printk(KERN_ERR
-              "icn: if_readstatus called with invalid driverId!\n");
-       return -ENODEV;
-}
-
-static int
-if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
-{
-       icn_card *card = icn_findcard(id);
-
-       if (card) {
-               if (!(card->flags & ICN_FLAGS_RUNNING))
-                       return -ENODEV;
-               return (icn_sendbuf(channel, ack, skb, card));
-       }
-       printk(KERN_ERR
-              "icn: if_sendbuf called with invalid driverId!\n");
-       return -ENODEV;
-}
-
-/*
- * Allocate a new card-struct, initialize it
- * link it into cards-list and register it at linklevel.
- */
-static icn_card *
-icn_initcard(int port, char *id)
-{
-       icn_card *card;
-       int i;
-
-       if (!(card = kzalloc(sizeof(icn_card), GFP_KERNEL))) {
-               printk(KERN_WARNING
-                      "icn: (%s) Could not allocate card-struct.\n", id);
-               return (icn_card *) 0;
-       }
-       spin_lock_init(&card->lock);
-       card->port = port;
-       card->interface.owner = THIS_MODULE;
-       card->interface.hl_hdrlen = 1;
-       card->interface.channels = ICN_BCH;
-       card->interface.maxbufsize = 4000;
-       card->interface.command = if_command;
-       card->interface.writebuf_skb = if_sendbuf;
-       card->interface.writecmd = if_writecmd;
-       card->interface.readstat = if_readstatus;
-       card->interface.features = ISDN_FEATURE_L2_X75I |
-               ISDN_FEATURE_L2_HDLC |
-               ISDN_FEATURE_L3_TRANS |
-               ISDN_FEATURE_P_UNKNOWN;
-       card->ptype = ISDN_PTYPE_UNKNOWN;
-       strlcpy(card->interface.id, id, sizeof(card->interface.id));
-       card->msg_buf_write = card->msg_buf;
-       card->msg_buf_read = card->msg_buf;
-       card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
-       for (i = 0; i < ICN_BCH; i++) {
-               card->l2_proto[i] = ISDN_PROTO_L2_X75I;
-               skb_queue_head_init(&card->spqueue[i]);
-       }
-       card->next = cards;
-       cards = card;
-       if (!register_isdn(&card->interface)) {
-               cards = cards->next;
-               printk(KERN_WARNING
-                      "icn: Unable to register %s\n", id);
-               kfree(card);
-               return (icn_card *) 0;
-       }
-       card->myid = card->interface.channels;
-       sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
-       return card;
-}
-
-static int
-icn_addcard(int port, char *id1, char *id2)
-{
-       icn_card *card;
-       icn_card *card2;
-
-       if (!(card = icn_initcard(port, id1))) {
-               return -EIO;
-       }
-       if (!strlen(id2)) {
-               printk(KERN_INFO
-                      "icn: (%s) ICN-2B, port 0x%x added\n",
-                      card->interface.id, port);
-               return 0;
-       }
-       if (!(card2 = icn_initcard(port, id2))) {
-               printk(KERN_INFO
-                      "icn: (%s) half ICN-4B, port 0x%x added\n", id2, port);
-               return 0;
-       }
-       card->doubleS0 = 1;
-       card->secondhalf = 0;
-       card->other = card2;
-       card2->doubleS0 = 1;
-       card2->secondhalf = 1;
-       card2->other = card;
-       printk(KERN_INFO
-              "icn: (%s and %s) ICN-4B, port 0x%x added\n",
-              card->interface.id, card2->interface.id, port);
-       return 0;
-}
-
-#ifndef MODULE
-static int __init
-icn_setup(char *line)
-{
-       char *p, *str;
-       int     ints[3];
-       static char sid[20];
-       static char sid2[20];
-
-       str = get_options(line, 2, ints);
-       if (ints[0])
-               portbase = ints[1];
-       if (ints[0] > 1)
-               membase = (unsigned long)ints[2];
-       if (str && *str) {
-               strlcpy(sid, str, sizeof(sid));
-               icn_id = sid;
-               if ((p = strchr(sid, ','))) {
-                       *p++ = 0;
-                       strcpy(sid2, p);
-                       icn_id2 = sid2;
-               }
-       }
-       return (1);
-}
-__setup("icn=", icn_setup);
-#endif /* MODULE */
-
-static int __init icn_init(void)
-{
-       char *p;
-       char rev[21];
-
-       memset(&dev, 0, sizeof(icn_dev));
-       dev.memaddr = (membase & 0x0ffc000);
-       dev.channel = -1;
-       dev.mcard = NULL;
-       dev.firstload = 1;
-       spin_lock_init(&dev.devlock);
-
-       if ((p = strchr(revision, ':'))) {
-               strncpy(rev, p + 1, 20);
-               rev[20] = '\0';
-               p = strchr(rev, '$');
-               if (p)
-                       *p = 0;
-       } else
-               strcpy(rev, " ??? ");
-       printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
-              dev.memaddr);
-       return (icn_addcard(portbase, icn_id, icn_id2));
-}
-
-static void __exit icn_exit(void)
-{
-       isdn_ctrl cmd;
-       icn_card *card = cards;
-       icn_card *last, *tmpcard;
-       int i;
-       unsigned long flags;
-
-       icn_stopallcards();
-       while (card) {
-               cmd.command = ISDN_STAT_UNLOAD;
-               cmd.driver = card->myid;
-               card->interface.statcallb(&cmd);
-               spin_lock_irqsave(&card->lock, flags);
-               if (card->rvalid) {
-                       OUTB_P(0, ICN_RUN);     /* Reset Controller     */
-                       OUTB_P(0, ICN_MAPRAM);  /* Disable RAM          */
-                       if (card->secondhalf || (!card->doubleS0)) {
-                               release_region(card->port, ICN_PORTLEN);
-                               card->rvalid = 0;
-                       }
-                       for (i = 0; i < ICN_BCH; i++)
-                               icn_free_queue(card, i);
-               }
-               tmpcard = card->next;
-               spin_unlock_irqrestore(&card->lock, flags);
-               card = tmpcard;
-       }
-       card = cards;
-       cards = NULL;
-       while (card) {
-               last = card;
-               card = card->next;
-               kfree(last);
-       }
-       if (dev.mvalid) {
-               iounmap(dev.shmem);
-               release_mem_region(dev.memaddr, 0x4000);
-       }
-       printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
-}
-
-module_init(icn_init);
-module_exit(icn_exit);
diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h
deleted file mode 100644 (file)
index f8f2e76..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-/* $Id: icn.h,v 1.30.6.5 2001/09/23 22:24:55 kai Exp $
- *
- * ISDN lowlevel-module for the ICN active ISDN-Card.
- *
- * Copyright 1994 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef icn_h
-#define icn_h
-
-#define ICN_IOCTL_SETMMIO   0
-#define ICN_IOCTL_GETMMIO   1
-#define ICN_IOCTL_SETPORT   2
-#define ICN_IOCTL_GETPORT   3
-#define ICN_IOCTL_LOADBOOT  4
-#define ICN_IOCTL_LOADPROTO 5
-#define ICN_IOCTL_LEASEDCFG 6
-#define ICN_IOCTL_GETDOUBLE 7
-#define ICN_IOCTL_DEBUGVAR  8
-#define ICN_IOCTL_ADDCARD   9
-
-/* Struct for adding new cards */
-typedef struct icn_cdef {
-       int port;
-       char id1[10];
-       char id2[10];
-} icn_cdef;
-
-#if defined(__KERNEL__) || defined(__DEBUGVAR__)
-
-#ifdef __KERNEL__
-/* Kernel includes */
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/slab.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/isdnif.h>
-
-#endif                          /* __KERNEL__ */
-
-/* some useful macros for debugging */
-#ifdef ICN_DEBUG_PORT
-#define OUTB_P(v, p) {printk(KERN_DEBUG "icn: outb_p(0x%02x,0x%03x)\n", v, p); outb_p(v, p);}
-#else
-#define OUTB_P outb
-#endif
-
-/* Defaults for Port-Address and shared-memory */
-#define ICN_BASEADDR 0x320
-#define ICN_PORTLEN (0x04)
-#define ICN_MEMADDR 0x0d0000
-
-#define ICN_FLAGS_B1ACTIVE 1    /* B-Channel-1 is open                     */
-#define ICN_FLAGS_B2ACTIVE 2    /* B-Channel-2 is open                     */
-#define ICN_FLAGS_RUNNING  4    /* Cards driver activated                  */
-#define ICN_FLAGS_RBTIMER  8    /* cyclic scheduling of B-Channel-poll     */
-
-#define ICN_BOOT_TIMEOUT1  1000 /* Delay for Boot-download (msecs)         */
-
-#define ICN_TIMER_BCREAD (HZ / 100)    /* B-Channel poll-cycle                    */
-#define ICN_TIMER_DCREAD (HZ / 2) /* D-Channel poll-cycle                    */
-
-#define ICN_CODE_STAGE1 4096    /* Size of bootcode                        */
-#define ICN_CODE_STAGE2 65536   /* Size of protocol-code                   */
-
-#define ICN_MAX_SQUEUE 8000     /* Max. outstanding send-data (2* hw-buf.) */
-#define ICN_FRAGSIZE (250)      /* Max. size of send-fragments             */
-#define ICN_BCH 2               /* Number of supported channels per card   */
-
-/* type-definitions for accessing the mmap-io-areas */
-
-#define SHM_DCTL_OFFSET (0)     /* Offset to data-controlstructures in shm */
-#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */
-#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm           */
-#define SHM_DBUF_OFFSET (0x2000)       /* Offset to data-buffers in shm           */
-
-/*
- * Layout of card's data buffers
- */
-typedef struct {
-       unsigned char length;   /* Bytecount of fragment (max 250)    */
-       unsigned char endflag;  /* 0=last frag., 0xff=frag. continued */
-       unsigned char data[ICN_FRAGSIZE];       /* The data                           */
-       /* Fill to 256 bytes */
-       char unused[0x100 - ICN_FRAGSIZE - 2];
-} frag_buf;
-
-/*
- * Layout of card's shared memory
- */
-typedef union {
-       struct {
-               unsigned char scns;     /* Index to free SendFrag.             */
-               unsigned char scnr;     /* Index to active SendFrag   READONLY */
-               unsigned char ecns;     /* Index to free RcvFrag.     READONLY */
-               unsigned char ecnr;     /* Index to valid RcvFrag              */
-               char unused[6];
-               unsigned short fuell1;  /* Internal Buf Bytecount              */
-       } data_control;
-       struct {
-               char unused[SHM_CCTL_OFFSET];
-               unsigned char iopc_i;   /* Read-Ptr Status-Queue      READONLY */
-               unsigned char iopc_o;   /* Write-Ptr Status-Queue              */
-               unsigned char pcio_i;   /* Write-Ptr Command-Queue             */
-               unsigned char pcio_o;   /* Read-Ptr Command Queue     READONLY */
-       } comm_control;
-       struct {
-               char unused[SHM_CBUF_OFFSET];
-               unsigned char pcio_buf[0x100];  /* Ring-Buffer Command-Queue           */
-               unsigned char iopc_buf[0x100];  /* Ring-Buffer Status-Queue            */
-       } comm_buffers;
-       struct {
-               char unused[SHM_DBUF_OFFSET];
-               frag_buf receive_buf[0x10];
-               frag_buf send_buf[0x10];
-       } data_buffers;
-} icn_shmem;
-
-/*
- * Per card driver data
- */
-typedef struct icn_card {
-       struct icn_card *next;  /* Pointer to next device struct    */
-       struct icn_card *other; /* Pointer to other card for ICN4B  */
-       unsigned short port;    /* Base-port-address                */
-       int myid;               /* Driver-Nr. assigned by linklevel */
-       int rvalid;             /* IO-portregion has been requested */
-       int leased;             /* Flag: This Adapter is connected  */
-                               /*       to a leased line           */
-       unsigned short flags;   /* Statusflags                      */
-       int doubleS0;           /* Flag: ICN4B                      */
-       int secondhalf;         /* Flag: Second half of a doubleS0  */
-       int fw_rev;             /* Firmware revision loaded         */
-       int ptype;              /* Protocol type (1TR6 or Euro)     */
-       struct timer_list st_timer;   /* Timer for Status-Polls     */
-       struct timer_list rb_timer;   /* Timer for B-Channel-Polls  */
-       u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers  */
-       int rcvidx[ICN_BCH];    /* Index for above buffers          */
-       int l2_proto[ICN_BCH];  /* Current layer-2-protocol         */
-       isdn_if interface;      /* Interface to upper layer         */
-       int iptr;               /* Index to imsg-buffer             */
-       char imsg[60];          /* Internal buf for status-parsing  */
-       char msg_buf[2048];     /* Buffer for status-messages       */
-       char *msg_buf_write;    /* Writepointer for statusbuffer    */
-       char *msg_buf_read;     /* Readpointer for statusbuffer     */
-       char *msg_buf_end;      /* Pointer to end of statusbuffer   */
-       int sndcount[ICN_BCH];  /* Byte-counters for B-Ch.-send     */
-       int xlen[ICN_BCH];      /* Byte-counters/Flags for sent-ACK */
-       struct sk_buff *xskb[ICN_BCH]; /* Current transmitted skb   */
-       struct sk_buff_head spqueue[ICN_BCH];  /* Sendqueue         */
-       char regname[35];       /* Name used for request_region     */
-       u_char xmit_lock[ICN_BCH]; /* Semaphore for pollbchan_send()*/
-       spinlock_t lock;        /* protect critical operations      */
-} icn_card;
-
-/*
- * Main driver data
- */
-typedef struct icn_dev {
-       spinlock_t devlock;     /* spinlock to protect this struct  */
-       unsigned long memaddr;  /* Address of memory mapped buffers */
-       icn_shmem __iomem *shmem;       /* Pointer to memory-mapped-buffers */
-       int mvalid;             /* IO-shmem has been requested      */
-       int channel;            /* Currently mapped channel         */
-       struct icn_card *mcard; /* Currently mapped card            */
-       int chanlock;           /* Semaphore for channel-mapping    */
-       int firstload;          /* Flag: firmware never loaded      */
-} icn_dev;
-
-typedef icn_dev *icn_devptr;
-
-#ifdef __KERNEL__
-
-static icn_card *cards = (icn_card *) 0;
-static u_char chan2bank[] =
-{0, 4, 8, 12};                  /* for icn_map_channel() */
-
-static icn_dev dev;
-
-#endif                          /* __KERNEL__ */
-
-/* Utility-Macros */
-
-/* Macros for accessing ports */
-#define ICN_CFG    (card->port)
-#define ICN_MAPRAM (card->port + 1)
-#define ICN_RUN    (card->port + 2)
-#define ICN_BANK   (card->port + 3)
-
-/* Return true, if there is a free transmit-buffer */
-#define sbfree (((readb(&dev.shmem->data_control.scns) + 1) & 0xf) !=  \
-               readb(&dev.shmem->data_control.scnr))
-
-/* Switch to next transmit-buffer */
-#define sbnext (writeb((readb(&dev.shmem->data_control.scns) + 1) & 0xf,       \
-                      &dev.shmem->data_control.scns))
-
-/* Shortcuts for transmit-buffer-access */
-#define sbuf_n dev.shmem->data_control.scns
-#define sbuf_d dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].data
-#define sbuf_l dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].length
-#define sbuf_f dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].endflag
-
-/* Return true, if there is receive-data is available */
-#define rbavl  (readb(&dev.shmem->data_control.ecnr) != \
-               readb(&dev.shmem->data_control.ecns))
-
-/* Switch to next receive-buffer */
-#define rbnext (writeb((readb(&dev.shmem->data_control.ecnr) + 1) & 0xf,       \
-                      &dev.shmem->data_control.ecnr))
-
-/* Shortcuts for receive-buffer-access */
-#define rbuf_n dev.shmem->data_control.ecnr
-#define rbuf_d dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].data
-#define rbuf_l dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].length
-#define rbuf_f dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].endflag
-
-/* Shortcuts for command-buffer-access */
-#define cmd_o (dev.shmem->comm_control.pcio_o)
-#define cmd_i (dev.shmem->comm_control.pcio_i)
-
-/* Return free space in command-buffer */
-#define cmd_free ((readb(&cmd_i) >= readb(&cmd_o)) ?           \
-                 0x100 - readb(&cmd_i) + readb(&cmd_o) :       \
-                 readb(&cmd_o) - readb(&cmd_i))
-
-/* Shortcuts for message-buffer-access */
-#define msg_o (dev.shmem->comm_control.iopc_o)
-#define msg_i (dev.shmem->comm_control.iopc_i)
-
-/* Return length of Message, if avail. */
-#define msg_avail ((readb(&msg_o) > readb(&msg_i)) ?           \
-                  0x100 - readb(&msg_o) + readb(&msg_i) :      \
-                  readb(&msg_i) - readb(&msg_o))
-
-#define CID (card->interface.id)
-
-#endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif                          /* icn_h */
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig
deleted file mode 100644 (file)
index e9b2dd8..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-config ISDN_DRV_PCBIT
-       tristate "PCBIT-D support"
-       depends on ISA && (BROKEN || X86)
-       help
-         This enables support for the PCBIT ISDN-card.  This card is
-         manufactured in Portugal by Octal.  For running this card,
-         additional firmware is necessary, which has to be downloaded into
-         the card using a utility which is distributed separately.  See
-         <file:Documentation/isdn/README> and
-         <file:Documentation/isdn/README.pcbit> for more information.
diff --git a/drivers/isdn/pcbit/Makefile b/drivers/isdn/pcbit/Makefile
deleted file mode 100644 (file)
index 2d026c3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# Makefile for the pcbit ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_PCBIT)   += pcbit.o
-
-# Multipart objects.
-
-pcbit-y                                := module.o edss1.o drv.o layer2.o capi.o callbacks.o
diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c
deleted file mode 100644 (file)
index efb6d6a..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Callbacks for the FSM
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * 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)
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-#include <linux/isdnif.h>
-
-#include "pcbit.h"
-#include "layer2.h"
-#include "edss1.h"
-#include "callbacks.h"
-#include "capi.h"
-
-ushort last_ref_num = 1;
-
-/*
- *  send_conn_req
- *
- */
-
-void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
-             struct callb_data *cbdata)
-{
-       struct sk_buff *skb;
-       int len;
-       ushort refnum;
-
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "Called Party Number: %s\n",
-              cbdata->data.setup.CalledPN);
-#endif
-       /*
-        * hdr - kmalloc in capi_conn_req
-        *     - kfree   when msg has been sent
-        */
-
-       if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb,
-                                chan->proto)) < 0)
-       {
-               printk("capi_conn_req failed\n");
-               return;
-       }
-
-
-       refnum = last_ref_num++ & 0x7fffU;
-
-       chan->callref = 0;
-       chan->layer2link = 0;
-       chan->snum = 0;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len);
-}
-
-/*
- *  rcv CONNECT
- *  will go into ACTIVE state
- *  send CONN_ACTIVE_RESP
- *  send Select protocol request
- */
-
-void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
-             struct callb_data *data)
-{
-       isdn_ctrl ictl;
-       struct sk_buff *skb;
-       int len;
-       ushort refnum;
-
-       if ((len = capi_conn_active_resp(chan, &skb)) < 0)
-       {
-               printk("capi_conn_active_req failed\n");
-               return;
-       }
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len);
-
-
-       ictl.command = ISDN_STAT_DCONN;
-       ictl.driver = dev->id;
-       ictl.arg = chan->id;
-       dev->dev_if->statcallb(&ictl);
-
-       /* ACTIVE D-channel */
-
-       /* Select protocol  */
-
-       if ((len = capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) {
-               printk("capi_select_proto_req failed\n");
-               return;
-       }
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
-}
-
-
-/*
- * Incoming call received
- * inform user
- */
-
-void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
-            struct callb_data *cbdata)
-{
-       isdn_ctrl ictl;
-       unsigned short refnum;
-       struct sk_buff *skb;
-       int len;
-
-
-       ictl.command = ISDN_STAT_ICALL;
-       ictl.driver = dev->id;
-       ictl.arg = chan->id;
-
-       /*
-        *  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;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "statstr: %s\n", ictl.num);
-#endif
-
-       dev->dev_if->statcallb(&ictl);
-
-
-       if ((len = capi_conn_resp(chan, &skb)) < 0) {
-               printk(KERN_DEBUG "capi_conn_resp failed\n");
-               return;
-       }
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len);
-}
-
-/*
- * user has replied
- * open the channel
- * send CONNECT message CONNECT_ACTIVE_REQ in CAPI
- */
-
-void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
-            struct callb_data *data)
-{
-       unsigned short refnum;
-       struct sk_buff *skb;
-       int len;
-
-       if ((len = capi_conn_active_req(chan, &skb)) < 0) {
-               printk(KERN_DEBUG "capi_conn_active_req failed\n");
-               return;
-       }
-
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n");
-       pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len);
-}
-
-/*
- * CONN_ACK arrived
- * start b-proto selection
- *
- */
-
-void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
-            struct callb_data *data)
-{
-       unsigned short refnum;
-       struct sk_buff *skb;
-       int len;
-
-       if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0)
-       {
-               printk("capi_select_proto_req failed\n");
-               return;
-       }
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
-
-}
-
-
-/*
- * Received disconnect ind on active state
- * send disconnect resp
- * send msg to user
- */
-void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
-              struct callb_data *data)
-{
-       struct sk_buff *skb;
-       int len;
-       ushort refnum;
-       isdn_ctrl ictl;
-
-       if ((len = capi_disc_resp(chan, &skb)) < 0) {
-               printk("capi_disc_resp failed\n");
-               return;
-       }
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len);
-
-       ictl.command = ISDN_STAT_BHUP;
-       ictl.driver = dev->id;
-       ictl.arg = chan->id;
-       dev->dev_if->statcallb(&ictl);
-}
-
-
-/*
- *  User HANGUP on active/call proceeding state
- *  send disc.req
- */
-void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
-              struct callb_data *data)
-{
-       struct sk_buff *skb;
-       int len;
-       ushort refnum;
-
-       if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0)
-       {
-               printk("capi_disc_req failed\n");
-               return;
-       }
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len);
-}
-
-/*
- *  Disc confirm received send BHUP
- *  Problem: when the HL driver sends the disc req itself
- *           LL receives BHUP
- */
-void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
-              struct callb_data *data)
-{
-       isdn_ctrl ictl;
-
-       ictl.command = ISDN_STAT_BHUP;
-       ictl.driver = dev->id;
-       ictl.arg = chan->id;
-       dev->dev_if->statcallb(&ictl);
-}
-
-void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan,
-               struct callb_data *data)
-{
-}
-
-/*
- * send activate b-chan protocol
- */
-void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
-              struct callb_data *data)
-{
-       struct sk_buff *skb;
-       int len;
-       ushort refnum;
-
-       if ((len = capi_activate_transp_req(chan, &skb)) < 0)
-       {
-               printk("capi_conn_activate_transp_req failed\n");
-               return;
-       }
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len);
-}
-
-/*
- *  Inform User that the B-channel is available
- */
-void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan,
-            struct callb_data *data)
-{
-       isdn_ctrl ictl;
-
-       ictl.command = ISDN_STAT_BCONN;
-       ictl.driver = dev->id;
-       ictl.arg = chan->id;
-       dev->dev_if->statcallb(&ictl);
-}
diff --git a/drivers/isdn/pcbit/callbacks.h b/drivers/isdn/pcbit/callbacks.h
deleted file mode 100644 (file)
index a036b4a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Callbacks prototypes for FSM
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef CALLBACKS_H
-#define CALLBACKS_H
-
-
-extern void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                    struct callb_data *data);
-
-extern void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                    struct callb_data *data);
-
-extern void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                   struct callb_data *data);
-extern void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                   struct callb_data *data);
-extern void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                   struct callb_data *data);
-
-extern void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                     struct callb_data *data);
-extern void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                     struct callb_data *data);
-extern void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                     struct callb_data *data);
-
-extern void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                      struct callb_data *data);
-
-extern void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                     struct callb_data *data);
-extern void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                   struct callb_data *data);
-
-#endif
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
deleted file mode 100644 (file)
index 4e3cbf8..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * CAPI encoder/decoder for
- * Portugal Telecom CAPI 2.0
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- *
- * Not compatible with the AVM Gmbh. CAPI 2.0
- *
- */
-
-/*
- *        Documentation:
- *        - "Common ISDN API - Perfil Português - Versão 2.1",
- *           Telecom Portugal, Fev 1992.
- *        - "Common ISDN API - Especificação de protocolos para
- *           acesso aos canais B", Inesc, Jan 1994.
- */
-
-/*
- *        TODO: better decoding of Information Elements
- *              for debug purposes mainly
- *              encode our number in CallerPN and ConnectedPN
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-#include <asm/string.h>
-
-#include <linux/isdnif.h>
-
-#include "pcbit.h"
-#include "edss1.h"
-#include "capi.h"
-
-
-/*
- *  Encoding of CAPI messages
- *
- */
-
-int capi_conn_req(const char *calledPN, struct sk_buff **skb, int proto)
-{
-       ushort len;
-
-       /*
-        * length
-        *   AppInfoMask - 2
-        *   BC0         - 3
-        *   BC1         - 1
-        *   Chan        - 2
-        *   Keypad      - 1
-        *   CPN         - 1
-        *   CPSA        - 1
-        *   CalledPN    - 2 + strlen
-        *   CalledPSA   - 1
-        *   rest...     - 4
-        *   ----------------
-        *   Total        18 + strlen
-        */
-
-       len = 18 + strlen(calledPN);
-
-       if (proto == ISDN_PROTO_L2_TRANS)
-               len++;
-
-       if ((*skb = dev_alloc_skb(len)) == NULL) {
-
-               printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n");
-               return -1;
-       }
-
-       /* InfoElmMask */
-       *((ushort *)skb_put(*skb, 2)) = AppInfoMask;
-
-       if (proto == ISDN_PROTO_L2_TRANS)
-       {
-               /* Bearer Capability - Mandatory*/
-               *(skb_put(*skb, 1)) = 3;        /* BC0.Length           */
-               *(skb_put(*skb, 1)) = 0x80;     /* Speech               */
-               *(skb_put(*skb, 1)) = 0x10;     /* Circuit Mode         */
-               *(skb_put(*skb, 1)) = 0x23;     /* A-law                */
-       }
-       else
-       {
-               /* Bearer Capability - Mandatory*/
-               *(skb_put(*skb, 1)) = 2;        /* BC0.Length           */
-               *(skb_put(*skb, 1)) = 0x88;     /* Digital Information  */
-               *(skb_put(*skb, 1)) = 0x90;     /* BC0.Octect4          */
-       }
-
-       /* Bearer Capability - Optional*/
-       *(skb_put(*skb, 1)) = 0;        /* BC1.Length = 0                    */
-
-       *(skb_put(*skb, 1)) = 1;        /* ChannelID.Length = 1              */
-       *(skb_put(*skb, 1)) = 0x83;     /* Basic Interface - Any Channel     */
-
-       *(skb_put(*skb, 1)) = 0;        /* Keypad.Length = 0                 */
-
-
-       *(skb_put(*skb, 1)) = 0;        /* CallingPN.Length = 0              */
-       *(skb_put(*skb, 1)) = 0;        /* CallingPSA.Length = 0             */
-
-       /* Called Party Number */
-       *(skb_put(*skb, 1)) = strlen(calledPN) + 1;
-       *(skb_put(*skb, 1)) = 0x81;
-       memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN));
-
-       /* '#' */
-
-       *(skb_put(*skb, 1)) = 0;       /* CalledPSA.Length = 0     */
-
-       /* LLC.Length  = 0; */
-       /* HLC0.Length = 0; */
-       /* HLC1.Length = 0; */
-       /* UTUS.Length = 0; */
-       memset(skb_put(*skb, 4), 0, 4);
-
-       return len;
-}
-
-int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb)
-{
-
-       if ((*skb = dev_alloc_skb(5)) == NULL) {
-
-               printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n");
-               return -1;
-       }
-
-       *((ushort *)skb_put(*skb, 2)) = chan->callref;
-       *(skb_put(*skb, 1)) = 0x01;  /* ACCEPT_CALL */
-       *(skb_put(*skb, 1)) = 0;
-       *(skb_put(*skb, 1)) = 0;
-
-       return 5;
-}
-
-int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb)
-{
-       /*
-        * 8 bytes
-        */
-
-       if ((*skb = dev_alloc_skb(8)) == NULL) {
-
-               printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n");
-               return -1;
-       }
-
-       *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
-#endif
-
-       *(skb_put(*skb, 1)) = 0;       /*  BC.Length = 0;          */
-       *(skb_put(*skb, 1)) = 0;       /*  ConnectedPN.Length = 0  */
-       *(skb_put(*skb, 1)) = 0;       /*  PSA.Length              */
-       *(skb_put(*skb, 1)) = 0;       /*  LLC.Length = 0;         */
-       *(skb_put(*skb, 1)) = 0;       /*  HLC.Length = 0;         */
-       *(skb_put(*skb, 1)) = 0;       /*  UTUS.Length = 0;        */
-
-       return 8;
-}
-
-int capi_conn_active_resp(struct pcbit_chan *chan, struct sk_buff **skb)
-{
-       /*
-        * 2 bytes
-        */
-
-       if ((*skb = dev_alloc_skb(2)) == NULL) {
-
-               printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n");
-               return -1;
-       }
-
-       *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
-       return 2;
-}
-
-
-int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
-                         int outgoing)
-{
-
-       /*
-        * 18 bytes
-        */
-
-       if ((*skb = dev_alloc_skb(18)) == NULL) {
-
-               printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n");
-               return -1;
-       }
-
-       *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
-       /* Layer2 protocol */
-
-       switch (chan->proto) {
-       case ISDN_PROTO_L2_X75I:
-               *(skb_put(*skb, 1)) = 0x05;            /* LAPB */
-               break;
-       case ISDN_PROTO_L2_HDLC:
-               *(skb_put(*skb, 1)) = 0x02;
-               break;
-       case ISDN_PROTO_L2_TRANS:
-               /*
-                *      Voice (a-law)
-                */
-               *(skb_put(*skb, 1)) = 0x06;
-               break;
-       default:
-#ifdef DEBUG
-               printk(KERN_DEBUG "Transparent\n");
-#endif
-               *(skb_put(*skb, 1)) = 0x03;
-               break;
-       }
-
-       *(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42);    /* Don't ask */
-       *(skb_put(*skb, 1)) = 0x00;
-
-       *((ushort *) skb_put(*skb, 2)) = MRU;
-
-
-       *(skb_put(*skb, 1)) = 0x08;           /* Modulo */
-       *(skb_put(*skb, 1)) = 0x07;           /* Max Window */
-
-       *(skb_put(*skb, 1)) = 0x01;           /* No Layer3 Protocol */
-
-       /*
-        * 2 - layer3 MTU       [10]
-        *   - Modulo           [12]
-        *   - Window
-        *   - layer1 proto     [14]
-        *   - bitrate
-        *   - sub-channel      [16]
-        *   - layer1dataformat [17]
-        */
-
-       memset(skb_put(*skb, 8), 0, 8);
-
-       return 18;
-}
-
-
-int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
-{
-
-       if ((*skb = dev_alloc_skb(7)) == NULL) {
-
-               printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n");
-               return -1;
-       }
-
-       *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
-
-       *(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */
-       *(skb_put(*skb, 1)) = 0x00;             /* Transmit by default */
-
-       *((ushort *) skb_put(*skb, 2)) = MRU;
-
-       *(skb_put(*skb, 1)) = 0x01;             /* Enables reception*/
-
-       return 7;
-}
-
-int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb)
-{
-       ushort data_len;
-
-
-       /*
-        * callref      - 2
-        * layer2link   - 1
-        * wBlockLength - 2
-        * data         - 4
-        * sernum       - 1
-        */
-
-       data_len = skb->len;
-
-       if (skb_headroom(skb) < 10)
-       {
-               printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb);
-       }
-       else
-       {
-               skb_push(skb, 10);
-       }
-
-       *((u16 *) (skb->data)) = chan->callref;
-       skb->data[2] = chan->layer2link;
-       *((u16 *) (skb->data + 3)) = data_len;
-
-       chan->s_refnum = (chan->s_refnum + 1) % 8;
-       *((u32 *) (skb->data + 5)) = chan->s_refnum;
-
-       skb->data[9] = 0;                           /* HDLC frame number */
-
-       return 10;
-}
-
-int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb)
-
-{
-       if ((*skb = dev_alloc_skb(4)) == NULL) {
-
-               printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n");
-               return -1;
-       }
-
-       *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
-       *(skb_put(*skb, 1)) = chan->layer2link;
-       *(skb_put(*skb, 1)) = chan->r_refnum;
-
-       return (*skb)->len;
-}
-
-int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
-{
-
-       if ((*skb = dev_alloc_skb(6)) == NULL) {
-
-               printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n");
-               return -1;
-       }
-
-       *((ushort *)skb_put(*skb, 2)) = callref;
-
-       *(skb_put(*skb, 1)) = 2;                  /* Cause.Length = 2; */
-       *(skb_put(*skb, 1)) = 0x80;
-       *(skb_put(*skb, 1)) = 0x80 | cause;
-
-       /*
-        * Change it: we should send 'Sic transit gloria Mundi' here ;-)
-        */
-
-       *(skb_put(*skb, 1)) = 0;                   /* UTUS.Length = 0;  */
-
-       return 6;
-}
-
-int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
-{
-       if ((*skb = dev_alloc_skb(2)) == NULL) {
-
-               printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n");
-               return -1;
-       }
-
-       *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
-       return 2;
-}
-
-
-/*
- *  Decoding of CAPI messages
- *
- */
-
-int capi_decode_conn_ind(struct pcbit_chan *chan,
-                        struct sk_buff *skb,
-                        struct callb_data *info)
-{
-       int CIlen, len;
-
-       /* Call Reference [CAPI] */
-       chan->callref = *((ushort *)skb->data);
-       skb_pull(skb, 2);
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
-#endif
-
-       /* Channel Identification */
-
-       /* Expect
-          Len = 1
-          Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ]
-       */
-
-       CIlen = skb->data[0];
-#ifdef DEBUG
-       if (CIlen == 1) {
-
-               if (((skb->data[1]) & 0xFC) == 0x48)
-                       printk(KERN_DEBUG "decode_conn_ind: chan ok\n");
-               printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03);
-       }
-       else
-               printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen);
-#endif
-       skb_pull(skb, CIlen + 1);
-
-       /* Calling Party Number */
-       /* An "additional service" as far as Portugal Telecom is concerned */
-
-       len = skb->data[0];
-
-       if (len > 0) {
-               int count = 1;
-
-#ifdef DEBUG
-               printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]);
-#endif
-               if ((skb->data[1] & 0x80) == 0)
-                       count = 2;
-
-               if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC)))
-                       return -1;
-
-               skb_copy_from_linear_data_offset(skb, count + 1,
-                                                info->data.setup.CallingPN,
-                                                len - count);
-               info->data.setup.CallingPN[len - count] = 0;
-
-       }
-       else {
-               info->data.setup.CallingPN = NULL;
-               printk(KERN_DEBUG "NULL CallingPN\n");
-       }
-
-       skb_pull(skb, len + 1);
-
-       /* Calling Party Subaddress */
-       skb_pull(skb, skb->data[0] + 1);
-
-       /* Called Party Number */
-
-       len = skb->data[0];
-
-       if (len > 0) {
-               int count = 1;
-
-               if ((skb->data[1] & 0x80) == 0)
-                       count = 2;
-
-               if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC)))
-                       return -1;
-
-               skb_copy_from_linear_data_offset(skb, count + 1,
-                                                info->data.setup.CalledPN,
-                                                len - count);
-               info->data.setup.CalledPN[len - count] = 0;
-
-       }
-       else {
-               info->data.setup.CalledPN = NULL;
-               printk(KERN_DEBUG "NULL CalledPN\n");
-       }
-
-       skb_pull(skb, len + 1);
-
-       /* Called Party Subaddress */
-       skb_pull(skb, skb->data[0] + 1);
-
-       /* LLC */
-       skb_pull(skb, skb->data[0] + 1);
-
-       /* HLC */
-       skb_pull(skb, skb->data[0] + 1);
-
-       /* U2U */
-       skb_pull(skb, skb->data[0] + 1);
-
-       return 0;
-}
-
-/*
- *  returns errcode
- */
-
-int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb,
-                         int *complete)
-{
-       int errcode;
-
-       chan->callref = *((ushort *)skb->data);     /* Update CallReference */
-       skb_pull(skb, 2);
-
-       errcode = *((ushort *) skb->data);   /* read errcode */
-       skb_pull(skb, 2);
-
-       *complete = *(skb->data);
-       skb_pull(skb, 1);
-
-       /* FIX ME */
-       /* This is actually a firmware bug */
-       if (!*complete)
-       {
-               printk(KERN_DEBUG "complete=%02x\n", *complete);
-               *complete = 1;
-       }
-
-
-       /* Optional Bearer Capability */
-       skb_pull(skb, *(skb->data) + 1);
-
-       /* Channel Identification */
-       skb_pull(skb, *(skb->data) + 1);
-
-       /* High Layer Compatibility follows */
-       skb_pull(skb, *(skb->data) + 1);
-
-       return errcode;
-}
-
-int capi_decode_conn_actv_ind(struct pcbit_chan *chan, struct sk_buff *skb)
-{
-       ushort len;
-#ifdef DEBUG
-       char str[32];
-#endif
-
-       /* Yet Another Bearer Capability */
-       skb_pull(skb, *(skb->data) + 1);
-
-
-       /* Connected Party Number */
-       len = *(skb->data);
-
-#ifdef DEBUG
-       if (len > 1 && len < 31) {
-               skb_copy_from_linear_data_offset(skb, 2, str, len - 1);
-               str[len] = 0;
-               printk(KERN_DEBUG "Connected Party Number: %s\n", str);
-       }
-       else
-               printk(KERN_DEBUG "actv_ind CPN len = %d\n", len);
-#endif
-
-       skb_pull(skb, len + 1);
-
-       /* Connected Subaddress */
-       skb_pull(skb, *(skb->data) + 1);
-
-       /* Low Layer Capability */
-       skb_pull(skb, *(skb->data) + 1);
-
-       /* High Layer Capability */
-       skb_pull(skb, *(skb->data) + 1);
-
-       return 0;
-}
-
-int capi_decode_conn_actv_conf(struct pcbit_chan *chan, struct sk_buff *skb)
-{
-       ushort errcode;
-
-       errcode = *((ushort *)skb->data);
-       skb_pull(skb, 2);
-
-       /* Channel Identification
-          skb_pull(skb, skb->data[0] + 1);
-       */
-       return errcode;
-}
-
-
-int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb)
-{
-       ushort errcode;
-
-       chan->layer2link = *(skb->data);
-       skb_pull(skb, 1);
-
-       errcode = *((ushort *)skb->data);
-       skb_pull(skb, 2);
-
-       return errcode;
-}
-
-int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb)
-{
-       ushort errcode;
-
-       if (chan->layer2link != *(skb->data))
-               printk("capi_decode_actv_trans_conf: layer2link doesn't match\n");
-
-       skb_pull(skb, 1);
-
-       errcode = *((ushort *)skb->data);
-       skb_pull(skb, 2);
-
-       return errcode;
-}
-
-int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
-{
-       ushort len;
-#ifdef DEBUG
-       int i;
-#endif
-       /* Cause */
-
-       len = *(skb->data);
-       skb_pull(skb, 1);
-
-#ifdef DEBUG
-
-       for (i = 0; i < len; i++)
-               printk(KERN_DEBUG "Cause Octect %d: %02x\n", i + 3,
-                      *(skb->data + i));
-#endif
-
-       skb_pull(skb, len);
-
-       return 0;
-}
-
-#ifdef DEBUG
-int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
-{
-       char str[64];
-       int len;
-
-       len = hdr[0];
-
-       if (len < 64 && len == hdrlen - 1) {
-               memcpy(str, hdr + 1, hdrlen - 1);
-               str[hdrlen - 1] = 0;
-               printk("%s\n", str);
-       }
-       else
-               printk("debug message incorrect\n");
-
-       return 0;
-}
-#endif
diff --git a/drivers/isdn/pcbit/capi.h b/drivers/isdn/pcbit/capi.h
deleted file mode 100644 (file)
index 635f634..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * CAPI encode/decode prototypes and defines
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef CAPI_H
-#define CAPI_H
-
-
-#define REQ_CAUSE         0x01
-#define REQ_DISPLAY       0x04
-#define REQ_USER_TO_USER  0x08
-
-#define AppInfoMask  REQ_CAUSE | REQ_DISPLAY | REQ_USER_TO_USER
-
-/* Connection Setup */
-extern int capi_conn_req(const char *calledPN, struct sk_buff **buf,
-                        int proto);
-extern int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb,
-                                int *complete);
-
-extern int capi_decode_conn_ind(struct pcbit_chan *chan, struct sk_buff *skb,
-                               struct callb_data *info);
-extern int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb);
-
-extern int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb);
-extern int capi_decode_conn_actv_conf(struct pcbit_chan *chan,
-                                     struct sk_buff *skb);
-
-extern int capi_decode_conn_actv_ind(struct pcbit_chan *chan,
-                                    struct sk_buff *skb);
-extern int capi_conn_active_resp(struct pcbit_chan *chan,
-                                struct sk_buff **skb);
-
-/* Data */
-extern int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
-                                int outgoing);
-extern int capi_decode_sel_proto_conf(struct pcbit_chan *chan,
-                                     struct sk_buff *skb);
-
-extern int capi_activate_transp_req(struct pcbit_chan *chan,
-                                   struct sk_buff **skb);
-extern int capi_decode_actv_trans_conf(struct pcbit_chan *chan,
-                                      struct sk_buff *skb);
-
-extern int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb);
-extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb);
-
-/* Connection Termination */
-extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause);
-
-extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb);
-extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb);
-
-#ifdef DEBUG
-extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen);
-#endif
-
-static inline struct pcbit_chan *
-capi_channel(struct pcbit_dev *dev, struct sk_buff *skb)
-{
-       ushort callref;
-
-       callref = *((ushort *)skb->data);
-       skb_pull(skb, 2);
-
-       if (dev->b1->callref == callref)
-               return dev->b1;
-       else if (dev->b2->callref == callref)
-               return dev->b2;
-
-       return NULL;
-}
-
-#endif
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
deleted file mode 100644 (file)
index 4172e22..0000000
+++ /dev/null
@@ -1,1077 +0,0 @@
-/*
- * PCBIT-D interface with isdn4linux
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- *     Fixes:
- *
- *     Nuno Grilo      <l38486@alfa.ist.utl.pt>
- *      fixed msn_list NULL pointer dereference.
- *
- */
-
-#include <linux/module.h>
-
-
-#include <linux/kernel.h>
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-
-#include <linux/isdnif.h>
-#include <asm/string.h>
-#include <asm/io.h>
-#include <linux/ioport.h>
-
-#include "pcbit.h"
-#include "edss1.h"
-#include "layer2.h"
-#include "capi.h"
-
-
-extern ushort last_ref_num;
-
-static int pcbit_ioctl(isdn_ctrl *ctl);
-
-static char *pcbit_devname[MAX_PCBIT_CARDS] = {
-       "pcbit0",
-       "pcbit1",
-       "pcbit2",
-       "pcbit3"
-};
-
-/*
- * prototypes
- */
-
-static int pcbit_command(isdn_ctrl *ctl);
-static int pcbit_stat(u_char __user *buf, int len, int, int);
-static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
-static int pcbit_writecmd(const u_char __user *, int, int, int);
-
-static int set_protocol_running(struct pcbit_dev *dev);
-
-static void pcbit_clear_msn(struct pcbit_dev *dev);
-static void pcbit_set_msn(struct pcbit_dev *dev, char *list);
-static int pcbit_check_msn(struct pcbit_dev *dev, char *msn);
-
-
-int pcbit_init_dev(int board, int mem_base, int irq)
-{
-       struct pcbit_dev *dev;
-       isdn_if *dev_if;
-
-       if ((dev = kzalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
-       {
-               printk("pcbit_init: couldn't malloc pcbit_dev struct\n");
-               return -ENOMEM;
-       }
-
-       dev_pcbit[board] = dev;
-       init_waitqueue_head(&dev->set_running_wq);
-       spin_lock_init(&dev->lock);
-
-       if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF) {
-               dev->ph_mem = mem_base;
-               if (!request_mem_region(dev->ph_mem, 4096, "PCBIT mem")) {
-                       printk(KERN_WARNING
-                              "PCBIT: memory region %lx-%lx already in use\n",
-                              dev->ph_mem, dev->ph_mem + 4096);
-                       kfree(dev);
-                       dev_pcbit[board] = NULL;
-                       return -EACCES;
-               }
-               dev->sh_mem = ioremap(dev->ph_mem, 4096);
-       }
-       else
-       {
-               printk("memory address invalid");
-               kfree(dev);
-               dev_pcbit[board] = NULL;
-               return -EACCES;
-       }
-
-       dev->b1 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
-       if (!dev->b1) {
-               printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
-               iounmap(dev->sh_mem);
-               release_mem_region(dev->ph_mem, 4096);
-               kfree(dev);
-               return -ENOMEM;
-       }
-
-       dev->b2 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
-       if (!dev->b2) {
-               printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
-               kfree(dev->b1);
-               iounmap(dev->sh_mem);
-               release_mem_region(dev->ph_mem, 4096);
-               kfree(dev);
-               return -ENOMEM;
-       }
-
-       dev->b2->id = 1;
-
-       INIT_WORK(&dev->qdelivery, pcbit_deliver);
-
-       /*
-        *  interrupts
-        */
-
-       if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0)
-       {
-               kfree(dev->b1);
-               kfree(dev->b2);
-               iounmap(dev->sh_mem);
-               release_mem_region(dev->ph_mem, 4096);
-               kfree(dev);
-               dev_pcbit[board] = NULL;
-               return -EIO;
-       }
-
-       dev->irq = irq;
-
-       /* next frame to be received */
-       dev->rcv_seq = 0;
-       dev->send_seq = 0;
-       dev->unack_seq = 0;
-
-       dev->hl_hdrlen = 16;
-
-       dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL);
-
-       if (!dev_if) {
-               free_irq(irq, dev);
-               kfree(dev->b1);
-               kfree(dev->b2);
-               iounmap(dev->sh_mem);
-               release_mem_region(dev->ph_mem, 4096);
-               kfree(dev);
-               dev_pcbit[board] = NULL;
-               return -EIO;
-       }
-
-       dev->dev_if = dev_if;
-
-       dev_if->owner = THIS_MODULE;
-
-       dev_if->channels = 2;
-
-       dev_if->features = (ISDN_FEATURE_P_EURO  | ISDN_FEATURE_L3_TRANS |
-                           ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS);
-
-       dev_if->writebuf_skb = pcbit_xmit;
-       dev_if->hl_hdrlen = 16;
-
-       dev_if->maxbufsize = MAXBUFSIZE;
-       dev_if->command  = pcbit_command;
-
-       dev_if->writecmd = pcbit_writecmd;
-       dev_if->readstat = pcbit_stat;
-
-
-       strcpy(dev_if->id, pcbit_devname[board]);
-
-       if (!register_isdn(dev_if)) {
-               free_irq(irq, dev);
-               kfree(dev->b1);
-               kfree(dev->b2);
-               iounmap(dev->sh_mem);
-               release_mem_region(dev->ph_mem, 4096);
-               kfree(dev);
-               dev_pcbit[board] = NULL;
-               return -EIO;
-       }
-
-       dev->id = dev_if->channels;
-
-
-       dev->l2_state = L2_DOWN;
-       dev->free = 511;
-
-       /*
-        * set_protocol_running(dev);
-        */
-
-       return 0;
-}
-
-#ifdef MODULE
-void pcbit_terminate(int board)
-{
-       struct pcbit_dev *dev;
-
-       dev = dev_pcbit[board];
-
-       if (dev) {
-               /* unregister_isdn(dev->dev_if); */
-               free_irq(dev->irq, dev);
-               pcbit_clear_msn(dev);
-               kfree(dev->dev_if);
-               if (dev->b1->fsm_timer.function)
-                       del_timer(&dev->b1->fsm_timer);
-               if (dev->b2->fsm_timer.function)
-                       del_timer(&dev->b2->fsm_timer);
-               kfree(dev->b1);
-               kfree(dev->b2);
-               iounmap(dev->sh_mem);
-               release_mem_region(dev->ph_mem, 4096);
-               kfree(dev);
-       }
-}
-#endif
-
-static int pcbit_command(isdn_ctrl *ctl)
-{
-       struct pcbit_dev *dev;
-       struct pcbit_chan *chan;
-       struct callb_data info;
-
-       dev = finddev(ctl->driver);
-
-       if (!dev)
-       {
-               printk("pcbit_command: unknown device\n");
-               return -1;
-       }
-
-       chan = (ctl->arg & 0x0F) ? dev->b2 : dev->b1;
-
-
-       switch (ctl->command) {
-       case ISDN_CMD_IOCTL:
-               return pcbit_ioctl(ctl);
-               break;
-       case ISDN_CMD_DIAL:
-               info.type = EV_USR_SETUP_REQ;
-               info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone;
-               pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info);
-               break;
-       case ISDN_CMD_ACCEPTD:
-               pcbit_fsm_event(dev, chan, EV_USR_SETUP_RESP, NULL);
-               break;
-       case ISDN_CMD_ACCEPTB:
-               printk("ISDN_CMD_ACCEPTB - not really needed\n");
-               break;
-       case ISDN_CMD_HANGUP:
-               pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
-               break;
-       case ISDN_CMD_SETL2:
-               chan->proto = (ctl->arg >> 8);
-               break;
-       case ISDN_CMD_CLREAZ:
-               pcbit_clear_msn(dev);
-               break;
-       case ISDN_CMD_SETEAZ:
-               pcbit_set_msn(dev, ctl->parm.num);
-               break;
-       case ISDN_CMD_SETL3:
-               if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS)
-                       printk(KERN_DEBUG "L3 protocol unknown\n");
-               break;
-       default:
-               printk(KERN_DEBUG "pcbit_command: unknown command\n");
-               break;
-       };
-
-       return 0;
-}
-
-/*
- * Another Hack :-(
- * on some conditions the board stops sending TDATA_CONFs
- * let's see if we can turn around the problem
- */
-
-#ifdef BLOCK_TIMER
-static void pcbit_block_timer(unsigned long data)
-{
-       struct pcbit_chan *chan;
-       struct pcbit_dev *dev;
-       isdn_ctrl ictl;
-
-       chan = (struct pcbit_chan *)data;
-
-       dev = chan2dev(chan);
-
-       if (dev == NULL) {
-               printk(KERN_DEBUG "pcbit: chan2dev failed\n");
-               return;
-       }
-
-       del_timer(&chan->block_timer);
-       chan->block_timer.function = NULL;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "pcbit_block_timer\n");
-#endif
-       chan->queued = 0;
-       ictl.driver = dev->id;
-       ictl.command = ISDN_STAT_BSENT;
-       ictl.arg = chan->id;
-       dev->dev_if->statcallb(&ictl);
-}
-#endif
-
-static int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
-{
-       ushort hdrlen;
-       int refnum, len;
-       struct pcbit_chan *chan;
-       struct pcbit_dev *dev;
-
-       dev = finddev(driver);
-       if (dev == NULL)
-       {
-               printk("finddev returned NULL");
-               return -1;
-       }
-
-       chan = chnum ? dev->b2 : dev->b1;
-
-
-       if (chan->fsm_state != ST_ACTIVE)
-               return -1;
-
-       if (chan->queued >= MAX_QUEUED)
-       {
-#ifdef DEBUG_QUEUE
-               printk(KERN_DEBUG
-                      "pcbit: %d packets already in queue - write fails\n",
-                      chan->queued);
-#endif
-               /*
-                * packet stays on the head of the device queue
-                * since dev_start_xmit will fail
-                * see net/core/dev.c
-                */
-#ifdef BLOCK_TIMER
-               if (chan->block_timer.function == NULL) {
-                       init_timer(&chan->block_timer);
-                       chan->block_timer.function =  &pcbit_block_timer;
-                       chan->block_timer.data = (long) chan;
-                       chan->block_timer.expires = jiffies + 1 * HZ;
-                       add_timer(&chan->block_timer);
-               }
-#endif
-               return 0;
-       }
-
-
-       chan->queued++;
-
-       len = skb->len;
-
-       hdrlen = capi_tdata_req(chan, skb);
-
-       refnum = last_ref_num++ & 0x7fffU;
-       chan->s_refnum = refnum;
-
-       pcbit_l2_write(dev, MSG_TDATA_REQ, refnum, skb, hdrlen);
-
-       return len;
-}
-
-static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
-{
-       struct pcbit_dev *dev;
-       int i, j;
-       const u_char *loadbuf;
-       u_char *ptr = NULL;
-       u_char *cbuf;
-
-       int errstat;
-
-       dev = finddev(driver);
-
-       if (!dev)
-       {
-               printk("pcbit_writecmd: couldn't find device");
-               return -ENODEV;
-       }
-
-       switch (dev->l2_state) {
-       case L2_LWMODE:
-               /* check (size <= rdp_size); write buf into board */
-               if (len < 0 || len > BANK4 + 1 || len > 1024)
-               {
-                       printk("pcbit_writecmd: invalid length %d\n", len);
-                       return -EINVAL;
-               }
-
-               cbuf = memdup_user(buf, len);
-               if (IS_ERR(cbuf))
-                       return PTR_ERR(cbuf);
-
-               memcpy_toio(dev->sh_mem, cbuf, len);
-               kfree(cbuf);
-               return len;
-       case L2_FWMODE:
-               /* this is the hard part */
-               /* dumb board */
-               /* get it into kernel space */
-               if ((ptr = kmalloc(len, GFP_KERNEL)) == NULL)
-                       return -ENOMEM;
-               if (copy_from_user(ptr, buf, len)) {
-                       kfree(ptr);
-                       return -EFAULT;
-               }
-               loadbuf = ptr;
-
-               errstat = 0;
-
-               for (i = 0; i < len; i++)
-               {
-                       for (j = 0; j < LOAD_RETRY; j++)
-                               if (!(readb(dev->sh_mem + dev->loadptr)))
-                                       break;
-
-                       if (j == LOAD_RETRY)
-                       {
-                               errstat = -ETIME;
-                               printk("TIMEOUT i=%d\n", i);
-                               break;
-                       }
-                       writeb(loadbuf[i], dev->sh_mem + dev->loadptr + 1);
-                       writeb(0x01, dev->sh_mem + dev->loadptr);
-
-                       dev->loadptr += 2;
-                       if (dev->loadptr > LOAD_ZONE_END)
-                               dev->loadptr = LOAD_ZONE_START;
-               }
-               kfree(ptr);
-
-               return errstat ? errstat : len;
-       default:
-               return -EBUSY;
-       }
-}
-
-/*
- *  demultiplexing of messages
- *
- */
-
-void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg,
-                     struct sk_buff *skb,
-                     ushort hdr_len, ushort refnum)
-{
-       struct pcbit_chan *chan;
-       struct sk_buff *skb2;
-       unsigned short len;
-       struct callb_data cbdata;
-       int complete, err;
-       isdn_ctrl ictl;
-
-       switch (msg) {
-
-       case MSG_TDATA_IND:
-               if (!(chan = capi_channel(dev, skb))) {
-                       printk(KERN_WARNING
-                              "CAPI header: unknown channel id\n");
-                       break;
-               }
-               chan->r_refnum = skb->data[7];
-               skb_pull(skb, 8);
-
-               dev->dev_if->rcvcallb_skb(dev->id, chan->id, skb);
-
-               if (capi_tdata_resp(chan, &skb2) > 0)
-                       pcbit_l2_write(dev, MSG_TDATA_RESP, refnum,
-                                      skb2, skb2->len);
-               return;
-               break;
-       case MSG_TDATA_CONF:
-               if (!(chan = capi_channel(dev, skb))) {
-                       printk(KERN_WARNING
-                              "CAPI header: unknown channel id\n");
-                       break;
-               }
-
-#ifdef DEBUG
-               if ((*((ushort *)(skb->data + 2))) != 0) {
-                       printk(KERN_DEBUG "TDATA_CONF error\n");
-               }
-#endif
-#ifdef BLOCK_TIMER
-               if (chan->queued == MAX_QUEUED) {
-                       del_timer(&chan->block_timer);
-                       chan->block_timer.function = NULL;
-               }
-
-#endif
-               chan->queued--;
-
-               ictl.driver = dev->id;
-               ictl.command = ISDN_STAT_BSENT;
-               ictl.arg = chan->id;
-               dev->dev_if->statcallb(&ictl);
-               break;
-
-       case MSG_CONN_IND:
-               /*
-                *  channel: 1st not used will do
-                *           if both are used we're in trouble
-                */
-
-               if (!dev->b1->fsm_state)
-                       chan = dev->b1;
-               else if (!dev->b2->fsm_state)
-                       chan = dev->b2;
-               else {
-                       printk(KERN_INFO
-                              "Incoming connection: no channels available");
-
-                       if ((len = capi_disc_req(*(ushort *)(skb->data), &skb2, CAUSE_NOCHAN)) > 0)
-                               pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb2, len);
-                       break;
-               }
-
-               cbdata.data.setup.CalledPN = NULL;
-               cbdata.data.setup.CallingPN = NULL;
-
-               capi_decode_conn_ind(chan, skb, &cbdata);
-               cbdata.type = EV_NET_SETUP;
-
-               pcbit_fsm_event(dev, chan, EV_NET_SETUP, NULL);
-
-               if (pcbit_check_msn(dev, cbdata.data.setup.CallingPN))
-                       pcbit_fsm_event(dev, chan, EV_USR_PROCED_REQ, &cbdata);
-               else
-                       pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
-
-               kfree(cbdata.data.setup.CalledPN);
-               kfree(cbdata.data.setup.CallingPN);
-               break;
-
-       case MSG_CONN_CONF:
-               /*
-                * We should be able to find the channel by the message
-                * reference number. The current version of the firmware
-                * doesn't sent the ref number correctly.
-                */
-#ifdef DEBUG
-               printk(KERN_DEBUG "refnum=%04x b1=%04x b2=%04x\n", refnum,
-                      dev->b1->s_refnum,
-                      dev->b2->s_refnum);
-#endif
-               /* We just try to find a channel in the right state */
-
-               if (dev->b1->fsm_state == ST_CALL_INIT)
-                       chan = dev->b1;
-               else {
-                       if (dev->b2->s_refnum == ST_CALL_INIT)
-                               chan = dev->b2;
-                       else {
-                               chan = NULL;
-                               printk(KERN_WARNING "Connection Confirm - no channel in Call Init state\n");
-                               break;
-                       }
-               }
-               if (capi_decode_conn_conf(chan, skb, &complete)) {
-                       printk(KERN_DEBUG "conn_conf indicates error\n");
-                       pcbit_fsm_event(dev, chan, EV_ERROR, NULL);
-               }
-               else
-                       if (complete)
-                               pcbit_fsm_event(dev, chan, EV_NET_CALL_PROC, NULL);
-                       else
-                               pcbit_fsm_event(dev, chan, EV_NET_SETUP_ACK, NULL);
-               break;
-       case MSG_CONN_ACTV_IND:
-
-               if (!(chan = capi_channel(dev, skb))) {
-                       printk(KERN_WARNING
-                              "CAPI header: unknown channel id\n");
-                       break;
-               }
-
-               if (capi_decode_conn_actv_ind(chan, skb)) {
-                       printk("error in capi_decode_conn_actv_ind\n");
-                       /* pcbit_fsm_event(dev, chan, EV_ERROR, NULL); */
-                       break;
-               }
-               chan->r_refnum = refnum;
-               pcbit_fsm_event(dev, chan, EV_NET_CONN, NULL);
-               break;
-       case MSG_CONN_ACTV_CONF:
-
-               if (!(chan = capi_channel(dev, skb))) {
-                       printk(KERN_WARNING
-                              "CAPI header: unknown channel id\n");
-                       break;
-               }
-
-               if (capi_decode_conn_actv_conf(chan, skb) == 0)
-                       pcbit_fsm_event(dev, chan, EV_NET_CONN_ACK, NULL);
-
-               else
-                       printk(KERN_DEBUG "decode_conn_actv_conf failed\n");
-               break;
-
-       case  MSG_SELP_CONF:
-
-               if (!(chan = capi_channel(dev, skb))) {
-                       printk(KERN_WARNING
-                              "CAPI header: unknown channel id\n");
-                       break;
-               }
-
-               if (!(err = capi_decode_sel_proto_conf(chan, skb)))
-                       pcbit_fsm_event(dev, chan, EV_NET_SELP_RESP, NULL);
-               else {
-                       /* Error */
-                       printk("error %d - capi_decode_sel_proto_conf\n", err);
-               }
-               break;
-       case MSG_ACT_TRANSP_CONF:
-               if (!(chan = capi_channel(dev, skb))) {
-                       printk(KERN_WARNING
-                              "CAPI header: unknown channel id\n");
-                       break;
-               }
-
-               if (!capi_decode_actv_trans_conf(chan, skb))
-                       pcbit_fsm_event(dev, chan, EV_NET_ACTV_RESP, NULL);
-               break;
-
-       case MSG_DISC_IND:
-
-               if (!(chan = capi_channel(dev, skb))) {
-                       printk(KERN_WARNING
-                              "CAPI header: unknown channel id\n");
-                       break;
-               }
-
-               if (!capi_decode_disc_ind(chan, skb))
-                       pcbit_fsm_event(dev, chan, EV_NET_DISC, NULL);
-               else
-                       printk(KERN_WARNING "capi_decode_disc_ind - error\n");
-               break;
-       case MSG_DISC_CONF:
-               if (!(chan = capi_channel(dev, skb))) {
-                       printk(KERN_WARNING
-                              "CAPI header: unknown channel id\n");
-                       break;
-               }
-
-               if (!capi_decode_disc_ind(chan, skb))
-                       pcbit_fsm_event(dev, chan, EV_NET_RELEASE, NULL);
-               else
-                       printk(KERN_WARNING "capi_decode_disc_conf - error\n");
-               break;
-       case MSG_INFO_IND:
-#ifdef DEBUG
-               printk(KERN_DEBUG "received Info Indication - discarded\n");
-#endif
-               break;
-#ifdef DEBUG
-       case MSG_DEBUG_188:
-               capi_decode_debug_188(skb->data, skb->len);
-               break;
-
-       default:
-               printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n",
-                      msg);
-               break;
-#endif
-       }
-
-       kfree_skb(skb);
-
-}
-
-/*
- *   Single statbuf
- *   should be a statbuf per device
- */
-
-static char statbuf[STATBUF_LEN];
-static int stat_st = 0;
-static int stat_end = 0;
-
-static int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
-{
-       int stat_count;
-       stat_count = stat_end - stat_st;
-
-       if (stat_count < 0)
-               stat_count = STATBUF_LEN - stat_st + stat_end;
-
-       /* FIXME: should we sleep and wait for more cookies ? */
-       if (len > stat_count)
-               len = stat_count;
-
-       if (stat_st < stat_end)
-       {
-               if (copy_to_user(buf, statbuf + stat_st, len))
-                       return -EFAULT;
-               stat_st += len;
-       }
-       else
-       {
-               if (len > STATBUF_LEN - stat_st)
-               {
-                       if (copy_to_user(buf, statbuf + stat_st,
-                                        STATBUF_LEN - stat_st))
-                               return -EFAULT;
-                       if (copy_to_user(buf, statbuf,
-                                        len - (STATBUF_LEN - stat_st)))
-                               return -EFAULT;
-
-                       stat_st = len - (STATBUF_LEN - stat_st);
-               }
-               else
-               {
-                       if (copy_to_user(buf, statbuf + stat_st, len))
-                               return -EFAULT;
-
-                       stat_st += len;
-
-                       if (stat_st == STATBUF_LEN)
-                               stat_st = 0;
-               }
-       }
-
-       if (stat_st == stat_end)
-               stat_st = stat_end = 0;
-
-       return len;
-}
-
-static void pcbit_logstat(struct pcbit_dev *dev, char *str)
-{
-       int i;
-       isdn_ctrl ictl;
-
-       for (i = stat_end; i < strlen(str); i++)
-       {
-               statbuf[i] = str[i];
-               stat_end = (stat_end + 1) % STATBUF_LEN;
-               if (stat_end == stat_st)
-                       stat_st = (stat_st + 1) % STATBUF_LEN;
-       }
-
-       ictl.command = ISDN_STAT_STAVAIL;
-       ictl.driver = dev->id;
-       ictl.arg = strlen(str);
-       dev->dev_if->statcallb(&ictl);
-}
-
-void pcbit_state_change(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                       unsigned short i, unsigned short ev, unsigned short f)
-{
-       char buf[256];
-
-       sprintf(buf, "change on device: %d channel:%d\n%s -> %s -> %s\n",
-               dev->id, chan->id,
-               isdn_state_table[i], strisdnevent(ev), isdn_state_table[f]
-               );
-
-#ifdef DEBUG
-       printk("%s", buf);
-#endif
-
-       pcbit_logstat(dev, buf);
-}
-
-static void set_running_timeout(unsigned long ptr)
-{
-       struct pcbit_dev *dev;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "set_running_timeout\n");
-#endif
-       dev = (struct pcbit_dev *) ptr;
-
-       dev->l2_state = L2_DOWN;
-       wake_up_interruptible(&dev->set_running_wq);
-}
-
-static int set_protocol_running(struct pcbit_dev *dev)
-{
-       isdn_ctrl ctl;
-
-       init_timer(&dev->set_running_timer);
-
-       dev->set_running_timer.function = &set_running_timeout;
-       dev->set_running_timer.data = (ulong) dev;
-       dev->set_running_timer.expires = jiffies + SET_RUN_TIMEOUT;
-
-       /* kick it */
-
-       dev->l2_state = L2_STARTING;
-
-       writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
-              dev->sh_mem + BANK4);
-
-       add_timer(&dev->set_running_timer);
-
-       wait_event(dev->set_running_wq, dev->l2_state == L2_RUNNING ||
-                                       dev->l2_state == L2_DOWN);
-
-       del_timer(&dev->set_running_timer);
-
-       if (dev->l2_state == L2_RUNNING)
-       {
-               printk(KERN_DEBUG "pcbit: running\n");
-
-               dev->unack_seq = dev->send_seq;
-
-               dev->writeptr = dev->sh_mem;
-               dev->readptr = dev->sh_mem + BANK2;
-
-               /* tell the good news to the upper layer */
-               ctl.driver = dev->id;
-               ctl.command = ISDN_STAT_RUN;
-
-               dev->dev_if->statcallb(&ctl);
-       }
-       else
-       {
-               printk(KERN_DEBUG "pcbit: initialization failed\n");
-               printk(KERN_DEBUG "pcbit: firmware not loaded\n");
-
-#ifdef DEBUG
-               printk(KERN_DEBUG "Bank3 = %02x\n",
-                      readb(dev->sh_mem + BANK3));
-#endif
-               writeb(0x40, dev->sh_mem + BANK4);
-
-               /* warn the upper layer */
-               ctl.driver = dev->id;
-               ctl.command = ISDN_STAT_STOP;
-
-               dev->dev_if->statcallb(&ctl);
-
-               return -EL2HLT; /* Level 2 halted */
-       }
-
-       return 0;
-}
-
-static int pcbit_ioctl(isdn_ctrl *ctl)
-{
-       struct pcbit_dev *dev;
-       struct pcbit_ioctl *cmd;
-
-       dev = finddev(ctl->driver);
-
-       if (!dev)
-       {
-               printk(KERN_DEBUG "pcbit_ioctl: unknown device\n");
-               return -ENODEV;
-       }
-
-       cmd = (struct pcbit_ioctl *) ctl->parm.num;
-
-       switch (ctl->arg) {
-       case PCBIT_IOCTL_GETSTAT:
-               cmd->info.l2_status = dev->l2_state;
-               break;
-
-       case PCBIT_IOCTL_STRLOAD:
-               if (dev->l2_state == L2_RUNNING)
-                       return -EBUSY;
-
-               dev->unack_seq = dev->send_seq = dev->rcv_seq = 0;
-
-               dev->writeptr = dev->sh_mem;
-               dev->readptr = dev->sh_mem + BANK2;
-
-               dev->l2_state = L2_LOADING;
-               break;
-
-       case PCBIT_IOCTL_LWMODE:
-               if (dev->l2_state != L2_LOADING)
-                       return -EINVAL;
-
-               dev->l2_state = L2_LWMODE;
-               break;
-
-       case PCBIT_IOCTL_FWMODE:
-               if (dev->l2_state == L2_RUNNING)
-                       return -EBUSY;
-               dev->loadptr = LOAD_ZONE_START;
-               dev->l2_state = L2_FWMODE;
-
-               break;
-       case PCBIT_IOCTL_ENDLOAD:
-               if (dev->l2_state == L2_RUNNING)
-                       return -EBUSY;
-               dev->l2_state = L2_DOWN;
-               break;
-
-       case PCBIT_IOCTL_SETBYTE:
-               if (dev->l2_state == L2_RUNNING)
-                       return -EBUSY;
-
-               /* check addr */
-               if (cmd->info.rdp_byte.addr > BANK4)
-                       return -EFAULT;
-
-               writeb(cmd->info.rdp_byte.value, dev->sh_mem + cmd->info.rdp_byte.addr);
-               break;
-       case PCBIT_IOCTL_GETBYTE:
-               if (dev->l2_state == L2_RUNNING)
-                       return -EBUSY;
-
-               /* check addr */
-
-               if (cmd->info.rdp_byte.addr > BANK4)
-               {
-                       printk("getbyte: invalid addr %04x\n", cmd->info.rdp_byte.addr);
-                       return -EFAULT;
-               }
-
-               cmd->info.rdp_byte.value = readb(dev->sh_mem + cmd->info.rdp_byte.addr);
-               break;
-       case PCBIT_IOCTL_RUNNING:
-               if (dev->l2_state == L2_RUNNING)
-                       return -EBUSY;
-               return set_protocol_running(dev);
-               break;
-       case PCBIT_IOCTL_WATCH188:
-               if (dev->l2_state != L2_LOADING)
-                       return -EINVAL;
-               pcbit_l2_write(dev, MSG_WATCH188, 0x0001, NULL, 0);
-               break;
-       case PCBIT_IOCTL_PING188:
-               if (dev->l2_state != L2_LOADING)
-                       return -EINVAL;
-               pcbit_l2_write(dev, MSG_PING188_REQ, 0x0001, NULL, 0);
-               break;
-       case PCBIT_IOCTL_APION:
-               if (dev->l2_state != L2_LOADING)
-                       return -EINVAL;
-               pcbit_l2_write(dev, MSG_API_ON, 0x0001, NULL, 0);
-               break;
-       case PCBIT_IOCTL_STOP:
-               dev->l2_state = L2_DOWN;
-               writeb(0x40, dev->sh_mem + BANK4);
-               dev->rcv_seq = 0;
-               dev->send_seq = 0;
-               dev->unack_seq = 0;
-               break;
-       default:
-               printk("error: unknown ioctl\n");
-               break;
-       };
-       return 0;
-}
-
-/*
- *        MSN list handling
- *
- *        if null reject all calls
- *        if first entry has null MSN accept all calls
- */
-
-static void pcbit_clear_msn(struct pcbit_dev *dev)
-{
-       struct msn_entry *ptr, *back;
-
-       for (ptr = dev->msn_list; ptr;)
-       {
-               back = ptr->next;
-               kfree(ptr);
-               ptr = back;
-       }
-
-       dev->msn_list = NULL;
-}
-
-static void pcbit_set_msn(struct pcbit_dev *dev, char *list)
-{
-       struct msn_entry *ptr;
-       struct msn_entry *back = NULL;
-       char *cp, *sp;
-       int len;
-
-       if (strlen(list) == 0) {
-               ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
-               if (!ptr) {
-                       printk(KERN_WARNING "kmalloc failed\n");
-                       return;
-               }
-
-               ptr->msn = NULL;
-
-               ptr->next = dev->msn_list;
-               dev->msn_list = ptr;
-
-               return;
-       }
-
-       if (dev->msn_list)
-               for (back = dev->msn_list; back->next; back = back->next);
-
-       sp = list;
-
-       do {
-               cp = strchr(sp, ',');
-               if (cp)
-                       len = cp - sp;
-               else
-                       len = strlen(sp);
-
-               ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
-
-               if (!ptr) {
-                       printk(KERN_WARNING "kmalloc failed\n");
-                       return;
-               }
-               ptr->next = NULL;
-
-               ptr->msn = kmalloc(len + 1, GFP_ATOMIC);
-               if (!ptr->msn) {
-                       printk(KERN_WARNING "kmalloc failed\n");
-                       kfree(ptr);
-                       return;
-               }
-
-               memcpy(ptr->msn, sp, len);
-               ptr->msn[len] = 0;
-
-#ifdef DEBUG
-               printk(KERN_DEBUG "msn: %s\n", ptr->msn);
-#endif
-               if (dev->msn_list == NULL)
-                       dev->msn_list = ptr;
-               else
-                       back->next = ptr;
-               back = ptr;
-               sp += len;
-       } while (cp);
-}
-
-/*
- *  check if we do signal or reject an incoming call
- */
-static int pcbit_check_msn(struct pcbit_dev *dev, char *msn)
-{
-       struct msn_entry *ptr;
-
-       for (ptr = dev->msn_list; ptr; ptr = ptr->next) {
-
-               if (ptr->msn == NULL)
-                       return 1;
-
-               if (strcmp(ptr->msn, msn) == 0)
-                       return 1;
-       }
-
-       return 0;
-}
diff --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c
deleted file mode 100644 (file)
index b2262ba..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * DSS.1 Finite State Machine
- * base: ITU-T Rec Q.931
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- *        TODO: complete the FSM
- *              move state/event descriptions to a user space logger
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/skbuff.h>
-
-#include <linux/timer.h>
-#include <asm/io.h>
-
-#include <linux/isdnif.h>
-
-#include "pcbit.h"
-#include "edss1.h"
-#include "layer2.h"
-#include "callbacks.h"
-
-
-const char * const isdn_state_table[] = {
-       "Closed",
-       "Call initiated",
-       "Overlap sending",
-       "Outgoing call proceeding",
-       "NOT DEFINED",
-       "Call delivered",
-       "Call present",
-       "Call received",
-       "Connect request",
-       "Incoming call proceeding",
-       "Active",
-       "Disconnect request",
-       "Disconnect indication",
-       "NOT DEFINED",
-       "NOT DEFINED",
-       "Suspend request",
-       "NOT DEFINED",
-       "Resume request",
-       "NOT DEFINED",
-       "Release Request",
-       "NOT DEFINED",
-       "NOT DEFINED",
-       "NOT DEFINED",
-       "NOT DEFINED",
-       "NOT DEFINED",
-       "Overlap receiving",
-       "Select protocol on B-Channel",
-       "Activate B-channel protocol"
-};
-
-#ifdef DEBUG_ERRS
-static
-struct CauseValue {
-       byte nr;
-       char *descr;
-} cvlist[] = {
-       {0x01, "Unallocated (unassigned) number"},
-       {0x02, "No route to specified transit network"},
-       {0x03, "No route to destination"},
-       {0x04, "Send special information tone"},
-       {0x05, "Misdialled trunk prefix"},
-       {0x06, "Channel unacceptable"},
-       {0x07, "Channel awarded and being delivered in an established channel"},
-       {0x08, "Preemption"},
-       {0x09, "Preemption - circuit reserved for reuse"},
-       {0x10, "Normal call clearing"},
-       {0x11, "User busy"},
-       {0x12, "No user responding"},
-       {0x13, "No answer from user (user alerted)"},
-       {0x14, "Subscriber absent"},
-       {0x15, "Call rejected"},
-       {0x16, "Number changed"},
-       {0x1a, "non-selected user clearing"},
-       {0x1b, "Destination out of order"},
-       {0x1c, "Invalid number format (address incomplete)"},
-       {0x1d, "Facility rejected"},
-       {0x1e, "Response to Status enquiry"},
-       {0x1f, "Normal, unspecified"},
-       {0x22, "No circuit/channel available"},
-       {0x26, "Network out of order"},
-       {0x27, "Permanent frame mode connection out-of-service"},
-       {0x28, "Permanent frame mode connection operational"},
-       {0x29, "Temporary failure"},
-       {0x2a, "Switching equipment congestion"},
-       {0x2b, "Access information discarded"},
-       {0x2c, "Requested circuit/channel not available"},
-       {0x2e, "Precedence call blocked"},
-       {0x2f, "Resource unavailable, unspecified"},
-       {0x31, "Quality of service unavailable"},
-       {0x32, "Requested facility not subscribed"},
-       {0x35, "Outgoing calls barred within CUG"},
-       {0x37, "Incoming calls barred within CUG"},
-       {0x39, "Bearer capability not authorized"},
-       {0x3a, "Bearer capability not presently available"},
-       {0x3e, "Inconsistency in designated outgoing access information and subscriber class"},
-       {0x3f, "Service or option not available, unspecified"},
-       {0x41, "Bearer capability not implemented"},
-       {0x42, "Channel type not implemented"},
-       {0x43, "Requested facility not implemented"},
-       {0x44, "Only restricted digital information bearer capability is available"},
-       {0x4f, "Service or option not implemented"},
-       {0x51, "Invalid call reference value"},
-       {0x52, "Identified channel does not exist"},
-       {0x53, "A suspended call exists, but this call identity does not"},
-       {0x54, "Call identity in use"},
-       {0x55, "No call suspended"},
-       {0x56, "Call having the requested call identity has been cleared"},
-       {0x57, "User not member of CUG"},
-       {0x58, "Incompatible destination"},
-       {0x5a, "Non-existent CUG"},
-       {0x5b, "Invalid transit network selection"},
-       {0x5f, "Invalid message, unspecified"},
-       {0x60, "Mandatory information element is missing"},
-       {0x61, "Message type non-existent or not implemented"},
-       {0x62, "Message not compatible with call state or message type non-existent or not implemented"},
-       {0x63, "Information element/parameter non-existent or not implemented"},
-       {0x64, "Invalid information element contents"},
-       {0x65, "Message not compatible with call state"},
-       {0x66, "Recovery on timer expiry"},
-       {0x67, "Parameter non-existent or not implemented - passed on"},
-       {0x6e, "Message with unrecognized parameter discarded"},
-       {0x6f, "Protocol error, unspecified"},
-       {0x7f, "Interworking, unspecified"}
-};
-
-#endif
-
-static struct isdn_event_desc {
-       unsigned short ev;
-       char *desc;
-} isdn_event_table[] = {
-       {EV_USR_SETUP_REQ,     "CC->L3: Setup Request"},
-       {EV_USR_SETUP_RESP,    "CC->L3: Setup Response"},
-       {EV_USR_PROCED_REQ,    "CC->L3: Proceeding Request"},
-       {EV_USR_RELEASE_REQ,   "CC->L3: Release Request"},
-
-       {EV_NET_SETUP,        "NET->TE: setup "},
-       {EV_NET_CALL_PROC,    "NET->TE: call proceeding"},
-       {EV_NET_SETUP_ACK,    "NET->TE: setup acknowledge (more info needed)"},
-       {EV_NET_CONN,         "NET->TE: connect"},
-       {EV_NET_CONN_ACK,     "NET->TE: connect acknowledge"},
-       {EV_NET_DISC,         "NET->TE: disconnect indication"},
-       {EV_NET_RELEASE,      "NET->TE: release"},
-       {EV_NET_RELEASE_COMP, "NET->TE: release complete"},
-       {EV_NET_SELP_RESP,    "Board: Select B-channel protocol ack"},
-       {EV_NET_ACTV_RESP,    "Board: Activate B-channel protocol ack"},
-       {EV_TIMER,            "Timeout"},
-       {0, "NULL"}
-};
-
-char *strisdnevent(ushort ev)
-{
-       struct isdn_event_desc *entry;
-
-       for (entry = isdn_event_table; entry->ev; entry++)
-               if (entry->ev == ev)
-                       break;
-
-       return entry->desc;
-}
-
-/*
- * Euro ISDN finite state machine
- */
-
-static struct fsm_timer_entry fsm_timers[] = {
-       {ST_CALL_PROC, 10},
-       {ST_DISC_REQ, 2},
-       {ST_ACTIVE_SELP, 5},
-       {ST_ACTIVE_ACTV, 5},
-       {ST_INCM_PROC, 10},
-       {ST_CONN_REQ, 2},
-       {0xff, 0}
-};
-
-static struct fsm_entry fsm_table[] = {
-/* Connect Phase */
-       /* Outgoing */
-       {ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1},
-
-       {ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone},
-       {ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL},
-       {ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2},
-
-       {ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2},
-       {ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1},
-       {ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
-       /* Incoming */
-       {ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL},
-
-       {ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1},
-       {ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
-       {ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2},
-       {ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
-       {ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3},
-
-       /* Active */
-       {ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1},
-       {ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-       {ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3},
-
-       /* Disconnect */
-
-       {ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1},
-       {ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3},
-
-       /* protocol selection */
-       {ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1},
-       {ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
-       {ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open},
-       {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
-       /* Timers */
-       {ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
-       {ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3},
-       {ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2},
-       {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2},
-       {ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
-       {ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2},
-
-       {0xff, 0, 0, NULL}
-};
-
-
-static void pcbit_fsm_timer(unsigned long data)
-{
-       struct pcbit_dev *dev;
-       struct pcbit_chan *chan;
-
-       chan = (struct pcbit_chan *) data;
-
-       del_timer(&chan->fsm_timer);
-       chan->fsm_timer.function = NULL;
-
-       dev = chan2dev(chan);
-
-       if (dev == NULL) {
-               printk(KERN_WARNING "pcbit: timer for unknown device\n");
-               return;
-       }
-
-       pcbit_fsm_event(dev, chan, EV_TIMER, NULL);
-}
-
-
-void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                    unsigned short event, struct callb_data *data)
-{
-       struct fsm_entry *action;
-       struct fsm_timer_entry *tentry;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->lock, flags);
-
-       for (action = fsm_table; action->init != 0xff; action++)
-               if (action->init == chan->fsm_state && action->event == event)
-                       break;
-
-       if (action->init == 0xff) {
-
-               spin_unlock_irqrestore(&dev->lock, flags);
-               printk(KERN_DEBUG "fsm error: event %x on state %x\n",
-                      event, chan->fsm_state);
-               return;
-       }
-
-       if (chan->fsm_timer.function) {
-               del_timer(&chan->fsm_timer);
-               chan->fsm_timer.function = NULL;
-       }
-
-       chan->fsm_state = action->final;
-
-       pcbit_state_change(dev, chan, action->init, event, action->final);
-
-       for (tentry = fsm_timers; tentry->init != 0xff; tentry++)
-               if (tentry->init == chan->fsm_state)
-                       break;
-
-       if (tentry->init != 0xff) {
-               init_timer(&chan->fsm_timer);
-               chan->fsm_timer.function = &pcbit_fsm_timer;
-               chan->fsm_timer.data = (ulong) chan;
-               chan->fsm_timer.expires = jiffies + tentry->timeout * HZ;
-               add_timer(&chan->fsm_timer);
-       }
-
-       spin_unlock_irqrestore(&dev->lock, flags);
-
-       if (action->callb)
-               action->callb(dev, chan, data);
-
-}
diff --git a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h
deleted file mode 100644 (file)
index 2f6b3a8..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * DSS.1 module definitions
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef EDSS1_H
-#define EDSS1_H
-
-/* ISDN states */
-
-#define ST_NULL      0
-#define ST_CALL_INIT 1    /* Call initiated */
-#define ST_OVER_SEND 2    /* Overlap sending - Requests More Info 4 call */
-#define ST_CALL_PROC 3    /* Call Proceeding */
-#define ST_CALL_DELV 4
-#define ST_CALL_PRES 6    /* Call Present - Received CONN.IND */
-#define ST_CALL_RECV 7    /* Alerting sent */
-#define ST_CONN_REQ  8    /* Answered - waiting 4 CONN.CONF */
-#define ST_INCM_PROC 9
-#define ST_ACTIVE    10
-#define ST_DISC_REQ  11
-#define ST_DISC_IND  12
-#define ST_SUSP_REQ  15
-#define ST_RESM_REQ  17
-#define ST_RELS_REQ  19
-#define ST_OVER_RECV 25
-
-#define ST_ACTIVE_SELP 26 /* Select protocol on B-Channel */
-#define ST_ACTIVE_ACTV 27 /* Activate B-channel protocol  */
-
-#define MAX_STATE ST_ACTIVE_ACTV
-
-#define EV_NULL               0
-#define EV_USR_SETUP_REQ      1
-#define EV_USR_SETUP_RESP     2
-#define EV_USR_PROCED_REQ     3
-#define EV_USR_RELEASE_REQ    4
-#define EV_USR_REJECT_REQ     4
-
-#define EV_NET_SETUP          16
-#define EV_NET_CALL_PROC      17
-#define EV_NET_SETUP_ACK      18
-#define EV_NET_CONN           19
-#define EV_NET_CONN_ACK       20
-
-#define EV_NET_SELP_RESP      21
-#define EV_NET_ACTV_RESP      22
-
-#define EV_NET_DISC           23
-#define EV_NET_RELEASE        24
-#define EV_NET_RELEASE_COMP   25
-
-#define EV_TIMER              26
-#define EV_ERROR              32
-
-/*
- *  Cause values
- *  only the ones we use
- */
-
-#define CAUSE_NORMAL          0x10U
-#define CAUSE_NOCHAN          0x22U
-
-struct callb_data {
-       unsigned short type;
-       union {
-               struct ConnInfo {
-                       char *CalledPN;
-                       char *CallingPN;
-               } setup;
-               unsigned short cause;
-       } data;
-};
-
-struct fsm_entry {
-       unsigned short init;
-       unsigned short final;
-       unsigned short event;
-       void (*callb)(struct pcbit_dev *, struct pcbit_chan *, struct callb_data*);
-};
-
-struct fsm_timer_entry {
-       unsigned short init;
-       unsigned long timeout;          /* in seconds */
-};
-
-extern const char * const isdn_state_table[];
-
-void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
-                    unsigned short event, struct callb_data *);
-char *strisdnevent(ushort ev);
-
-#endif
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
deleted file mode 100644 (file)
index 46e1240..0000000
+++ /dev/null
@@ -1,712 +0,0 @@
-/*
- * PCBIT-D low-layer interface
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * 19991203 - Fernando Carvalho - takion@superbofh.org
- * Hacked to compile with egcs and run with current version of isdn modules
- */
-
-/*
- *        Based on documentation provided by Inesc:
- *        - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93
- */
-
-/*
- *        TODO: better handling of errors
- *              re-write/remove debug printks
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/mm.h>
-#include <linux/skbuff.h>
-
-#include <linux/isdnif.h>
-
-#include <asm/io.h>
-
-
-#include "pcbit.h"
-#include "layer2.h"
-#include "edss1.h"
-
-#undef DEBUG_FRAG
-
-
-/*
- *  Prototypes
- */
-
-static void pcbit_transmit(struct pcbit_dev *dev);
-
-static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
-
-static void pcbit_l2_error(struct pcbit_dev *dev);
-static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
-static void pcbit_l2_err_recover(unsigned long data);
-
-static void pcbit_firmware_bug(struct pcbit_dev *dev);
-
-static __inline__ void
-pcbit_sched_delivery(struct pcbit_dev *dev)
-{
-       schedule_work(&dev->qdelivery);
-}
-
-
-/*
- *  Called from layer3
- */
-
-int
-pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
-              struct sk_buff *skb, unsigned short hdr_len)
-{
-       struct frame_buf *frame,
-               *ptr;
-       unsigned long flags;
-
-       if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
-               dev_kfree_skb(skb);
-               return -1;
-       }
-       if ((frame = kmalloc(sizeof(struct frame_buf),
-                            GFP_ATOMIC)) == NULL) {
-               dev_kfree_skb(skb);
-               return -1;
-       }
-       frame->msg = msg;
-       frame->refnum = refnum;
-       frame->copied = 0;
-       frame->hdr_len = hdr_len;
-
-       if (skb)
-               frame->dt_len = skb->len - hdr_len;
-       else
-               frame->dt_len = 0;
-
-       frame->skb = skb;
-
-       frame->next = NULL;
-
-       spin_lock_irqsave(&dev->lock, flags);
-
-       if (dev->write_queue == NULL) {
-               dev->write_queue = frame;
-               spin_unlock_irqrestore(&dev->lock, flags);
-               pcbit_transmit(dev);
-       } else {
-               for (ptr = dev->write_queue; ptr->next; ptr = ptr->next);
-               ptr->next = frame;
-
-               spin_unlock_irqrestore(&dev->lock, flags);
-       }
-       return 0;
-}
-
-static __inline__ void
-pcbit_tx_update(struct pcbit_dev *dev, ushort len)
-{
-       u_char info;
-
-       dev->send_seq = (dev->send_seq + 1) % 8;
-
-       dev->fsize[dev->send_seq] = len;
-       info = 0;
-       info |= dev->rcv_seq << 3;
-       info |= dev->send_seq;
-
-       writeb(info, dev->sh_mem + BANK4);
-
-}
-
-/*
- * called by interrupt service routine or by write_2
- */
-
-static void
-pcbit_transmit(struct pcbit_dev *dev)
-{
-       struct frame_buf *frame = NULL;
-       unsigned char unacked;
-       int flen;               /* fragment frame length including all headers */
-       int free;
-       int count,
-               cp_len;
-       unsigned long flags;
-       unsigned short tt;
-
-       if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
-               return;
-
-       unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
-
-       spin_lock_irqsave(&dev->lock, flags);
-
-       if (dev->free > 16 && dev->write_queue && unacked < 7) {
-
-               if (!dev->w_busy)
-                       dev->w_busy = 1;
-               else {
-                       spin_unlock_irqrestore(&dev->lock, flags);
-                       return;
-               }
-
-
-               frame = dev->write_queue;
-               free = dev->free;
-
-               spin_unlock_irqrestore(&dev->lock, flags);
-
-               if (frame->copied == 0) {
-
-                       /* Type 0 frame */
-
-                       ulong   msg;
-
-                       if (frame->skb)
-                               flen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
-                       else
-                               flen = FRAME_HDR_LEN + PREHDR_LEN;
-
-                       if (flen > free)
-                               flen = free;
-
-                       msg = frame->msg;
-
-                       /*
-                        *  Board level 2 header
-                        */
-
-                       pcbit_writew(dev, flen - FRAME_HDR_LEN);
-
-                       pcbit_writeb(dev, GET_MSG_CPU(msg));
-
-                       pcbit_writeb(dev, GET_MSG_PROC(msg));
-
-                       /* TH */
-                       pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
-
-                       /* TD */
-                       pcbit_writew(dev, frame->dt_len);
-
-
-                       /*
-                        *  Board level 3 fixed-header
-                        */
-
-                       /* LEN = TH */
-                       pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
-
-                       /* XX */
-                       pcbit_writew(dev, 0);
-
-                       /* C + S */
-                       pcbit_writeb(dev, GET_MSG_CMD(msg));
-                       pcbit_writeb(dev, GET_MSG_SCMD(msg));
-
-                       /* NUM */
-                       pcbit_writew(dev, frame->refnum);
-
-                       count = FRAME_HDR_LEN + PREHDR_LEN;
-               } else {
-                       /* Type 1 frame */
-
-                       flen = 2 + (frame->skb->len - frame->copied);
-
-                       if (flen > free)
-                               flen = free;
-
-                       /* TT */
-                       tt = ((ushort) (flen - 2)) | 0x8000U;   /* Type 1 */
-                       pcbit_writew(dev, tt);
-
-                       count = 2;
-               }
-
-               if (frame->skb) {
-                       cp_len = frame->skb->len - frame->copied;
-                       if (cp_len > flen - count)
-                               cp_len = flen - count;
-
-                       memcpy_topcbit(dev, frame->skb->data + frame->copied,
-                                      cp_len);
-                       frame->copied += cp_len;
-               }
-               /* bookkeeping */
-               dev->free -= flen;
-               pcbit_tx_update(dev, flen);
-
-               spin_lock_irqsave(&dev->lock, flags);
-
-               if (frame->skb == NULL || frame->copied == frame->skb->len) {
-
-                       dev->write_queue = frame->next;
-
-                       if (frame->skb != NULL) {
-                               /* free frame */
-                               dev_kfree_skb(frame->skb);
-                       }
-                       kfree(frame);
-               }
-               dev->w_busy = 0;
-               spin_unlock_irqrestore(&dev->lock, flags);
-       } else {
-               spin_unlock_irqrestore(&dev->lock, flags);
-#ifdef DEBUG
-               printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
-                      unacked, dev->free, dev->write_queue ? "not empty" :
-                      "empty");
-#endif
-       }
-}
-
-
-/*
- *  deliver a queued frame to the upper layer
- */
-
-void
-pcbit_deliver(struct work_struct *work)
-{
-       struct frame_buf *frame;
-       unsigned long flags, msg;
-       struct pcbit_dev *dev =
-               container_of(work, struct pcbit_dev, qdelivery);
-
-       spin_lock_irqsave(&dev->lock, flags);
-
-       while ((frame = dev->read_queue)) {
-               dev->read_queue = frame->next;
-               spin_unlock_irqrestore(&dev->lock, flags);
-
-               msg = 0;
-               SET_MSG_CPU(msg, 0);
-               SET_MSG_PROC(msg, 0);
-               SET_MSG_CMD(msg, frame->skb->data[2]);
-               SET_MSG_SCMD(msg, frame->skb->data[3]);
-
-               frame->refnum = *((ushort *)frame->skb->data + 4);
-               frame->msg = *((ulong *)&msg);
-
-               skb_pull(frame->skb, 6);
-
-               pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
-                                frame->refnum);
-
-               kfree(frame);
-
-               spin_lock_irqsave(&dev->lock, flags);
-       }
-
-       spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-/*
- * Reads BANK 2 & Reassembles
- */
-
-static void
-pcbit_receive(struct pcbit_dev *dev)
-{
-       unsigned short tt;
-       u_char cpu,
-               proc;
-       struct frame_buf *frame = NULL;
-       unsigned long flags;
-       u_char type1;
-
-       if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
-               return;
-
-       tt = pcbit_readw(dev);
-
-       if ((tt & 0x7fffU) > 511) {
-               printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
-                      tt);
-               pcbit_l2_error(dev);
-               return;
-       }
-       if (!(tt & 0x8000U)) {  /* Type 0 */
-               type1 = 0;
-
-               if (dev->read_frame) {
-                       printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
-                       /* discard previous queued frame */
-                       kfree_skb(dev->read_frame->skb);
-                       kfree(dev->read_frame);
-                       dev->read_frame = NULL;
-               }
-               frame = kzalloc(sizeof(struct frame_buf), GFP_ATOMIC);
-
-               if (frame == NULL) {
-                       printk(KERN_WARNING "kmalloc failed\n");
-                       return;
-               }
-
-               cpu = pcbit_readb(dev);
-               proc = pcbit_readb(dev);
-
-
-               if (cpu != 0x06 && cpu != 0x02) {
-                       printk(KERN_DEBUG "pcbit: invalid cpu value\n");
-                       kfree(frame);
-                       pcbit_l2_error(dev);
-                       return;
-               }
-               /*
-                * we discard cpu & proc on receiving
-                * but we read it to update the pointer
-                */
-
-               frame->hdr_len = pcbit_readw(dev);
-               frame->dt_len = pcbit_readw(dev);
-
-               /*
-                * 0 sized packet
-                * I don't know if they are an error or not...
-                * But they are very frequent
-                * Not documented
-                */
-
-               if (frame->hdr_len == 0) {
-                       kfree(frame);
-#ifdef DEBUG
-                       printk(KERN_DEBUG "0 sized frame\n");
-#endif
-                       pcbit_firmware_bug(dev);
-                       return;
-               }
-               /* sanity check the length values */
-               if (frame->hdr_len > 1024 || frame->dt_len > 2048) {
-#ifdef DEBUG
-                       printk(KERN_DEBUG "length problem: ");
-                       printk(KERN_DEBUG "TH=%04x TD=%04x\n",
-                              frame->hdr_len,
-                              frame->dt_len);
-#endif
-                       pcbit_l2_error(dev);
-                       kfree(frame);
-                       return;
-               }
-               /* minimum frame read */
-
-               frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
-                                          ((frame->hdr_len + 15) & ~15));
-
-               if (!frame->skb) {
-                       printk(KERN_DEBUG "pcbit_receive: out of memory\n");
-                       kfree(frame);
-                       return;
-               }
-               /* 16 byte alignment for IP */
-               if (frame->dt_len)
-                       skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
-
-       } else {
-               /* Type 1 */
-               type1 = 1;
-               tt &= 0x7fffU;
-
-               if (!(frame = dev->read_frame)) {
-                       printk("Type 1 frame and no frame queued\n");
-                       /* usually after an error: toss frame */
-                       dev->readptr += tt;
-                       if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
-                               dev->readptr -= BANKLEN;
-                       return;
-
-               }
-       }
-
-       memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
-
-       frame->copied += tt;
-       spin_lock_irqsave(&dev->lock, flags);
-       if (frame->copied == frame->hdr_len + frame->dt_len) {
-
-               if (type1) {
-                       dev->read_frame = NULL;
-               }
-               if (dev->read_queue) {
-                       struct frame_buf *ptr;
-                       for (ptr = dev->read_queue; ptr->next; ptr = ptr->next);
-                       ptr->next = frame;
-               } else
-                       dev->read_queue = frame;
-
-       } else {
-               dev->read_frame = frame;
-       }
-       spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-/*
- *  The board sends 0 sized frames
- *  They are TDATA_CONFs that get messed up somehow
- *  gotta send a fake acknowledgment to the upper layer somehow
- */
-
-static __inline__ void
-pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan)
-{
-       isdn_ctrl ictl;
-
-       if (chan->queued) {
-               chan->queued--;
-
-               ictl.driver = dev->id;
-               ictl.command = ISDN_STAT_BSENT;
-               ictl.arg = chan->id;
-               dev->dev_if->statcallb(&ictl);
-       }
-}
-
-static void
-pcbit_firmware_bug(struct pcbit_dev *dev)
-{
-       struct pcbit_chan *chan;
-
-       chan = dev->b1;
-
-       if (chan->fsm_state == ST_ACTIVE) {
-               pcbit_fake_conf(dev, chan);
-       }
-       chan = dev->b2;
-
-       if (chan->fsm_state == ST_ACTIVE) {
-               pcbit_fake_conf(dev, chan);
-       }
-}
-
-irqreturn_t
-pcbit_irq_handler(int interrupt, void *devptr)
-{
-       struct pcbit_dev *dev;
-       u_char info,
-               ack_seq,
-               read_seq;
-
-       dev = (struct pcbit_dev *) devptr;
-
-       if (!dev) {
-               printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
-               return IRQ_NONE;
-       }
-       if (dev->interrupt) {
-               printk(KERN_DEBUG "pcbit: reentering interrupt handler\n");
-               return IRQ_HANDLED;
-       }
-       dev->interrupt = 1;
-
-       info = readb(dev->sh_mem + BANK3);
-
-       if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) {
-               pcbit_l2_active_conf(dev, info);
-               dev->interrupt = 0;
-               return IRQ_HANDLED;
-       }
-       if (info & 0x40U) {     /* E bit set */
-#ifdef DEBUG
-               printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n");
-#endif
-               pcbit_l2_error(dev);
-               dev->interrupt = 0;
-               return IRQ_HANDLED;
-       }
-       if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
-               dev->interrupt = 0;
-               return IRQ_HANDLED;
-       }
-       ack_seq = (info >> 3) & 0x07U;
-       read_seq = (info & 0x07U);
-
-       dev->interrupt = 0;
-
-       if (read_seq != dev->rcv_seq) {
-               while (read_seq != dev->rcv_seq) {
-                       pcbit_receive(dev);
-                       dev->rcv_seq = (dev->rcv_seq + 1) % 8;
-               }
-               pcbit_sched_delivery(dev);
-       }
-       if (ack_seq != dev->unack_seq) {
-               pcbit_recv_ack(dev, ack_seq);
-       }
-       info = dev->rcv_seq << 3;
-       info |= dev->send_seq;
-
-       writeb(info, dev->sh_mem + BANK4);
-       return IRQ_HANDLED;
-}
-
-
-static void
-pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
-{
-       u_char state;
-
-       state = dev->l2_state;
-
-#ifdef DEBUG
-       printk(KERN_DEBUG "layer2_active_confirm\n");
-#endif
-
-
-       if (info & 0x80U) {
-               dev->rcv_seq = info & 0x07U;
-               dev->l2_state = L2_RUNNING;
-       } else
-               dev->l2_state = L2_DOWN;
-
-       if (state == L2_STARTING)
-               wake_up_interruptible(&dev->set_running_wq);
-
-       if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
-               pcbit_transmit(dev);
-       }
-}
-
-static void
-pcbit_l2_err_recover(unsigned long data)
-{
-
-       struct pcbit_dev *dev;
-       struct frame_buf *frame;
-
-       dev = (struct pcbit_dev *) data;
-
-       del_timer(&dev->error_recover_timer);
-       if (dev->w_busy || dev->r_busy) {
-               init_timer(&dev->error_recover_timer);
-               dev->error_recover_timer.expires = jiffies + ERRTIME;
-               add_timer(&dev->error_recover_timer);
-               return;
-       }
-       dev->w_busy = dev->r_busy = 1;
-
-       if (dev->read_frame) {
-               kfree_skb(dev->read_frame->skb);
-               kfree(dev->read_frame);
-               dev->read_frame = NULL;
-       }
-       if (dev->write_queue) {
-               frame = dev->write_queue;
-#ifdef FREE_ON_ERROR
-               dev->write_queue = dev->write_queue->next;
-
-               if (frame->skb) {
-                       dev_kfree_skb(frame->skb);
-               }
-               kfree(frame);
-#else
-               frame->copied = 0;
-#endif
-       }
-       dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
-       dev->free = 511;
-       dev->l2_state = L2_ERROR;
-
-       /* this is an hack... */
-       pcbit_firmware_bug(dev);
-
-       dev->writeptr = dev->sh_mem;
-       dev->readptr = dev->sh_mem + BANK2;
-
-       writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
-              dev->sh_mem + BANK4);
-       dev->w_busy = dev->r_busy = 0;
-
-}
-
-static void
-pcbit_l2_error(struct pcbit_dev *dev)
-{
-       if (dev->l2_state == L2_RUNNING) {
-
-               printk(KERN_INFO "pcbit: layer 2 error\n");
-
-#ifdef DEBUG
-               log_state(dev);
-#endif
-
-               dev->l2_state = L2_DOWN;
-
-               init_timer(&dev->error_recover_timer);
-               dev->error_recover_timer.function = &pcbit_l2_err_recover;
-               dev->error_recover_timer.data = (ulong) dev;
-               dev->error_recover_timer.expires = jiffies + ERRTIME;
-               add_timer(&dev->error_recover_timer);
-       }
-}
-
-/*
- * Description:
- * if board acks frames
- *   update dev->free
- *   call pcbit_transmit to write possible queued frames
- */
-
-static void
-pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
-{
-       int i,
-               count;
-       int unacked;
-
-       unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
-
-       /* dev->unack_seq < ack <= dev->send_seq; */
-
-       if (unacked) {
-
-               if (dev->send_seq > dev->unack_seq) {
-                       if (ack <= dev->unack_seq || ack > dev->send_seq) {
-                               printk(KERN_DEBUG
-                                      "layer 2 ack unacceptable - dev %d",
-                                      dev->id);
-
-                               pcbit_l2_error(dev);
-                       } else if (ack > dev->send_seq && ack <= dev->unack_seq) {
-                               printk(KERN_DEBUG
-                                      "layer 2 ack unacceptable - dev %d",
-                                      dev->id);
-                               pcbit_l2_error(dev);
-                       }
-               }
-               /* ack is acceptable */
-
-
-               i = dev->unack_seq;
-
-               do {
-                       dev->unack_seq = i = (i + 1) % 8;
-                       dev->free += dev->fsize[i];
-               } while (i != ack);
-
-               count = 0;
-               while (count < 7 && dev->write_queue) {
-                       u8 lsend_seq = dev->send_seq;
-
-                       pcbit_transmit(dev);
-
-                       if (dev->send_seq == lsend_seq)
-                               break;
-                       count++;
-               }
-       } else
-               printk(KERN_DEBUG "recv_ack: unacked = 0\n");
-}
diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h
deleted file mode 100644 (file)
index be1327b..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * PCBIT-D low-layer interface definitions
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * 19991203 - Fernando Carvalho - takion@superbofh.org
- * Hacked to compile with egcs and run with current version of isdn modules
- */
-
-#ifndef LAYER2_H
-#define LAYER2_H
-
-#include <linux/interrupt.h>
-
-#include <asm/byteorder.h>
-
-#define BANK1 0x0000U /* PC -> Board */
-#define BANK2 0x01ffU /* Board -> PC */
-#define BANK3 0x03feU /* Att Board */
-#define BANK4 0x03ffU /* Att PC */
-
-#define BANKLEN 0x01FFU
-
-#define LOAD_ZONE_START 0x03f8U
-#define LOAD_ZONE_END   0x03fdU
-
-#define LOAD_RETRY      18000000
-
-
-
-/* TAM - XX - C - S  - NUM */
-#define PREHDR_LEN 8
-/* TT  - M  - I - TH - TD  */
-#define FRAME_HDR_LEN  8
-
-#define MSG_CONN_REQ           0x08000100
-#define MSG_CONN_CONF          0x00000101
-#define MSG_CONN_IND           0x00000102
-#define MSG_CONN_RESP          0x08000103
-
-#define MSG_CONN_ACTV_REQ      0x08000300
-#define MSG_CONN_ACTV_CONF     0x00000301
-#define MSG_CONN_ACTV_IND      0x00000302
-#define MSG_CONN_ACTV_RESP     0x08000303
-
-#define MSG_DISC_REQ           0x08000400
-#define MSG_DISC_CONF          0x00000401
-#define MSG_DISC_IND           0x00000402
-#define MSG_DISC_RESP          0x08000403
-
-#define MSG_TDATA_REQ          0x0908E200
-#define MSG_TDATA_CONF         0x0000E201
-#define MSG_TDATA_IND          0x0000E202
-#define MSG_TDATA_RESP         0x0908E203
-
-#define MSG_SELP_REQ           0x09004000
-#define MSG_SELP_CONF          0x00004001
-
-#define MSG_ACT_TRANSP_REQ      0x0908E000
-#define MSG_ACT_TRANSP_CONF     0x0000E001
-
-#define MSG_STPROT_REQ         0x09004100
-#define MSG_STPROT_CONF                0x00004101
-
-#define MSG_PING188_REQ                0x09030500
-#define MSG_PING188_CONF        0x000005bc
-
-#define MSG_WATCH188           0x09030400
-
-#define MSG_API_ON              0x08020102
-#define MSG_POOL_PCBIT          0x08020400
-#define MSG_POOL_PCBIT_CONF     0x00000401
-
-#define MSG_INFO_IND            0x00002602
-#define MSG_INFO_RESP           0x08002603
-
-#define MSG_DEBUG_188           0x0000ff00
-
-/*
-
-  long  4 3 2 1
-  Intel 1 2 3 4
-*/
-
-#ifdef __LITTLE_ENDIAN
-#define SET_MSG_SCMD(msg, ch)  (msg = (msg & 0xffffff00) | (((ch) & 0xff)))
-#define SET_MSG_CMD(msg, ch)   (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8))
-#define SET_MSG_PROC(msg, ch)  (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16))
-#define SET_MSG_CPU(msg, ch)   (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24))
-
-#define GET_MSG_SCMD(msg)      ((msg) & 0xFF)
-#define GET_MSG_CMD(msg)       ((msg) >> 8 & 0xFF)
-#define GET_MSG_PROC(msg)      ((msg) >> 16 & 0xFF)
-#define GET_MSG_CPU(msg)       ((msg) >> 24)
-
-#else
-#error "Non-Intel CPU"
-#endif
-
-#define MAX_QUEUED 7
-
-#define SCHED_READ    0x01
-#define SCHED_WRITE   0x02
-
-#define SET_RUN_TIMEOUT 2 * HZ /* 2 seconds */
-
-struct frame_buf {
-       ulong msg;
-       unsigned int refnum;
-       unsigned int dt_len;
-       unsigned int hdr_len;
-       struct sk_buff *skb;
-       unsigned int copied;
-       struct frame_buf *next;
-};
-
-extern int pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
-                         struct sk_buff *skb, unsigned short hdr_len);
-
-extern irqreturn_t pcbit_irq_handler(int interrupt, void *);
-
-extern struct pcbit_dev *dev_pcbit[MAX_PCBIT_CARDS];
-
-#ifdef DEBUG
-static __inline__ void log_state(struct pcbit_dev *dev) {
-       printk(KERN_DEBUG "writeptr = %ld\n",
-              (ulong) (dev->writeptr - dev->sh_mem));
-       printk(KERN_DEBUG "readptr  = %ld\n",
-              (ulong) (dev->readptr - (dev->sh_mem + BANK2)));
-       printk(KERN_DEBUG "{rcv_seq=%01x, send_seq=%01x, unack_seq=%01x}\n",
-              dev->rcv_seq, dev->send_seq, dev->unack_seq);
-}
-#endif
-
-static __inline__ struct pcbit_dev *chan2dev(struct pcbit_chan *chan)
-{
-       struct pcbit_dev *dev;
-       int i;
-
-
-       for (i = 0; i < MAX_PCBIT_CARDS; i++)
-               if ((dev = dev_pcbit[i]))
-                       if (dev->b1 == chan || dev->b2 == chan)
-                               return dev;
-       return NULL;
-
-}
-
-static __inline__ struct pcbit_dev *finddev(int id)
-{
-       struct pcbit_dev *dev;
-       int i;
-
-       for (i = 0; i < MAX_PCBIT_CARDS; i++)
-               if ((dev = dev_pcbit[i]))
-                       if (dev->id == id)
-                               return dev;
-       return NULL;
-}
-
-
-/*
- *  Support routines for reading and writing in the board
- */
-
-static __inline__ void pcbit_writeb(struct pcbit_dev *dev, unsigned char dt)
-{
-       writeb(dt, dev->writeptr++);
-       if (dev->writeptr == dev->sh_mem + BANKLEN)
-               dev->writeptr = dev->sh_mem;
-}
-
-static __inline__ void pcbit_writew(struct pcbit_dev *dev, unsigned short dt)
-{
-       int dist;
-
-       dist = BANKLEN - (dev->writeptr - dev->sh_mem);
-       switch (dist) {
-       case 2:
-               writew(dt, dev->writeptr);
-               dev->writeptr = dev->sh_mem;
-               break;
-       case 1:
-               writeb((u_char) (dt & 0x00ffU), dev->writeptr);
-               dev->writeptr = dev->sh_mem;
-               writeb((u_char) (dt >> 8), dev->writeptr++);
-               break;
-       default:
-               writew(dt, dev->writeptr);
-               dev->writeptr += 2;
-               break;
-       };
-}
-
-static __inline__ void memcpy_topcbit(struct pcbit_dev *dev, u_char *data,
-                                     int len)
-{
-       int diff;
-
-       diff = len - (BANKLEN - (dev->writeptr - dev->sh_mem));
-
-       if (diff > 0)
-       {
-               memcpy_toio(dev->writeptr, data, len - diff);
-               memcpy_toio(dev->sh_mem, data + (len - diff), diff);
-               dev->writeptr = dev->sh_mem + diff;
-       }
-       else
-       {
-               memcpy_toio(dev->writeptr, data, len);
-
-               dev->writeptr += len;
-               if (diff == 0)
-                       dev->writeptr = dev->sh_mem;
-       }
-}
-
-static __inline__ unsigned char pcbit_readb(struct pcbit_dev *dev)
-{
-       unsigned char val;
-
-       val = readb(dev->readptr++);
-       if (dev->readptr == dev->sh_mem + BANK2 + BANKLEN)
-               dev->readptr = dev->sh_mem + BANK2;
-
-       return val;
-}
-
-static __inline__ unsigned short pcbit_readw(struct pcbit_dev *dev)
-{
-       int dist;
-       unsigned short val;
-
-       dist = BANKLEN - (dev->readptr - (dev->sh_mem + BANK2));
-       switch (dist) {
-       case 2:
-               val = readw(dev->readptr);
-               dev->readptr = dev->sh_mem + BANK2;
-               break;
-       case 1:
-               val = readb(dev->readptr);
-               dev->readptr = dev->sh_mem + BANK2;
-               val = (readb(dev->readptr++) << 8) | val;
-               break;
-       default:
-               val = readw(dev->readptr);
-               dev->readptr += 2;
-               break;
-       };
-       return val;
-}
-
-static __inline__ void memcpy_frompcbit(struct pcbit_dev *dev, u_char *data, int len)
-{
-       int diff;
-
-       diff = len - (BANKLEN - (dev->readptr - (dev->sh_mem + BANK2)));
-       if (diff > 0)
-       {
-               memcpy_fromio(data, dev->readptr, len - diff);
-               memcpy_fromio(data + (len - diff), dev->sh_mem + BANK2 , diff);
-               dev->readptr = dev->sh_mem + BANK2 + diff;
-       }
-       else
-       {
-               memcpy_fromio(data, dev->readptr, len);
-               dev->readptr += len;
-               if (diff == 0)
-                       dev->readptr = dev->sh_mem + BANK2;
-       }
-}
-
-
-#endif
diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c
deleted file mode 100644 (file)
index 0a59bd0..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * PCBIT-D module support
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-
-#include <linux/isdnif.h>
-#include "pcbit.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: Driver for PCBIT-T card");
-MODULE_AUTHOR("Pedro Roque Marques");
-MODULE_LICENSE("GPL");
-
-static int mem[MAX_PCBIT_CARDS];
-static int irq[MAX_PCBIT_CARDS];
-
-module_param_array(mem, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-
-static int num_boards;
-struct pcbit_dev *dev_pcbit[MAX_PCBIT_CARDS];
-
-static int __init pcbit_init(void)
-{
-       int board;
-
-       num_boards = 0;
-
-       printk(KERN_NOTICE
-              "PCBIT-D device driver v 0.5-fjpc0 19991204 - "
-              "Copyright (C) 1996 Universidade de Lisboa\n");
-
-       if (mem[0] || irq[0])
-       {
-               for (board = 0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++)
-               {
-                       if (!mem[board])
-                               mem[board] = 0xD0000;
-                       if (!irq[board])
-                               irq[board] = 5;
-
-                       if (pcbit_init_dev(board, mem[board], irq[board]) == 0)
-                               num_boards++;
-
-                       else
-                       {
-                               printk(KERN_WARNING
-                                      "pcbit_init failed for dev %d",
-                                      board + 1);
-                               return -EIO;
-                       }
-               }
-       }
-
-       /* Hardcoded default settings detection */
-
-       if (!num_boards)
-       {
-               printk(KERN_INFO
-                      "Trying to detect board using default settings\n");
-               if (pcbit_init_dev(0, 0xD0000, 5) == 0)
-                       num_boards++;
-               else
-                       return -EIO;
-       }
-       return 0;
-}
-
-static void __exit pcbit_exit(void)
-{
-#ifdef MODULE
-       int board;
-
-       for (board = 0; board < num_boards; board++)
-               pcbit_terminate(board);
-       printk(KERN_NOTICE
-              "PCBIT-D module unloaded\n");
-#endif
-}
-
-#ifndef MODULE
-#define MAX_PARA       (MAX_PCBIT_CARDS * 2)
-static int __init pcbit_setup(char *line)
-{
-       int i, j, argc;
-       char *str;
-       int ints[MAX_PARA + 1];
-
-       str = get_options(line, MAX_PARA, ints);
-       argc = ints[0];
-       i = 0;
-       j = 1;
-
-       while (argc && (i < MAX_PCBIT_CARDS)) {
-
-               if (argc) {
-                       mem[i]  = ints[j];
-                       j++; argc--;
-               }
-
-               if (argc) {
-                       irq[i]  = ints[j];
-                       j++; argc--;
-               }
-
-               i++;
-       }
-       return (1);
-}
-__setup("pcbit=", pcbit_setup);
-#endif
-
-module_init(pcbit_init);
-module_exit(pcbit_exit);
diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h
deleted file mode 100644 (file)
index 0a5a994..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * PCBIT-D device driver definitions
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef PCBIT_H
-#define PCBIT_H
-
-#include <linux/workqueue.h>
-
-#define MAX_PCBIT_CARDS 4
-
-
-#define BLOCK_TIMER
-
-#ifdef __KERNEL__
-
-struct pcbit_chan {
-       unsigned short id;
-       unsigned short callref;                   /* Call Reference */
-       unsigned char  proto;                     /* layer2protocol  */
-       unsigned char  queued;                    /* unacked data messages */
-       unsigned char  layer2link;                /* used in TData */
-       unsigned char  snum;                      /* used in TData */
-       unsigned short s_refnum;
-       unsigned short r_refnum;
-       unsigned short fsm_state;
-       struct timer_list fsm_timer;
-#ifdef BLOCK_TIMER
-       struct timer_list block_timer;
-#endif
-};
-
-struct msn_entry {
-       char *msn;
-       struct msn_entry *next;
-};
-
-struct pcbit_dev {
-       /* board */
-
-       volatile unsigned char __iomem *sh_mem;         /* RDP address  */
-       unsigned long ph_mem;
-       unsigned int irq;
-       unsigned int id;
-       unsigned int interrupt;                 /* set during interrupt
-                                                  processing */
-       spinlock_t lock;
-       /* isdn4linux */
-
-       struct msn_entry *msn_list;             /* ISDN address list */
-
-       isdn_if *dev_if;
-
-       ushort ll_hdrlen;
-       ushort hl_hdrlen;
-
-       /* link layer */
-       unsigned char l2_state;
-
-       struct frame_buf *read_queue;
-       struct frame_buf *read_frame;
-       struct frame_buf *write_queue;
-
-       /* Protocol start */
-       wait_queue_head_t set_running_wq;
-       struct timer_list set_running_timer;
-
-       struct timer_list error_recover_timer;
-
-       struct work_struct qdelivery;
-
-       u_char w_busy;
-       u_char r_busy;
-
-       volatile unsigned char __iomem *readptr;
-       volatile unsigned char __iomem *writeptr;
-
-       ushort loadptr;
-
-       unsigned short fsize[8];                /* sent layer2 frames size */
-
-       unsigned char send_seq;
-       unsigned char rcv_seq;
-       unsigned char unack_seq;
-
-       unsigned short free;
-
-       /* channels */
-
-       struct pcbit_chan *b1;
-       struct pcbit_chan *b2;
-};
-
-#define STATS_TIMER (10 * HZ)
-#define ERRTIME     (HZ / 10)
-
-/* MRU */
-#define MAXBUFSIZE  1534
-#define MRU   MAXBUFSIZE
-
-#define STATBUF_LEN 2048
-/*
- *
- */
-
-#endif /* __KERNEL__ */
-
-/* isdn_ctrl only allows a long sized argument */
-
-struct pcbit_ioctl {
-       union {
-               struct byte_op {
-                       ushort addr;
-                       ushort value;
-               } rdp_byte;
-               unsigned long l2_status;
-       } info;
-};
-
-
-
-#define PCBIT_IOCTL_GETSTAT  0x01    /* layer2 status */
-#define PCBIT_IOCTL_LWMODE   0x02    /* linear write mode */
-#define PCBIT_IOCTL_STRLOAD  0x03    /* start load mode */
-#define PCBIT_IOCTL_ENDLOAD  0x04    /* end load mode */
-#define PCBIT_IOCTL_SETBYTE  0x05    /* set byte */
-#define PCBIT_IOCTL_GETBYTE  0x06    /* get byte */
-#define PCBIT_IOCTL_RUNNING  0x07    /* set protocol running */
-#define PCBIT_IOCTL_WATCH188 0x08    /* set watch 188 */
-#define PCBIT_IOCTL_PING188  0x09    /* ping 188 */
-#define PCBIT_IOCTL_FWMODE   0x0A    /* firmware write mode */
-#define PCBIT_IOCTL_STOP     0x0B    /* stop protocol */
-#define PCBIT_IOCTL_APION    0x0C    /* issue API_ON  */
-
-#ifndef __KERNEL__
-
-#define PCBIT_GETSTAT  (PCBIT_IOCTL_GETSTAT  + IIOCDRVCTL)
-#define PCBIT_LWMODE   (PCBIT_IOCTL_LWMODE   + IIOCDRVCTL)
-#define PCBIT_STRLOAD  (PCBIT_IOCTL_STRLOAD  + IIOCDRVCTL)
-#define PCBIT_ENDLOAD  (PCBIT_IOCTL_ENDLOAD  + IIOCDRVCTL)
-#define PCBIT_SETBYTE  (PCBIT_IOCTL_SETBYTE  + IIOCDRVCTL)
-#define PCBIT_GETBYTE  (PCBIT_IOCTL_GETBYTE  + IIOCDRVCTL)
-#define PCBIT_RUNNING  (PCBIT_IOCTL_RUNNING  + IIOCDRVCTL)
-#define PCBIT_WATCH188 (PCBIT_IOCTL_WATCH188 + IIOCDRVCTL)
-#define PCBIT_PING188  (PCBIT_IOCTL_PING188  + IIOCDRVCTL)
-#define PCBIT_FWMODE   (PCBIT_IOCTL_FWMODE   + IIOCDRVCTL)
-#define PCBIT_STOP     (PCBIT_IOCTL_STOP     + IIOCDRVCTL)
-#define PCBIT_APION    (PCBIT_IOCTL_APION    + IIOCDRVCTL)
-
-#define MAXSUPERLINE 3000
-
-#endif
-
-#define L2_DOWN     0
-#define L2_LOADING  1
-#define L2_LWMODE   2
-#define L2_FWMODE   3
-#define L2_STARTING 4
-#define L2_RUNNING  5
-#define L2_ERROR    6
-
-void pcbit_deliver(struct work_struct *work);
-int pcbit_init_dev(int board, int mem_base, int irq);
-void pcbit_terminate(int board);
-void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, struct sk_buff *skb,
-                     ushort hdr_len, ushort refnum);
-void pcbit_state_change(struct pcbit_dev *dev, struct pcbit_chan *chan,
-                       unsigned short i, unsigned short ev, unsigned short f);
-
-#endif
index 5f9a97a77393162a8c2e371bb2722c4bbec6eb23..ff894bc63b3bf9e280c5364d03917cb15e464600 100644 (file)
@@ -104,4 +104,6 @@ source "drivers/staging/wilc1000/Kconfig"
 
 source "drivers/staging/most/Kconfig"
 
+source "drivers/staging/i4l/Kconfig"
+
 endif # STAGING
index b3920c224013cecd2e586b8a9fbffc1e6afcbe5b..8242923371ad9aef2c254aad2332dca595919a60 100644 (file)
@@ -41,3 +41,4 @@ obj-$(CONFIG_FB_TFT)          += fbtft/
 obj-$(CONFIG_FSL_MC_BUS)       += fsl-mc/
 obj-$(CONFIG_WILC1000)         += wilc1000/
 obj-$(CONFIG_MOST)             += most/
+obj-$(CONFIG_ISDN_I4L)         += i4l/
diff --git a/drivers/staging/i4l/Documentation/README.act2000 b/drivers/staging/i4l/Documentation/README.act2000
new file mode 100644 (file)
index 0000000..ce7115e
--- /dev/null
@@ -0,0 +1,104 @@
+$Id: README.act2000,v 1.3 2000/08/06 09:22:51 armin Exp $
+
+This document describes the ACT2000 driver for the
+IBM Active 2000 ISDN card.
+
+There are 3 Types of this card available. A ISA-, MCA-, and PCMCIA-Bus
+Version. Currently, only the ISA-Bus version of the card is supported.
+However MCA and PCMCIA will follow soon.
+
+The ISA-Bus Version uses 8 IO-ports. The base port address has to be set
+manually using the DIP switches.
+
+Setting up the DIP switches for the IBM Active 2000 ISDN card:
+
+        Note: S5 and S6 always set off!
+
+     S1  S2  S3  S4  Base-port
+     on  on  on  on  0x0200 (Factory default)
+     off on  on  on  0x0240 
+     on  off on  on  0x0280 
+     off off on  on  0x02c0 
+     on  on  off on  0x0300 
+     off on  off on  0x0340 
+     on  off off on  0x0380 
+     on  on  on  off 0xcfe0
+     off on  on  off 0xcfa0 
+     on  off on  off 0xcf60 
+     off off on  off 0xcf20 
+     on  on  off off 0xcee0 
+     off on  off off 0xcea0 
+     on  off off off 0xce60 
+     off off off off Card disabled 
+
+IRQ is configured by software. Possible values are:
+
+  3, 5, 7, 10, 11, 12, 15 and none (polled mode)
+
+
+The ACT2000 driver may either be built into the kernel or as a module.
+Initialization depends on how the driver is built:
+
+Driver built into the kernel:
+
+  The ACT2000 driver can be configured using the commandline-feature while
+  loading the kernel with LILO or LOADLIN. It accepts the following syntax:
+
+  act2000=b,p,i[,idstring]
+
+  where
+
+    b = Bus-Type      (1=ISA, 2=MCA, 3=PCMCIA)
+    p = portbase      (-1 means autoprobe)
+    i = Interrupt     (-1 means use next free IRQ, 0 means polled mode)
+
+  The idstring is an arbitrary string used for referencing the card
+  by the actctrl tool later.
+
+  Defaults used, when no parameters given at all:
+
+    1,-1,-1,""
+
+  which means: Autoprobe for an ISA card, use next free IRQ, let the
+  ISDN linklevel fill the IdString (usually "line0" for the first card).
+  If you like to use more than one card, you can use the program
+  "actctrl" from the utility-package to configure additional cards.
+
+  Using the "actctrl"-utility, portbase and irq can also be changed
+  during runtime. The D-channel protocol is configured by the "dproto"
+  option of the "actctrl"-utility after loading the firmware into the
+  card's memory using the "actctrl"-utility.
+
+Driver built as module:
+
+  The module act2000.o can be configured during modprobe (insmod) by
+  appending its parameters to the modprobe resp. insmod commandline.
+  The following syntax is accepted:
+
+    act_bus=b act_port=p act_irq=i act_id=idstring
+
+  where b, p, i and idstring have the same meanings as the parameters
+  described for the builtin version above.
+
+  Using the "actctrl"-utility, the same features apply to the modularized
+  version as to the kernel-builtin one. (i.e. loading of firmware and
+  configuring the D-channel protocol)
+
+Loading the firmware into the card:
+
+  The firmware is supplied together with the isdn4k-utils package. It
+  can be found in the subdirectory act2000/firmware/
+
+  Assuming you have installed the utility-package correctly, the firmware
+  will be downloaded into the card using the following command:
+
+    actctrl -d idstring load /etc/isdn/bip11.btl
+
+  where idstring is the Name of the card, given during insmod-time or
+  (for kernel-builtin driver) on the kernel commandline. If only one
+  ISDN card is used, the -d isdstrin may be omitted.
+
+  For further documentation (adding more IBM Active 2000 cards), refer to
+  the manpage actctrl.8 which is included in the isdn4k-utils package.
+
diff --git a/drivers/staging/i4l/Documentation/README.icn b/drivers/staging/i4l/Documentation/README.icn
new file mode 100644 (file)
index 0000000..13f833d
--- /dev/null
@@ -0,0 +1,148 @@
+$Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $
+
+You can get the ICN-ISDN-card from:
+
+Thinking Objects Software GmbH
+Versbacher Röthe 159
+97078 Würzburg
+Tel: +49 931 2877950
+Fax: +49 931 2877951
+
+email info@think.de
+WWW   http:/www.think.de
+
+
+The card communicates with the PC by two interfaces:
+  1. A range of 4 successive port-addresses, whose base address can be 
+     configured with the switches.
+  2. A memory window with 16KB-256KB size, which can be setup in 16k steps
+     over the whole range of 16MB. Isdn4linux only uses a 16k window.
+     The base address of the window can be configured when loading
+     the lowlevel-module (see README). If using more than one card,
+     all cards are mapped to the same window and activated as needed.
+
+Setting up the IO-address dipswitches for the ICN-ISDN-card:
+
+  Two types of cards exist, one with dip-switches and one with
+  hook-switches.
+
+  1. Setting for the card with hook-switches:
+
+     (0 = switch closed, 1 = switch open)
+
+     S3 S2 S1  Base-address
+      0  0  0  0x300
+      0  0  1  0x310
+      0  1  0  0x320 (Default for isdn4linux)
+      0  1  1  0x330
+      1  0  0  0x340
+      1  0  1  0x350
+      1  1  0  0x360
+      1  1  1  NOT ALLOWED!
+    
+  2. Setting for the card with dip-switches:
+
+     (0 = switch closed, 1 = switch open)
+
+     S1 S2 S3 S4  Base-Address
+      0  0  0  0  0x300
+      0  0  0  1  0x310
+      0  0  1  0  0x320 (Default for isdn4linux)
+      0  0  1  1  0x330
+      0  1  0  0  0x340
+      0  1  0  1  0x350
+      0  1  1  0  0x360
+      0  1  1  1  NOT ALLOWED!
+      1  0  0  0  0x308
+      1  0  0  1  0x318
+      1  0  1  0  0x328
+      1  0  1  1  0x338
+      1  1  0  0  0x348
+      1  1  0  1  0x358
+      1  1  1  0  0x368
+      1  1  1  1  NOT ALLOWED!
+
+The ICN driver may be built into the kernel or as a module. Initialization
+depends on how the driver is built:
+
+Driver built into the kernel:
+
+  The ICN driver can be configured using the commandline-feature while
+  loading the kernel with LILO or LOADLIN. It accepts the following syntax:
+
+  icn=p,m[,idstring1[,idstring2]]
+
+  where
+
+    p = portbase      (default: 0x320)
+    m = shared memory (default: 0xd0000)
+
+  When using the ICN double card (4B), you MUST define TWO idstrings.
+  idstring must start with a character! There is no way for the driver
+  to distinguish between a 2B and 4B type card. Therefore, by supplying
+  TWO idstrings, you tell the driver that you have a 4B installed.
+  
+  If you like to use more than one card, you can use the program
+  "icnctrl" from the utility-package to configure additional cards.
+  You need to configure shared memory only once, since the icn-driver
+  maps all cards into the same address-space.
+
+  Using the "icnctrl"-utility, portbase and shared memory can also be
+  changed during runtime.
+
+  The D-channel protocol is configured by loading different firmware
+  into the card's memory using the "icnctrl"-utility.
+
+
+Driver built as module:
+
+  The module icn.o can be configured during "insmod'ing" it by
+  appending its parameters to the insmod-commandline. The following
+  syntax is accepted:
+
+    portbase=p membase=m icn_id=idstring [icn_id2=idstring2]
+
+  where p, m, idstring1 and idstring2 have the same meanings as the
+  parameters described for the kernel-version above.
+      
+  When using the ICN double card (4B), you MUST define TWO idstrings.
+  idstring must start with a character! There is no way for the driver
+  to distinguish between a 2B and 4B type card. Therefore, by supplying
+  TWO idstrings, you tell the driver that you have a 4B installed.
+  
+  Using the "icnctrl"-utility, the same features apply to the modularized
+  version like to the kernel-builtin one.
+
+  The D-channel protocol is configured by loading different firmware
+  into the card's memory using the "icnctrl"-utility.
+
+Loading the firmware into the card:
+
+  The firmware is supplied together with the isdn4k-utils package. It
+  can be found in the subdirectory icnctrl/firmware/
+
+  There are 3 files:
+
+    loadpg.bin   - Image of the bootstrap loader.
+    pc_1t_ca.bin - Image of firmware for german 1TR6 protocol.
+    pc_eu_ca.bin - Image if firmware for EDSS1 (Euro-ISDN) protocol.
+
+  Assuming you have installed the utility-package correctly, the firmware
+  will be downloaded into the 2B-card using the following command:
+
+    icnctrl -d Idstring load /etc/isdn/loadpg.bin /etc/isdn/pc_XX_ca.bin
+
+  where XX is either "1t" or "eu", depending on the D-Channel protocol
+  used on your S0-bus and Idstring is the Name of the card, given during
+  insmod-time or (for kernel-builtin driver) on the kernel commandline.
+
+  To load a 4B-card, the same command is used, except a second firmware
+  file is appended to the commandline of icnctrl.
+
+  -> After downloading firmware, the two LEDs at the back cover of the card
+     (ICN-4B: 4 LEDs) must be blinking intermittently now. If a connection
+     is up, the corresponding led is lit continuously.
+
+  For further documentation (adding more ICN-cards), refer to the manpage
+  icnctrl.8 which is included in the isdn4k-utils package.
+
diff --git a/drivers/staging/i4l/Documentation/README.pcbit b/drivers/staging/i4l/Documentation/README.pcbit
new file mode 100644 (file)
index 0000000..5125002
--- /dev/null
@@ -0,0 +1,40 @@
+------------------------------------------------------------------------------
+ README file for the PCBIT-D Device Driver.
+------------------------------------------------------------------------------
+
+The PCBIT is a Euro ISDN adapter manufactured in Portugal by Octal and
+developed in cooperation with Portugal Telecom and Inesc.
+The driver interfaces with the standard kernel isdn facilities
+originally developed by Fritz Elfert in the isdn4linux project.
+
+The common versions of the pcbit board require a firmware that is 
+distributed (and copyrighted) by the manufacturer. To load this
+firmware you need "pcbitctl" available on the standard isdn4k-utils
+package or in the pcbit package available in:
+
+ftp://ftp.di.fc.ul.pt/pub/systems/Linux/isdn
+
+Known Limitations:
+
+- The board reset procedure is at the moment incorrect and will only
+allow you to load the firmware after a hard reset.
+
+- Only HDLC in B-channels is supported at the moment. There is no
+current support for X.25 in B or D channels nor LAPD in B
+channels. The main reason is that these two other protocol modes have,
+to my knowledge, very little use. If you want to see them implemented
+*do* send me a mail.
+
+- The driver often triggers errors in the board that I and the
+manufacturer believe to be caused by bugs in the firmware. The current
+version includes several procedures for error recovery that should
+allow normal operation. Plans for the future include cooperation with
+the manufacturer in order to solve this problem.
+
+Information/hints/help can be obtained in the linux isdn
+mailing list (isdn4linux@listserv.isdn4linux.de) or directly from me.
+
+regards,
+  Pedro.
+               
+<roque@di.fc.ul.pt>
diff --git a/drivers/staging/i4l/Documentation/README.sc b/drivers/staging/i4l/Documentation/README.sc
new file mode 100644 (file)
index 0000000..1153cd9
--- /dev/null
@@ -0,0 +1,281 @@
+Welcome to Beta Release 2 of the combination ISDN driver for SpellCaster's
+ISA ISDN adapters. Please note this release 2 includes support for the
+DataCommute/BRI and TeleCommute/BRI adapters only and any other use is 
+guaranteed to fail. If you have a DataCommute/PRI installed in the test
+computer, we recommend removing it as it will be detected but will not
+be usable.  To see what we have done to Beta Release 2, see section 3.
+
+Speaking of guarantees, THIS IS BETA SOFTWARE and as such contains
+bugs and defects either known or unknown. Use this software at your own
+risk. There is NO SUPPORT for this software. Some help may be available
+through the web site or the mailing list but such support is totally at
+our own option and without warranty. If you choose to assume all and
+total risk by using this driver, we encourage you to join the beta
+mailing list.
+
+To join the Linux beta mailing list, send a message to:
+majordomo@spellcast.com with the words "subscribe linux-beta" as the only
+contents of the message. Do not include a signature. If you choose to
+remove yourself from this list at a later date, send another message to
+the same address with the words "unsubscribe linux-beta" as its only
+contents.
+
+TABLE OF CONTENTS
+-----------------
+       1. Introduction
+        1.1 What is ISDN4Linux?
+        1.2 What is different between this driver and previous drivers?
+        1.3 How do I setup my system with the correct software to use
+            this driver release?
+       
+       2. Basic Operations
+        2.1 Unpacking and installing the driver
+        2.2 Read the man pages!!!
+        2.3 Installing the driver
+        2.4 Removing the driver
+        2.5 What to do if it doesn't load
+        2.6 How to setup ISDN4Linux with the driver
+
+       3. Beta Change Summaries and Miscellaneous Notes
+
+1. Introduction
+---------------
+
+The revision 2 Linux driver for SpellCaster ISA ISDN adapters is built
+upon ISDN4Linux available separately or as included in Linux 2.0 and later.
+The driver will support a maximum of 4 adapters in any one system of any
+type including DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI for a
+maximum of 92 channels for host. The driver is supplied as a module in
+source form and needs to be complied before it can be used. It has been
+tested on Linux 2.0.20.
+
+1.1 What Is ISDN4Linux
+
+ISDN4Linux is a driver and set of tools used to access and use ISDN devices
+on a Linux platform in a common and standard way. It supports HDLC and PPP
+protocols and offers channel bundling and MLPPP support. To use ISDN4Linux
+you need to configure your kernel for ISDN support and get the ISDN4Linux
+tool kit from our web site.
+
+ISDN4Linux creates a channel pool from all of the available ISDN channels
+and therefore can function across adapters. When an ISDN4Linux compliant
+driver (such as ours) is loaded, all of the channels go into a pool and
+are used on a first-come first-served basis. In addition, individual
+channels can be specifically bound to particular interfaces.
+
+1.2 What is different between this driver and previous drivers?
+
+The revision 2 driver besides adopting the ISDN4Linux architecture has many
+subtle and not so subtle functional differences from previous releases. These
+include:
+       - More efficient shared memory management combined with a simpler
+         configuration. All adapters now use only 16Kbytes of shared RAM
+         versus between 16K and 64K. New methods for using the shared RAM
+         allow us to utilize all of the available RAM on the adapter through
+         only one 16K page.
+       - Better detection of available upper memory. The probing routines
+         have been improved to better detect available shared RAM pages and
+         used pages are now locked.
+       - Decreased loading time and a wider range of I/O ports probed.
+         We have significantly reduced the amount of time it takes to load
+         the driver and at the same time doubled the number of I/O ports
+         probed increasing the likelihood of finding an adapter.
+       - We now support all ISA adapter models with a single driver instead
+         of separate drivers for each model. The revision 2 driver supports
+         the DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI in any
+         combination up to a maximum of four adapters per system.
+       - On board PPP protocol support has been removed in favour of the
+         sync-PPP support used in ISDN4Linux. This means more control of
+         the protocol parameters, faster negotiation time and a more
+         familiar interface.
+
+1.3 How do I setup my system with the correct software to use
+    this driver release?
+
+Before you can compile, install and use the SpellCaster ISA ISDN driver, you
+must ensure that the following software is installed, configured and running:
+
+       - Linux kernel 2.0.20 or later with the required init and ps
+         versions. Please see your distribution vendor for the correct
+         utility packages. The latest kernel is available from
+         ftp://sunsite.unc.edu/pub/Linux/kernel/v2.0/
+
+       - The latest modules package (modules-2.0.0.tar.gz) from
+         ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
+
+       - The ISDN4Linux tools available from 
+         ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz
+         This package may fail to compile for you so you can alternatively
+         get a pre-compiled version from
+         ftp://ftp.spellcast.com/pub/drivers/isdn4linux/isdn4k-bin-2.0.tar.gz
+
+
+2. Basic Operations
+-------------------
+
+2.1 Unpacking and installing the driver
+
+       1. As root, create a directory in a convenient place. We suggest
+          /usr/src/spellcaster.
+       
+       2. Unpack the archive with :
+               tar xzf sc-n.nn.tar.gz -C /usr/src/spellcaster
+       
+       3. Change directory to /usr/src/spellcaster
+
+       4. Read the README and RELNOTES files.
+
+       5. Run 'make' and if all goes well, run 'make install'.
+
+2.2 Read the man pages!!!
+
+Make sure you read the scctrl(8) and sc(4) manual pages before continuing
+any further. Type 'man 8 scctrl' and 'man 4 sc'.
+
+2.3 Installing the driver
+
+To install the driver, type '/sbin/insmod sc' as root. sc(4) details options
+you can specify but you shouldn't need to use any unless this doesn't work.
+
+Make sure the driver loaded and detected all of the adapters by typing
+'dmesg'.
+
+The driver can be configured so that it is loaded upon startup.  To do this, 
+edit the file "/etc/modules/'uname -f'/'uname -v'" and insert the driver name
+"sc" into this file.
+
+2.4 Removing the driver
+
+To remove the driver, delete any interfaces that may exist (see isdnctrl(8)
+for more on this) and then type '/sbin/rmmod sc'.
+
+2.5 What to do if it doesn't load
+
+If, when you try to install the driver, you get a message mentioning
+'register_isdn' then you do not have the ISDN4Linux system installed. Please
+make sure that ISDN support is configured in the kernel.
+
+If you get a message that says 'initialization of sc failed', then the
+driver failed to detect an adapter or failed to find resources needed such
+as a free IRQ line or shared memory segment. If you are sure there are free
+resources available, use the insmod options detailed in sc(4) to override
+the probing function.  
+
+Upon testing, the following problem was noted, the driver would load without
+problems, but the board would not respond beyond that point.  When a check was 
+done with 'cat /proc/interrupts' the interrupt count for sc was 0.  In the event 
+of this problem, change the BIOS settings so that the interrupts in question are
+reserved for ISA use only.   
+
+
+2.6 How to setup ISDN4Linux with the driver
+
+There are three main configurations which you can use with the driver:
+
+A)     Basic HDLC connection
+B)     PPP connection
+C)     MLPPP connection
+
+It should be mentioned here that you may also use a tty connection if you
+desire. The Documentation directory of the isdn4linux subsystem offers good
+documentation on this feature.
+
+A) 10 steps to the establishment of a basic HDLC connection
+-----------------------------------------------------------
+
+- please open the isdn-hdlc file in the examples directory and follow along...
+       
+       This file is a script used to configure a BRI ISDN TA to establish a 
+       basic HDLC connection between its two channels.  Two network 
+       interfaces are created and two routes added between the channels.
+
+       i)   using the isdnctrl utility, add an interface with "addif" and 
+            name it "isdn0"
+       ii)  add the outgoing and inbound telephone numbers
+       iii) set the Layer 2 protocol to hdlc
+       iv)  set the eaz of the interface to be the phone number of that 
+            specific channel
+       v)   to turn the callback features off, set the callback to "off" and
+            the callback delay (cbdelay) to 0.
+       vi)  the hangup timeout can be set to a specified number of seconds
+       vii) the hangup upon incoming call can be set on or off 
+       viii) use the ifconfig command to bring up the network interface with 
+             a specific IP address and point to point address
+       ix)  add a route to the IP address through the isdn0 interface
+       x)   a ping should result in the establishment of the connection
+
+       
+B) Establishment of a PPP connection
+------------------------------------
+
+- please open the isdn-ppp file in the examples directory and follow along...
+       
+       This file is a script used to configure a BRI ISDN TA to establish a 
+       PPP connection  between the two channels.  The file is almost 
+       identical to the HDLC connection example except that the packet 
+       encapsulation type has to be set.
+       
+       use the same procedure as in the HDLC connection from steps i) to 
+       iii) then, after the Layer 2 protocol is set, set the encapsulation 
+       "encap" to syncppp. With this done, the rest of the steps, iv) to x) 
+       can be followed from above.
+
+       Then, the ipppd (ippp daemon) must be setup:
+       
+       xi)   use the ipppd function found in /sbin/ipppd to set the following:
+       xii)  take out (minus) VJ compression and bsd compression
+       xiii) set the mru size to 2000
+       xiv)  link the two /dev interfaces to the daemon
+
+NOTE:  A "*" in the inbound telephone number specifies that a call can be 
+accepted on any number.
+
+C) Establishment of a MLPPP connection
+--------------------------------------
+
+- please open the isdn-mppp file in the examples directory and follow along...
+       
+       This file is a script used to configure a BRI ISDN TA to accept a 
+       Multi Link PPP connection. 
+       
+       i)   using the isdnctrl utility, add an interface with "addif" and 
+            name it "ippp0"
+       ii)  add the inbound telephone number
+       iii) set the Layer 2 protocol to hdlc and the Layer 3 protocol to 
+            trans (transparent)
+       iv)  set the packet encapsulation to syncppp
+       v)   set the eaz of the interface to be the phone number of that 
+            specific channel
+       vi)  to turn the callback features off, set the callback to "off" and
+            the callback delay (cbdelay) to 0.
+       vi)  the hangup timeout can be set to a specified number of seconds
+       vii) the hangup upon incoming call can be set on or off 
+       viii) add a slave interface and name it "ippp32" for example
+       ix)  set the similar parameters for the ippp32 interface
+       x)   use the ifconfig command to bring-up the ippp0 interface with a 
+            specific IP address and point to point address
+       xi)  add a route to the IP address through the ippp0 interface
+       xii) use the ipppd function found in /sbin/ipppd to set the following:
+       xiii) take out (minus) bsd compression
+       xiv) set the mru size to 2000
+       xv)  add (+) the multi-link function "+mp"
+       xvi)  link the two /dev interfaces to the daemon
+
+NOTE:  To use the MLPPP connection to dial OUT to a MLPPP connection, change 
+the inbound telephone numbers to the outgoing telephone numbers of the MLPPP 
+host.
+
+       
+3. Beta Change Summaries and Miscellaneous Notes
+------------------------------------------------
+When using the "scctrl" utility to upload firmware revisions on the board,
+please note that the byte count displayed at the end of the operation may be
+different from the total number of bytes in the "dcbfwn.nn.sr" file. Please
+disregard the displayed byte count.
+
+It was noted that in Beta Release 1, the module would fail to load and result
+in a segmentation fault when 'insmod'ed. This problem was created when one of
+the isdn4linux parameters, (isdn_ctrl, data field) was filled in. In some
+cases, this data field was NULL, and was left unchecked, so when it was
+referenced... segv. The bug has been fixed around line 63-68 of event.c.
+
diff --git a/drivers/staging/i4l/Kconfig b/drivers/staging/i4l/Kconfig
new file mode 100644 (file)
index 0000000..920216e
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Old ISDN4Linux config
+#
+menu "Old ISDN4Linux (deprecated)"
+       depends on ISDN_I4L
+
+source "drivers/staging/i4l/icn/Kconfig"
+
+source "drivers/staging/i4l/pcbit/Kconfig"
+
+source "drivers/staging/i4l/act2000/Kconfig"
+
+endmenu
diff --git a/drivers/staging/i4l/Makefile b/drivers/staging/i4l/Makefile
new file mode 100644 (file)
index 0000000..158b870
--- /dev/null
@@ -0,0 +1,5 @@
+# Makefile for the old ISDN I4L subsystem and device drivers.
+
+obj-$(CONFIG_ISDN_DRV_ICN)             += icn/
+obj-$(CONFIG_ISDN_DRV_PCBIT)           += pcbit/
+obj-$(CONFIG_ISDN_DRV_ACT2000)         += act2000/
diff --git a/drivers/staging/i4l/TODO b/drivers/staging/i4l/TODO
new file mode 100644 (file)
index 0000000..6fe2c08
--- /dev/null
@@ -0,0 +1,3 @@
+* The icn, pcbit and act2000 drivers are dead, remove them in 2017
+  after another longterm kernel has been released, just in the
+  unlikely case someone still has this hardware.
diff --git a/drivers/staging/i4l/act2000/Kconfig b/drivers/staging/i4l/act2000/Kconfig
new file mode 100644 (file)
index 0000000..fa2673f
--- /dev/null
@@ -0,0 +1,9 @@
+config ISDN_DRV_ACT2000
+       tristate "IBM Active 2000 support"
+       depends on ISA
+       help
+         Say Y here if you have an IBM Active 2000 ISDN card. In order to use
+         this card, additional firmware is necessary, which has to be loaded
+         into the card using a utility which is part of the latest
+         isdn4k-utils package. Please read the file
+         <file:Documentation/isdn/README.act2000> for more information.
diff --git a/drivers/staging/i4l/act2000/Makefile b/drivers/staging/i4l/act2000/Makefile
new file mode 100644 (file)
index 0000000..05e582f
--- /dev/null
@@ -0,0 +1,9 @@
+# Makefile for the act2000 ISDN device driver
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o
+
+# Multipart objects.
+
+act2000-y                      := module.o capi.o act2000_isa.o
diff --git a/drivers/staging/i4l/act2000/act2000.h b/drivers/staging/i4l/act2000/act2000.h
new file mode 100644 (file)
index 0000000..321d437
--- /dev/null
@@ -0,0 +1,202 @@
+/* $Id: act2000.h,v 1.8.6.3 2001/09/23 22:24:32 kai Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Author       Fritz Elfert
+ * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ */
+
+#ifndef act2000_h
+#define act2000_h
+
+#include <linux/compiler.h>
+
+#define ACT2000_IOCTL_SETPORT    1
+#define ACT2000_IOCTL_GETPORT    2
+#define ACT2000_IOCTL_SETIRQ     3
+#define ACT2000_IOCTL_GETIRQ     4
+#define ACT2000_IOCTL_SETBUS     5
+#define ACT2000_IOCTL_GETBUS     6
+#define ACT2000_IOCTL_SETPROTO   7
+#define ACT2000_IOCTL_GETPROTO   8
+#define ACT2000_IOCTL_SETMSN     9
+#define ACT2000_IOCTL_GETMSN    10
+#define ACT2000_IOCTL_LOADBOOT  11
+#define ACT2000_IOCTL_ADDCARD   12
+
+#define ACT2000_IOCTL_TEST      98
+#define ACT2000_IOCTL_DEBUGVAR  99
+
+#define ACT2000_BUS_ISA          1
+#define ACT2000_BUS_MCA          2
+#define ACT2000_BUS_PCMCIA       3
+
+/* Struct for adding new cards */
+typedef struct act2000_cdef {
+       int bus;
+       int port;
+       int irq;
+       char id[10];
+} act2000_cdef;
+
+/* Struct for downloading firmware */
+typedef struct act2000_ddef {
+       int length;             /* Length of code */
+       char __user *buffer;    /* Ptr. to code   */
+} act2000_ddef;
+
+typedef struct act2000_fwid {
+       char isdn[4];
+       char revlen[2];
+       char revision[504];
+} act2000_fwid;
+
+#if defined(__KERNEL__) || defined(__DEBUGVAR__)
+
+#ifdef __KERNEL__
+/* Kernel includes */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/isdnif.h>
+
+#endif                           /* __KERNEL__ */
+
+#define ACT2000_PORTLEN        8
+
+#define ACT2000_FLAGS_RUNNING  1 /* Cards driver activated */
+#define ACT2000_FLAGS_PVALID   2 /* Cards port is valid    */
+#define ACT2000_FLAGS_IVALID   4 /* Cards irq is valid     */
+#define ACT2000_FLAGS_LOADED   8 /* Firmware loaded        */
+
+#define ACT2000_BCH            2 /* # of channels per card */
+
+/* D-Channel states */
+#define ACT2000_STATE_NULL     0
+#define ACT2000_STATE_ICALL    1
+#define ACT2000_STATE_OCALL    2
+#define ACT2000_STATE_IWAIT    3
+#define ACT2000_STATE_OWAIT    4
+#define ACT2000_STATE_IBWAIT   5
+#define ACT2000_STATE_OBWAIT   6
+#define ACT2000_STATE_BWAIT    7
+#define ACT2000_STATE_BHWAIT   8
+#define ACT2000_STATE_BHWAIT2  9
+#define ACT2000_STATE_DHWAIT  10
+#define ACT2000_STATE_DHWAIT2 11
+#define ACT2000_STATE_BSETUP  12
+#define ACT2000_STATE_ACTIVE  13
+
+#define ACT2000_MAX_QUEUED  8000 /* 2 * maxbuff */
+
+#define ACT2000_LOCK_TX 0
+#define ACT2000_LOCK_RX 1
+
+typedef struct act2000_chan {
+       unsigned short callref;          /* Call Reference              */
+       unsigned short fsm_state;        /* Current D-Channel state     */
+       unsigned short eazmask;          /* EAZ-Mask for this Channel   */
+       short queued;                    /* User-Data Bytes in TX queue */
+       unsigned short plci;
+       unsigned short ncci;
+       unsigned char  l2prot;           /* Layer 2 protocol            */
+       unsigned char  l3prot;           /* Layer 3 protocol            */
+} act2000_chan;
+
+typedef struct msn_entry {
+       char eaz;
+       char msn[16];
+       struct msn_entry *next;
+} msn_entry;
+
+typedef struct irq_data_isa {
+       __u8           *rcvptr;
+       __u16           rcvidx;
+       __u16           rcvlen;
+       struct sk_buff *rcvskb;
+       __u8            rcvignore;
+       __u8            rcvhdr[8];
+} irq_data_isa;
+
+typedef union act2000_irq_data {
+       irq_data_isa isa;
+} act2000_irq_data;
+
+/*
+ * Per card driver data
+ */
+typedef struct act2000_card {
+       unsigned short port;            /* Base-port-address                */
+       unsigned short irq;             /* Interrupt                        */
+       u_char ptype;                   /* Protocol type (1TR6 or Euro)     */
+       u_char bus;                     /* Cardtype (ISA, MCA, PCMCIA)      */
+       struct act2000_card *next;      /* Pointer to next device struct    */
+       spinlock_t lock;                /* protect critical operations      */
+       int myid;                       /* Driver-Nr. assigned by linklevel */
+       unsigned long flags;            /* Statusflags                      */
+       unsigned long ilock;            /* Semaphores for IRQ-Routines      */
+       struct sk_buff_head rcvq;       /* Receive-Message queue            */
+       struct sk_buff_head sndq;       /* Send-Message queue               */
+       struct sk_buff_head ackq;       /* Data-Ack-Message queue           */
+       u_char *ack_msg;                /* Ptr to User Data in User skb     */
+       __u16 need_b3ack;               /* Flag: Need ACK for current skb   */
+       struct sk_buff *sbuf;           /* skb which is currently sent      */
+       struct timer_list ptimer;       /* Poll timer                       */
+       struct work_struct snd_tq;      /* Task struct for xmit bh          */
+       struct work_struct rcv_tq;      /* Task struct for rcv bh           */
+       struct work_struct poll_tq;     /* Task struct for polled rcv bh    */
+       msn_entry *msn_list;
+       unsigned short msgnum;          /* Message number for sending       */
+       spinlock_t mnlock;              /* lock for msgnum                  */
+       act2000_chan bch[ACT2000_BCH];  /* B-Channel status/control         */
+       char   status_buf[256];         /* Buffer for status messages       */
+       char   *status_buf_read;
+       char   *status_buf_write;
+       char   *status_buf_end;
+       act2000_irq_data idat;          /* Data used for IRQ handler        */
+       isdn_if interface;              /* Interface to upper layer         */
+       char regname[35];               /* Name used for request_region     */
+} act2000_card;
+
+static inline void act2000_schedule_tx(act2000_card *card)
+{
+       schedule_work(&card->snd_tq);
+}
+
+static inline void act2000_schedule_rx(act2000_card *card)
+{
+       schedule_work(&card->rcv_tq);
+}
+
+static inline void act2000_schedule_poll(act2000_card *card)
+{
+       schedule_work(&card->poll_tq);
+}
+
+extern char *act2000_find_eaz(act2000_card *, char);
+
+#endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif                          /* act2000_h */
diff --git a/drivers/staging/i4l/act2000/act2000_isa.c b/drivers/staging/i4l/act2000/act2000_isa.c
new file mode 100644 (file)
index 0000000..b5fad29
--- /dev/null
@@ -0,0 +1,443 @@
+/* $Id: act2000_isa.c,v 1.11.6.3 2001/09/23 22:24:32 kai Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
+ *
+ * Author       Fritz Elfert
+ * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ */
+
+#include "act2000.h"
+#include "act2000_isa.h"
+#include "capi.h"
+
+/*
+ * Reset Controller, then try to read the Card's signature.
+ + Return:
+ *   1 = Signature found.
+ *   0 = Signature not found.
+ */
+static int
+act2000_isa_reset(unsigned short portbase)
+{
+       unsigned char reg;
+       int i;
+       int found;
+       int serial = 0;
+
+       found = 0;
+       if ((reg = inb(portbase + ISA_COR)) != 0xff) {
+               outb(reg | ISA_COR_RESET, portbase + ISA_COR);
+               mdelay(10);
+               outb(reg, portbase + ISA_COR);
+               mdelay(10);
+
+               for (i = 0; i < 16; i++) {
+                       if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
+                               serial |= 0x10000;
+                       serial >>= 1;
+               }
+               if (serial == ISA_SER_ID)
+                       found++;
+       }
+       return found;
+}
+
+int
+act2000_isa_detect(unsigned short portbase)
+{
+       int ret = 0;
+
+       if (request_region(portbase, ACT2000_PORTLEN, "act2000isa")) {
+               ret = act2000_isa_reset(portbase);
+               release_region(portbase, ISA_REGION);
+       }
+       return ret;
+}
+
+static irqreturn_t
+act2000_isa_interrupt(int dummy, void *dev_id)
+{
+       act2000_card *card = dev_id;
+       u_char istatus;
+
+       istatus = (inb(ISA_PORT_ISR) & 0x07);
+       if (istatus & ISA_ISR_OUT) {
+               /* RX fifo has data */
+               istatus &= ISA_ISR_OUT_MASK;
+               outb(0, ISA_PORT_SIS);
+               act2000_isa_receive(card);
+               outb(ISA_SIS_INT, ISA_PORT_SIS);
+       }
+       if (istatus & ISA_ISR_ERR) {
+               /* Error Interrupt */
+               istatus &= ISA_ISR_ERR_MASK;
+               printk(KERN_WARNING "act2000: errIRQ\n");
+       }
+       if (istatus)
+               printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", card->irq, istatus);
+       return IRQ_HANDLED;
+}
+
+static void
+act2000_isa_select_irq(act2000_card *card)
+{
+       unsigned char reg;
+
+       reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
+       switch (card->irq) {
+       case 3:
+               reg = ISA_COR_IRQ03;
+               break;
+       case 5:
+               reg = ISA_COR_IRQ05;
+               break;
+       case 7:
+               reg = ISA_COR_IRQ07;
+               break;
+       case 10:
+               reg = ISA_COR_IRQ10;
+               break;
+       case 11:
+               reg = ISA_COR_IRQ11;
+               break;
+       case 12:
+               reg = ISA_COR_IRQ12;
+               break;
+       case 15:
+               reg = ISA_COR_IRQ15;
+               break;
+       }
+       outb(reg, ISA_PORT_COR);
+}
+
+static void
+act2000_isa_enable_irq(act2000_card *card)
+{
+       act2000_isa_select_irq(card);
+       /* Enable READ irq */
+       outb(ISA_SIS_INT, ISA_PORT_SIS);
+}
+
+/*
+ * Install interrupt handler, enable irq on card.
+ * If irq is -1, choose next free irq, else irq is given explicitly.
+ */
+int
+act2000_isa_config_irq(act2000_card *card, short irq)
+{
+       int old_irq;
+
+       if (card->flags & ACT2000_FLAGS_IVALID) {
+               free_irq(card->irq, card);
+       }
+       card->flags &= ~ACT2000_FLAGS_IVALID;
+       outb(ISA_COR_IRQOFF, ISA_PORT_COR);
+       if (!irq)
+               return 0;
+
+       old_irq = card->irq;
+       card->irq = irq;
+       if (request_irq(irq, &act2000_isa_interrupt, 0, card->regname, card)) {
+               card->irq = old_irq;
+               card->flags |= ACT2000_FLAGS_IVALID;
+               printk(KERN_WARNING
+                      "act2000: Could not request irq %d\n", irq);
+               return -EBUSY;
+       } else {
+               act2000_isa_select_irq(card);
+               /* Disable READ and WRITE irq */
+               outb(0, ISA_PORT_SIS);
+               outb(0, ISA_PORT_SOS);
+       }
+       return 0;
+}
+
+int
+act2000_isa_config_port(act2000_card *card, unsigned short portbase)
+{
+       if (card->flags & ACT2000_FLAGS_PVALID) {
+               release_region(card->port, ISA_REGION);
+               card->flags &= ~ACT2000_FLAGS_PVALID;
+       }
+       if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
+               return -EBUSY;
+       else {
+               card->port = portbase;
+               card->flags |= ACT2000_FLAGS_PVALID;
+               return 0;
+       }
+}
+
+/*
+ * Release ressources, used by an adaptor.
+ */
+void
+act2000_isa_release(act2000_card *card)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       if (card->flags & ACT2000_FLAGS_IVALID)
+               free_irq(card->irq, card);
+
+       card->flags &= ~ACT2000_FLAGS_IVALID;
+       if (card->flags & ACT2000_FLAGS_PVALID)
+               release_region(card->port, ISA_REGION);
+       card->flags &= ~ACT2000_FLAGS_PVALID;
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static int
+act2000_isa_writeb(act2000_card *card, u_char data)
+{
+       u_char timeout = 40;
+
+       while (timeout) {
+               if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
+                       outb(data, ISA_PORT_SDO);
+                       return 0;
+               } else {
+                       timeout--;
+                       udelay(10);
+               }
+       }
+       return 1;
+}
+
+static int
+act2000_isa_readb(act2000_card *card, u_char *data)
+{
+       u_char timeout = 40;
+
+       while (timeout) {
+               if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
+                       *data = inb(ISA_PORT_SDI);
+                       return 0;
+               } else {
+                       timeout--;
+                       udelay(10);
+               }
+       }
+       return 1;
+}
+
+void
+act2000_isa_receive(act2000_card *card)
+{
+       u_char c;
+
+       if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
+               return;
+       while (!act2000_isa_readb(card, &c)) {
+               if (card->idat.isa.rcvidx < 8) {
+                       card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
+                       if (card->idat.isa.rcvidx == 8) {
+                               int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
+
+                               if (valid) {
+                                       card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
+                                       card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
+                                       if (card->idat.isa.rcvskb == NULL) {
+                                               card->idat.isa.rcvignore = 1;
+                                               printk(KERN_WARNING
+                                                      "act2000_isa_receive: no memory\n");
+                                               test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
+                                               return;
+                                       }
+                                       memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
+                                       card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
+                               } else {
+                                       card->idat.isa.rcvidx = 0;
+                                       printk(KERN_WARNING
+                                              "act2000_isa_receive: Invalid CAPI msg\n");
+                                       {
+                                               int i; __u8 *p; __u8 *t; __u8 tmp[30];
+                                               for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, t = tmp; i < 8; i++)
+                                                       t += sprintf(t, "%02x ", *(p++));
+                                               printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
+                                       }
+                               }
+                       }
+               } else {
+                       if (!card->idat.isa.rcvignore)
+                               *card->idat.isa.rcvptr++ = c;
+                       if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
+                               if (!card->idat.isa.rcvignore) {
+                                       skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
+                                       act2000_schedule_rx(card);
+                               }
+                               card->idat.isa.rcvidx = 0;
+                               card->idat.isa.rcvlen = 8;
+                               card->idat.isa.rcvignore = 0;
+                               card->idat.isa.rcvskb = NULL;
+                               card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
+                       }
+               }
+       }
+       if (!(card->flags & ACT2000_FLAGS_IVALID)) {
+               /* In polling mode, schedule myself */
+               if ((card->idat.isa.rcvidx) &&
+                   (card->idat.isa.rcvignore ||
+                    (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
+                       act2000_schedule_poll(card);
+       }
+       test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
+}
+
+void
+act2000_isa_send(act2000_card *card)
+{
+       unsigned long flags;
+       struct sk_buff *skb;
+       actcapi_msg *msg;
+       int l;
+
+       if (test_and_set_bit(ACT2000_LOCK_TX, (void *) &card->ilock) != 0)
+               return;
+       while (1) {
+               spin_lock_irqsave(&card->lock, flags);
+               if (!(card->sbuf)) {
+                       if ((card->sbuf = skb_dequeue(&card->sndq))) {
+                               card->ack_msg = card->sbuf->data;
+                               msg = (actcapi_msg *)card->sbuf->data;
+                               if ((msg->hdr.cmd.cmd == 0x86) &&
+                                   (msg->hdr.cmd.subcmd == 0)) {
+                                       /* Save flags in message */
+                                       card->need_b3ack = msg->msg.data_b3_req.flags;
+                                       msg->msg.data_b3_req.flags = 0;
+                               }
+                       }
+               }
+               spin_unlock_irqrestore(&card->lock, flags);
+               if (!(card->sbuf)) {
+                       /* No more data to send */
+                       test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
+                       return;
+               }
+               skb = card->sbuf;
+               l = 0;
+               while (skb->len) {
+                       if (act2000_isa_writeb(card, *(skb->data))) {
+                               /* Fifo is full, but more data to send */
+                               test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
+                               /* Schedule myself */
+                               act2000_schedule_tx(card);
+                               return;
+                       }
+                       skb_pull(skb, 1);
+                       l++;
+               }
+               msg = (actcapi_msg *)card->ack_msg;
+               if ((msg->hdr.cmd.cmd == 0x86) &&
+                   (msg->hdr.cmd.subcmd == 0)) {
+                       /*
+                        * If it's user data, reset data-ptr
+                        * and put skb into ackq.
+                        */
+                       skb->data = card->ack_msg;
+                       /* Restore flags in message */
+                       msg->msg.data_b3_req.flags = card->need_b3ack;
+                       skb_queue_tail(&card->ackq, skb);
+               } else
+                       dev_kfree_skb(skb);
+               card->sbuf = NULL;
+       }
+}
+
+/*
+ * Get firmware ID, check for 'ISDN' signature.
+ */
+static int
+act2000_isa_getid(act2000_card *card)
+{
+
+       act2000_fwid fid;
+       u_char *p = (u_char *)&fid;
+       int count = 0;
+
+       while (1) {
+               if (count > 510)
+                       return -EPROTO;
+               if (act2000_isa_readb(card, p++))
+                       break;
+               count++;
+       }
+       if (count <= 20) {
+               printk(KERN_WARNING "act2000: No Firmware-ID!\n");
+               return -ETIME;
+       }
+       *p = '\0';
+       fid.revlen[0] = '\0';
+       if (strcmp(fid.isdn, "ISDN")) {
+               printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
+               return -EPROTO;
+       }
+       if ((p = strchr(fid.revision, '\n')))
+               *p = '\0';
+       printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
+       if (card->flags & ACT2000_FLAGS_IVALID) {
+               printk(KERN_DEBUG "Enabling Interrupts ...\n");
+               act2000_isa_enable_irq(card);
+       }
+       return 0;
+}
+
+/*
+ * Download microcode into card, check Firmware signature.
+ */
+int
+act2000_isa_download(act2000_card *card, act2000_ddef __user *cb)
+{
+       unsigned int length;
+       int l;
+       int c;
+       long timeout;
+       u_char *b;
+       u_char __user *p;
+       u_char *buf;
+       act2000_ddef cblock;
+
+       if (!act2000_isa_reset(card->port))
+               return -ENXIO;
+       msleep_interruptible(500);
+       if (copy_from_user(&cblock, cb, sizeof(cblock)))
+               return -EFAULT;
+       length = cblock.length;
+       p = cblock.buffer;
+       if (!access_ok(VERIFY_READ, p, length))
+               return -EFAULT;
+       buf = kmalloc(1024, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       timeout = 0;
+       while (length) {
+               l = (length > 1024) ? 1024 : length;
+               c = 0;
+               b = buf;
+               if (copy_from_user(buf, p, l)) {
+                       kfree(buf);
+                       return -EFAULT;
+               }
+               while (c < l) {
+                       if (act2000_isa_writeb(card, *b++)) {
+                               printk(KERN_WARNING
+                                      "act2000: loader timed out"
+                                      " len=%d c=%d\n", length, c);
+                               kfree(buf);
+                               return -ETIME;
+                       }
+                       c++;
+               }
+               length -= l;
+               p += l;
+       }
+       kfree(buf);
+       msleep_interruptible(500);
+       return (act2000_isa_getid(card));
+}
diff --git a/drivers/staging/i4l/act2000/act2000_isa.h b/drivers/staging/i4l/act2000/act2000_isa.h
new file mode 100644 (file)
index 0000000..1a72898
--- /dev/null
@@ -0,0 +1,136 @@
+/* $Id: act2000_isa.h,v 1.4.6.1 2001/09/23 22:24:32 kai Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
+ *
+ * Author       Fritz Elfert
+ * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ */
+
+#ifndef act2000_isa_h
+#define act2000_isa_h
+
+#define ISA_POLL_LOOP 40        /* Try to read-write before give up */
+
+typedef enum {
+       INT_NO_CHANGE = 0,      /* Do not change the Mask */
+       INT_ON = 1,             /* Set to Enable */
+       INT_OFF = 2,            /* Set to Disable */
+} ISA_INT_T;
+
+/**************************************************************************/
+/*      Configuration Register COR (RW)                                   */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/* Soft Res|  IRQM  |        IRQ Select        |   N/A  |  WAIT  |Proc err */
+/**************************************************************************/
+#define        ISA_COR             0   /* Offset for ISA config register */
+#define        ISA_COR_PERR     0x01   /* Processor Error Enabled        */
+#define        ISA_COR_WS       0x02   /* Insert Wait State if 1         */
+#define        ISA_COR_IRQOFF   0x38   /* No Interrupt                   */
+#define        ISA_COR_IRQ07    0x30   /* IRQ 7 Enable                   */
+#define        ISA_COR_IRQ05    0x28   /* IRQ 5 Enable                   */
+#define        ISA_COR_IRQ03    0x20   /* IRQ 3 Enable                   */
+#define        ISA_COR_IRQ10    0x18   /* IRQ 10 Enable                  */
+#define        ISA_COR_IRQ11    0x10   /* IRQ 11 Enable                  */
+#define        ISA_COR_IRQ12    0x08   /* IRQ 12 Enable                  */
+#define        ISA_COR_IRQ15    0x00   /* IRQ 15 Enable                  */
+#define        ISA_COR_IRQPULSE 0x40   /* 0 = Level 1 = Pulse Interrupt  */
+#define        ISA_COR_RESET    0x80   /* Soft Reset for Transputer      */
+
+/**************************************************************************/
+/*      Interrupt Source Register ISR (RO)                                */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/*   N/A   |  N/A   |   N/A  |Err sig |Ser ID  |IN Intr |Out Intr| Error  */
+/**************************************************************************/
+#define        ISA_ISR             1   /* Offset for Interrupt Register  */
+#define        ISA_ISR_ERR      0x01   /* Error Interrupt                */
+#define        ISA_ISR_OUT      0x02   /* Output Interrupt               */
+#define        ISA_ISR_INP      0x04   /* Input Interrupt                */
+#define        ISA_ISR_SERIAL   0x08   /* Read out Serial ID after Reset */
+#define        ISA_ISR_ERRSIG   0x10   /* Error Signal Input             */
+#define        ISA_ISR_ERR_MASK 0xfe    /* Mask Error Interrupt           */
+#define        ISA_ISR_OUT_MASK 0xfd    /* Mask Output Interrupt          */
+#define        ISA_ISR_INP_MASK 0xfb    /* Mask Input Interrupt           */
+
+/* Signature delivered after Reset at ISA_ISR_SERIAL (LSB first)          */
+#define        ISA_SER_ID     0x0201   /* ID for ISA Card                */
+
+/**************************************************************************/
+/*      EEPROM Register EPR (RW)                                          */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/*   N/A   |  N/A   |   N/A  |ROM Hold| ROM CS |ROM CLK | ROM IN |ROM Out */
+/**************************************************************************/
+#define        ISA_EPR             2   /* Offset for this Register       */
+#define        ISA_EPR_OUT      0x01   /* Rome Register Out (RO)         */
+#define        ISA_EPR_IN       0x02   /* Rom Register In (WR)           */
+#define        ISA_EPR_CLK      0x04   /* Rom Clock (WR)                 */
+#define        ISA_EPR_CS       0x08   /* Rom Cip Select (WR)            */
+#define        ISA_EPR_HOLD     0x10   /* Rom Hold Signal (WR)           */
+
+/**************************************************************************/
+/*      EEPROM enable Register EER (unused)                               */
+/**************************************************************************/
+#define        ISA_EER             3   /* Offset for this Register       */
+
+/**************************************************************************/
+/*      SLC Data Input SDI (RO)                                           */
+/**************************************************************************/
+#define        ISA_SDI             4   /* Offset for this Register       */
+
+/**************************************************************************/
+/*      SLC Data Output SDO (WO)                                          */
+/**************************************************************************/
+#define        ISA_SDO             5   /* Offset for this Register       */
+
+/**************************************************************************/
+/*      IMS C011 Mode 2 Input Status Register for INMOS CPU SIS (RW)      */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/*   N/A   |  N/A   |   N/A  |  N/A   |   N/A  |   N/A  |Int Ena |Data Pre */
+/**************************************************************************/
+#define        ISA_SIS             6   /* Offset for this Register       */
+#define        ISA_SIS_READY    0x01   /* If 1 : data is available       */
+#define        ISA_SIS_INT      0x02   /* Enable Interrupt for READ      */
+
+/**************************************************************************/
+/*      IMS C011 Mode 2 Output Status Register from INMOS CPU SOS (RW)    */
+/**************************************************************************/
+/*    7    |   6    |    5   |   4    |    3   |    2   |    1   |    0   */
+/*   N/A   |  N/A   |   N/A  |  N/A   |   N/A  |   N/A  |Int Ena |Out Rdy */
+/**************************************************************************/
+#define        ISA_SOS             7   /* Offset for this Register       */
+#define        ISA_SOS_READY    0x01   /* If 1 : we can write Data       */
+#define        ISA_SOS_INT      0x02   /* Enable Interrupt for WRITE     */
+
+#define        ISA_REGION          8   /* Number of Registers            */
+
+
+/* Macros for accessing ports */
+#define ISA_PORT_COR (card->port + ISA_COR)
+#define ISA_PORT_ISR (card->port + ISA_ISR)
+#define ISA_PORT_EPR (card->port + ISA_EPR)
+#define ISA_PORT_EER (card->port + ISA_EER)
+#define ISA_PORT_SDI (card->port + ISA_SDI)
+#define ISA_PORT_SDO (card->port + ISA_SDO)
+#define ISA_PORT_SIS (card->port + ISA_SIS)
+#define ISA_PORT_SOS (card->port + ISA_SOS)
+
+/* Prototypes */
+
+extern int act2000_isa_detect(unsigned short portbase);
+extern int act2000_isa_config_irq(act2000_card *card, short irq);
+extern int act2000_isa_config_port(act2000_card *card, unsigned short portbase);
+extern int act2000_isa_download(act2000_card *card, act2000_ddef __user *cb);
+extern void act2000_isa_release(act2000_card *card);
+extern void act2000_isa_receive(act2000_card *card);
+extern void act2000_isa_send(act2000_card *card);
+
+#endif                          /* act2000_isa_h */
diff --git a/drivers/staging/i4l/act2000/capi.c b/drivers/staging/i4l/act2000/capi.c
new file mode 100644 (file)
index 0000000..3f66ca2
--- /dev/null
@@ -0,0 +1,1180 @@
+/* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ * CAPI encoder/decoder
+ *
+ * Author       Fritz Elfert
+ * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ */
+
+#include "act2000.h"
+#include "capi.h"
+
+static actcapi_msgdsc valid_msg[] = {
+       {{ 0x86, 0x02}, "DATA_B3_IND"},       /* DATA_B3_IND/CONF must be first because of speed!!! */
+       {{ 0x86, 0x01}, "DATA_B3_CONF"},
+       {{ 0x02, 0x01}, "CONNECT_CONF"},
+       {{ 0x02, 0x02}, "CONNECT_IND"},
+       {{ 0x09, 0x01}, "CONNECT_INFO_CONF"},
+       {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"},
+       {{ 0x04, 0x01}, "DISCONNECT_CONF"},
+       {{ 0x04, 0x02}, "DISCONNECT_IND"},
+       {{ 0x05, 0x01}, "LISTEN_CONF"},
+       {{ 0x06, 0x01}, "GET_PARAMS_CONF"},
+       {{ 0x07, 0x01}, "INFO_CONF"},
+       {{ 0x07, 0x02}, "INFO_IND"},
+       {{ 0x08, 0x01}, "DATA_CONF"},
+       {{ 0x08, 0x02}, "DATA_IND"},
+       {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"},
+       {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"},
+       {{ 0x81, 0x01}, "LISTEN_B3_CONF"},
+       {{ 0x82, 0x01}, "CONNECT_B3_CONF"},
+       {{ 0x82, 0x02}, "CONNECT_B3_IND"},
+       {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"},
+       {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"},
+       {{ 0x84, 0x02}, "DISCONNECT_B3_IND"},
+       {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"},
+       {{ 0x01, 0x01}, "RESET_B3_CONF"},
+       {{ 0x01, 0x02}, "RESET_B3_IND"},
+       /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */
+       {{ 0xff, 0x01}, "MANUFACTURER_CONF"},
+       {{ 0xff, 0x02}, "MANUFACTURER_IND"},
+#ifdef DEBUG_MSG
+       /* Requests */
+       {{ 0x01, 0x00}, "RESET_B3_REQ"},
+       {{ 0x02, 0x00}, "CONNECT_REQ"},
+       {{ 0x04, 0x00}, "DISCONNECT_REQ"},
+       {{ 0x05, 0x00}, "LISTEN_REQ"},
+       {{ 0x06, 0x00}, "GET_PARAMS_REQ"},
+       {{ 0x07, 0x00}, "INFO_REQ"},
+       {{ 0x08, 0x00}, "DATA_REQ"},
+       {{ 0x09, 0x00}, "CONNECT_INFO_REQ"},
+       {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"},
+       {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"},
+       {{ 0x81, 0x00}, "LISTEN_B3_REQ"},
+       {{ 0x82, 0x00}, "CONNECT_B3_REQ"},
+       {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"},
+       {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"},
+       {{ 0x86, 0x00}, "DATA_B3_REQ"},
+       {{ 0xff, 0x00}, "MANUFACTURER_REQ"},
+       /* Responses */
+       {{ 0x01, 0x03}, "RESET_B3_RESP"},
+       {{ 0x02, 0x03}, "CONNECT_RESP"},
+       {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"},
+       {{ 0x04, 0x03}, "DISCONNECT_RESP"},
+       {{ 0x07, 0x03}, "INFO_RESP"},
+       {{ 0x08, 0x03}, "DATA_RESP"},
+       {{ 0x82, 0x03}, "CONNECT_B3_RESP"},
+       {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"},
+       {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
+       {{ 0x86, 0x03}, "DATA_B3_RESP"},
+       {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
+#endif
+       {{ 0x00, 0x00}, NULL},
+};
+#define num_valid_imsg 27 /* MANUFACTURER_IND */
+
+/*
+ * Check for a valid incoming CAPI message.
+ * Return:
+ *   0 = Invalid message
+ *   1 = Valid message, no B-Channel-data
+ *   2 = Valid message, B-Channel-data
+ */
+int
+actcapi_chkhdr(act2000_card *card, actcapi_msghdr *hdr)
+{
+       int i;
+
+       if (hdr->applicationID != 1)
+               return 0;
+       if (hdr->len < 9)
+               return 0;
+       for (i = 0; i < num_valid_imsg; i++)
+               if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) &&
+                   (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) {
+                       return (i ? 1 : 2);
+               }
+       return 0;
+}
+
+#define ACTCAPI_MKHDR(l, c, s) {                               \
+               skb = alloc_skb(l + 8, GFP_ATOMIC);             \
+               if (skb) {                                      \
+                       m = (actcapi_msg *)skb_put(skb, l + 8); \
+                       m->hdr.len = l + 8;                     \
+                       m->hdr.applicationID = 1;               \
+                       m->hdr.cmd.cmd = c;                     \
+                       m->hdr.cmd.subcmd = s;                  \
+                       m->hdr.msgnum = actcapi_nextsmsg(card); \
+               } else m = NULL;                                \
+       }
+
+#define ACTCAPI_CHKSKB if (!skb) {                                     \
+               printk(KERN_WARNING "actcapi: alloc_skb failed\n");     \
+               return;                                                 \
+       }
+
+#define ACTCAPI_QUEUE_TX {                             \
+               actcapi_debug_msg(skb, 1);              \
+               skb_queue_tail(&card->sndq, skb);       \
+               act2000_schedule_tx(card);              \
+       }
+
+int
+actcapi_listen_req(act2000_card *card)
+{
+       __u16 eazmask = 0;
+       int i;
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       for (i = 0; i < ACT2000_BCH; i++)
+               eazmask |= card->bch[i].eazmask;
+       ACTCAPI_MKHDR(9, 0x05, 0x00);
+       if (!skb) {
+               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+               return -ENOMEM;
+       }
+       m->msg.listen_req.controller = 0;
+       m->msg.listen_req.infomask = 0x3f; /* All information */
+       m->msg.listen_req.eazmask = eazmask;
+       m->msg.listen_req.simask = (eazmask) ? 0x86 : 0; /* All SI's  */
+       ACTCAPI_QUEUE_TX;
+       return 0;
+}
+
+int
+actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
+                   char eaz, int si1, int si2)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00);
+       if (!skb) {
+               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+               chan->fsm_state = ACT2000_STATE_NULL;
+               return -ENOMEM;
+       }
+       m->msg.connect_req.controller = 0;
+       m->msg.connect_req.bchan = 0x83;
+       m->msg.connect_req.infomask = 0x3f;
+       m->msg.connect_req.si1 = si1;
+       m->msg.connect_req.si2 = si2;
+       m->msg.connect_req.eaz = eaz ? eaz : '0';
+       m->msg.connect_req.addr.len = strlen(phone) + 1;
+       m->msg.connect_req.addr.tnp = 0x81;
+       memcpy(m->msg.connect_req.addr.num, phone, strlen(phone));
+       chan->callref = m->hdr.msgnum;
+       ACTCAPI_QUEUE_TX;
+       return 0;
+}
+
+static void
+actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(17, 0x82, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_b3_req.plci = chan->plci;
+       memset(&m->msg.connect_b3_req.ncpi, 0,
+              sizeof(m->msg.connect_b3_req.ncpi));
+       m->msg.connect_b3_req.ncpi.len = 13;
+       m->msg.connect_b3_req.ncpi.modulo = 8;
+       ACTCAPI_QUEUE_TX;
+}
+
+/*
+ * Set net type (1TR6) or (EDSS1)
+ */
+int
+actcapi_manufacturer_req_net(act2000_card *card)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(5, 0xff, 0x00);
+       if (!skb) {
+               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+               return -ENOMEM;
+       }
+       m->msg.manufacturer_req_net.manuf_msg = 0x11;
+       m->msg.manufacturer_req_net.controller = 1;
+       m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO) ? 1 : 0;
+       ACTCAPI_QUEUE_TX;
+       printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n",
+              card->interface.id, (card->ptype == ISDN_PTYPE_EURO) ? "euro" : "1tr6");
+       card->interface.features &=
+               ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6);
+       card->interface.features |=
+               ((card->ptype == ISDN_PTYPE_EURO) ? ISDN_FEATURE_P_EURO : ISDN_FEATURE_P_1TR6);
+       return 0;
+}
+
+/*
+ * Switch V.42 on or off
+ */
+#if 0
+int
+actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(8, 0xff, 0x00);
+       if (!skb) {
+
+               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+               return -ENOMEM;
+       }
+       m->msg.manufacturer_req_v42.manuf_msg = 0x10;
+       m->msg.manufacturer_req_v42.controller = 0;
+       m->msg.manufacturer_req_v42.v42control = (arg ? 1 : 0);
+       ACTCAPI_QUEUE_TX;
+       return 0;
+}
+#endif  /*  0  */
+
+/*
+ * Set error-handler
+ */
+int
+actcapi_manufacturer_req_errh(act2000_card *card)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(4, 0xff, 0x00);
+       if (!skb) {
+
+               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+               return -ENOMEM;
+       }
+       m->msg.manufacturer_req_err.manuf_msg = 0x03;
+       m->msg.manufacturer_req_err.controller = 0;
+       ACTCAPI_QUEUE_TX;
+       return 0;
+}
+
+/*
+ * Set MSN-Mapping.
+ */
+int
+actcapi_manufacturer_req_msn(act2000_card *card)
+{
+       msn_entry *p = card->msn_list;
+       actcapi_msg *m;
+       struct sk_buff *skb;
+       int len;
+
+       while (p) {
+               int i;
+
+               len = strlen(p->msn);
+               for (i = 0; i < 2; i++) {
+                       ACTCAPI_MKHDR(6 + len, 0xff, 0x00);
+                       if (!skb) {
+                               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+                               return -ENOMEM;
+                       }
+                       m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i;
+                       m->msg.manufacturer_req_msn.controller = 0;
+                       m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz;
+                       m->msg.manufacturer_req_msn.msnmap.len = len;
+                       memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len);
+                       ACTCAPI_QUEUE_TX;
+               }
+               p = p->next;
+       }
+       return 0;
+}
+
+void
+actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(10, 0x40, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.select_b2_protocol_req.plci = chan->plci;
+       memset(&m->msg.select_b2_protocol_req.dlpd, 0,
+              sizeof(m->msg.select_b2_protocol_req.dlpd));
+       m->msg.select_b2_protocol_req.dlpd.len = 6;
+       switch (chan->l2prot) {
+       case ISDN_PROTO_L2_TRANS:
+               m->msg.select_b2_protocol_req.protocol = 0x03;
+               m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+               break;
+       case ISDN_PROTO_L2_HDLC:
+               m->msg.select_b2_protocol_req.protocol = 0x02;
+               m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+               break;
+       case ISDN_PROTO_L2_X75I:
+       case ISDN_PROTO_L2_X75UI:
+       case ISDN_PROTO_L2_X75BUI:
+               m->msg.select_b2_protocol_req.protocol = 0x01;
+               m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
+               m->msg.select_b2_protocol_req.dlpd.laa = 3;
+               m->msg.select_b2_protocol_req.dlpd.lab = 1;
+               m->msg.select_b2_protocol_req.dlpd.win = 7;
+               m->msg.select_b2_protocol_req.dlpd.modulo = 8;
+               break;
+       }
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(17, 0x80, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.select_b3_protocol_req.plci = chan->plci;
+       memset(&m->msg.select_b3_protocol_req.ncpd, 0,
+              sizeof(m->msg.select_b3_protocol_req.ncpd));
+       switch (chan->l3prot) {
+       case ISDN_PROTO_L3_TRANS:
+               m->msg.select_b3_protocol_req.protocol = 0x04;
+               m->msg.select_b3_protocol_req.ncpd.len = 13;
+               m->msg.select_b3_protocol_req.ncpd.modulo = 8;
+               break;
+       }
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x81, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.listen_b3_req.plci = chan->plci;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(3, 0x04, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.disconnect_req.plci = chan->plci;
+       m->msg.disconnect_req.cause = 0;
+       ACTCAPI_QUEUE_TX;
+}
+
+void
+actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(17, 0x84, 0x00);
+       ACTCAPI_CHKSKB;
+       m->msg.disconnect_b3_req.ncci = chan->ncci;
+       memset(&m->msg.disconnect_b3_req.ncpi, 0,
+              sizeof(m->msg.disconnect_b3_req.ncpi));
+       m->msg.disconnect_b3_req.ncpi.len = 13;
+       m->msg.disconnect_b3_req.ncpi.modulo = 8;
+       chan->fsm_state = ACT2000_STATE_BHWAIT;
+       ACTCAPI_QUEUE_TX;
+}
+
+void
+actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(3, 0x02, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_resp.plci = chan->plci;
+       m->msg.connect_resp.rejectcause = cause;
+       if (cause) {
+               chan->fsm_state = ACT2000_STATE_NULL;
+               chan->plci = 0x8000;
+       } else
+               chan->fsm_state = ACT2000_STATE_IWAIT;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x03, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_resp.plci = chan->plci;
+       if (chan->fsm_state == ACT2000_STATE_IWAIT)
+               chan->fsm_state = ACT2000_STATE_IBWAIT;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR((rejectcause ? 3 : 17), 0x82, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_b3_resp.ncci = chan->ncci;
+       m->msg.connect_b3_resp.rejectcause = rejectcause;
+       if (!rejectcause) {
+               memset(&m->msg.connect_b3_resp.ncpi, 0,
+                      sizeof(m->msg.connect_b3_resp.ncpi));
+               m->msg.connect_b3_resp.ncpi.len = 13;
+               m->msg.connect_b3_resp.ncpi.modulo = 8;
+               chan->fsm_state = ACT2000_STATE_BWAIT;
+       }
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x83, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.connect_b3_active_resp.ncci = chan->ncci;
+       chan->fsm_state = ACT2000_STATE_ACTIVE;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_info_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x07, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.info_resp.plci = chan->plci;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x84, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.disconnect_b3_resp.ncci = chan->ncci;
+       chan->ncci = 0x8000;
+       chan->queued = 0;
+       ACTCAPI_QUEUE_TX;
+}
+
+static void
+actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
+{
+       actcapi_msg *m;
+       struct sk_buff *skb;
+
+       ACTCAPI_MKHDR(2, 0x04, 0x03);
+       ACTCAPI_CHKSKB;
+       m->msg.disconnect_resp.plci = chan->plci;
+       chan->plci = 0x8000;
+       ACTCAPI_QUEUE_TX;
+}
+
+static int
+new_plci(act2000_card *card, __u16 plci)
+{
+       int i;
+       for (i = 0; i < ACT2000_BCH; i++)
+               if (card->bch[i].plci == 0x8000) {
+                       card->bch[i].plci = plci;
+                       return i;
+               }
+       return -1;
+}
+
+static int
+find_plci(act2000_card *card, __u16 plci)
+{
+       int i;
+       for (i = 0; i < ACT2000_BCH; i++)
+               if (card->bch[i].plci == plci)
+                       return i;
+       return -1;
+}
+
+static int
+find_ncci(act2000_card *card, __u16 ncci)
+{
+       int i;
+       for (i = 0; i < ACT2000_BCH; i++)
+               if (card->bch[i].ncci == ncci)
+                       return i;
+       return -1;
+}
+
+static int
+find_dialing(act2000_card *card, __u16 callref)
+{
+       int i;
+       for (i = 0; i < ACT2000_BCH; i++)
+               if ((card->bch[i].callref == callref) &&
+                   (card->bch[i].fsm_state == ACT2000_STATE_OCALL))
+                       return i;
+       return -1;
+}
+
+static int
+actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) {
+       __u16 plci;
+       __u16 ncci;
+       __u16 controller;
+       __u8  blocknr;
+       int chan;
+       actcapi_msg *msg = (actcapi_msg *)skb->data;
+
+       EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, controller, ncci);
+       chan = find_ncci(card, ncci);
+       if (chan < 0)
+               return 0;
+       if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE)
+               return 0;
+       if (card->bch[chan].plci != plci)
+               return 0;
+       blocknr = msg->msg.data_b3_ind.blocknr;
+       skb_pull(skb, 19);
+       card->interface.rcvcallb_skb(card->myid, chan, skb);
+       if (!(skb = alloc_skb(11, GFP_ATOMIC))) {
+               printk(KERN_WARNING "actcapi: alloc_skb failed\n");
+               return 1;
+       }
+       msg = (actcapi_msg *)skb_put(skb, 11);
+       msg->hdr.len = 11;
+       msg->hdr.applicationID = 1;
+       msg->hdr.cmd.cmd = 0x86;
+       msg->hdr.cmd.subcmd = 0x03;
+       msg->hdr.msgnum = actcapi_nextsmsg(card);
+       msg->msg.data_b3_resp.ncci = ncci;
+       msg->msg.data_b3_resp.blocknr = blocknr;
+       ACTCAPI_QUEUE_TX;
+       return 1;
+}
+
+/*
+ * Walk over ackq, unlink DATA_B3_REQ from it, if
+ * ncci and blocknr are matching.
+ * Decrement queued-bytes counter.
+ */
+static int
+handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
+       unsigned long flags;
+       struct sk_buff *skb;
+       struct sk_buff *tmp;
+       struct actcapi_msg *m;
+       int ret = 0;
+
+       spin_lock_irqsave(&card->lock, flags);
+       skb = skb_peek(&card->ackq);
+       spin_unlock_irqrestore(&card->lock, flags);
+       if (!skb) {
+               printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
+               return 0;
+       }
+       tmp = skb;
+       while (1) {
+               m = (actcapi_msg *)tmp->data;
+               if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
+                   (m->msg.data_b3_req.blocknr == blocknr)) {
+                       /* found corresponding DATA_B3_REQ */
+                       skb_unlink(tmp, &card->ackq);
+                       chan->queued -= m->msg.data_b3_req.datalen;
+                       if (m->msg.data_b3_req.flags)
+                               ret = m->msg.data_b3_req.datalen;
+                       dev_kfree_skb(tmp);
+                       if (chan->queued < 0)
+                               chan->queued = 0;
+                       return ret;
+               }
+               spin_lock_irqsave(&card->lock, flags);
+               tmp = skb_peek((struct sk_buff_head *)tmp);
+               spin_unlock_irqrestore(&card->lock, flags);
+               if ((tmp == skb) || (tmp == NULL)) {
+                       /* reached end of queue */
+                       printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
+                       return 0;
+               }
+       }
+}
+
+void
+actcapi_dispatch(struct work_struct *work)
+{
+       struct act2000_card *card =
+               container_of(work, struct act2000_card, rcv_tq);
+       struct sk_buff *skb;
+       actcapi_msg *msg;
+       __u16 ccmd;
+       int chan;
+       int len;
+       act2000_chan *ctmp;
+       isdn_ctrl cmd;
+       char tmp[170];
+
+       while ((skb = skb_dequeue(&card->rcvq))) {
+               actcapi_debug_msg(skb, 0);
+               msg = (actcapi_msg *)skb->data;
+               ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd);
+               switch (ccmd) {
+               case 0x8602:
+                       /* DATA_B3_IND */
+                       if (actcapi_data_b3_ind(card, skb))
+                               return;
+                       break;
+               case 0x8601:
+                       /* DATA_B3_CONF */
+                       chan = find_ncci(card, msg->msg.data_b3_conf.ncci);
+                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) {
+                               if (msg->msg.data_b3_conf.info != 0)
+                                       printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n",
+                                              msg->msg.data_b3_conf.info);
+                               len = handle_ack(card, &card->bch[chan],
+                                                msg->msg.data_b3_conf.blocknr);
+                               if (len) {
+                                       cmd.driver = card->myid;
+                                       cmd.command = ISDN_STAT_BSENT;
+                                       cmd.arg = chan;
+                                       cmd.parm.length = len;
+                                       card->interface.statcallb(&cmd);
+                               }
+                       }
+                       break;
+               case 0x0201:
+                       /* CONNECT_CONF */
+                       chan = find_dialing(card, msg->hdr.msgnum);
+                       if (chan >= 0) {
+                               if (msg->msg.connect_conf.info) {
+                                       card->bch[chan].fsm_state = ACT2000_STATE_NULL;
+                                       cmd.driver = card->myid;
+                                       cmd.command = ISDN_STAT_DHUP;
+                                       cmd.arg = chan;
+                                       card->interface.statcallb(&cmd);
+                               } else {
+                                       card->bch[chan].fsm_state = ACT2000_STATE_OWAIT;
+                                       card->bch[chan].plci = msg->msg.connect_conf.plci;
+                               }
+                       }
+                       break;
+               case 0x0202:
+                       /* CONNECT_IND */
+                       chan = new_plci(card, msg->msg.connect_ind.plci);
+                       if (chan < 0) {
+                               ctmp = (act2000_chan *)tmp;
+                               ctmp->plci = msg->msg.connect_ind.plci;
+                               actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
+                       } else {
+                               card->bch[chan].fsm_state = ACT2000_STATE_ICALL;
+                               cmd.driver = card->myid;
+                               cmd.command = ISDN_STAT_ICALL;
+                               cmd.arg = chan;
+                               cmd.parm.setup.si1 = msg->msg.connect_ind.si1;
+                               cmd.parm.setup.si2 = msg->msg.connect_ind.si2;
+                               if (card->ptype == ISDN_PTYPE_EURO)
+                                       strcpy(cmd.parm.setup.eazmsn,
+                                              act2000_find_eaz(card, msg->msg.connect_ind.eaz));
+                               else {
+                                       cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz;
+                                       cmd.parm.setup.eazmsn[1] = 0;
+                               }
+                               memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone));
+                               memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num,
+                                      msg->msg.connect_ind.addr.len - 1);
+                               cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp;
+                               cmd.parm.setup.screen = 0;
+                               if (card->interface.statcallb(&cmd) == 2)
+                                       actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */
+                       }
+                       break;
+               case 0x0302:
+                       /* CONNECT_ACTIVE_IND */
+                       chan = find_plci(card, msg->msg.connect_active_ind.plci);
+                       if (chan >= 0)
+                               switch (card->bch[chan].fsm_state) {
+                               case ACT2000_STATE_IWAIT:
+                                       actcapi_connect_active_resp(card, &card->bch[chan]);
+                                       break;
+                               case ACT2000_STATE_OWAIT:
+                                       actcapi_connect_active_resp(card, &card->bch[chan]);
+                                       actcapi_select_b2_protocol_req(card, &card->bch[chan]);
+                                       break;
+                               }
+                       break;
+               case 0x8202:
+                       /* CONNECT_B3_IND */
+                       chan = find_plci(card, msg->msg.connect_b3_ind.plci);
+                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) {
+                               card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci;
+                               actcapi_connect_b3_resp(card, &card->bch[chan], 0);
+                       } else {
+                               ctmp = (act2000_chan *)tmp;
+                               ctmp->ncci = msg->msg.connect_b3_ind.ncci;
+                               actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
+                       }
+                       break;
+               case 0x8302:
+                       /* CONNECT_B3_ACTIVE_IND */
+                       chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci);
+                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) {
+                               actcapi_connect_b3_active_resp(card, &card->bch[chan]);
+                               cmd.driver = card->myid;
+                               cmd.command = ISDN_STAT_BCONN;
+                               cmd.arg = chan;
+                               card->interface.statcallb(&cmd);
+                       }
+                       break;
+               case 0x8402:
+                       /* DISCONNECT_B3_IND */
+                       chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci);
+                       if (chan >= 0) {
+                               ctmp = &card->bch[chan];
+                               actcapi_disconnect_b3_resp(card, ctmp);
+                               switch (ctmp->fsm_state) {
+                               case ACT2000_STATE_ACTIVE:
+                                       ctmp->fsm_state = ACT2000_STATE_DHWAIT2;
+                                       cmd.driver = card->myid;
+                                       cmd.command = ISDN_STAT_BHUP;
+                                       cmd.arg = chan;
+                                       card->interface.statcallb(&cmd);
+                                       break;
+                               case ACT2000_STATE_BHWAIT2:
+                                       actcapi_disconnect_req(card, ctmp);
+                                       ctmp->fsm_state = ACT2000_STATE_DHWAIT;
+                                       cmd.driver = card->myid;
+                                       cmd.command = ISDN_STAT_BHUP;
+                                       cmd.arg = chan;
+                                       card->interface.statcallb(&cmd);
+                                       break;
+                               }
+                       }
+                       break;
+               case 0x0402:
+                       /* DISCONNECT_IND */
+                       chan = find_plci(card, msg->msg.disconnect_ind.plci);
+                       if (chan >= 0) {
+                               ctmp = &card->bch[chan];
+                               actcapi_disconnect_resp(card, ctmp);
+                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                               cmd.driver = card->myid;
+                               cmd.command = ISDN_STAT_DHUP;
+                               cmd.arg = chan;
+                               card->interface.statcallb(&cmd);
+                       } else {
+                               ctmp = (act2000_chan *)tmp;
+                               ctmp->plci = msg->msg.disconnect_ind.plci;
+                               actcapi_disconnect_resp(card, ctmp);
+                       }
+                       break;
+               case 0x4001:
+                       /* SELECT_B2_PROTOCOL_CONF */
+                       chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci);
+                       if (chan >= 0)
+                               switch (card->bch[chan].fsm_state) {
+                               case ACT2000_STATE_ICALL:
+                               case ACT2000_STATE_OWAIT:
+                                       ctmp = &card->bch[chan];
+                                       if (msg->msg.select_b2_protocol_conf.info == 0)
+                                               actcapi_select_b3_protocol_req(card, ctmp);
+                                       else {
+                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                               cmd.driver = card->myid;
+                                               cmd.command = ISDN_STAT_DHUP;
+                                               cmd.arg = chan;
+                                               card->interface.statcallb(&cmd);
+                                       }
+                                       break;
+                               }
+                       break;
+               case 0x8001:
+                       /* SELECT_B3_PROTOCOL_CONF */
+                       chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci);
+                       if (chan >= 0)
+                               switch (card->bch[chan].fsm_state) {
+                               case ACT2000_STATE_ICALL:
+                               case ACT2000_STATE_OWAIT:
+                                       ctmp = &card->bch[chan];
+                                       if (msg->msg.select_b3_protocol_conf.info == 0)
+                                               actcapi_listen_b3_req(card, ctmp);
+                                       else {
+                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                               cmd.driver = card->myid;
+                                               cmd.command = ISDN_STAT_DHUP;
+                                               cmd.arg = chan;
+                                               card->interface.statcallb(&cmd);
+                                       }
+                               }
+                       break;
+               case 0x8101:
+                       /* LISTEN_B3_CONF */
+                       chan = find_plci(card, msg->msg.listen_b3_conf.plci);
+                       if (chan >= 0)
+                               switch (card->bch[chan].fsm_state) {
+                               case ACT2000_STATE_ICALL:
+                                       ctmp = &card->bch[chan];
+                                       if (msg->msg.listen_b3_conf.info == 0)
+                                               actcapi_connect_resp(card, ctmp, 0);
+                                       else {
+                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                               cmd.driver = card->myid;
+                                               cmd.command = ISDN_STAT_DHUP;
+                                               cmd.arg = chan;
+                                               card->interface.statcallb(&cmd);
+                                       }
+                                       break;
+                               case ACT2000_STATE_OWAIT:
+                                       ctmp = &card->bch[chan];
+                                       if (msg->msg.listen_b3_conf.info == 0) {
+                                               actcapi_connect_b3_req(card, ctmp);
+                                               ctmp->fsm_state = ACT2000_STATE_OBWAIT;
+                                               cmd.driver = card->myid;
+                                               cmd.command = ISDN_STAT_DCONN;
+                                               cmd.arg = chan;
+                                               card->interface.statcallb(&cmd);
+                                       } else {
+                                               ctmp->fsm_state = ACT2000_STATE_NULL;
+                                               cmd.driver = card->myid;
+                                               cmd.command = ISDN_STAT_DHUP;
+                                               cmd.arg = chan;
+                                               card->interface.statcallb(&cmd);
+                                       }
+                                       break;
+                               }
+                       break;
+               case 0x8201:
+                       /* CONNECT_B3_CONF */
+                       chan = find_plci(card, msg->msg.connect_b3_conf.plci);
+                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) {
+                               ctmp = &card->bch[chan];
+                               if (msg->msg.connect_b3_conf.info) {
+                                       ctmp->fsm_state = ACT2000_STATE_NULL;
+                                       cmd.driver = card->myid;
+                                       cmd.command = ISDN_STAT_DHUP;
+                                       cmd.arg = chan;
+                                       card->interface.statcallb(&cmd);
+                               } else {
+                                       ctmp->ncci = msg->msg.connect_b3_conf.ncci;
+                                       ctmp->fsm_state = ACT2000_STATE_BWAIT;
+                               }
+                       }
+                       break;
+               case 0x8401:
+                       /* DISCONNECT_B3_CONF */
+                       chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci);
+                       if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT))
+                               card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2;
+                       break;
+               case 0x0702:
+                       /* INFO_IND */
+                       chan = find_plci(card, msg->msg.info_ind.plci);
+                       if (chan >= 0)
+                               /* TODO: Eval Charging info / cause */
+                               actcapi_info_resp(card, &card->bch[chan]);
+                       break;
+               case 0x0401:
+                       /* LISTEN_CONF */
+               case 0x0501:
+                       /* LISTEN_CONF */
+               case 0xff01:
+                       /* MANUFACTURER_CONF */
+                       break;
+               case 0xff02:
+                       /* MANUFACTURER_IND */
+                       if (msg->msg.manuf_msg == 3) {
+                               memset(tmp, 0, sizeof(tmp));
+                               strncpy(tmp,
+                                       &msg->msg.manufacturer_ind_err.errstring,
+                                       msg->hdr.len - 16);
+                               if (msg->msg.manufacturer_ind_err.errcode)
+                                       printk(KERN_WARNING "act2000: %s\n", tmp);
+                               else {
+                                       printk(KERN_DEBUG "act2000: %s\n", tmp);
+                                       if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) ||
+                                           (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) {
+                                               card->flags |= ACT2000_FLAGS_RUNNING;
+                                               cmd.command = ISDN_STAT_RUN;
+                                               cmd.driver = card->myid;
+                                               cmd.arg = 0;
+                                               actcapi_manufacturer_req_net(card);
+                                               actcapi_manufacturer_req_msn(card);
+                                               actcapi_listen_req(card);
+                                               card->interface.statcallb(&cmd);
+                                       }
+                               }
+                       }
+                       break;
+               default:
+                       printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
+                       break;
+               }
+               dev_kfree_skb(skb);
+       }
+}
+
+#ifdef DEBUG_MSG
+static void
+actcapi_debug_caddr(actcapi_addr *addr)
+{
+       char tmp[30];
+
+       printk(KERN_DEBUG " Alen  = %d\n", addr->len);
+       if (addr->len > 0)
+               printk(KERN_DEBUG " Atnp  = 0x%02x\n", addr->tnp);
+       if (addr->len > 1) {
+               memset(tmp, 0, 30);
+               memcpy(tmp, addr->num, addr->len - 1);
+               printk(KERN_DEBUG " Anum  = '%s'\n", tmp);
+       }
+}
+
+static void
+actcapi_debug_ncpi(actcapi_ncpi *ncpi)
+{
+       printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len);
+       if (ncpi->len >= 2)
+               printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic);
+       if (ncpi->len >= 4)
+               printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic);
+       if (ncpi->len >= 6)
+               printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc);
+       if (ncpi->len >= 8)
+               printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc);
+       if (ncpi->len >= 10)
+               printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc);
+       if (ncpi->len >= 12)
+               printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc);
+       if (ncpi->len >= 13)
+               printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo);
+}
+
+static void
+actcapi_debug_dlpd(actcapi_dlpd *dlpd)
+{
+       printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len);
+       if (dlpd->len >= 2)
+               printk(KERN_DEBUG " dlpd.dlen   = 0x%04x\n", dlpd->dlen);
+       if (dlpd->len >= 3)
+               printk(KERN_DEBUG " dlpd.laa    = 0x%02x\n", dlpd->laa);
+       if (dlpd->len >= 4)
+               printk(KERN_DEBUG " dlpd.lab    = 0x%02x\n", dlpd->lab);
+       if (dlpd->len >= 5)
+               printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo);
+       if (dlpd->len >= 6)
+               printk(KERN_DEBUG " dlpd.win    = %d\n", dlpd->win);
+}
+
+#ifdef DEBUG_DUMP_SKB
+static void dump_skb(struct sk_buff *skb) {
+       char tmp[80];
+       char *p = skb->data;
+       char *t = tmp;
+       int i;
+
+       for (i = 0; i < skb->len; i++) {
+               t += sprintf(t, "%02x ", *p++ & 0xff);
+               if ((i & 0x0f) == 8) {
+                       printk(KERN_DEBUG "dump: %s\n", tmp);
+                       t = tmp;
+               }
+       }
+       if (i & 0x07)
+               printk(KERN_DEBUG "dump: %s\n", tmp);
+}
+#endif
+
+void
+actcapi_debug_msg(struct sk_buff *skb, int direction)
+{
+       actcapi_msg *msg = (actcapi_msg *)skb->data;
+       char *descr;
+       int i;
+       char tmp[170];
+
+#ifndef DEBUG_DATA_MSG
+       if (msg->hdr.cmd.cmd == 0x86)
+               return;
+#endif
+       descr = "INVALID";
+#ifdef DEBUG_DUMP_SKB
+       dump_skb(skb);
+#endif
+       for (i = 0; i < ARRAY_SIZE(valid_msg); i++)
+               if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
+                   (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
+                       descr = valid_msg[i].description;
+                       break;
+               }
+       printk(KERN_DEBUG "%s %s msg\n", direction ? "Outgoing" : "Incoming", descr);
+       printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID);
+       printk(KERN_DEBUG " Len    = %d\n", msg->hdr.len);
+       printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum);
+       printk(KERN_DEBUG " Cmd    = 0x%02x\n", msg->hdr.cmd.cmd);
+       printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd);
+       switch (i) {
+       case 0:
+               /* DATA B3 IND */
+               printk(KERN_DEBUG " BLOCK = 0x%02x\n",
+                      msg->msg.data_b3_ind.blocknr);
+               break;
+       case 2:
+               /* CONNECT CONF */
+               printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                      msg->msg.connect_conf.plci);
+               printk(KERN_DEBUG " Info = 0x%04x\n",
+                      msg->msg.connect_conf.info);
+               break;
+       case 3:
+               /* CONNECT IND */
+               printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                      msg->msg.connect_ind.plci);
+               printk(KERN_DEBUG " Contr = %d\n",
+                      msg->msg.connect_ind.controller);
+               printk(KERN_DEBUG " SI1   = %d\n",
+                      msg->msg.connect_ind.si1);
+               printk(KERN_DEBUG " SI2   = %d\n",
+                      msg->msg.connect_ind.si2);
+               printk(KERN_DEBUG " EAZ   = '%c'\n",
+                      msg->msg.connect_ind.eaz);
+               actcapi_debug_caddr(&msg->msg.connect_ind.addr);
+               break;
+       case 5:
+               /* CONNECT ACTIVE IND */
+               printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                      msg->msg.connect_active_ind.plci);
+               actcapi_debug_caddr(&msg->msg.connect_active_ind.addr);
+               break;
+       case 8:
+               /* LISTEN CONF */
+               printk(KERN_DEBUG " Contr = %d\n",
+                      msg->msg.listen_conf.controller);
+               printk(KERN_DEBUG " Info = 0x%04x\n",
+                      msg->msg.listen_conf.info);
+               break;
+       case 11:
+               /* INFO IND */
+               printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                      msg->msg.info_ind.plci);
+               printk(KERN_DEBUG " Imsk = 0x%04x\n",
+                      msg->msg.info_ind.nr.mask);
+               if (msg->hdr.len > 12) {
+                       int l = msg->hdr.len - 12;
+                       int j;
+                       char *p = tmp;
+                       for (j = 0; j < l; j++)
+                               p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]);
+                       printk(KERN_DEBUG " D = '%s'\n", tmp);
+               }
+               break;
+       case 14:
+               /* SELECT B2 PROTOCOL CONF */
+               printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                      msg->msg.select_b2_protocol_conf.plci);
+               printk(KERN_DEBUG " Info = 0x%04x\n",
+                      msg->msg.select_b2_protocol_conf.info);
+               break;
+       case 15:
+               /* SELECT B3 PROTOCOL CONF */
+               printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                      msg->msg.select_b3_protocol_conf.plci);
+               printk(KERN_DEBUG " Info = 0x%04x\n",
+                      msg->msg.select_b3_protocol_conf.info);
+               break;
+       case 16:
+               /* LISTEN B3 CONF */
+               printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                      msg->msg.listen_b3_conf.plci);
+               printk(KERN_DEBUG " Info = 0x%04x\n",
+                      msg->msg.listen_b3_conf.info);
+               break;
+       case 18:
+               /* CONNECT B3 IND */
+               printk(KERN_DEBUG " NCCI = 0x%04x\n",
+                      msg->msg.connect_b3_ind.ncci);
+               printk(KERN_DEBUG " PLCI = 0x%04x\n",
+                      msg->msg.connect_b3_ind.plci);
+               actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi);
+               break;
+       case 19:
+               /* CONNECT B3 ACTIVE IND */
+               printk(KERN_DEBUG " NCCI = 0x%04x\n",
+                      msg->msg.connect_b3_active_ind.ncci);
+               actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi);
+               break;
+       case 26:
+               /* MANUFACTURER IND */
+               printk(KERN_DEBUG " Mmsg = 0x%02x\n",
+                      msg->msg.manufacturer_ind_err.manuf_msg);
+               switch (msg->msg.manufacturer_ind_err.manuf_msg) {
+               case 3:
+                       printk(KERN_DEBUG " Contr = %d\n",
+                              msg->msg.manufacturer_ind_err.controller);
+                       printk(KERN_DEBUG " Code = 0x%08x\n",
+                              msg->msg.manufacturer_ind_err.errcode);
+                       memset(tmp, 0, sizeof(tmp));
+                       strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring,
+                               msg->hdr.len - 16);
+                       printk(KERN_DEBUG " Emsg = '%s'\n", tmp);
+                       break;
+               }
+               break;
+       case 30:
+               /* LISTEN REQ */
+               printk(KERN_DEBUG " Imsk = 0x%08x\n",
+                      msg->msg.listen_req.infomask);
+               printk(KERN_DEBUG " Emsk = 0x%04x\n",
+                      msg->msg.listen_req.eazmask);
+               printk(KERN_DEBUG " Smsk = 0x%04x\n",
+                      msg->msg.listen_req.simask);
+               break;
+       case 35:
+               /* SELECT_B2_PROTOCOL_REQ */
+               printk(KERN_DEBUG " PLCI  = 0x%04x\n",
+                      msg->msg.select_b2_protocol_req.plci);
+               printk(KERN_DEBUG " prot  = 0x%02x\n",
+                      msg->msg.select_b2_protocol_req.protocol);
+               if (msg->hdr.len >= 11)
+                       printk(KERN_DEBUG "No dlpd\n");
+               else
+                       actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd);
+               break;
+       case 44:
+               /* CONNECT RESP */
+               printk(KERN_DEBUG " PLCI  = 0x%04x\n",
+                      msg->msg.connect_resp.plci);
+               printk(KERN_DEBUG " CAUSE = 0x%02x\n",
+                      msg->msg.connect_resp.rejectcause);
+               break;
+       case 45:
+               /* CONNECT ACTIVE RESP */
+               printk(KERN_DEBUG " PLCI  = 0x%04x\n",
+                      msg->msg.connect_active_resp.plci);
+               break;
+       }
+}
+#endif
diff --git a/drivers/staging/i4l/act2000/capi.h b/drivers/staging/i4l/act2000/capi.h
new file mode 100644 (file)
index 0000000..01ccdec
--- /dev/null
@@ -0,0 +1,365 @@
+/* $Id: capi.h,v 1.6.6.2 2001/09/23 22:24:32 kai Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Author       Fritz Elfert
+ * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ */
+
+#ifndef CAPI_H
+#define CAPI_H
+
+/* Command-part of a CAPI message */
+typedef struct actcapi_msgcmd {
+       __u8 cmd;
+       __u8 subcmd;
+} actcapi_msgcmd;
+
+/* CAPI message header */
+typedef struct actcapi_msghdr {
+       __u16 len;
+       __u16 applicationID;
+       actcapi_msgcmd cmd;
+       __u16 msgnum;
+} actcapi_msghdr;
+
+/* CAPI message description (for debugging) */
+typedef struct actcapi_msgdsc {
+       actcapi_msgcmd cmd;
+       char *description;
+} actcapi_msgdsc;
+
+/* CAPI Address */
+typedef struct actcapi_addr {
+       __u8 len;                            /* Length of element            */
+       __u8 tnp;                            /* Type/Numbering Plan          */
+       __u8 num[20];                        /* Caller ID                    */
+} actcapi_addr;
+
+/* CAPI INFO element mask */
+typedef  union actcapi_infonr {              /* info number                  */
+       __u16 mask;                          /* info-mask field              */
+       struct bmask {                       /* bit definitions              */
+               unsigned  codes:3;           /* code set                     */
+               unsigned  rsvd:5;            /* reserved                     */
+               unsigned  svind:1;           /* single, variable length ind. */
+               unsigned  wtype:7;           /* W-element type               */
+       } bmask;
+} actcapi_infonr;
+
+/* CAPI INFO element */
+typedef union  actcapi_infoel {              /* info element                 */
+       __u8 len;                            /* length of info element       */
+       __u8 display[40];                    /* display contents             */
+       __u8 uuinfo[40];                     /* User-user info field         */
+       struct cause {                       /* Cause information            */
+               unsigned ext2:1;             /* extension                    */
+               unsigned cod:2;              /* coding standard              */
+               unsigned spare:1;            /* spare                        */
+               unsigned loc:4;              /* location                     */
+               unsigned ext1:1;             /* extension                    */
+               unsigned cval:7;             /* Cause value                  */
+       } cause;
+       struct charge {                      /* Charging information         */
+               __u8 toc;                    /* type of charging info        */
+               __u8 unit[10];               /* charging units               */
+       } charge;
+       __u8 date[20];                       /* date fields                  */
+       __u8 stat;                           /* state of remote party        */
+} actcapi_infoel;
+
+/* Message for EAZ<->MSN Mapping */
+typedef struct actcapi_msn {
+       __u8 eaz;
+       __u8 len;                            /* Length of MSN                */
+       __u8 msn[15];
+}  __attribute__((packed)) actcapi_msn;
+
+typedef struct actcapi_dlpd {
+       __u8 len;                            /* Length of structure          */
+       __u16 dlen;                          /* Data Length                  */
+       __u8 laa;                            /* Link Address A               */
+       __u8 lab;                            /* Link Address B               */
+       __u8 modulo;                         /* Modulo Mode                  */
+       __u8 win;                            /* Window size                  */
+       __u8 xid[100];                       /* XID Information              */
+} __attribute__((packed)) actcapi_dlpd;
+
+typedef struct actcapi_ncpd {
+       __u8   len;                          /* Length of structure          */
+       __u16  lic;
+       __u16  hic;
+       __u16  ltc;
+       __u16  htc;
+       __u16  loc;
+       __u16  hoc;
+       __u8   modulo;
+} __attribute__((packed)) actcapi_ncpd;
+#define actcapi_ncpi actcapi_ncpd
+
+/*
+ * Layout of NCCI field in a B3 DATA CAPI message is different from
+ * standard at act2000:
+ *
+ * Bit 0-4  = PLCI
+ * Bit 5-7  = Controller
+ * Bit 8-15 = NCCI
+ */
+#define MAKE_NCCI(plci, contr, ncci)                                   \
+       ((plci & 0x1f) | ((contr & 0x7) << 5) | ((ncci & 0xff) << 8))
+
+#define EVAL_NCCI(fakencci, plci, contr, ncci) {       \
+               plci  = fakencci & 0x1f;                \
+               contr = (fakencci >> 5) & 0x7;          \
+               ncci  = (fakencci >> 8) & 0xff;         \
+       }
+
+/*
+ * Layout of PLCI field in a B3 DATA CAPI message is different from
+ * standard at act2000:
+ *
+ * Bit 0-4  = PLCI
+ * Bit 5-7  = Controller
+ * Bit 8-15 = reserved (must be 0)
+ */
+#define MAKE_PLCI(plci, contr)                 \
+       ((plci & 0x1f) | ((contr & 0x7) << 5))
+
+#define EVAL_PLCI(fakeplci, plci, contr) {     \
+               plci  = fakeplci & 0x1f;        \
+               contr = (fakeplci >> 5) & 0x7;  \
+       }
+
+typedef struct actcapi_msg {
+       actcapi_msghdr hdr;
+       union {
+               __u16 manuf_msg;
+               struct manufacturer_req_net {
+                       __u16 manuf_msg;
+                       __u16 controller;
+                       __u8  nettype;
+               } manufacturer_req_net;
+               struct manufacturer_req_v42 {
+                       __u16 manuf_msg;
+                       __u16 controller;
+                       __u32 v42control;
+               } manufacturer_req_v42;
+               struct manufacturer_conf_v42 {
+                       __u16 manuf_msg;
+                       __u16 controller;
+               } manufacturer_conf_v42;
+               struct manufacturer_req_err {
+                       __u16 manuf_msg;
+                       __u16 controller;
+               } manufacturer_req_err;
+               struct manufacturer_ind_err {
+                       __u16 manuf_msg;
+                       __u16 controller;
+                       __u32 errcode;
+                       __u8  errstring; /* actually up to 160 */
+               } manufacturer_ind_err;
+               struct manufacturer_req_msn {
+                       __u16 manuf_msg;
+                       __u16 controller;
+                       actcapi_msn msnmap;
+               } __attribute ((packed)) manufacturer_req_msn;
+               /* TODO: TraceInit-req/conf/ind/resp and
+                *       TraceDump-req/conf/ind/resp
+                */
+               struct connect_req {
+                       __u8  controller;
+                       __u8  bchan;
+                       __u32 infomask;
+                       __u8  si1;
+                       __u8  si2;
+                       __u8  eaz;
+                       actcapi_addr addr;
+               } __attribute__ ((packed)) connect_req;
+               struct connect_conf {
+                       __u16 plci;
+                       __u16 info;
+               } connect_conf;
+               struct connect_ind {
+                       __u16 plci;
+                       __u8  controller;
+                       __u8  si1;
+                       __u8  si2;
+                       __u8  eaz;
+                       actcapi_addr addr;
+               } __attribute__ ((packed)) connect_ind;
+               struct connect_resp {
+                       __u16 plci;
+                       __u8  rejectcause;
+               } connect_resp;
+               struct connect_active_ind {
+                       __u16 plci;
+                       actcapi_addr addr;
+               } __attribute__ ((packed)) connect_active_ind;
+               struct connect_active_resp {
+                       __u16 plci;
+               } connect_active_resp;
+               struct connect_b3_req {
+                       __u16 plci;
+                       actcapi_ncpi ncpi;
+               } __attribute__ ((packed)) connect_b3_req;
+               struct connect_b3_conf {
+                       __u16 plci;
+                       __u16 ncci;
+                       __u16 info;
+               } connect_b3_conf;
+               struct connect_b3_ind {
+                       __u16 ncci;
+                       __u16 plci;
+                       actcapi_ncpi ncpi;
+               } __attribute__ ((packed)) connect_b3_ind;
+               struct connect_b3_resp {
+                       __u16 ncci;
+                       __u8  rejectcause;
+                       actcapi_ncpi ncpi;
+               } __attribute__ ((packed)) connect_b3_resp;
+               struct disconnect_req {
+                       __u16 plci;
+                       __u8  cause;
+               } disconnect_req;
+               struct disconnect_conf {
+                       __u16 plci;
+                       __u16 info;
+               } disconnect_conf;
+               struct disconnect_ind {
+                       __u16 plci;
+                       __u16 info;
+               } disconnect_ind;
+               struct disconnect_resp {
+                       __u16 plci;
+               } disconnect_resp;
+               struct connect_b3_active_ind {
+                       __u16 ncci;
+                       actcapi_ncpi ncpi;
+               } __attribute__ ((packed)) connect_b3_active_ind;
+               struct connect_b3_active_resp {
+                       __u16 ncci;
+               } connect_b3_active_resp;
+               struct disconnect_b3_req {
+                       __u16 ncci;
+                       actcapi_ncpi ncpi;
+               } __attribute__ ((packed)) disconnect_b3_req;
+               struct disconnect_b3_conf {
+                       __u16 ncci;
+                       __u16 info;
+               } disconnect_b3_conf;
+               struct disconnect_b3_ind {
+                       __u16 ncci;
+                       __u16 info;
+                       actcapi_ncpi ncpi;
+               } __attribute__ ((packed)) disconnect_b3_ind;
+               struct disconnect_b3_resp {
+                       __u16 ncci;
+               } disconnect_b3_resp;
+               struct info_ind {
+                       __u16 plci;
+                       actcapi_infonr nr;
+                       actcapi_infoel el;
+               } __attribute__ ((packed)) info_ind;
+               struct info_resp {
+                       __u16 plci;
+               } info_resp;
+               struct listen_b3_req {
+                       __u16 plci;
+               } listen_b3_req;
+               struct listen_b3_conf {
+                       __u16 plci;
+                       __u16 info;
+               } listen_b3_conf;
+               struct select_b2_protocol_req {
+                       __u16 plci;
+                       __u8  protocol;
+                       actcapi_dlpd dlpd;
+               } __attribute__ ((packed)) select_b2_protocol_req;
+               struct select_b2_protocol_conf {
+                       __u16 plci;
+                       __u16 info;
+               } select_b2_protocol_conf;
+               struct select_b3_protocol_req {
+                       __u16 plci;
+                       __u8  protocol;
+                       actcapi_ncpd ncpd;
+               } __attribute__ ((packed)) select_b3_protocol_req;
+               struct select_b3_protocol_conf {
+                       __u16 plci;
+                       __u16 info;
+               } select_b3_protocol_conf;
+               struct listen_req {
+                       __u8  controller;
+                       __u32 infomask;
+                       __u16 eazmask;
+                       __u16 simask;
+               } __attribute__ ((packed)) listen_req;
+               struct listen_conf {
+                       __u8  controller;
+                       __u16 info;
+               } __attribute__ ((packed)) listen_conf;
+               struct data_b3_req {
+                       __u16 fakencci;
+                       __u16 datalen;
+                       __u32 unused;
+                       __u8  blocknr;
+                       __u16 flags;
+               } __attribute ((packed)) data_b3_req;
+               struct data_b3_ind {
+                       __u16 fakencci;
+                       __u16 datalen;
+                       __u32 unused;
+                       __u8  blocknr;
+                       __u16 flags;
+               } __attribute__ ((packed)) data_b3_ind;
+               struct data_b3_resp {
+                       __u16 ncci;
+                       __u8  blocknr;
+               } __attribute__ ((packed)) data_b3_resp;
+               struct data_b3_conf {
+                       __u16 ncci;
+                       __u8  blocknr;
+                       __u16 info;
+               } __attribute__ ((packed)) data_b3_conf;
+       } msg;
+} __attribute__ ((packed)) actcapi_msg;
+
+static inline unsigned short
+actcapi_nextsmsg(act2000_card *card)
+{
+       unsigned long flags;
+       unsigned short n;
+
+       spin_lock_irqsave(&card->mnlock, flags);
+       n = card->msgnum;
+       card->msgnum++;
+       card->msgnum &= 0x7fff;
+       spin_unlock_irqrestore(&card->mnlock, flags);
+       return n;
+}
+#define DEBUG_MSG
+#undef DEBUG_DATA_MSG
+#undef DEBUG_DUMP_SKB
+
+extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
+extern int actcapi_listen_req(act2000_card *);
+extern int actcapi_manufacturer_req_net(act2000_card *);
+extern int actcapi_manufacturer_req_errh(act2000_card *);
+extern int actcapi_manufacturer_req_msn(act2000_card *);
+extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
+extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *);
+extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *);
+extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8);
+extern void actcapi_dispatch(struct work_struct *);
+#ifdef DEBUG_MSG
+extern void actcapi_debug_msg(struct sk_buff *skb, int);
+#else
+#define actcapi_debug_msg(skb, len)
+#endif
+#endif
diff --git a/drivers/staging/i4l/act2000/module.c b/drivers/staging/i4l/act2000/module.c
new file mode 100644 (file)
index 0000000..68073d0
--- /dev/null
@@ -0,0 +1,813 @@
+/* $Id: module.c,v 1.14.6.4 2001/09/23 22:24:32 kai Exp $
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+ * Author       Fritz Elfert
+ * Copyright    by Fritz Elfert      <fritz@isdn4linux.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * Thanks to Friedemann Baitinger and IBM Germany
+ *
+ */
+
+#include "act2000.h"
+#include "act2000_isa.h"
+#include "capi.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+static unsigned short act2000_isa_ports[] =
+{
+       0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
+       0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
+};
+
+static act2000_card *cards = (act2000_card *) NULL;
+
+/* Parameters to be set by insmod */
+static int   act_bus  =  0;
+static int   act_port = -1;  /* -1 = Autoprobe  */
+static int   act_irq  = -1;
+static char *act_id   = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
+MODULE_DESCRIPTION("ISDN4Linux: Driver for IBM Active 2000 ISDN card");
+MODULE_AUTHOR("Fritz Elfert");
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");
+MODULE_PARM_DESC(act_port, "Base port address of first card");
+MODULE_PARM_DESC(act_irq, "IRQ of first card");
+MODULE_PARM_DESC(act_id, "ID-String of first card");
+module_param(act_bus, int, 0);
+module_param(act_port, int, 0);
+module_param(act_irq, int, 0);
+module_param(act_id, charp, 0);
+
+static int act2000_addcard(int, int, int, char *);
+
+static act2000_chan *
+find_channel(act2000_card *card, int channel)
+{
+       if ((channel >= 0) && (channel < ACT2000_BCH))
+               return &(card->bch[channel]);
+       printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);
+       return NULL;
+}
+
+/*
+ * Free MSN list
+ */
+static void
+act2000_clear_msn(act2000_card *card)
+{
+       struct msn_entry *p = card->msn_list;
+       struct msn_entry *q;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       card->msn_list = NULL;
+       spin_unlock_irqrestore(&card->lock, flags);
+       while (p) {
+               q  = p->next;
+               kfree(p);
+               p = q;
+       }
+}
+
+/*
+ * Find an MSN entry in the list.
+ * If ia5 != 0, return IA5-encoded EAZ, else
+ * return a bitmask with corresponding bit set.
+ */
+static __u16
+act2000_find_msn(act2000_card *card, char *msn, int ia5)
+{
+       struct msn_entry *p = card->msn_list;
+       __u8 eaz = '0';
+
+       while (p) {
+               if (!strcmp(p->msn, msn)) {
+                       eaz = p->eaz;
+                       break;
+               }
+               p = p->next;
+       }
+       if (!ia5)
+               return (1 << (eaz - '0'));
+       else
+               return eaz;
+}
+
+/*
+ * Find an EAZ entry in the list.
+ * return a string with corresponding msn.
+ */
+char *
+act2000_find_eaz(act2000_card *card, char eaz)
+{
+       struct msn_entry *p = card->msn_list;
+
+       while (p) {
+               if (p->eaz == eaz)
+                       return (p->msn);
+               p = p->next;
+       }
+       return ("\0");
+}
+
+/*
+ * Add or delete an MSN to the MSN list
+ *
+ * First character of msneaz is EAZ, rest is MSN.
+ * If length of eazmsn is 1, delete that entry.
+ */
+static int
+act2000_set_msn(act2000_card *card, char *eazmsn)
+{
+       struct msn_entry *p = card->msn_list;
+       struct msn_entry *q = NULL;
+       unsigned long flags;
+       int i;
+
+       if (!strlen(eazmsn))
+               return 0;
+       if (strlen(eazmsn) > 16)
+               return -EINVAL;
+       for (i = 0; i < strlen(eazmsn); i++)
+               if (!isdigit(eazmsn[i]))
+                       return -EINVAL;
+       if (strlen(eazmsn) == 1) {
+               /* Delete a single MSN */
+               while (p) {
+                       if (p->eaz == eazmsn[0]) {
+                               spin_lock_irqsave(&card->lock, flags);
+                               if (q)
+                                       q->next = p->next;
+                               else
+                                       card->msn_list = p->next;
+                               spin_unlock_irqrestore(&card->lock, flags);
+                               kfree(p);
+                               printk(KERN_DEBUG
+                                      "Mapping for EAZ %c deleted\n",
+                                      eazmsn[0]);
+                               return 0;
+                       }
+                       q = p;
+                       p = p->next;
+               }
+               return 0;
+       }
+       /* Add a single MSN */
+       while (p) {
+               /* Found in list, replace MSN */
+               if (p->eaz == eazmsn[0]) {
+                       spin_lock_irqsave(&card->lock, flags);
+                       strcpy(p->msn, &eazmsn[1]);
+                       spin_unlock_irqrestore(&card->lock, flags);
+                       printk(KERN_DEBUG
+                              "Mapping for EAZ %c changed to %s\n",
+                              eazmsn[0],
+                              &eazmsn[1]);
+                       return 0;
+               }
+               p = p->next;
+       }
+       /* Not found in list, add new entry */
+       p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+       p->eaz = eazmsn[0];
+       strcpy(p->msn, &eazmsn[1]);
+       p->next = card->msn_list;
+       spin_lock_irqsave(&card->lock, flags);
+       card->msn_list = p;
+       spin_unlock_irqrestore(&card->lock, flags);
+       printk(KERN_DEBUG
+              "Mapping %c -> %s added\n",
+              eazmsn[0],
+              &eazmsn[1]);
+       return 0;
+}
+
+static void
+act2000_transmit(struct work_struct *work)
+{
+       struct act2000_card *card =
+               container_of(work, struct act2000_card, snd_tq);
+
+       switch (card->bus) {
+       case ACT2000_BUS_ISA:
+               act2000_isa_send(card);
+               break;
+       case ACT2000_BUS_PCMCIA:
+       case ACT2000_BUS_MCA:
+       default:
+               printk(KERN_WARNING
+                      "act2000_transmit: Illegal bustype %d\n", card->bus);
+       }
+}
+
+static void
+act2000_receive(struct work_struct *work)
+{
+       struct act2000_card *card =
+               container_of(work, struct act2000_card, poll_tq);
+
+       switch (card->bus) {
+       case ACT2000_BUS_ISA:
+               act2000_isa_receive(card);
+               break;
+       case ACT2000_BUS_PCMCIA:
+       case ACT2000_BUS_MCA:
+       default:
+               printk(KERN_WARNING
+                      "act2000_receive: Illegal bustype %d\n", card->bus);
+       }
+}
+
+static void
+act2000_poll(unsigned long data)
+{
+       act2000_card *card = (act2000_card *)data;
+       unsigned long flags;
+
+       act2000_receive(&card->poll_tq);
+       spin_lock_irqsave(&card->lock, flags);
+       mod_timer(&card->ptimer, jiffies + 3);
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static int
+act2000_command(act2000_card *card, isdn_ctrl *c)
+{
+       ulong a;
+       act2000_chan *chan;
+       act2000_cdef cdef;
+       isdn_ctrl cmd;
+       char tmp[17];
+       int ret;
+       unsigned long flags;
+       void __user *arg;
+
+       switch (c->command) {
+       case ISDN_CMD_IOCTL:
+               memcpy(&a, c->parm.num, sizeof(ulong));
+               arg = (void __user *)a;
+               switch (c->arg) {
+               case ACT2000_IOCTL_LOADBOOT:
+                       switch (card->bus) {
+                       case ACT2000_BUS_ISA:
+                               ret = act2000_isa_download(card,
+                                                          arg);
+                               if (!ret) {
+                                       card->flags |= ACT2000_FLAGS_LOADED;
+                                       if (!(card->flags & ACT2000_FLAGS_IVALID)) {
+                                               card->ptimer.expires = jiffies + 3;
+                                               card->ptimer.function = act2000_poll;
+                                               card->ptimer.data = (unsigned long)card;
+                                               add_timer(&card->ptimer);
+                                       }
+                                       actcapi_manufacturer_req_errh(card);
+                               }
+                               break;
+                       default:
+                               printk(KERN_WARNING
+                                      "act2000: Illegal BUS type %d\n",
+                                      card->bus);
+                               ret = -EIO;
+                       }
+                       return ret;
+               case ACT2000_IOCTL_SETPROTO:
+                       card->ptype = a ? ISDN_PTYPE_EURO : ISDN_PTYPE_1TR6;
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                               return 0;
+                       actcapi_manufacturer_req_net(card);
+                       return 0;
+               case ACT2000_IOCTL_SETMSN:
+                       if (copy_from_user(tmp, arg,
+                                          sizeof(tmp)))
+                               return -EFAULT;
+                       if ((ret = act2000_set_msn(card, tmp)))
+                               return ret;
+                       if (card->flags & ACT2000_FLAGS_RUNNING)
+                               return (actcapi_manufacturer_req_msn(card));
+                       return 0;
+               case ACT2000_IOCTL_ADDCARD:
+                       if (copy_from_user(&cdef, arg,
+                                          sizeof(cdef)))
+                               return -EFAULT;
+                       if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))
+                               return -EIO;
+                       return 0;
+               case ACT2000_IOCTL_TEST:
+                       if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                               return -ENODEV;
+                       return 0;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case ISDN_CMD_DIAL:
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (!(chan = find_channel(card, c->arg & 0x0f)))
+                       break;
+               spin_lock_irqsave(&card->lock, flags);
+               if (chan->fsm_state != ACT2000_STATE_NULL) {
+                       spin_unlock_irqrestore(&card->lock, flags);
+                       printk(KERN_WARNING "Dial on channel with state %d\n",
+                              chan->fsm_state);
+                       return -EBUSY;
+               }
+               if (card->ptype == ISDN_PTYPE_EURO)
+                       tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);
+               else
+                       tmp[0] = c->parm.setup.eazmsn[0];
+               chan->fsm_state = ACT2000_STATE_OCALL;
+               chan->callref = 0xffff;
+               spin_unlock_irqrestore(&card->lock, flags);
+               ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
+                                         tmp[0], c->parm.setup.si1,
+                                         c->parm.setup.si2);
+               if (ret) {
+                       cmd.driver = card->myid;
+                       cmd.command = ISDN_STAT_DHUP;
+                       cmd.arg &= 0x0f;
+                       card->interface.statcallb(&cmd);
+               }
+               return ret;
+       case ISDN_CMD_ACCEPTD:
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (!(chan = find_channel(card, c->arg & 0x0f)))
+                       break;
+               if (chan->fsm_state == ACT2000_STATE_ICALL)
+                       actcapi_select_b2_protocol_req(card, chan);
+               return 0;
+       case ISDN_CMD_ACCEPTB:
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               return 0;
+       case ISDN_CMD_HANGUP:
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (!(chan = find_channel(card, c->arg & 0x0f)))
+                       break;
+               switch (chan->fsm_state) {
+               case ACT2000_STATE_ICALL:
+               case ACT2000_STATE_BSETUP:
+                       actcapi_connect_resp(card, chan, 0x15);
+                       break;
+               case ACT2000_STATE_ACTIVE:
+                       actcapi_disconnect_b3_req(card, chan);
+                       break;
+               }
+               return 0;
+       case ISDN_CMD_SETEAZ:
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (!(chan = find_channel(card, c->arg & 0x0f)))
+                       break;
+               if (strlen(c->parm.num)) {
+                       if (card->ptype == ISDN_PTYPE_EURO) {
+                               chan->eazmask = act2000_find_msn(card, c->parm.num, 0);
+                       }
+                       if (card->ptype == ISDN_PTYPE_1TR6) {
+                               int i;
+                               chan->eazmask = 0;
+                               for (i = 0; i < strlen(c->parm.num); i++)
+                                       if (isdigit(c->parm.num[i]))
+                                               chan->eazmask |= (1 << (c->parm.num[i] - '0'));
+                       }
+               } else
+                       chan->eazmask = 0x3ff;
+               actcapi_listen_req(card);
+               return 0;
+       case ISDN_CMD_CLREAZ:
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (!(chan = find_channel(card, c->arg & 0x0f)))
+                       break;
+               chan->eazmask = 0;
+               actcapi_listen_req(card);
+               return 0;
+       case ISDN_CMD_SETL2:
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (!(chan = find_channel(card, c->arg & 0x0f)))
+                       break;
+               chan->l2prot = (c->arg >> 8);
+               return 0;
+       case ISDN_CMD_SETL3:
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
+                       printk(KERN_WARNING "L3 protocol unknown\n");
+                       return -1;
+               }
+               if (!(chan = find_channel(card, c->arg & 0x0f)))
+                       break;
+               chan->l3prot = (c->arg >> 8);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int
+act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb)
+{
+       struct sk_buff *xmit_skb;
+       int len;
+       act2000_chan *chan;
+       actcapi_msg *msg;
+
+       if (!(chan = find_channel(card, channel)))
+               return -1;
+       if (chan->fsm_state != ACT2000_STATE_ACTIVE)
+               return -1;
+       len = skb->len;
+       if ((chan->queued + len) >= ACT2000_MAX_QUEUED)
+               return 0;
+       if (!len)
+               return 0;
+       if (skb_headroom(skb) < 19) {
+               printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n",
+                      skb_headroom(skb));
+               xmit_skb = alloc_skb(len + 19, GFP_ATOMIC);
+               if (!xmit_skb) {
+                       printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
+                       return 0;
+               }
+               skb_reserve(xmit_skb, 19);
+               skb_copy_from_linear_data(skb, skb_put(xmit_skb, len), len);
+       } else {
+               xmit_skb = skb_clone(skb, GFP_ATOMIC);
+               if (!xmit_skb) {
+                       printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
+                       return 0;
+               }
+       }
+       dev_kfree_skb(skb);
+       msg = (actcapi_msg *)skb_push(xmit_skb, 19);
+       msg->hdr.len = 19 + len;
+       msg->hdr.applicationID = 1;
+       msg->hdr.cmd.cmd = 0x86;
+       msg->hdr.cmd.subcmd = 0x00;
+       msg->hdr.msgnum = actcapi_nextsmsg(card);
+       msg->msg.data_b3_req.datalen = len;
+       msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff);
+       msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci);
+       msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */
+       actcapi_debug_msg(xmit_skb, 1);
+       chan->queued += len;
+       skb_queue_tail(&card->sndq, xmit_skb);
+       act2000_schedule_tx(card);
+       return len;
+}
+
+
+/* Read the Status-replies from the Interface */
+static int
+act2000_readstatus(u_char __user *buf, int len, act2000_card *card)
+{
+       int count;
+       u_char __user *p;
+
+       for (p = buf, count = 0; count < len; p++, count++) {
+               if (card->status_buf_read == card->status_buf_write)
+                       return count;
+               put_user(*card->status_buf_read++, p);
+               if (card->status_buf_read > card->status_buf_end)
+                       card->status_buf_read = card->status_buf;
+       }
+       return count;
+}
+
+/*
+ * Find card with given driverId
+ */
+static inline act2000_card *
+act2000_findcard(int driverid)
+{
+       act2000_card *p = cards;
+
+       while (p) {
+               if (p->myid == driverid)
+                       return p;
+               p = p->next;
+       }
+       return (act2000_card *) 0;
+}
+
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl *c)
+{
+       act2000_card *card = act2000_findcard(c->driver);
+
+       if (card)
+               return (act2000_command(card, c));
+       printk(KERN_ERR
+              "act2000: if_command %d called with invalid driverId %d!\n",
+              c->command, c->driver);
+       return -ENODEV;
+}
+
+static int
+if_writecmd(const u_char __user *buf, int len, int id, int channel)
+{
+       act2000_card *card = act2000_findcard(id);
+
+       if (card) {
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               return (len);
+       }
+       printk(KERN_ERR
+              "act2000: if_writecmd called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+static int
+if_readstatus(u_char __user *buf, int len, int id, int channel)
+{
+       act2000_card *card = act2000_findcard(id);
+
+       if (card) {
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               return (act2000_readstatus(buf, len, card));
+       }
+       printk(KERN_ERR
+              "act2000: if_readstatus called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+static int
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
+{
+       act2000_card *card = act2000_findcard(id);
+
+       if (card) {
+               if (!(card->flags & ACT2000_FLAGS_RUNNING))
+                       return -ENODEV;
+               return (act2000_sendbuf(card, channel, ack, skb));
+       }
+       printk(KERN_ERR
+              "act2000: if_sendbuf called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list.
+ */
+static void
+act2000_alloccard(int bus, int port, int irq, char *id)
+{
+       int i;
+       act2000_card *card;
+       if (!(card = kzalloc(sizeof(act2000_card), GFP_KERNEL))) {
+               printk(KERN_WARNING
+                      "act2000: (%s) Could not allocate card-struct.\n", id);
+               return;
+       }
+       spin_lock_init(&card->lock);
+       spin_lock_init(&card->mnlock);
+       skb_queue_head_init(&card->sndq);
+       skb_queue_head_init(&card->rcvq);
+       skb_queue_head_init(&card->ackq);
+       INIT_WORK(&card->snd_tq, act2000_transmit);
+       INIT_WORK(&card->rcv_tq, actcapi_dispatch);
+       INIT_WORK(&card->poll_tq, act2000_receive);
+       init_timer(&card->ptimer);
+       card->interface.owner = THIS_MODULE;
+       card->interface.channels = ACT2000_BCH;
+       card->interface.maxbufsize = 4000;
+       card->interface.command = if_command;
+       card->interface.writebuf_skb = if_sendbuf;
+       card->interface.writecmd = if_writecmd;
+       card->interface.readstat = if_readstatus;
+       card->interface.features =
+               ISDN_FEATURE_L2_X75I |
+               ISDN_FEATURE_L2_HDLC |
+               ISDN_FEATURE_L3_TRANS |
+               ISDN_FEATURE_P_UNKNOWN;
+       card->interface.hl_hdrlen = 20;
+       card->ptype = ISDN_PTYPE_EURO;
+       strlcpy(card->interface.id, id, sizeof(card->interface.id));
+       for (i = 0; i < ACT2000_BCH; i++) {
+               card->bch[i].plci = 0x8000;
+               card->bch[i].ncci = 0x8000;
+               card->bch[i].l2prot = ISDN_PROTO_L2_X75I;
+               card->bch[i].l3prot = ISDN_PROTO_L3_TRANS;
+       }
+       card->myid = -1;
+       card->bus = bus;
+       card->port = port;
+       card->irq = irq;
+       card->next = cards;
+       cards = card;
+}
+
+/*
+ * register card at linklevel
+ */
+static int
+act2000_registercard(act2000_card *card)
+{
+       switch (card->bus) {
+       case ACT2000_BUS_ISA:
+               break;
+       case ACT2000_BUS_MCA:
+       case ACT2000_BUS_PCMCIA:
+       default:
+               printk(KERN_WARNING
+                      "act2000: Illegal BUS type %d\n",
+                      card->bus);
+               return -1;
+       }
+       if (!register_isdn(&card->interface)) {
+               printk(KERN_WARNING
+                      "act2000: Unable to register %s\n",
+                      card->interface.id);
+               return -1;
+       }
+       card->myid = card->interface.channels;
+       sprintf(card->regname, "act2000-isdn (%s)", card->interface.id);
+       return 0;
+}
+
+static void
+unregister_card(act2000_card *card)
+{
+       isdn_ctrl cmd;
+
+       cmd.command = ISDN_STAT_UNLOAD;
+       cmd.driver = card->myid;
+       card->interface.statcallb(&cmd);
+       switch (card->bus) {
+       case ACT2000_BUS_ISA:
+               act2000_isa_release(card);
+               break;
+       case ACT2000_BUS_MCA:
+       case ACT2000_BUS_PCMCIA:
+       default:
+               printk(KERN_WARNING
+                      "act2000: Invalid BUS type %d\n",
+                      card->bus);
+               break;
+       }
+}
+
+static int
+act2000_addcard(int bus, int port, int irq, char *id)
+{
+       act2000_card *p;
+       act2000_card *q = NULL;
+       int initialized;
+       int added = 0;
+       int failed = 0;
+       int i;
+
+       if (!bus)
+               bus = ACT2000_BUS_ISA;
+       if (port != -1) {
+               /* Port defined, do fixed setup */
+               act2000_alloccard(bus, port, irq, id);
+       } else {
+               /* No port defined, perform autoprobing.
+                * This may result in more than one card detected.
+                */
+               switch (bus) {
+               case ACT2000_BUS_ISA:
+                       for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++)
+                               if (act2000_isa_detect(act2000_isa_ports[i])) {
+                                       printk(KERN_INFO "act2000: Detected "
+                                              "ISA card at port 0x%x\n",
+                                              act2000_isa_ports[i]);
+                                       act2000_alloccard(bus,
+                                                         act2000_isa_ports[i], irq, id);
+                               }
+                       break;
+               case ACT2000_BUS_MCA:
+               case ACT2000_BUS_PCMCIA:
+               default:
+                       printk(KERN_WARNING
+                              "act2000: addcard: Invalid BUS type %d\n", bus);
+               }
+       }
+       if (!cards)
+               return 1;
+       p = cards;
+       while (p) {
+               initialized = 0;
+               if (!p->interface.statcallb) {
+                       /* Not yet registered.
+                        * Try to register and activate it.
+                        */
+                       added++;
+                       switch (p->bus) {
+                       case ACT2000_BUS_ISA:
+                               if (act2000_isa_detect(p->port)) {
+                                       if (act2000_registercard(p))
+                                               break;
+                                       if (act2000_isa_config_port(p, p->port)) {
+                                               printk(KERN_WARNING
+                                                      "act2000: Could not request port 0x%04x\n",
+                                                      p->port);
+                                               unregister_card(p);
+                                               p->interface.statcallb = NULL;
+                                               break;
+                                       }
+                                       if (act2000_isa_config_irq(p, p->irq)) {
+                                               printk(KERN_INFO
+                                                      "act2000: No IRQ available, fallback to polling\n");
+                                               /* Fall back to polled operation */
+                                               p->irq = 0;
+                                       }
+                                       printk(KERN_INFO
+                                              "act2000: ISA"
+                                              "-type card at port "
+                                              "0x%04x ",
+                                              p->port);
+                                       if (p->irq)
+                                               printk("irq %d\n", p->irq);
+                                       else
+                                               printk("polled\n");
+                                       initialized = 1;
+                               }
+                               break;
+                       case ACT2000_BUS_MCA:
+                       case ACT2000_BUS_PCMCIA:
+                       default:
+                               printk(KERN_WARNING
+                                      "act2000: addcard: Invalid BUS type %d\n",
+                                      p->bus);
+                       }
+               } else
+                       /* Card already initialized */
+                       initialized = 1;
+               if (initialized) {
+                       /* Init OK, next card ... */
+                       q = p;
+                       p = p->next;
+               } else {
+                       /* Init failed, remove card from list, free memory */
+                       printk(KERN_WARNING
+                              "act2000: Initialization of %s failed\n",
+                              p->interface.id);
+                       if (q) {
+                               q->next = p->next;
+                               kfree(p);
+                               p = q->next;
+                       } else {
+                               cards = p->next;
+                               kfree(p);
+                               p = cards;
+                       }
+                       failed++;
+               }
+       }
+       return (added - failed);
+}
+
+#define DRIVERNAME "IBM Active 2000 ISDN driver"
+
+static int __init act2000_init(void)
+{
+       printk(KERN_INFO "%s\n", DRIVERNAME);
+       if (!cards)
+               act2000_addcard(act_bus, act_port, act_irq, act_id);
+       if (!cards)
+               printk(KERN_INFO "act2000: No cards defined yet\n");
+       return 0;
+}
+
+static void __exit act2000_exit(void)
+{
+       act2000_card *card = cards;
+       act2000_card *last;
+       while (card) {
+               unregister_card(card);
+               del_timer_sync(&card->ptimer);
+               card = card->next;
+       }
+       card = cards;
+       while (card) {
+               last = card;
+               card = card->next;
+               act2000_clear_msn(last);
+               kfree(last);
+       }
+       printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
+}
+
+module_init(act2000_init);
+module_exit(act2000_exit);
diff --git a/drivers/staging/i4l/icn/Kconfig b/drivers/staging/i4l/icn/Kconfig
new file mode 100644 (file)
index 0000000..4534f21
--- /dev/null
@@ -0,0 +1,12 @@
+config ISDN_DRV_ICN
+       tristate "ICN 2B and 4B support"
+       depends on ISA
+       help
+         This enables support for two kinds of ISDN-cards made by a German
+         company called ICN.  2B is the standard version for a single ISDN
+         line with two B-channels, 4B supports two ISDN lines.  For running
+         this card, additional firmware is necessary, which has to be
+         downloaded into the card using a utility which is distributed
+         separately.  See <file:Documentation/isdn/README> and
+         <file:Documentation/isdn/README.icn> for more
+         information.
diff --git a/drivers/staging/i4l/icn/Makefile b/drivers/staging/i4l/icn/Makefile
new file mode 100644 (file)
index 0000000..d9b476f
--- /dev/null
@@ -0,0 +1,5 @@
+# Makefile for the icn ISDN device driver
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_ICN)     += icn.o
diff --git a/drivers/staging/i4l/icn/icn.c b/drivers/staging/i4l/icn/icn.c
new file mode 100644 (file)
index 0000000..46d957c
--- /dev/null
@@ -0,0 +1,1693 @@
+/* $Id: icn.c,v 1.65.6.8 2001/09/23 22:24:55 kai Exp $
+ *
+ * ISDN low-level module for the ICN active ISDN-Card.
+ *
+ * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "icn.h"
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+static int portbase = ICN_BASEADDR;
+static unsigned long membase = ICN_MEMADDR;
+static char *icn_id = "\0";
+static char *icn_id2 = "\0";
+
+MODULE_DESCRIPTION("ISDN4Linux: Driver for ICN active ISDN card");
+MODULE_AUTHOR("Fritz Elfert");
+MODULE_LICENSE("GPL");
+module_param(portbase, int, 0);
+MODULE_PARM_DESC(portbase, "Port address of first card");
+module_param(membase, ulong, 0);
+MODULE_PARM_DESC(membase, "Shared memory address of all cards");
+module_param(icn_id, charp, 0);
+MODULE_PARM_DESC(icn_id, "ID-String of first card");
+module_param(icn_id2, charp, 0);
+MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
+
+/*
+ * Verbose bootcode- and protocol-downloading.
+ */
+#undef BOOT_DEBUG
+
+/*
+ * Verbose Shmem-Mapping.
+ */
+#undef MAP_DEBUG
+
+static char
+*revision = "$Revision: 1.65.6.8 $";
+
+static int icn_addcard(int, char *, char *);
+
+/*
+ * Free send-queue completely.
+ * Parameter:
+ *   card   = pointer to card struct
+ *   channel = channel number
+ */
+static void
+icn_free_queue(icn_card *card, int channel)
+{
+       struct sk_buff_head *queue = &card->spqueue[channel];
+       struct sk_buff *skb;
+
+       skb_queue_purge(queue);
+       card->xlen[channel] = 0;
+       card->sndcount[channel] = 0;
+       if ((skb = card->xskb[channel])) {
+               card->xskb[channel] = NULL;
+               dev_kfree_skb(skb);
+       }
+}
+
+/* Put a value into a shift-register, highest bit first.
+ * Parameters:
+ *            port     = port for output (bit 0 is significant)
+ *            val      = value to be output
+ *            firstbit = Bit-Number of highest bit
+ *            bitcount = Number of bits to output
+ */
+static inline void
+icn_shiftout(unsigned short port,
+            unsigned long val,
+            int firstbit,
+            int bitcount)
+{
+
+       register u_char s;
+       register u_char c;
+
+       for (s = firstbit, c = bitcount; c > 0; s--, c--)
+               OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
+}
+
+/*
+ * disable a cards shared memory
+ */
+static inline void
+icn_disable_ram(icn_card *card)
+{
+       OUTB_P(0, ICN_MAPRAM);
+}
+
+/*
+ * enable a cards shared memory
+ */
+static inline void
+icn_enable_ram(icn_card *card)
+{
+       OUTB_P(0xff, ICN_MAPRAM);
+}
+
+/*
+ * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
+ *
+ * must called with holding the devlock
+ */
+static inline void
+icn_map_channel(icn_card *card, int channel)
+{
+#ifdef MAP_DEBUG
+       printk(KERN_DEBUG "icn_map_channel %d %d\n", dev.channel, channel);
+#endif
+       if ((channel == dev.channel) && (card == dev.mcard))
+               return;
+       if (dev.mcard)
+               icn_disable_ram(dev.mcard);
+       icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4);       /* Select Bank          */
+       icn_enable_ram(card);
+       dev.mcard = card;
+       dev.channel = channel;
+#ifdef MAP_DEBUG
+       printk(KERN_DEBUG "icn_map_channel done\n");
+#endif
+}
+
+/*
+ * Lock a cards channel.
+ * Return 0 if requested card/channel is unmapped (failure).
+ * Return 1 on success.
+ *
+ * must called with holding the devlock
+ */
+static inline int
+icn_lock_channel(icn_card *card, int channel)
+{
+       register int retval;
+
+#ifdef MAP_DEBUG
+       printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
+#endif
+       if ((dev.channel == channel) && (card == dev.mcard)) {
+               dev.chanlock++;
+               retval = 1;
+#ifdef MAP_DEBUG
+               printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
+#endif
+       } else {
+               retval = 0;
+#ifdef MAP_DEBUG
+               printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev.channel);
+#endif
+       }
+       return retval;
+}
+
+/*
+ * Release current card/channel lock
+ *
+ * must called with holding the devlock
+ */
+static inline void
+__icn_release_channel(void)
+{
+#ifdef MAP_DEBUG
+       printk(KERN_DEBUG "icn_release_channel l=%d\n", dev.chanlock);
+#endif
+       if (dev.chanlock > 0)
+               dev.chanlock--;
+}
+
+/*
+ * Release current card/channel lock
+ */
+static inline void
+icn_release_channel(void)
+{
+       ulong flags;
+
+       spin_lock_irqsave(&dev.devlock, flags);
+       __icn_release_channel();
+       spin_unlock_irqrestore(&dev.devlock, flags);
+}
+
+/*
+ * Try to map and lock a cards channel.
+ * Return 1 on success, 0 on failure.
+ */
+static inline int
+icn_trymaplock_channel(icn_card *card, int channel)
+{
+       ulong flags;
+
+#ifdef MAP_DEBUG
+       printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
+              dev.chanlock);
+#endif
+       spin_lock_irqsave(&dev.devlock, flags);
+       if ((!dev.chanlock) ||
+           ((dev.channel == channel) && (dev.mcard == card))) {
+               dev.chanlock++;
+               icn_map_channel(card, channel);
+               spin_unlock_irqrestore(&dev.devlock, flags);
+#ifdef MAP_DEBUG
+               printk(KERN_DEBUG "trymaplock %d OK\n", channel);
+#endif
+               return 1;
+       }
+       spin_unlock_irqrestore(&dev.devlock, flags);
+#ifdef MAP_DEBUG
+       printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
+#endif
+       return 0;
+}
+
+/*
+ * Release current card/channel lock,
+ * then map same or other channel without locking.
+ */
+static inline void
+icn_maprelease_channel(icn_card *card, int channel)
+{
+       ulong flags;
+
+#ifdef MAP_DEBUG
+       printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
+#endif
+       spin_lock_irqsave(&dev.devlock, flags);
+       if (dev.chanlock > 0)
+               dev.chanlock--;
+       if (!dev.chanlock)
+               icn_map_channel(card, channel);
+       spin_unlock_irqrestore(&dev.devlock, flags);
+}
+
+/* Get Data from the B-Channel, assemble fragmented packets and put them
+ * into receive-queue. Wake up any B-Channel-reading processes.
+ * This routine is called via timer-callback from icn_pollbchan().
+ */
+
+static void
+icn_pollbchan_receive(int channel, icn_card *card)
+{
+       int mch = channel + ((card->secondhalf) ? 2 : 0);
+       int eflag;
+       int cnt;
+       struct sk_buff *skb;
+
+       if (icn_trymaplock_channel(card, mch)) {
+               while (rbavl) {
+                       cnt = readb(&rbuf_l);
+                       if ((card->rcvidx[channel] + cnt) > 4000) {
+                               printk(KERN_WARNING
+                                      "icn: (%s) bogus packet on ch%d, dropping.\n",
+                                      CID,
+                                      channel + 1);
+                               card->rcvidx[channel] = 0;
+                               eflag = 0;
+                       } else {
+                               memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
+                                             &rbuf_d, cnt);
+                               card->rcvidx[channel] += cnt;
+                               eflag = readb(&rbuf_f);
+                       }
+                       rbnext;
+                       icn_maprelease_channel(card, mch & 2);
+                       if (!eflag) {
+                               if ((cnt = card->rcvidx[channel])) {
+                                       if (!(skb = dev_alloc_skb(cnt))) {
+                                               printk(KERN_WARNING "icn: receive out of memory\n");
+                                               break;
+                                       }
+                                       memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
+                                       card->rcvidx[channel] = 0;
+                                       card->interface.rcvcallb_skb(card->myid, channel, skb);
+                               }
+                       }
+                       if (!icn_trymaplock_channel(card, mch))
+                               break;
+               }
+               icn_maprelease_channel(card, mch & 2);
+       }
+}
+
+/* Send data-packet to B-Channel, split it up into fragments of
+ * ICN_FRAGSIZE length. If last fragment is sent out, signal
+ * success to upper layers via statcallb with ISDN_STAT_BSENT argument.
+ * This routine is called via timer-callback from icn_pollbchan() or
+ * directly from icn_sendbuf().
+ */
+
+static void
+icn_pollbchan_send(int channel, icn_card *card)
+{
+       int mch = channel + ((card->secondhalf) ? 2 : 0);
+       int cnt;
+       unsigned long flags;
+       struct sk_buff *skb;
+       isdn_ctrl cmd;
+
+       if (!(card->sndcount[channel] || card->xskb[channel] ||
+             !skb_queue_empty(&card->spqueue[channel])))
+               return;
+       if (icn_trymaplock_channel(card, mch)) {
+               while (sbfree &&
+                      (card->sndcount[channel] ||
+                       !skb_queue_empty(&card->spqueue[channel]) ||
+                       card->xskb[channel])) {
+                       spin_lock_irqsave(&card->lock, flags);
+                       if (card->xmit_lock[channel]) {
+                               spin_unlock_irqrestore(&card->lock, flags);
+                               break;
+                       }
+                       card->xmit_lock[channel]++;
+                       spin_unlock_irqrestore(&card->lock, flags);
+                       skb = card->xskb[channel];
+                       if (!skb) {
+                               skb = skb_dequeue(&card->spqueue[channel]);
+                               if (skb) {
+                                       /* Pop ACK-flag off skb.
+                                        * Store length to xlen.
+                                        */
+                                       if (*(skb_pull(skb, 1)))
+                                               card->xlen[channel] = skb->len;
+                                       else
+                                               card->xlen[channel] = 0;
+                               }
+                       }
+                       if (!skb)
+                               break;
+                       if (skb->len > ICN_FRAGSIZE) {
+                               writeb(0xff, &sbuf_f);
+                               cnt = ICN_FRAGSIZE;
+                       } else {
+                               writeb(0x0, &sbuf_f);
+                               cnt = skb->len;
+                       }
+                       writeb(cnt, &sbuf_l);
+                       memcpy_toio(&sbuf_d, skb->data, cnt);
+                       skb_pull(skb, cnt);
+                       sbnext; /* switch to next buffer        */
+                       icn_maprelease_channel(card, mch & 2);
+                       spin_lock_irqsave(&card->lock, flags);
+                       card->sndcount[channel] -= cnt;
+                       if (!skb->len) {
+                               if (card->xskb[channel])
+                                       card->xskb[channel] = NULL;
+                               card->xmit_lock[channel] = 0;
+                               spin_unlock_irqrestore(&card->lock, flags);
+                               dev_kfree_skb(skb);
+                               if (card->xlen[channel]) {
+                                       cmd.command = ISDN_STAT_BSENT;
+                                       cmd.driver = card->myid;
+                                       cmd.arg = channel;
+                                       cmd.parm.length = card->xlen[channel];
+                                       card->interface.statcallb(&cmd);
+                               }
+                       } else {
+                               card->xskb[channel] = skb;
+                               card->xmit_lock[channel] = 0;
+                               spin_unlock_irqrestore(&card->lock, flags);
+                       }
+                       if (!icn_trymaplock_channel(card, mch))
+                               break;
+               }
+               icn_maprelease_channel(card, mch & 2);
+       }
+}
+
+/* Send/Receive Data to/from the B-Channel.
+ * This routine is called via timer-callback.
+ * It schedules itself while any B-Channel is open.
+ */
+
+static void
+icn_pollbchan(unsigned long data)
+{
+       icn_card *card = (icn_card *) data;
+       unsigned long flags;
+
+       if (card->flags & ICN_FLAGS_B1ACTIVE) {
+               icn_pollbchan_receive(0, card);
+               icn_pollbchan_send(0, card);
+       }
+       if (card->flags & ICN_FLAGS_B2ACTIVE) {
+               icn_pollbchan_receive(1, card);
+               icn_pollbchan_send(1, card);
+       }
+       if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
+               /* schedule b-channel polling again */
+               spin_lock_irqsave(&card->lock, flags);
+               mod_timer(&card->rb_timer, jiffies + ICN_TIMER_BCREAD);
+               card->flags |= ICN_FLAGS_RBTIMER;
+               spin_unlock_irqrestore(&card->lock, flags);
+       } else
+               card->flags &= ~ICN_FLAGS_RBTIMER;
+}
+
+typedef struct icn_stat {
+       char *statstr;
+       int command;
+       int action;
+} icn_stat;
+/* *INDENT-OFF* */
+static icn_stat icn_stat_table[] =
+{
+       {"BCON_",          ISDN_STAT_BCONN, 1}, /* B-Channel connected        */
+       {"BDIS_",          ISDN_STAT_BHUP,  2}, /* B-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  */
+       {"CIF",            ISDN_STAT_CINF,  5}, /* Charge-info, 1TR6-type     */
+       {"AOC",            ISDN_STAT_CINF,  6}, /* Charge-info, DSS1-type     */
+       {"CAU",            ISDN_STAT_CAUSE, 7}, /* Cause code                 */
+       {"TEI OK",         ISDN_STAT_RUN,   0}, /* Card connected to wallplug */
+       {"E_L1: ACT FAIL", ISDN_STAT_BHUP,  8}, /* Layer-1 activation failed  */
+       {"E_L2: DATA LIN", ISDN_STAT_BHUP,  8}, /* Layer-2 data link lost     */
+       {"E_L1: ACTIVATION FAILED",
+        ISDN_STAT_BHUP,  8},   /* Layer-1 activation failed  */
+       {NULL, 0, -1}
+};
+/* *INDENT-ON* */
+
+
+/*
+ * Check Statusqueue-Pointer from isdn-cards.
+ * If there are new status-replies from the interface, check
+ * them against B-Channel-connects/disconnects and set flags accordingly.
+ * Wake-Up any processes, who are reading the status-device.
+ * If there are B-Channels open, initiate a timer-callback to
+ * icn_pollbchan().
+ * This routine is called periodically via timer.
+ */
+
+static void
+icn_parse_status(u_char *status, int channel, icn_card *card)
+{
+       icn_stat *s = icn_stat_table;
+       int action = -1;
+       unsigned long flags;
+       isdn_ctrl cmd;
+
+       while (s->statstr) {
+               if (!strncmp(status, s->statstr, strlen(s->statstr))) {
+                       cmd.command = s->command;
+                       action = s->action;
+                       break;
+               }
+               s++;
+       }
+       if (action == -1)
+               return;
+       cmd.driver = card->myid;
+       cmd.arg = channel;
+       switch (action) {
+       case 11:
+               spin_lock_irqsave(&card->lock, flags);
+               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;
+                       spin_unlock_irqrestore(&card->lock, flags);
+                       card->interface.statcallb(&cmd);
+               } else
+                       spin_unlock_irqrestore(&card->lock, flags);
+               break;
+       case 1:
+               spin_lock_irqsave(&card->lock, flags);
+               icn_free_queue(card, channel);
+               card->flags |= (channel) ?
+                       ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
+               spin_unlock_irqrestore(&card->lock, flags);
+               break;
+       case 2:
+               spin_lock_irqsave(&card->lock, flags);
+               card->flags &= ~((channel) ?
+                                ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
+               icn_free_queue(card, channel);
+               card->rcvidx[channel] = 0;
+               spin_unlock_irqrestore(&card->lock, flags);
+               break;
+       case 3:
+       {
+               char *t = status + 6;
+               char *s = strchr(t, ',');
+
+               *s++ = '\0';
+               strlcpy(cmd.parm.setup.phone, t,
+                       sizeof(cmd.parm.setup.phone));
+               s = strchr(t = s, ',');
+               *s++ = '\0';
+               if (!strlen(t))
+                       cmd.parm.setup.si1 = 0;
+               else
+                       cmd.parm.setup.si1 =
+                               simple_strtoul(t, NULL, 10);
+               s = strchr(t = s, ',');
+               *s++ = '\0';
+               if (!strlen(t))
+                       cmd.parm.setup.si2 = 0;
+               else
+                       cmd.parm.setup.si2 =
+                               simple_strtoul(t, NULL, 10);
+               strlcpy(cmd.parm.setup.eazmsn, s,
+                       sizeof(cmd.parm.setup.eazmsn));
+       }
+       cmd.parm.setup.plan = 0;
+       cmd.parm.setup.screen = 0;
+       break;
+       case 4:
+               sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
+               sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
+               cmd.parm.setup.si1 = 7;
+               cmd.parm.setup.si2 = 0;
+               cmd.parm.setup.plan = 0;
+               cmd.parm.setup.screen = 0;
+               break;
+       case 5:
+               strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
+               break;
+       case 6:
+               snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
+                        (int) simple_strtoul(status + 7, NULL, 16));
+               break;
+       case 7:
+               status += 3;
+               if (strlen(status) == 4)
+                       snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
+                                status + 2, *status, *(status + 1));
+               else
+                       strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
+               break;
+       case 8:
+               spin_lock_irqsave(&card->lock, flags);
+               card->flags &= ~ICN_FLAGS_B1ACTIVE;
+               icn_free_queue(card, 0);
+               card->rcvidx[0] = 0;
+               spin_unlock_irqrestore(&card->lock, flags);
+               cmd.arg = 0;
+               cmd.driver = card->myid;
+               card->interface.statcallb(&cmd);
+               cmd.command = ISDN_STAT_DHUP;
+               cmd.arg = 0;
+               cmd.driver = card->myid;
+               card->interface.statcallb(&cmd);
+               cmd.command = ISDN_STAT_BHUP;
+               spin_lock_irqsave(&card->lock, flags);
+               card->flags &= ~ICN_FLAGS_B2ACTIVE;
+               icn_free_queue(card, 1);
+               card->rcvidx[1] = 0;
+               spin_unlock_irqrestore(&card->lock, flags);
+               cmd.arg = 1;
+               cmd.driver = card->myid;
+               card->interface.statcallb(&cmd);
+               cmd.command = ISDN_STAT_DHUP;
+               cmd.arg = 1;
+               cmd.driver = card->myid;
+               break;
+       }
+       card->interface.statcallb(&cmd);
+       return;
+}
+
+static void
+icn_putmsg(icn_card *card, unsigned char c)
+{
+       ulong flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+       if (card->msg_buf_write == card->msg_buf_read) {
+               if (++card->msg_buf_read > card->msg_buf_end)
+                       card->msg_buf_read = card->msg_buf;
+       }
+       if (card->msg_buf_write > card->msg_buf_end)
+               card->msg_buf_write = card->msg_buf;
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void
+icn_polldchan(unsigned long data)
+{
+       icn_card *card = (icn_card *) data;
+       int mch = card->secondhalf ? 2 : 0;
+       int avail = 0;
+       int left;
+       u_char c;
+       int ch;
+       unsigned long flags;
+       int i;
+       u_char *p;
+       isdn_ctrl cmd;
+
+       if (icn_trymaplock_channel(card, mch)) {
+               avail = msg_avail;
+               for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
+                       c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
+                       icn_putmsg(card, c);
+                       if (c == 0xff) {
+                               card->imsg[card->iptr] = 0;
+                               card->iptr = 0;
+                               if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
+                                   card->imsg[1] <= '2' && card->imsg[2] == ';') {
+                                       ch = (card->imsg[1] - '0') - 1;
+                                       p = &card->imsg[3];
+                                       icn_parse_status(p, ch, card);
+                               } else {
+                                       p = card->imsg;
+                                       if (!strncmp(p, "DRV1.", 5)) {
+                                               u_char vstr[10];
+                                               u_char *q = vstr;
+
+                                               printk(KERN_INFO "icn: (%s) %s\n", CID, p);
+                                               if (!strncmp(p + 7, "TC", 2)) {
+                                                       card->ptype = ISDN_PTYPE_1TR6;
+                                                       card->interface.features |= ISDN_FEATURE_P_1TR6;
+                                                       printk(KERN_INFO
+                                                              "icn: (%s) 1TR6-Protocol loaded and running\n", CID);
+                                               }
+                                               if (!strncmp(p + 7, "EC", 2)) {
+                                                       card->ptype = ISDN_PTYPE_EURO;
+                                                       card->interface.features |= ISDN_FEATURE_P_EURO;
+                                                       printk(KERN_INFO
+                                                              "icn: (%s) Euro-Protocol loaded and running\n", CID);
+                                               }
+                                               p = strstr(card->imsg, "BRV") + 3;
+                                               while (*p) {
+                                                       if (*p >= '0' && *p <= '9')
+                                                               *q++ = *p;
+                                                       p++;
+                                               }
+                                               *q = '\0';
+                                               strcat(vstr, "000");
+                                               vstr[3] = '\0';
+                                               card->fw_rev = (int) simple_strtoul(vstr, NULL, 10);
+                                               continue;
+
+                                       }
+                               }
+                       } else {
+                               card->imsg[card->iptr] = c;
+                               if (card->iptr < 59)
+                                       card->iptr++;
+                       }
+               }
+               writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
+               icn_release_channel();
+       }
+       if (avail) {
+               cmd.command = ISDN_STAT_STAVAIL;
+               cmd.driver = card->myid;
+               cmd.arg = avail;
+               card->interface.statcallb(&cmd);
+       }
+       spin_lock_irqsave(&card->lock, flags);
+       if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
+               if (!(card->flags & ICN_FLAGS_RBTIMER)) {
+                       /* schedule b-channel polling */
+                       card->flags |= ICN_FLAGS_RBTIMER;
+                       del_timer(&card->rb_timer);
+                       card->rb_timer.function = icn_pollbchan;
+                       card->rb_timer.data = (unsigned long) card;
+                       card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+                       add_timer(&card->rb_timer);
+               }
+       /* schedule again */
+       mod_timer(&card->st_timer, jiffies + ICN_TIMER_DCREAD);
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* Append a packet to the transmit buffer-queue.
+ * Parameters:
+ *   channel = Number of B-channel
+ *   skb     = pointer to sk_buff
+ *   card    = pointer to card-struct
+ * Return:
+ *   Number of bytes transferred, -E??? on error
+ */
+
+static int
+icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card *card)
+{
+       int len = skb->len;
+       unsigned long flags;
+       struct sk_buff *nskb;
+
+       if (len > 4000) {
+               printk(KERN_WARNING
+                      "icn: Send packet too large\n");
+               return -EINVAL;
+       }
+       if (len) {
+               if (!(card->flags & (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE))
+                       return 0;
+               if (card->sndcount[channel] > ICN_MAX_SQUEUE)
+                       return 0;
+               /* TODO test headroom or use skb->nb to flag ACK */
+               nskb = skb_clone(skb, GFP_ATOMIC);
+               if (nskb) {
+                       /* Push ACK flag as one
+                        * byte in front of data.
+                        */
+                       *(skb_push(nskb, 1)) = ack ? 1 : 0;
+                       skb_queue_tail(&card->spqueue[channel], nskb);
+                       dev_kfree_skb(skb);
+               } else
+                       len = 0;
+               spin_lock_irqsave(&card->lock, flags);
+               card->sndcount[channel] += len;
+               spin_unlock_irqrestore(&card->lock, flags);
+       }
+       return len;
+}
+
+/*
+ * Check card's status after starting the bootstrap loader.
+ * On entry, the card's shared memory has already to be mapped.
+ * Return:
+ *   0 on success (Boot loader ready)
+ *   -EIO on failure (timeout)
+ */
+static int
+icn_check_loader(int cardnumber)
+{
+       int timer = 0;
+
+       while (1) {
+#ifdef BOOT_DEBUG
+               printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
+#endif
+               if (readb(&dev.shmem->data_control.scns) ||
+                   readb(&dev.shmem->data_control.scnr)) {
+                       if (timer++ > 5) {
+                               printk(KERN_WARNING
+                                      "icn: Boot-Loader %d timed out.\n",
+                                      cardnumber);
+                               icn_release_channel();
+                               return -EIO;
+                       }
+#ifdef BOOT_DEBUG
+                       printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
+#endif
+                       msleep_interruptible(ICN_BOOT_TIMEOUT1);
+               } else {
+#ifdef BOOT_DEBUG
+                       printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
+#endif
+                       icn_release_channel();
+                       return 0;
+               }
+       }
+}
+
+/* Load the boot-code into the interface-card's memory and start it.
+ * Always called from user-process.
+ *
+ * Parameters:
+ *            buffer = pointer to packet
+ * Return:
+ *        0 if successfully loaded
+ */
+
+#ifdef BOOT_DEBUG
+#define SLEEP(sec) {                                           \
+               int slsec = sec;                                \
+               printk(KERN_DEBUG "SLEEP(%d)\n", slsec);        \
+               while (slsec) {                                 \
+                       msleep_interruptible(1000);             \
+                       slsec--;                                \
+               }                                               \
+       }
+#else
+#define SLEEP(sec)
+#endif
+
+static int
+icn_loadboot(u_char __user *buffer, icn_card *card)
+{
+       int ret;
+       u_char *codebuf;
+       unsigned long flags;
+
+#ifdef BOOT_DEBUG
+       printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
+#endif
+       if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) {
+               printk(KERN_WARNING "icn: Could not allocate code buffer\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+       if (copy_from_user(codebuf, buffer, ICN_CODE_STAGE1)) {
+               ret = -EFAULT;
+               goto out_kfree;
+       }
+       if (!card->rvalid) {
+               if (!request_region(card->port, ICN_PORTLEN, card->regname)) {
+                       printk(KERN_WARNING
+                              "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+                              CID,
+                              card->port,
+                              card->port + ICN_PORTLEN);
+                       ret = -EBUSY;
+                       goto out_kfree;
+               }
+               card->rvalid = 1;
+               if (card->doubleS0)
+                       card->other->rvalid = 1;
+       }
+       if (!dev.mvalid) {
+               if (!request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)")) {
+                       printk(KERN_WARNING
+                              "icn: memory at 0x%08lx in use.\n", dev.memaddr);
+                       ret = -EBUSY;
+                       goto out_kfree;
+               }
+               dev.shmem = ioremap(dev.memaddr, 0x4000);
+               dev.mvalid = 1;
+       }
+       OUTB_P(0, ICN_RUN);     /* Reset Controller */
+       OUTB_P(0, ICN_MAPRAM);  /* Disable RAM      */
+       icn_shiftout(ICN_CFG, 0x0f, 3, 4);      /* Windowsize= 16k  */
+       icn_shiftout(ICN_CFG, dev.memaddr, 23, 10);     /* Set RAM-Addr.    */
+#ifdef BOOT_DEBUG
+       printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
+#endif
+       SLEEP(1);
+#ifdef BOOT_DEBUG
+       printk(KERN_DEBUG "Map Bank 0\n");
+#endif
+       spin_lock_irqsave(&dev.devlock, flags);
+       icn_map_channel(card, 0);       /* Select Bank 0    */
+       icn_lock_channel(card, 0);      /* Lock Bank 0      */
+       spin_unlock_irqrestore(&dev.devlock, flags);
+       SLEEP(1);
+       memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);       /* Copy code        */
+#ifdef BOOT_DEBUG
+       printk(KERN_DEBUG "Bootloader transferred\n");
+#endif
+       if (card->doubleS0) {
+               SLEEP(1);
+#ifdef BOOT_DEBUG
+               printk(KERN_DEBUG "Map Bank 8\n");
+#endif
+               spin_lock_irqsave(&dev.devlock, flags);
+               __icn_release_channel();
+               icn_map_channel(card, 2);       /* Select Bank 8   */
+               icn_lock_channel(card, 2);      /* Lock Bank 8     */
+               spin_unlock_irqrestore(&dev.devlock, flags);
+               SLEEP(1);
+               memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);       /* Copy code        */
+#ifdef BOOT_DEBUG
+               printk(KERN_DEBUG "Bootloader transferred\n");
+#endif
+       }
+       SLEEP(1);
+       OUTB_P(0xff, ICN_RUN);  /* Start Boot-Code */
+       if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) {
+               goto out_kfree;
+       }
+       if (!card->doubleS0) {
+               ret = 0;
+               goto out_kfree;
+       }
+       /* reached only, if we have a Double-S0-Card */
+#ifdef BOOT_DEBUG
+       printk(KERN_DEBUG "Map Bank 0\n");
+#endif
+       spin_lock_irqsave(&dev.devlock, flags);
+       icn_map_channel(card, 0);       /* Select Bank 0   */
+       icn_lock_channel(card, 0);      /* Lock Bank 0     */
+       spin_unlock_irqrestore(&dev.devlock, flags);
+       SLEEP(1);
+       ret = (icn_check_loader(1));
+
+out_kfree:
+       kfree(codebuf);
+out:
+       return ret;
+}
+
+static int
+icn_loadproto(u_char __user *buffer, icn_card *card)
+{
+       register u_char __user *p = buffer;
+       u_char codebuf[256];
+       uint left = ICN_CODE_STAGE2;
+       uint cnt;
+       int timer;
+       unsigned long flags;
+
+#ifdef BOOT_DEBUG
+       printk(KERN_DEBUG "icn_loadproto called\n");
+#endif
+       if (!access_ok(VERIFY_READ, buffer, ICN_CODE_STAGE2))
+               return -EFAULT;
+       timer = 0;
+       spin_lock_irqsave(&dev.devlock, flags);
+       if (card->secondhalf) {
+               icn_map_channel(card, 2);
+               icn_lock_channel(card, 2);
+       } else {
+               icn_map_channel(card, 0);
+               icn_lock_channel(card, 0);
+       }
+       spin_unlock_irqrestore(&dev.devlock, flags);
+       while (left) {
+               if (sbfree) {   /* If there is a free buffer...  */
+                       cnt = left;
+                       if (cnt > 256)
+                               cnt = 256;
+                       if (copy_from_user(codebuf, p, cnt)) {
+                               icn_maprelease_channel(card, 0);
+                               return -EFAULT;
+                       }
+                       memcpy_toio(&sbuf_l, codebuf, cnt);     /* copy data                     */
+                       sbnext; /* switch to next buffer         */
+                       p += cnt;
+                       left -= cnt;
+                       timer = 0;
+               } else {
+#ifdef BOOT_DEBUG
+                       printk(KERN_DEBUG "boot 2 !sbfree\n");
+#endif
+                       if (timer++ > 5) {
+                               icn_maprelease_channel(card, 0);
+                               return -EIO;
+                       }
+                       schedule_timeout_interruptible(10);
+               }
+       }
+       writeb(0x20, &sbuf_n);
+       timer = 0;
+       while (1) {
+               if (readb(&cmd_o) || readb(&cmd_i)) {
+#ifdef BOOT_DEBUG
+                       printk(KERN_DEBUG "Proto?\n");
+#endif
+                       if (timer++ > 5) {
+                               printk(KERN_WARNING
+                                      "icn: (%s) Protocol timed out.\n",
+                                      CID);
+#ifdef BOOT_DEBUG
+                               printk(KERN_DEBUG "Proto TO!\n");
+#endif
+                               icn_maprelease_channel(card, 0);
+                               return -EIO;
+                       }
+#ifdef BOOT_DEBUG
+                       printk(KERN_DEBUG "Proto TO?\n");
+#endif
+                       msleep_interruptible(ICN_BOOT_TIMEOUT1);
+               } else {
+                       if ((card->secondhalf) || (!card->doubleS0)) {
+#ifdef BOOT_DEBUG
+                               printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
+                                      card->secondhalf);
+#endif
+                               spin_lock_irqsave(&card->lock, flags);
+                               init_timer(&card->st_timer);
+                               card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+                               card->st_timer.function = icn_polldchan;
+                               card->st_timer.data = (unsigned long) card;
+                               add_timer(&card->st_timer);
+                               card->flags |= ICN_FLAGS_RUNNING;
+                               if (card->doubleS0) {
+                                       init_timer(&card->other->st_timer);
+                                       card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+                                       card->other->st_timer.function = icn_polldchan;
+                                       card->other->st_timer.data = (unsigned long) card->other;
+                                       add_timer(&card->other->st_timer);
+                                       card->other->flags |= ICN_FLAGS_RUNNING;
+                               }
+                               spin_unlock_irqrestore(&card->lock, flags);
+                       }
+                       icn_maprelease_channel(card, 0);
+                       return 0;
+               }
+       }
+}
+
+/* Read the Status-replies from the Interface */
+static int
+icn_readstatus(u_char __user *buf, int len, icn_card *card)
+{
+       int count;
+       u_char __user *p;
+
+       for (p = buf, count = 0; count < len; p++, count++) {
+               if (card->msg_buf_read == card->msg_buf_write)
+                       return count;
+               if (put_user(*card->msg_buf_read++, p))
+                       return -EFAULT;
+               if (card->msg_buf_read > card->msg_buf_end)
+                       card->msg_buf_read = card->msg_buf;
+       }
+       return count;
+}
+
+/* Put command-strings into the command-queue of the Interface */
+static int
+icn_writecmd(const u_char *buf, int len, int user, icn_card *card)
+{
+       int mch = card->secondhalf ? 2 : 0;
+       int pp;
+       int i;
+       int count;
+       int xcount;
+       int ocount;
+       int loop;
+       unsigned long flags;
+       int lastmap_channel;
+       struct icn_card *lastmap_card;
+       u_char *p;
+       isdn_ctrl cmd;
+       u_char msg[0x100];
+
+       ocount = 1;
+       xcount = loop = 0;
+       while (len) {
+               count = cmd_free;
+               if (count > len)
+                       count = len;
+               if (user) {
+                       if (copy_from_user(msg, buf, count))
+                               return -EFAULT;
+               } else
+                       memcpy(msg, buf, count);
+
+               spin_lock_irqsave(&dev.devlock, flags);
+               lastmap_card = dev.mcard;
+               lastmap_channel = dev.channel;
+               icn_map_channel(card, mch);
+
+               icn_putmsg(card, '>');
+               for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
+                            ++) {
+                       writeb((*p == '\n') ? 0xff : *p,
+                              &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
+                       len--;
+                       xcount++;
+                       icn_putmsg(card, *p);
+                       if ((*p == '\n') && (i > 1)) {
+                               icn_putmsg(card, '>');
+                               ocount++;
+                       }
+                       ocount++;
+               }
+               writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
+               if (lastmap_card)
+                       icn_map_channel(lastmap_card, lastmap_channel);
+               spin_unlock_irqrestore(&dev.devlock, flags);
+               if (len) {
+                       mdelay(1);
+                       if (loop++ > 20)
+                               break;
+               } else
+                       break;
+       }
+       if (len && (!user))
+               printk(KERN_WARNING "icn: writemsg incomplete!\n");
+       cmd.command = ISDN_STAT_STAVAIL;
+       cmd.driver = card->myid;
+       cmd.arg = ocount;
+       card->interface.statcallb(&cmd);
+       return xcount;
+}
+
+/*
+ * Delete card's pending timers, send STOP to linklevel
+ */
+static void
+icn_stopcard(icn_card *card)
+{
+       unsigned long flags;
+       isdn_ctrl cmd;
+
+       spin_lock_irqsave(&card->lock, flags);
+       if (card->flags & ICN_FLAGS_RUNNING) {
+               card->flags &= ~ICN_FLAGS_RUNNING;
+               del_timer(&card->st_timer);
+               del_timer(&card->rb_timer);
+               spin_unlock_irqrestore(&card->lock, flags);
+               cmd.command = ISDN_STAT_STOP;
+               cmd.driver = card->myid;
+               card->interface.statcallb(&cmd);
+               if (card->doubleS0)
+                       icn_stopcard(card->other);
+       } else
+               spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void
+icn_stopallcards(void)
+{
+       icn_card *p = cards;
+
+       while (p) {
+               icn_stopcard(p);
+               p = p->next;
+       }
+}
+
+/*
+ * Unmap all cards, because some of them may be mapped accidetly during
+ * autoprobing of some network drivers (SMC-driver?)
+ */
+static void
+icn_disable_cards(void)
+{
+       icn_card *card = cards;
+
+       while (card) {
+               if (!request_region(card->port, ICN_PORTLEN, "icn-isdn")) {
+                       printk(KERN_WARNING
+                              "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+                              CID,
+                              card->port,
+                              card->port + ICN_PORTLEN);
+               } else {
+                       OUTB_P(0, ICN_RUN);     /* Reset Controller     */
+                       OUTB_P(0, ICN_MAPRAM);  /* Disable RAM          */
+                       release_region(card->port, ICN_PORTLEN);
+               }
+               card = card->next;
+       }
+}
+
+static int
+icn_command(isdn_ctrl *c, icn_card *card)
+{
+       ulong a;
+       ulong flags;
+       int i;
+       char cbuf[80];
+       isdn_ctrl cmd;
+       icn_cdef cdef;
+       char __user *arg;
+
+       switch (c->command) {
+       case ISDN_CMD_IOCTL:
+               memcpy(&a, c->parm.num, sizeof(ulong));
+               arg = (char __user *)a;
+               switch (c->arg) {
+               case ICN_IOCTL_SETMMIO:
+                       if (dev.memaddr != (a & 0x0ffc000)) {
+                               if (!request_mem_region(a & 0x0ffc000, 0x4000, "icn-isdn (all cards)")) {
+                                       printk(KERN_WARNING
+                                              "icn: memory at 0x%08lx in use.\n",
+                                              a & 0x0ffc000);
+                                       return -EINVAL;
+                               }
+                               release_mem_region(a & 0x0ffc000, 0x4000);
+                               icn_stopallcards();
+                               spin_lock_irqsave(&card->lock, flags);
+                               if (dev.mvalid) {
+                                       iounmap(dev.shmem);
+                                       release_mem_region(dev.memaddr, 0x4000);
+                               }
+                               dev.mvalid = 0;
+                               dev.memaddr = a & 0x0ffc000;
+                               spin_unlock_irqrestore(&card->lock, flags);
+                               printk(KERN_INFO
+                                      "icn: (%s) mmio set to 0x%08lx\n",
+                                      CID,
+                                      dev.memaddr);
+                       }
+                       break;
+               case ICN_IOCTL_GETMMIO:
+                       return (long) dev.memaddr;
+               case ICN_IOCTL_SETPORT:
+                       if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
+                           || a == 0x340 || a == 0x350 || a == 0x360 ||
+                           a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
+                           || a == 0x348 || a == 0x358 || a == 0x368) {
+                               if (card->port != (unsigned short) a) {
+                                       if (!request_region((unsigned short) a, ICN_PORTLEN, "icn-isdn")) {
+                                               printk(KERN_WARNING
+                                                      "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+                                                      CID, (int) a, (int) a + ICN_PORTLEN);
+                                               return -EINVAL;
+                                       }
+                                       release_region((unsigned short) a, ICN_PORTLEN);
+                                       icn_stopcard(card);
+                                       spin_lock_irqsave(&card->lock, flags);
+                                       if (card->rvalid)
+                                               release_region(card->port, ICN_PORTLEN);
+                                       card->port = (unsigned short) a;
+                                       card->rvalid = 0;
+                                       if (card->doubleS0) {
+                                               card->other->port = (unsigned short) a;
+                                               card->other->rvalid = 0;
+                                       }
+                                       spin_unlock_irqrestore(&card->lock, flags);
+                                       printk(KERN_INFO
+                                              "icn: (%s) port set to 0x%03x\n",
+                                              CID, card->port);
+                               }
+                       } else
+                               return -EINVAL;
+                       break;
+               case ICN_IOCTL_GETPORT:
+                       return (int) card->port;
+               case ICN_IOCTL_GETDOUBLE:
+                       return (int) card->doubleS0;
+               case ICN_IOCTL_DEBUGVAR:
+                       if (copy_to_user(arg,
+                                        &card,
+                                        sizeof(ulong)))
+                               return -EFAULT;
+                       a += sizeof(ulong);
+                       {
+                               ulong l = (ulong)&dev;
+                               if (copy_to_user(arg,
+                                                &l,
+                                                sizeof(ulong)))
+                                       return -EFAULT;
+                       }
+                       return 0;
+               case ICN_IOCTL_LOADBOOT:
+                       if (dev.firstload) {
+                               icn_disable_cards();
+                               dev.firstload = 0;
+                       }
+                       icn_stopcard(card);
+                       return (icn_loadboot(arg, card));
+               case ICN_IOCTL_LOADPROTO:
+                       icn_stopcard(card);
+                       if ((i = (icn_loadproto(arg, card))))
+                               return i;
+                       if (card->doubleS0)
+                               i = icn_loadproto(arg + ICN_CODE_STAGE2, card->other);
+                       return i;
+                       break;
+               case ICN_IOCTL_ADDCARD:
+                       if (!dev.firstload)
+                               return -EBUSY;
+                       if (copy_from_user(&cdef,
+                                          arg,
+                                          sizeof(cdef)))
+                               return -EFAULT;
+                       return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
+                       break;
+               case ICN_IOCTL_LEASEDCFG:
+                       if (a) {
+                               if (!card->leased) {
+                                       card->leased = 1;
+                                       while (card->ptype == ISDN_PTYPE_UNKNOWN) {
+                                               msleep_interruptible(ICN_BOOT_TIMEOUT1);
+                                       }
+                                       msleep_interruptible(ICN_BOOT_TIMEOUT1);
+                                       sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
+                                               (a & 1) ? '1' : 'C', (a & 2) ? '2' : 'C');
+                                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+                                       printk(KERN_INFO
+                                              "icn: (%s) Leased-line mode enabled\n",
+                                              CID);
+                                       cmd.command = ISDN_STAT_RUN;
+                                       cmd.driver = card->myid;
+                                       cmd.arg = 0;
+                                       card->interface.statcallb(&cmd);
+                               }
+                       } else {
+                               if (card->leased) {
+                                       card->leased = 0;
+                                       sprintf(cbuf, "00;FV2OFF\n");
+                                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+                                       printk(KERN_INFO
+                                              "icn: (%s) Leased-line mode disabled\n",
+                                              CID);
+                                       cmd.command = ISDN_STAT_RUN;
+                                       cmd.driver = card->myid;
+                                       cmd.arg = 0;
+                                       card->interface.statcallb(&cmd);
+                               }
+                       }
+                       return 0;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case ISDN_CMD_DIAL:
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (card->leased)
+                       break;
+               if ((c->arg & 255) < ICN_BCH) {
+                       char *p;
+                       char dcode[4];
+
+                       a = c->arg;
+                       p = c->parm.setup.phone;
+                       if (*p == 's' || *p == 'S') {
+                               /* Dial for SPV */
+                               p++;
+                               strcpy(dcode, "SCA");
+                       } else
+                               /* Normal Dial */
+                               strcpy(dcode, "CAL");
+                       snprintf(cbuf, sizeof(cbuf),
+                                "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
+                                dcode, p, c->parm.setup.si1,
+                                c->parm.setup.si2, c->parm.setup.eazmsn);
+                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+               }
+               break;
+       case ISDN_CMD_ACCEPTD:
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (c->arg < ICN_BCH) {
+                       a = c->arg + 1;
+                       if (card->fw_rev >= 300) {
+                               switch (card->l2_proto[a - 1]) {
+                               case ISDN_PROTO_L2_X75I:
+                                       sprintf(cbuf, "%02d;BX75\n", (int) a);
+                                       break;
+                               case ISDN_PROTO_L2_HDLC:
+                                       sprintf(cbuf, "%02d;BTRA\n", (int) a);
+                                       break;
+                               }
+                               i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+                       }
+                       sprintf(cbuf, "%02d;DCON_R\n", (int) a);
+                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+               }
+               break;
+       case ISDN_CMD_ACCEPTB:
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (c->arg < ICN_BCH) {
+                       a = c->arg + 1;
+                       if (card->fw_rev >= 300)
+                               switch (card->l2_proto[a - 1]) {
+                               case ISDN_PROTO_L2_X75I:
+                                       sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
+                                       break;
+                               case ISDN_PROTO_L2_HDLC:
+                                       sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
+                                       break;
+                               } else
+                               sprintf(cbuf, "%02d;BCON_R\n", (int) a);
+                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+               }
+               break;
+       case ISDN_CMD_HANGUP:
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (c->arg < ICN_BCH) {
+                       a = c->arg + 1;
+                       sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
+                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+               }
+               break;
+       case ISDN_CMD_SETEAZ:
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (card->leased)
+                       break;
+               if (c->arg < ICN_BCH) {
+                       a = c->arg + 1;
+                       if (card->ptype == ISDN_PTYPE_EURO) {
+                               sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
+                                       c->parm.num[0] ? "N" : "ALL", c->parm.num);
+                       } else
+                               sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
+                                       c->parm.num[0] ? (char *)(c->parm.num) : "0123456789");
+                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+               }
+               break;
+       case ISDN_CMD_CLREAZ:
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               if (card->leased)
+                       break;
+               if (c->arg < ICN_BCH) {
+                       a = c->arg + 1;
+                       if (card->ptype == ISDN_PTYPE_EURO)
+                               sprintf(cbuf, "%02d;MSNC\n", (int) a);
+                       else
+                               sprintf(cbuf, "%02d;EAZC\n", (int) a);
+                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+               }
+               break;
+       case ISDN_CMD_SETL2:
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               if ((c->arg & 255) < ICN_BCH) {
+                       a = c->arg;
+                       switch (a >> 8) {
+                       case ISDN_PROTO_L2_X75I:
+                               sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
+                               break;
+                       case ISDN_PROTO_L2_HDLC:
+                               sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+                       card->l2_proto[a & 255] = (a >> 8);
+               }
+               break;
+       case ISDN_CMD_SETL3:
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * Find card with given driverId
+ */
+static inline icn_card *
+icn_findcard(int driverid)
+{
+       icn_card *p = cards;
+
+       while (p) {
+               if (p->myid == driverid)
+                       return p;
+               p = p->next;
+       }
+       return (icn_card *) 0;
+}
+
+/*
+ * Wrapper functions for interface to linklevel
+ */
+static int
+if_command(isdn_ctrl *c)
+{
+       icn_card *card = icn_findcard(c->driver);
+
+       if (card)
+               return (icn_command(c, card));
+       printk(KERN_ERR
+              "icn: if_command %d called with invalid driverId %d!\n",
+              c->command, c->driver);
+       return -ENODEV;
+}
+
+static int
+if_writecmd(const u_char __user *buf, int len, int id, int channel)
+{
+       icn_card *card = icn_findcard(id);
+
+       if (card) {
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               return (icn_writecmd(buf, len, 1, card));
+       }
+       printk(KERN_ERR
+              "icn: if_writecmd called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+static int
+if_readstatus(u_char __user *buf, int len, int id, int channel)
+{
+       icn_card *card = icn_findcard(id);
+
+       if (card) {
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               return (icn_readstatus(buf, len, card));
+       }
+       printk(KERN_ERR
+              "icn: if_readstatus called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+static int
+if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
+{
+       icn_card *card = icn_findcard(id);
+
+       if (card) {
+               if (!(card->flags & ICN_FLAGS_RUNNING))
+                       return -ENODEV;
+               return (icn_sendbuf(channel, ack, skb, card));
+       }
+       printk(KERN_ERR
+              "icn: if_sendbuf called with invalid driverId!\n");
+       return -ENODEV;
+}
+
+/*
+ * Allocate a new card-struct, initialize it
+ * link it into cards-list and register it at linklevel.
+ */
+static icn_card *
+icn_initcard(int port, char *id)
+{
+       icn_card *card;
+       int i;
+
+       if (!(card = kzalloc(sizeof(icn_card), GFP_KERNEL))) {
+               printk(KERN_WARNING
+                      "icn: (%s) Could not allocate card-struct.\n", id);
+               return (icn_card *) 0;
+       }
+       spin_lock_init(&card->lock);
+       card->port = port;
+       card->interface.owner = THIS_MODULE;
+       card->interface.hl_hdrlen = 1;
+       card->interface.channels = ICN_BCH;
+       card->interface.maxbufsize = 4000;
+       card->interface.command = if_command;
+       card->interface.writebuf_skb = if_sendbuf;
+       card->interface.writecmd = if_writecmd;
+       card->interface.readstat = if_readstatus;
+       card->interface.features = ISDN_FEATURE_L2_X75I |
+               ISDN_FEATURE_L2_HDLC |
+               ISDN_FEATURE_L3_TRANS |
+               ISDN_FEATURE_P_UNKNOWN;
+       card->ptype = ISDN_PTYPE_UNKNOWN;
+       strlcpy(card->interface.id, id, sizeof(card->interface.id));
+       card->msg_buf_write = card->msg_buf;
+       card->msg_buf_read = card->msg_buf;
+       card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
+       for (i = 0; i < ICN_BCH; i++) {
+               card->l2_proto[i] = ISDN_PROTO_L2_X75I;
+               skb_queue_head_init(&card->spqueue[i]);
+       }
+       card->next = cards;
+       cards = card;
+       if (!register_isdn(&card->interface)) {
+               cards = cards->next;
+               printk(KERN_WARNING
+                      "icn: Unable to register %s\n", id);
+               kfree(card);
+               return (icn_card *) 0;
+       }
+       card->myid = card->interface.channels;
+       sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
+       return card;
+}
+
+static int
+icn_addcard(int port, char *id1, char *id2)
+{
+       icn_card *card;
+       icn_card *card2;
+
+       if (!(card = icn_initcard(port, id1))) {
+               return -EIO;
+       }
+       if (!strlen(id2)) {
+               printk(KERN_INFO
+                      "icn: (%s) ICN-2B, port 0x%x added\n",
+                      card->interface.id, port);
+               return 0;
+       }
+       if (!(card2 = icn_initcard(port, id2))) {
+               printk(KERN_INFO
+                      "icn: (%s) half ICN-4B, port 0x%x added\n", id2, port);
+               return 0;
+       }
+       card->doubleS0 = 1;
+       card->secondhalf = 0;
+       card->other = card2;
+       card2->doubleS0 = 1;
+       card2->secondhalf = 1;
+       card2->other = card;
+       printk(KERN_INFO
+              "icn: (%s and %s) ICN-4B, port 0x%x added\n",
+              card->interface.id, card2->interface.id, port);
+       return 0;
+}
+
+#ifndef MODULE
+static int __init
+icn_setup(char *line)
+{
+       char *p, *str;
+       int     ints[3];
+       static char sid[20];
+       static char sid2[20];
+
+       str = get_options(line, 2, ints);
+       if (ints[0])
+               portbase = ints[1];
+       if (ints[0] > 1)
+               membase = (unsigned long)ints[2];
+       if (str && *str) {
+               strlcpy(sid, str, sizeof(sid));
+               icn_id = sid;
+               if ((p = strchr(sid, ','))) {
+                       *p++ = 0;
+                       strcpy(sid2, p);
+                       icn_id2 = sid2;
+               }
+       }
+       return (1);
+}
+__setup("icn=", icn_setup);
+#endif /* MODULE */
+
+static int __init icn_init(void)
+{
+       char *p;
+       char rev[21];
+
+       memset(&dev, 0, sizeof(icn_dev));
+       dev.memaddr = (membase & 0x0ffc000);
+       dev.channel = -1;
+       dev.mcard = NULL;
+       dev.firstload = 1;
+       spin_lock_init(&dev.devlock);
+
+       if ((p = strchr(revision, ':'))) {
+               strncpy(rev, p + 1, 20);
+               rev[20] = '\0';
+               p = strchr(rev, '$');
+               if (p)
+                       *p = 0;
+       } else
+               strcpy(rev, " ??? ");
+       printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
+              dev.memaddr);
+       return (icn_addcard(portbase, icn_id, icn_id2));
+}
+
+static void __exit icn_exit(void)
+{
+       isdn_ctrl cmd;
+       icn_card *card = cards;
+       icn_card *last, *tmpcard;
+       int i;
+       unsigned long flags;
+
+       icn_stopallcards();
+       while (card) {
+               cmd.command = ISDN_STAT_UNLOAD;
+               cmd.driver = card->myid;
+               card->interface.statcallb(&cmd);
+               spin_lock_irqsave(&card->lock, flags);
+               if (card->rvalid) {
+                       OUTB_P(0, ICN_RUN);     /* Reset Controller     */
+                       OUTB_P(0, ICN_MAPRAM);  /* Disable RAM          */
+                       if (card->secondhalf || (!card->doubleS0)) {
+                               release_region(card->port, ICN_PORTLEN);
+                               card->rvalid = 0;
+                       }
+                       for (i = 0; i < ICN_BCH; i++)
+                               icn_free_queue(card, i);
+               }
+               tmpcard = card->next;
+               spin_unlock_irqrestore(&card->lock, flags);
+               card = tmpcard;
+       }
+       card = cards;
+       cards = NULL;
+       while (card) {
+               last = card;
+               card = card->next;
+               kfree(last);
+       }
+       if (dev.mvalid) {
+               iounmap(dev.shmem);
+               release_mem_region(dev.memaddr, 0x4000);
+       }
+       printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
+}
+
+module_init(icn_init);
+module_exit(icn_exit);
diff --git a/drivers/staging/i4l/icn/icn.h b/drivers/staging/i4l/icn/icn.h
new file mode 100644 (file)
index 0000000..f8f2e76
--- /dev/null
@@ -0,0 +1,253 @@
+/* $Id: icn.h,v 1.30.6.5 2001/09/23 22:24:55 kai Exp $
+ *
+ * ISDN lowlevel-module for the ICN active ISDN-Card.
+ *
+ * Copyright 1994 by Fritz Elfert (fritz@isdn4linux.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#ifndef icn_h
+#define icn_h
+
+#define ICN_IOCTL_SETMMIO   0
+#define ICN_IOCTL_GETMMIO   1
+#define ICN_IOCTL_SETPORT   2
+#define ICN_IOCTL_GETPORT   3
+#define ICN_IOCTL_LOADBOOT  4
+#define ICN_IOCTL_LOADPROTO 5
+#define ICN_IOCTL_LEASEDCFG 6
+#define ICN_IOCTL_GETDOUBLE 7
+#define ICN_IOCTL_DEBUGVAR  8
+#define ICN_IOCTL_ADDCARD   9
+
+/* Struct for adding new cards */
+typedef struct icn_cdef {
+       int port;
+       char id1[10];
+       char id2[10];
+} icn_cdef;
+
+#if defined(__KERNEL__) || defined(__DEBUGVAR__)
+
+#ifdef __KERNEL__
+/* Kernel includes */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/slab.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/isdnif.h>
+
+#endif                          /* __KERNEL__ */
+
+/* some useful macros for debugging */
+#ifdef ICN_DEBUG_PORT
+#define OUTB_P(v, p) {printk(KERN_DEBUG "icn: outb_p(0x%02x,0x%03x)\n", v, p); outb_p(v, p);}
+#else
+#define OUTB_P outb
+#endif
+
+/* Defaults for Port-Address and shared-memory */
+#define ICN_BASEADDR 0x320
+#define ICN_PORTLEN (0x04)
+#define ICN_MEMADDR 0x0d0000
+
+#define ICN_FLAGS_B1ACTIVE 1    /* B-Channel-1 is open                     */
+#define ICN_FLAGS_B2ACTIVE 2    /* B-Channel-2 is open                     */
+#define ICN_FLAGS_RUNNING  4    /* Cards driver activated                  */
+#define ICN_FLAGS_RBTIMER  8    /* cyclic scheduling of B-Channel-poll     */
+
+#define ICN_BOOT_TIMEOUT1  1000 /* Delay for Boot-download (msecs)         */
+
+#define ICN_TIMER_BCREAD (HZ / 100)    /* B-Channel poll-cycle                    */
+#define ICN_TIMER_DCREAD (HZ / 2) /* D-Channel poll-cycle                    */
+
+#define ICN_CODE_STAGE1 4096    /* Size of bootcode                        */
+#define ICN_CODE_STAGE2 65536   /* Size of protocol-code                   */
+
+#define ICN_MAX_SQUEUE 8000     /* Max. outstanding send-data (2* hw-buf.) */
+#define ICN_FRAGSIZE (250)      /* Max. size of send-fragments             */
+#define ICN_BCH 2               /* Number of supported channels per card   */
+
+/* type-definitions for accessing the mmap-io-areas */
+
+#define SHM_DCTL_OFFSET (0)     /* Offset to data-controlstructures in shm */
+#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */
+#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm           */
+#define SHM_DBUF_OFFSET (0x2000)       /* Offset to data-buffers in shm           */
+
+/*
+ * Layout of card's data buffers
+ */
+typedef struct {
+       unsigned char length;   /* Bytecount of fragment (max 250)    */
+       unsigned char endflag;  /* 0=last frag., 0xff=frag. continued */
+       unsigned char data[ICN_FRAGSIZE];       /* The data                           */
+       /* Fill to 256 bytes */
+       char unused[0x100 - ICN_FRAGSIZE - 2];
+} frag_buf;
+
+/*
+ * Layout of card's shared memory
+ */
+typedef union {
+       struct {
+               unsigned char scns;     /* Index to free SendFrag.             */
+               unsigned char scnr;     /* Index to active SendFrag   READONLY */
+               unsigned char ecns;     /* Index to free RcvFrag.     READONLY */
+               unsigned char ecnr;     /* Index to valid RcvFrag              */
+               char unused[6];
+               unsigned short fuell1;  /* Internal Buf Bytecount              */
+       } data_control;
+       struct {
+               char unused[SHM_CCTL_OFFSET];
+               unsigned char iopc_i;   /* Read-Ptr Status-Queue      READONLY */
+               unsigned char iopc_o;   /* Write-Ptr Status-Queue              */
+               unsigned char pcio_i;   /* Write-Ptr Command-Queue             */
+               unsigned char pcio_o;   /* Read-Ptr Command Queue     READONLY */
+       } comm_control;
+       struct {
+               char unused[SHM_CBUF_OFFSET];
+               unsigned char pcio_buf[0x100];  /* Ring-Buffer Command-Queue           */
+               unsigned char iopc_buf[0x100];  /* Ring-Buffer Status-Queue            */
+       } comm_buffers;
+       struct {
+               char unused[SHM_DBUF_OFFSET];
+               frag_buf receive_buf[0x10];
+               frag_buf send_buf[0x10];
+       } data_buffers;
+} icn_shmem;
+
+/*
+ * Per card driver data
+ */
+typedef struct icn_card {
+       struct icn_card *next;  /* Pointer to next device struct    */
+       struct icn_card *other; /* Pointer to other card for ICN4B  */
+       unsigned short port;    /* Base-port-address                */
+       int myid;               /* Driver-Nr. assigned by linklevel */
+       int rvalid;             /* IO-portregion has been requested */
+       int leased;             /* Flag: This Adapter is connected  */
+                               /*       to a leased line           */
+       unsigned short flags;   /* Statusflags                      */
+       int doubleS0;           /* Flag: ICN4B                      */
+       int secondhalf;         /* Flag: Second half of a doubleS0  */
+       int fw_rev;             /* Firmware revision loaded         */
+       int ptype;              /* Protocol type (1TR6 or Euro)     */
+       struct timer_list st_timer;   /* Timer for Status-Polls     */
+       struct timer_list rb_timer;   /* Timer for B-Channel-Polls  */
+       u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers  */
+       int rcvidx[ICN_BCH];    /* Index for above buffers          */
+       int l2_proto[ICN_BCH];  /* Current layer-2-protocol         */
+       isdn_if interface;      /* Interface to upper layer         */
+       int iptr;               /* Index to imsg-buffer             */
+       char imsg[60];          /* Internal buf for status-parsing  */
+       char msg_buf[2048];     /* Buffer for status-messages       */
+       char *msg_buf_write;    /* Writepointer for statusbuffer    */
+       char *msg_buf_read;     /* Readpointer for statusbuffer     */
+       char *msg_buf_end;      /* Pointer to end of statusbuffer   */
+       int sndcount[ICN_BCH];  /* Byte-counters for B-Ch.-send     */
+       int xlen[ICN_BCH];      /* Byte-counters/Flags for sent-ACK */
+       struct sk_buff *xskb[ICN_BCH]; /* Current transmitted skb   */
+       struct sk_buff_head spqueue[ICN_BCH];  /* Sendqueue         */
+       char regname[35];       /* Name used for request_region     */
+       u_char xmit_lock[ICN_BCH]; /* Semaphore for pollbchan_send()*/
+       spinlock_t lock;        /* protect critical operations      */
+} icn_card;
+
+/*
+ * Main driver data
+ */
+typedef struct icn_dev {
+       spinlock_t devlock;     /* spinlock to protect this struct  */
+       unsigned long memaddr;  /* Address of memory mapped buffers */
+       icn_shmem __iomem *shmem;       /* Pointer to memory-mapped-buffers */
+       int mvalid;             /* IO-shmem has been requested      */
+       int channel;            /* Currently mapped channel         */
+       struct icn_card *mcard; /* Currently mapped card            */
+       int chanlock;           /* Semaphore for channel-mapping    */
+       int firstload;          /* Flag: firmware never loaded      */
+} icn_dev;
+
+typedef icn_dev *icn_devptr;
+
+#ifdef __KERNEL__
+
+static icn_card *cards = (icn_card *) 0;
+static u_char chan2bank[] =
+{0, 4, 8, 12};                  /* for icn_map_channel() */
+
+static icn_dev dev;
+
+#endif                          /* __KERNEL__ */
+
+/* Utility-Macros */
+
+/* Macros for accessing ports */
+#define ICN_CFG    (card->port)
+#define ICN_MAPRAM (card->port + 1)
+#define ICN_RUN    (card->port + 2)
+#define ICN_BANK   (card->port + 3)
+
+/* Return true, if there is a free transmit-buffer */
+#define sbfree (((readb(&dev.shmem->data_control.scns) + 1) & 0xf) !=  \
+               readb(&dev.shmem->data_control.scnr))
+
+/* Switch to next transmit-buffer */
+#define sbnext (writeb((readb(&dev.shmem->data_control.scns) + 1) & 0xf,       \
+                      &dev.shmem->data_control.scns))
+
+/* Shortcuts for transmit-buffer-access */
+#define sbuf_n dev.shmem->data_control.scns
+#define sbuf_d dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].data
+#define sbuf_l dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].length
+#define sbuf_f dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].endflag
+
+/* Return true, if there is receive-data is available */
+#define rbavl  (readb(&dev.shmem->data_control.ecnr) != \
+               readb(&dev.shmem->data_control.ecns))
+
+/* Switch to next receive-buffer */
+#define rbnext (writeb((readb(&dev.shmem->data_control.ecnr) + 1) & 0xf,       \
+                      &dev.shmem->data_control.ecnr))
+
+/* Shortcuts for receive-buffer-access */
+#define rbuf_n dev.shmem->data_control.ecnr
+#define rbuf_d dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].data
+#define rbuf_l dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].length
+#define rbuf_f dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].endflag
+
+/* Shortcuts for command-buffer-access */
+#define cmd_o (dev.shmem->comm_control.pcio_o)
+#define cmd_i (dev.shmem->comm_control.pcio_i)
+
+/* Return free space in command-buffer */
+#define cmd_free ((readb(&cmd_i) >= readb(&cmd_o)) ?           \
+                 0x100 - readb(&cmd_i) + readb(&cmd_o) :       \
+                 readb(&cmd_o) - readb(&cmd_i))
+
+/* Shortcuts for message-buffer-access */
+#define msg_o (dev.shmem->comm_control.iopc_o)
+#define msg_i (dev.shmem->comm_control.iopc_i)
+
+/* Return length of Message, if avail. */
+#define msg_avail ((readb(&msg_o) > readb(&msg_i)) ?           \
+                  0x100 - readb(&msg_o) + readb(&msg_i) :      \
+                  readb(&msg_i) - readb(&msg_o))
+
+#define CID (card->interface.id)
+
+#endif                          /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif                          /* icn_h */
diff --git a/drivers/staging/i4l/pcbit/Kconfig b/drivers/staging/i4l/pcbit/Kconfig
new file mode 100644 (file)
index 0000000..e9b2dd8
--- /dev/null
@@ -0,0 +1,10 @@
+config ISDN_DRV_PCBIT
+       tristate "PCBIT-D support"
+       depends on ISA && (BROKEN || X86)
+       help
+         This enables support for the PCBIT ISDN-card.  This card is
+         manufactured in Portugal by Octal.  For running this card,
+         additional firmware is necessary, which has to be downloaded into
+         the card using a utility which is distributed separately.  See
+         <file:Documentation/isdn/README> and
+         <file:Documentation/isdn/README.pcbit> for more information.
diff --git a/drivers/staging/i4l/pcbit/Makefile b/drivers/staging/i4l/pcbit/Makefile
new file mode 100644 (file)
index 0000000..2d026c3
--- /dev/null
@@ -0,0 +1,9 @@
+# Makefile for the pcbit ISDN device driver
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_PCBIT)   += pcbit.o
+
+# Multipart objects.
+
+pcbit-y                                := module.o edss1.o drv.o layer2.o capi.o callbacks.o
diff --git a/drivers/staging/i4l/pcbit/callbacks.c b/drivers/staging/i4l/pcbit/callbacks.c
new file mode 100644 (file)
index 0000000..efb6d6a
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Callbacks for the FSM
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ * 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)
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+
+#include <linux/isdnif.h>
+
+#include "pcbit.h"
+#include "layer2.h"
+#include "edss1.h"
+#include "callbacks.h"
+#include "capi.h"
+
+ushort last_ref_num = 1;
+
+/*
+ *  send_conn_req
+ *
+ */
+
+void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+             struct callb_data *cbdata)
+{
+       struct sk_buff *skb;
+       int len;
+       ushort refnum;
+
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "Called Party Number: %s\n",
+              cbdata->data.setup.CalledPN);
+#endif
+       /*
+        * hdr - kmalloc in capi_conn_req
+        *     - kfree   when msg has been sent
+        */
+
+       if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb,
+                                chan->proto)) < 0)
+       {
+               printk("capi_conn_req failed\n");
+               return;
+       }
+
+
+       refnum = last_ref_num++ & 0x7fffU;
+
+       chan->callref = 0;
+       chan->layer2link = 0;
+       chan->snum = 0;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len);
+}
+
+/*
+ *  rcv CONNECT
+ *  will go into ACTIVE state
+ *  send CONN_ACTIVE_RESP
+ *  send Select protocol request
+ */
+
+void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+             struct callb_data *data)
+{
+       isdn_ctrl ictl;
+       struct sk_buff *skb;
+       int len;
+       ushort refnum;
+
+       if ((len = capi_conn_active_resp(chan, &skb)) < 0)
+       {
+               printk("capi_conn_active_req failed\n");
+               return;
+       }
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len);
+
+
+       ictl.command = ISDN_STAT_DCONN;
+       ictl.driver = dev->id;
+       ictl.arg = chan->id;
+       dev->dev_if->statcallb(&ictl);
+
+       /* ACTIVE D-channel */
+
+       /* Select protocol  */
+
+       if ((len = capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) {
+               printk("capi_select_proto_req failed\n");
+               return;
+       }
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
+}
+
+
+/*
+ * Incoming call received
+ * inform user
+ */
+
+void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+            struct callb_data *cbdata)
+{
+       isdn_ctrl ictl;
+       unsigned short refnum;
+       struct sk_buff *skb;
+       int len;
+
+
+       ictl.command = ISDN_STAT_ICALL;
+       ictl.driver = dev->id;
+       ictl.arg = chan->id;
+
+       /*
+        *  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;
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "statstr: %s\n", ictl.num);
+#endif
+
+       dev->dev_if->statcallb(&ictl);
+
+
+       if ((len = capi_conn_resp(chan, &skb)) < 0) {
+               printk(KERN_DEBUG "capi_conn_resp failed\n");
+               return;
+       }
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len);
+}
+
+/*
+ * user has replied
+ * open the channel
+ * send CONNECT message CONNECT_ACTIVE_REQ in CAPI
+ */
+
+void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+            struct callb_data *data)
+{
+       unsigned short refnum;
+       struct sk_buff *skb;
+       int len;
+
+       if ((len = capi_conn_active_req(chan, &skb)) < 0) {
+               printk(KERN_DEBUG "capi_conn_active_req failed\n");
+               return;
+       }
+
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n");
+       pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len);
+}
+
+/*
+ * CONN_ACK arrived
+ * start b-proto selection
+ *
+ */
+
+void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
+            struct callb_data *data)
+{
+       unsigned short refnum;
+       struct sk_buff *skb;
+       int len;
+
+       if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0)
+       {
+               printk("capi_select_proto_req failed\n");
+               return;
+       }
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
+
+}
+
+
+/*
+ * Received disconnect ind on active state
+ * send disconnect resp
+ * send msg to user
+ */
+void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+              struct callb_data *data)
+{
+       struct sk_buff *skb;
+       int len;
+       ushort refnum;
+       isdn_ctrl ictl;
+
+       if ((len = capi_disc_resp(chan, &skb)) < 0) {
+               printk("capi_disc_resp failed\n");
+               return;
+       }
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len);
+
+       ictl.command = ISDN_STAT_BHUP;
+       ictl.driver = dev->id;
+       ictl.arg = chan->id;
+       dev->dev_if->statcallb(&ictl);
+}
+
+
+/*
+ *  User HANGUP on active/call proceeding state
+ *  send disc.req
+ */
+void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+              struct callb_data *data)
+{
+       struct sk_buff *skb;
+       int len;
+       ushort refnum;
+
+       if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0)
+       {
+               printk("capi_disc_req failed\n");
+               return;
+       }
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len);
+}
+
+/*
+ *  Disc confirm received send BHUP
+ *  Problem: when the HL driver sends the disc req itself
+ *           LL receives BHUP
+ */
+void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
+              struct callb_data *data)
+{
+       isdn_ctrl ictl;
+
+       ictl.command = ISDN_STAT_BHUP;
+       ictl.driver = dev->id;
+       ictl.arg = chan->id;
+       dev->dev_if->statcallb(&ictl);
+}
+
+void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan,
+               struct callb_data *data)
+{
+}
+
+/*
+ * send activate b-chan protocol
+ */
+void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+              struct callb_data *data)
+{
+       struct sk_buff *skb;
+       int len;
+       ushort refnum;
+
+       if ((len = capi_activate_transp_req(chan, &skb)) < 0)
+       {
+               printk("capi_conn_activate_transp_req failed\n");
+               return;
+       }
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len);
+}
+
+/*
+ *  Inform User that the B-channel is available
+ */
+void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan,
+            struct callb_data *data)
+{
+       isdn_ctrl ictl;
+
+       ictl.command = ISDN_STAT_BCONN;
+       ictl.driver = dev->id;
+       ictl.arg = chan->id;
+       dev->dev_if->statcallb(&ictl);
+}
diff --git a/drivers/staging/i4l/pcbit/callbacks.h b/drivers/staging/i4l/pcbit/callbacks.h
new file mode 100644 (file)
index 0000000..a036b4a
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Callbacks prototypes for FSM
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef CALLBACKS_H
+#define CALLBACKS_H
+
+
+extern void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                    struct callb_data *data);
+
+extern void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                    struct callb_data *data);
+
+extern void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                   struct callb_data *data);
+extern void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                   struct callb_data *data);
+extern void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                   struct callb_data *data);
+
+extern void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                     struct callb_data *data);
+extern void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                     struct callb_data *data);
+extern void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                     struct callb_data *data);
+
+extern void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                      struct callb_data *data);
+
+extern void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                     struct callb_data *data);
+extern void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                   struct callb_data *data);
+
+#endif
diff --git a/drivers/staging/i4l/pcbit/capi.c b/drivers/staging/i4l/pcbit/capi.c
new file mode 100644 (file)
index 0000000..4e3cbf8
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * CAPI encoder/decoder for
+ * Portugal Telecom CAPI 2.0
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ *
+ * Not compatible with the AVM Gmbh. CAPI 2.0
+ *
+ */
+
+/*
+ *        Documentation:
+ *        - "Common ISDN API - Perfil Português - Versão 2.1",
+ *           Telecom Portugal, Fev 1992.
+ *        - "Common ISDN API - Especificação de protocolos para
+ *           acesso aos canais B", Inesc, Jan 1994.
+ */
+
+/*
+ *        TODO: better decoding of Information Elements
+ *              for debug purposes mainly
+ *              encode our number in CallerPN and ConnectedPN
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+#include <asm/string.h>
+
+#include <linux/isdnif.h>
+
+#include "pcbit.h"
+#include "edss1.h"
+#include "capi.h"
+
+
+/*
+ *  Encoding of CAPI messages
+ *
+ */
+
+int capi_conn_req(const char *calledPN, struct sk_buff **skb, int proto)
+{
+       ushort len;
+
+       /*
+        * length
+        *   AppInfoMask - 2
+        *   BC0         - 3
+        *   BC1         - 1
+        *   Chan        - 2
+        *   Keypad      - 1
+        *   CPN         - 1
+        *   CPSA        - 1
+        *   CalledPN    - 2 + strlen
+        *   CalledPSA   - 1
+        *   rest...     - 4
+        *   ----------------
+        *   Total        18 + strlen
+        */
+
+       len = 18 + strlen(calledPN);
+
+       if (proto == ISDN_PROTO_L2_TRANS)
+               len++;
+
+       if ((*skb = dev_alloc_skb(len)) == NULL) {
+
+               printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n");
+               return -1;
+       }
+
+       /* InfoElmMask */
+       *((ushort *)skb_put(*skb, 2)) = AppInfoMask;
+
+       if (proto == ISDN_PROTO_L2_TRANS)
+       {
+               /* Bearer Capability - Mandatory*/
+               *(skb_put(*skb, 1)) = 3;        /* BC0.Length           */
+               *(skb_put(*skb, 1)) = 0x80;     /* Speech               */
+               *(skb_put(*skb, 1)) = 0x10;     /* Circuit Mode         */
+               *(skb_put(*skb, 1)) = 0x23;     /* A-law                */
+       }
+       else
+       {
+               /* Bearer Capability - Mandatory*/
+               *(skb_put(*skb, 1)) = 2;        /* BC0.Length           */
+               *(skb_put(*skb, 1)) = 0x88;     /* Digital Information  */
+               *(skb_put(*skb, 1)) = 0x90;     /* BC0.Octect4          */
+       }
+
+       /* Bearer Capability - Optional*/
+       *(skb_put(*skb, 1)) = 0;        /* BC1.Length = 0                    */
+
+       *(skb_put(*skb, 1)) = 1;        /* ChannelID.Length = 1              */
+       *(skb_put(*skb, 1)) = 0x83;     /* Basic Interface - Any Channel     */
+
+       *(skb_put(*skb, 1)) = 0;        /* Keypad.Length = 0                 */
+
+
+       *(skb_put(*skb, 1)) = 0;        /* CallingPN.Length = 0              */
+       *(skb_put(*skb, 1)) = 0;        /* CallingPSA.Length = 0             */
+
+       /* Called Party Number */
+       *(skb_put(*skb, 1)) = strlen(calledPN) + 1;
+       *(skb_put(*skb, 1)) = 0x81;
+       memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN));
+
+       /* '#' */
+
+       *(skb_put(*skb, 1)) = 0;       /* CalledPSA.Length = 0     */
+
+       /* LLC.Length  = 0; */
+       /* HLC0.Length = 0; */
+       /* HLC1.Length = 0; */
+       /* UTUS.Length = 0; */
+       memset(skb_put(*skb, 4), 0, 4);
+
+       return len;
+}
+
+int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+
+       if ((*skb = dev_alloc_skb(5)) == NULL) {
+
+               printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n");
+               return -1;
+       }
+
+       *((ushort *)skb_put(*skb, 2)) = chan->callref;
+       *(skb_put(*skb, 1)) = 0x01;  /* ACCEPT_CALL */
+       *(skb_put(*skb, 1)) = 0;
+       *(skb_put(*skb, 1)) = 0;
+
+       return 5;
+}
+
+int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+       /*
+        * 8 bytes
+        */
+
+       if ((*skb = dev_alloc_skb(8)) == NULL) {
+
+               printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n");
+               return -1;
+       }
+
+       *((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
+#endif
+
+       *(skb_put(*skb, 1)) = 0;       /*  BC.Length = 0;          */
+       *(skb_put(*skb, 1)) = 0;       /*  ConnectedPN.Length = 0  */
+       *(skb_put(*skb, 1)) = 0;       /*  PSA.Length              */
+       *(skb_put(*skb, 1)) = 0;       /*  LLC.Length = 0;         */
+       *(skb_put(*skb, 1)) = 0;       /*  HLC.Length = 0;         */
+       *(skb_put(*skb, 1)) = 0;       /*  UTUS.Length = 0;        */
+
+       return 8;
+}
+
+int capi_conn_active_resp(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+       /*
+        * 2 bytes
+        */
+
+       if ((*skb = dev_alloc_skb(2)) == NULL) {
+
+               printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n");
+               return -1;
+       }
+
+       *((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+       return 2;
+}
+
+
+int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
+                         int outgoing)
+{
+
+       /*
+        * 18 bytes
+        */
+
+       if ((*skb = dev_alloc_skb(18)) == NULL) {
+
+               printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n");
+               return -1;
+       }
+
+       *((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+       /* Layer2 protocol */
+
+       switch (chan->proto) {
+       case ISDN_PROTO_L2_X75I:
+               *(skb_put(*skb, 1)) = 0x05;            /* LAPB */
+               break;
+       case ISDN_PROTO_L2_HDLC:
+               *(skb_put(*skb, 1)) = 0x02;
+               break;
+       case ISDN_PROTO_L2_TRANS:
+               /*
+                *      Voice (a-law)
+                */
+               *(skb_put(*skb, 1)) = 0x06;
+               break;
+       default:
+#ifdef DEBUG
+               printk(KERN_DEBUG "Transparent\n");
+#endif
+               *(skb_put(*skb, 1)) = 0x03;
+               break;
+       }
+
+       *(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42);    /* Don't ask */
+       *(skb_put(*skb, 1)) = 0x00;
+
+       *((ushort *) skb_put(*skb, 2)) = MRU;
+
+
+       *(skb_put(*skb, 1)) = 0x08;           /* Modulo */
+       *(skb_put(*skb, 1)) = 0x07;           /* Max Window */
+
+       *(skb_put(*skb, 1)) = 0x01;           /* No Layer3 Protocol */
+
+       /*
+        * 2 - layer3 MTU       [10]
+        *   - Modulo           [12]
+        *   - Window
+        *   - layer1 proto     [14]
+        *   - bitrate
+        *   - sub-channel      [16]
+        *   - layer1dataformat [17]
+        */
+
+       memset(skb_put(*skb, 8), 0, 8);
+
+       return 18;
+}
+
+
+int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+
+       if ((*skb = dev_alloc_skb(7)) == NULL) {
+
+               printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n");
+               return -1;
+       }
+
+       *((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+
+       *(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */
+       *(skb_put(*skb, 1)) = 0x00;             /* Transmit by default */
+
+       *((ushort *) skb_put(*skb, 2)) = MRU;
+
+       *(skb_put(*skb, 1)) = 0x01;             /* Enables reception*/
+
+       return 7;
+}
+
+int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+       ushort data_len;
+
+
+       /*
+        * callref      - 2
+        * layer2link   - 1
+        * wBlockLength - 2
+        * data         - 4
+        * sernum       - 1
+        */
+
+       data_len = skb->len;
+
+       if (skb_headroom(skb) < 10)
+       {
+               printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb);
+       }
+       else
+       {
+               skb_push(skb, 10);
+       }
+
+       *((u16 *) (skb->data)) = chan->callref;
+       skb->data[2] = chan->layer2link;
+       *((u16 *) (skb->data + 3)) = data_len;
+
+       chan->s_refnum = (chan->s_refnum + 1) % 8;
+       *((u32 *) (skb->data + 5)) = chan->s_refnum;
+
+       skb->data[9] = 0;                           /* HDLC frame number */
+
+       return 10;
+}
+
+int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb)
+
+{
+       if ((*skb = dev_alloc_skb(4)) == NULL) {
+
+               printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n");
+               return -1;
+       }
+
+       *((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+       *(skb_put(*skb, 1)) = chan->layer2link;
+       *(skb_put(*skb, 1)) = chan->r_refnum;
+
+       return (*skb)->len;
+}
+
+int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
+{
+
+       if ((*skb = dev_alloc_skb(6)) == NULL) {
+
+               printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n");
+               return -1;
+       }
+
+       *((ushort *)skb_put(*skb, 2)) = callref;
+
+       *(skb_put(*skb, 1)) = 2;                  /* Cause.Length = 2; */
+       *(skb_put(*skb, 1)) = 0x80;
+       *(skb_put(*skb, 1)) = 0x80 | cause;
+
+       /*
+        * Change it: we should send 'Sic transit gloria Mundi' here ;-)
+        */
+
+       *(skb_put(*skb, 1)) = 0;                   /* UTUS.Length = 0;  */
+
+       return 6;
+}
+
+int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+       if ((*skb = dev_alloc_skb(2)) == NULL) {
+
+               printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n");
+               return -1;
+       }
+
+       *((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+       return 2;
+}
+
+
+/*
+ *  Decoding of CAPI messages
+ *
+ */
+
+int capi_decode_conn_ind(struct pcbit_chan *chan,
+                        struct sk_buff *skb,
+                        struct callb_data *info)
+{
+       int CIlen, len;
+
+       /* Call Reference [CAPI] */
+       chan->callref = *((ushort *)skb->data);
+       skb_pull(skb, 2);
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
+#endif
+
+       /* Channel Identification */
+
+       /* Expect
+          Len = 1
+          Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ]
+       */
+
+       CIlen = skb->data[0];
+#ifdef DEBUG
+       if (CIlen == 1) {
+
+               if (((skb->data[1]) & 0xFC) == 0x48)
+                       printk(KERN_DEBUG "decode_conn_ind: chan ok\n");
+               printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03);
+       }
+       else
+               printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen);
+#endif
+       skb_pull(skb, CIlen + 1);
+
+       /* Calling Party Number */
+       /* An "additional service" as far as Portugal Telecom is concerned */
+
+       len = skb->data[0];
+
+       if (len > 0) {
+               int count = 1;
+
+#ifdef DEBUG
+               printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]);
+#endif
+               if ((skb->data[1] & 0x80) == 0)
+                       count = 2;
+
+               if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC)))
+                       return -1;
+
+               skb_copy_from_linear_data_offset(skb, count + 1,
+                                                info->data.setup.CallingPN,
+                                                len - count);
+               info->data.setup.CallingPN[len - count] = 0;
+
+       }
+       else {
+               info->data.setup.CallingPN = NULL;
+               printk(KERN_DEBUG "NULL CallingPN\n");
+       }
+
+       skb_pull(skb, len + 1);
+
+       /* Calling Party Subaddress */
+       skb_pull(skb, skb->data[0] + 1);
+
+       /* Called Party Number */
+
+       len = skb->data[0];
+
+       if (len > 0) {
+               int count = 1;
+
+               if ((skb->data[1] & 0x80) == 0)
+                       count = 2;
+
+               if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC)))
+                       return -1;
+
+               skb_copy_from_linear_data_offset(skb, count + 1,
+                                                info->data.setup.CalledPN,
+                                                len - count);
+               info->data.setup.CalledPN[len - count] = 0;
+
+       }
+       else {
+               info->data.setup.CalledPN = NULL;
+               printk(KERN_DEBUG "NULL CalledPN\n");
+       }
+
+       skb_pull(skb, len + 1);
+
+       /* Called Party Subaddress */
+       skb_pull(skb, skb->data[0] + 1);
+
+       /* LLC */
+       skb_pull(skb, skb->data[0] + 1);
+
+       /* HLC */
+       skb_pull(skb, skb->data[0] + 1);
+
+       /* U2U */
+       skb_pull(skb, skb->data[0] + 1);
+
+       return 0;
+}
+
+/*
+ *  returns errcode
+ */
+
+int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb,
+                         int *complete)
+{
+       int errcode;
+
+       chan->callref = *((ushort *)skb->data);     /* Update CallReference */
+       skb_pull(skb, 2);
+
+       errcode = *((ushort *) skb->data);   /* read errcode */
+       skb_pull(skb, 2);
+
+       *complete = *(skb->data);
+       skb_pull(skb, 1);
+
+       /* FIX ME */
+       /* This is actually a firmware bug */
+       if (!*complete)
+       {
+               printk(KERN_DEBUG "complete=%02x\n", *complete);
+               *complete = 1;
+       }
+
+
+       /* Optional Bearer Capability */
+       skb_pull(skb, *(skb->data) + 1);
+
+       /* Channel Identification */
+       skb_pull(skb, *(skb->data) + 1);
+
+       /* High Layer Compatibility follows */
+       skb_pull(skb, *(skb->data) + 1);
+
+       return errcode;
+}
+
+int capi_decode_conn_actv_ind(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+       ushort len;
+#ifdef DEBUG
+       char str[32];
+#endif
+
+       /* Yet Another Bearer Capability */
+       skb_pull(skb, *(skb->data) + 1);
+
+
+       /* Connected Party Number */
+       len = *(skb->data);
+
+#ifdef DEBUG
+       if (len > 1 && len < 31) {
+               skb_copy_from_linear_data_offset(skb, 2, str, len - 1);
+               str[len] = 0;
+               printk(KERN_DEBUG "Connected Party Number: %s\n", str);
+       }
+       else
+               printk(KERN_DEBUG "actv_ind CPN len = %d\n", len);
+#endif
+
+       skb_pull(skb, len + 1);
+
+       /* Connected Subaddress */
+       skb_pull(skb, *(skb->data) + 1);
+
+       /* Low Layer Capability */
+       skb_pull(skb, *(skb->data) + 1);
+
+       /* High Layer Capability */
+       skb_pull(skb, *(skb->data) + 1);
+
+       return 0;
+}
+
+int capi_decode_conn_actv_conf(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+       ushort errcode;
+
+       errcode = *((ushort *)skb->data);
+       skb_pull(skb, 2);
+
+       /* Channel Identification
+          skb_pull(skb, skb->data[0] + 1);
+       */
+       return errcode;
+}
+
+
+int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+       ushort errcode;
+
+       chan->layer2link = *(skb->data);
+       skb_pull(skb, 1);
+
+       errcode = *((ushort *)skb->data);
+       skb_pull(skb, 2);
+
+       return errcode;
+}
+
+int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+       ushort errcode;
+
+       if (chan->layer2link != *(skb->data))
+               printk("capi_decode_actv_trans_conf: layer2link doesn't match\n");
+
+       skb_pull(skb, 1);
+
+       errcode = *((ushort *)skb->data);
+       skb_pull(skb, 2);
+
+       return errcode;
+}
+
+int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+       ushort len;
+#ifdef DEBUG
+       int i;
+#endif
+       /* Cause */
+
+       len = *(skb->data);
+       skb_pull(skb, 1);
+
+#ifdef DEBUG
+
+       for (i = 0; i < len; i++)
+               printk(KERN_DEBUG "Cause Octect %d: %02x\n", i + 3,
+                      *(skb->data + i));
+#endif
+
+       skb_pull(skb, len);
+
+       return 0;
+}
+
+#ifdef DEBUG
+int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
+{
+       char str[64];
+       int len;
+
+       len = hdr[0];
+
+       if (len < 64 && len == hdrlen - 1) {
+               memcpy(str, hdr + 1, hdrlen - 1);
+               str[hdrlen - 1] = 0;
+               printk("%s\n", str);
+       }
+       else
+               printk("debug message incorrect\n");
+
+       return 0;
+}
+#endif
diff --git a/drivers/staging/i4l/pcbit/capi.h b/drivers/staging/i4l/pcbit/capi.h
new file mode 100644 (file)
index 0000000..635f634
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * CAPI encode/decode prototypes and defines
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef CAPI_H
+#define CAPI_H
+
+
+#define REQ_CAUSE         0x01
+#define REQ_DISPLAY       0x04
+#define REQ_USER_TO_USER  0x08
+
+#define AppInfoMask  REQ_CAUSE | REQ_DISPLAY | REQ_USER_TO_USER
+
+/* Connection Setup */
+extern int capi_conn_req(const char *calledPN, struct sk_buff **buf,
+                        int proto);
+extern int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb,
+                                int *complete);
+
+extern int capi_decode_conn_ind(struct pcbit_chan *chan, struct sk_buff *skb,
+                               struct callb_data *info);
+extern int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb);
+
+extern int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb);
+extern int capi_decode_conn_actv_conf(struct pcbit_chan *chan,
+                                     struct sk_buff *skb);
+
+extern int capi_decode_conn_actv_ind(struct pcbit_chan *chan,
+                                    struct sk_buff *skb);
+extern int capi_conn_active_resp(struct pcbit_chan *chan,
+                                struct sk_buff **skb);
+
+/* Data */
+extern int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
+                                int outgoing);
+extern int capi_decode_sel_proto_conf(struct pcbit_chan *chan,
+                                     struct sk_buff *skb);
+
+extern int capi_activate_transp_req(struct pcbit_chan *chan,
+                                   struct sk_buff **skb);
+extern int capi_decode_actv_trans_conf(struct pcbit_chan *chan,
+                                      struct sk_buff *skb);
+
+extern int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb);
+extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb);
+
+/* Connection Termination */
+extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause);
+
+extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb);
+extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb);
+
+#ifdef DEBUG
+extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen);
+#endif
+
+static inline struct pcbit_chan *
+capi_channel(struct pcbit_dev *dev, struct sk_buff *skb)
+{
+       ushort callref;
+
+       callref = *((ushort *)skb->data);
+       skb_pull(skb, 2);
+
+       if (dev->b1->callref == callref)
+               return dev->b1;
+       else if (dev->b2->callref == callref)
+               return dev->b2;
+
+       return NULL;
+}
+
+#endif
diff --git a/drivers/staging/i4l/pcbit/drv.c b/drivers/staging/i4l/pcbit/drv.c
new file mode 100644 (file)
index 0000000..4172e22
--- /dev/null
@@ -0,0 +1,1077 @@
+/*
+ * PCBIT-D interface with isdn4linux
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ *     Fixes:
+ *
+ *     Nuno Grilo      <l38486@alfa.ist.utl.pt>
+ *      fixed msn_list NULL pointer dereference.
+ *
+ */
+
+#include <linux/module.h>
+
+
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+#include <asm/string.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+
+#include "pcbit.h"
+#include "edss1.h"
+#include "layer2.h"
+#include "capi.h"
+
+
+extern ushort last_ref_num;
+
+static int pcbit_ioctl(isdn_ctrl *ctl);
+
+static char *pcbit_devname[MAX_PCBIT_CARDS] = {
+       "pcbit0",
+       "pcbit1",
+       "pcbit2",
+       "pcbit3"
+};
+
+/*
+ * prototypes
+ */
+
+static int pcbit_command(isdn_ctrl *ctl);
+static int pcbit_stat(u_char __user *buf, int len, int, int);
+static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
+static int pcbit_writecmd(const u_char __user *, int, int, int);
+
+static int set_protocol_running(struct pcbit_dev *dev);
+
+static void pcbit_clear_msn(struct pcbit_dev *dev);
+static void pcbit_set_msn(struct pcbit_dev *dev, char *list);
+static int pcbit_check_msn(struct pcbit_dev *dev, char *msn);
+
+
+int pcbit_init_dev(int board, int mem_base, int irq)
+{
+       struct pcbit_dev *dev;
+       isdn_if *dev_if;
+
+       if ((dev = kzalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
+       {
+               printk("pcbit_init: couldn't malloc pcbit_dev struct\n");
+               return -ENOMEM;
+       }
+
+       dev_pcbit[board] = dev;
+       init_waitqueue_head(&dev->set_running_wq);
+       spin_lock_init(&dev->lock);
+
+       if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF) {
+               dev->ph_mem = mem_base;
+               if (!request_mem_region(dev->ph_mem, 4096, "PCBIT mem")) {
+                       printk(KERN_WARNING
+                              "PCBIT: memory region %lx-%lx already in use\n",
+                              dev->ph_mem, dev->ph_mem + 4096);
+                       kfree(dev);
+                       dev_pcbit[board] = NULL;
+                       return -EACCES;
+               }
+               dev->sh_mem = ioremap(dev->ph_mem, 4096);
+       }
+       else
+       {
+               printk("memory address invalid");
+               kfree(dev);
+               dev_pcbit[board] = NULL;
+               return -EACCES;
+       }
+
+       dev->b1 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+       if (!dev->b1) {
+               printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
+               iounmap(dev->sh_mem);
+               release_mem_region(dev->ph_mem, 4096);
+               kfree(dev);
+               return -ENOMEM;
+       }
+
+       dev->b2 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+       if (!dev->b2) {
+               printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
+               kfree(dev->b1);
+               iounmap(dev->sh_mem);
+               release_mem_region(dev->ph_mem, 4096);
+               kfree(dev);
+               return -ENOMEM;
+       }
+
+       dev->b2->id = 1;
+
+       INIT_WORK(&dev->qdelivery, pcbit_deliver);
+
+       /*
+        *  interrupts
+        */
+
+       if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0)
+       {
+               kfree(dev->b1);
+               kfree(dev->b2);
+               iounmap(dev->sh_mem);
+               release_mem_region(dev->ph_mem, 4096);
+               kfree(dev);
+               dev_pcbit[board] = NULL;
+               return -EIO;
+       }
+
+       dev->irq = irq;
+
+       /* next frame to be received */
+       dev->rcv_seq = 0;
+       dev->send_seq = 0;
+       dev->unack_seq = 0;
+
+       dev->hl_hdrlen = 16;
+
+       dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL);
+
+       if (!dev_if) {
+               free_irq(irq, dev);
+               kfree(dev->b1);
+               kfree(dev->b2);
+               iounmap(dev->sh_mem);
+               release_mem_region(dev->ph_mem, 4096);
+               kfree(dev);
+               dev_pcbit[board] = NULL;
+               return -EIO;
+       }
+
+       dev->dev_if = dev_if;
+
+       dev_if->owner = THIS_MODULE;
+
+       dev_if->channels = 2;
+
+       dev_if->features = (ISDN_FEATURE_P_EURO  | ISDN_FEATURE_L3_TRANS |
+                           ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS);
+
+       dev_if->writebuf_skb = pcbit_xmit;
+       dev_if->hl_hdrlen = 16;
+
+       dev_if->maxbufsize = MAXBUFSIZE;
+       dev_if->command  = pcbit_command;
+
+       dev_if->writecmd = pcbit_writecmd;
+       dev_if->readstat = pcbit_stat;
+
+
+       strcpy(dev_if->id, pcbit_devname[board]);
+
+       if (!register_isdn(dev_if)) {
+               free_irq(irq, dev);
+               kfree(dev->b1);
+               kfree(dev->b2);
+               iounmap(dev->sh_mem);
+               release_mem_region(dev->ph_mem, 4096);
+               kfree(dev);
+               dev_pcbit[board] = NULL;
+               return -EIO;
+       }
+
+       dev->id = dev_if->channels;
+
+
+       dev->l2_state = L2_DOWN;
+       dev->free = 511;
+
+       /*
+        * set_protocol_running(dev);
+        */
+
+       return 0;
+}
+
+#ifdef MODULE
+void pcbit_terminate(int board)
+{
+       struct pcbit_dev *dev;
+
+       dev = dev_pcbit[board];
+
+       if (dev) {
+               /* unregister_isdn(dev->dev_if); */
+               free_irq(dev->irq, dev);
+               pcbit_clear_msn(dev);
+               kfree(dev->dev_if);
+               if (dev->b1->fsm_timer.function)
+                       del_timer(&dev->b1->fsm_timer);
+               if (dev->b2->fsm_timer.function)
+                       del_timer(&dev->b2->fsm_timer);
+               kfree(dev->b1);
+               kfree(dev->b2);
+               iounmap(dev->sh_mem);
+               release_mem_region(dev->ph_mem, 4096);
+               kfree(dev);
+       }
+}
+#endif
+
+static int pcbit_command(isdn_ctrl *ctl)
+{
+       struct pcbit_dev *dev;
+       struct pcbit_chan *chan;
+       struct callb_data info;
+
+       dev = finddev(ctl->driver);
+
+       if (!dev)
+       {
+               printk("pcbit_command: unknown device\n");
+               return -1;
+       }
+
+       chan = (ctl->arg & 0x0F) ? dev->b2 : dev->b1;
+
+
+       switch (ctl->command) {
+       case ISDN_CMD_IOCTL:
+               return pcbit_ioctl(ctl);
+               break;
+       case ISDN_CMD_DIAL:
+               info.type = EV_USR_SETUP_REQ;
+               info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone;
+               pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info);
+               break;
+       case ISDN_CMD_ACCEPTD:
+               pcbit_fsm_event(dev, chan, EV_USR_SETUP_RESP, NULL);
+               break;
+       case ISDN_CMD_ACCEPTB:
+               printk("ISDN_CMD_ACCEPTB - not really needed\n");
+               break;
+       case ISDN_CMD_HANGUP:
+               pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
+               break;
+       case ISDN_CMD_SETL2:
+               chan->proto = (ctl->arg >> 8);
+               break;
+       case ISDN_CMD_CLREAZ:
+               pcbit_clear_msn(dev);
+               break;
+       case ISDN_CMD_SETEAZ:
+               pcbit_set_msn(dev, ctl->parm.num);
+               break;
+       case ISDN_CMD_SETL3:
+               if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS)
+                       printk(KERN_DEBUG "L3 protocol unknown\n");
+               break;
+       default:
+               printk(KERN_DEBUG "pcbit_command: unknown command\n");
+               break;
+       };
+
+       return 0;
+}
+
+/*
+ * Another Hack :-(
+ * on some conditions the board stops sending TDATA_CONFs
+ * let's see if we can turn around the problem
+ */
+
+#ifdef BLOCK_TIMER
+static void pcbit_block_timer(unsigned long data)
+{
+       struct pcbit_chan *chan;
+       struct pcbit_dev *dev;
+       isdn_ctrl ictl;
+
+       chan = (struct pcbit_chan *)data;
+
+       dev = chan2dev(chan);
+
+       if (dev == NULL) {
+               printk(KERN_DEBUG "pcbit: chan2dev failed\n");
+               return;
+       }
+
+       del_timer(&chan->block_timer);
+       chan->block_timer.function = NULL;
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "pcbit_block_timer\n");
+#endif
+       chan->queued = 0;
+       ictl.driver = dev->id;
+       ictl.command = ISDN_STAT_BSENT;
+       ictl.arg = chan->id;
+       dev->dev_if->statcallb(&ictl);
+}
+#endif
+
+static int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
+{
+       ushort hdrlen;
+       int refnum, len;
+       struct pcbit_chan *chan;
+       struct pcbit_dev *dev;
+
+       dev = finddev(driver);
+       if (dev == NULL)
+       {
+               printk("finddev returned NULL");
+               return -1;
+       }
+
+       chan = chnum ? dev->b2 : dev->b1;
+
+
+       if (chan->fsm_state != ST_ACTIVE)
+               return -1;
+
+       if (chan->queued >= MAX_QUEUED)
+       {
+#ifdef DEBUG_QUEUE
+               printk(KERN_DEBUG
+                      "pcbit: %d packets already in queue - write fails\n",
+                      chan->queued);
+#endif
+               /*
+                * packet stays on the head of the device queue
+                * since dev_start_xmit will fail
+                * see net/core/dev.c
+                */
+#ifdef BLOCK_TIMER
+               if (chan->block_timer.function == NULL) {
+                       init_timer(&chan->block_timer);
+                       chan->block_timer.function =  &pcbit_block_timer;
+                       chan->block_timer.data = (long) chan;
+                       chan->block_timer.expires = jiffies + 1 * HZ;
+                       add_timer(&chan->block_timer);
+               }
+#endif
+               return 0;
+       }
+
+
+       chan->queued++;
+
+       len = skb->len;
+
+       hdrlen = capi_tdata_req(chan, skb);
+
+       refnum = last_ref_num++ & 0x7fffU;
+       chan->s_refnum = refnum;
+
+       pcbit_l2_write(dev, MSG_TDATA_REQ, refnum, skb, hdrlen);
+
+       return len;
+}
+
+static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
+{
+       struct pcbit_dev *dev;
+       int i, j;
+       const u_char *loadbuf;
+       u_char *ptr = NULL;
+       u_char *cbuf;
+
+       int errstat;
+
+       dev = finddev(driver);
+
+       if (!dev)
+       {
+               printk("pcbit_writecmd: couldn't find device");
+               return -ENODEV;
+       }
+
+       switch (dev->l2_state) {
+       case L2_LWMODE:
+               /* check (size <= rdp_size); write buf into board */
+               if (len < 0 || len > BANK4 + 1 || len > 1024)
+               {
+                       printk("pcbit_writecmd: invalid length %d\n", len);
+                       return -EINVAL;
+               }
+
+               cbuf = memdup_user(buf, len);
+               if (IS_ERR(cbuf))
+                       return PTR_ERR(cbuf);
+
+               memcpy_toio(dev->sh_mem, cbuf, len);
+               kfree(cbuf);
+               return len;
+       case L2_FWMODE:
+               /* this is the hard part */
+               /* dumb board */
+               /* get it into kernel space */
+               if ((ptr = kmalloc(len, GFP_KERNEL)) == NULL)
+                       return -ENOMEM;
+               if (copy_from_user(ptr, buf, len)) {
+                       kfree(ptr);
+                       return -EFAULT;
+               }
+               loadbuf = ptr;
+
+               errstat = 0;
+
+               for (i = 0; i < len; i++)
+               {
+                       for (j = 0; j < LOAD_RETRY; j++)
+                               if (!(readb(dev->sh_mem + dev->loadptr)))
+                                       break;
+
+                       if (j == LOAD_RETRY)
+                       {
+                               errstat = -ETIME;
+                               printk("TIMEOUT i=%d\n", i);
+                               break;
+                       }
+                       writeb(loadbuf[i], dev->sh_mem + dev->loadptr + 1);
+                       writeb(0x01, dev->sh_mem + dev->loadptr);
+
+                       dev->loadptr += 2;
+                       if (dev->loadptr > LOAD_ZONE_END)
+                               dev->loadptr = LOAD_ZONE_START;
+               }
+               kfree(ptr);
+
+               return errstat ? errstat : len;
+       default:
+               return -EBUSY;
+       }
+}
+
+/*
+ *  demultiplexing of messages
+ *
+ */
+
+void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg,
+                     struct sk_buff *skb,
+                     ushort hdr_len, ushort refnum)
+{
+       struct pcbit_chan *chan;
+       struct sk_buff *skb2;
+       unsigned short len;
+       struct callb_data cbdata;
+       int complete, err;
+       isdn_ctrl ictl;
+
+       switch (msg) {
+
+       case MSG_TDATA_IND:
+               if (!(chan = capi_channel(dev, skb))) {
+                       printk(KERN_WARNING
+                              "CAPI header: unknown channel id\n");
+                       break;
+               }
+               chan->r_refnum = skb->data[7];
+               skb_pull(skb, 8);
+
+               dev->dev_if->rcvcallb_skb(dev->id, chan->id, skb);
+
+               if (capi_tdata_resp(chan, &skb2) > 0)
+                       pcbit_l2_write(dev, MSG_TDATA_RESP, refnum,
+                                      skb2, skb2->len);
+               return;
+               break;
+       case MSG_TDATA_CONF:
+               if (!(chan = capi_channel(dev, skb))) {
+                       printk(KERN_WARNING
+                              "CAPI header: unknown channel id\n");
+                       break;
+               }
+
+#ifdef DEBUG
+               if ((*((ushort *)(skb->data + 2))) != 0) {
+                       printk(KERN_DEBUG "TDATA_CONF error\n");
+               }
+#endif
+#ifdef BLOCK_TIMER
+               if (chan->queued == MAX_QUEUED) {
+                       del_timer(&chan->block_timer);
+                       chan->block_timer.function = NULL;
+               }
+
+#endif
+               chan->queued--;
+
+               ictl.driver = dev->id;
+               ictl.command = ISDN_STAT_BSENT;
+               ictl.arg = chan->id;
+               dev->dev_if->statcallb(&ictl);
+               break;
+
+       case MSG_CONN_IND:
+               /*
+                *  channel: 1st not used will do
+                *           if both are used we're in trouble
+                */
+
+               if (!dev->b1->fsm_state)
+                       chan = dev->b1;
+               else if (!dev->b2->fsm_state)
+                       chan = dev->b2;
+               else {
+                       printk(KERN_INFO
+                              "Incoming connection: no channels available");
+
+                       if ((len = capi_disc_req(*(ushort *)(skb->data), &skb2, CAUSE_NOCHAN)) > 0)
+                               pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb2, len);
+                       break;
+               }
+
+               cbdata.data.setup.CalledPN = NULL;
+               cbdata.data.setup.CallingPN = NULL;
+
+               capi_decode_conn_ind(chan, skb, &cbdata);
+               cbdata.type = EV_NET_SETUP;
+
+               pcbit_fsm_event(dev, chan, EV_NET_SETUP, NULL);
+
+               if (pcbit_check_msn(dev, cbdata.data.setup.CallingPN))
+                       pcbit_fsm_event(dev, chan, EV_USR_PROCED_REQ, &cbdata);
+               else
+                       pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
+
+               kfree(cbdata.data.setup.CalledPN);
+               kfree(cbdata.data.setup.CallingPN);
+               break;
+
+       case MSG_CONN_CONF:
+               /*
+                * We should be able to find the channel by the message
+                * reference number. The current version of the firmware
+                * doesn't sent the ref number correctly.
+                */
+#ifdef DEBUG
+               printk(KERN_DEBUG "refnum=%04x b1=%04x b2=%04x\n", refnum,
+                      dev->b1->s_refnum,
+                      dev->b2->s_refnum);
+#endif
+               /* We just try to find a channel in the right state */
+
+               if (dev->b1->fsm_state == ST_CALL_INIT)
+                       chan = dev->b1;
+               else {
+                       if (dev->b2->s_refnum == ST_CALL_INIT)
+                               chan = dev->b2;
+                       else {
+                               chan = NULL;
+                               printk(KERN_WARNING "Connection Confirm - no channel in Call Init state\n");
+                               break;
+                       }
+               }
+               if (capi_decode_conn_conf(chan, skb, &complete)) {
+                       printk(KERN_DEBUG "conn_conf indicates error\n");
+                       pcbit_fsm_event(dev, chan, EV_ERROR, NULL);
+               }
+               else
+                       if (complete)
+                               pcbit_fsm_event(dev, chan, EV_NET_CALL_PROC, NULL);
+                       else
+                               pcbit_fsm_event(dev, chan, EV_NET_SETUP_ACK, NULL);
+               break;
+       case MSG_CONN_ACTV_IND:
+
+               if (!(chan = capi_channel(dev, skb))) {
+                       printk(KERN_WARNING
+                              "CAPI header: unknown channel id\n");
+                       break;
+               }
+
+               if (capi_decode_conn_actv_ind(chan, skb)) {
+                       printk("error in capi_decode_conn_actv_ind\n");
+                       /* pcbit_fsm_event(dev, chan, EV_ERROR, NULL); */
+                       break;
+               }
+               chan->r_refnum = refnum;
+               pcbit_fsm_event(dev, chan, EV_NET_CONN, NULL);
+               break;
+       case MSG_CONN_ACTV_CONF:
+
+               if (!(chan = capi_channel(dev, skb))) {
+                       printk(KERN_WARNING
+                              "CAPI header: unknown channel id\n");
+                       break;
+               }
+
+               if (capi_decode_conn_actv_conf(chan, skb) == 0)
+                       pcbit_fsm_event(dev, chan, EV_NET_CONN_ACK, NULL);
+
+               else
+                       printk(KERN_DEBUG "decode_conn_actv_conf failed\n");
+               break;
+
+       case  MSG_SELP_CONF:
+
+               if (!(chan = capi_channel(dev, skb))) {
+                       printk(KERN_WARNING
+                              "CAPI header: unknown channel id\n");
+                       break;
+               }
+
+               if (!(err = capi_decode_sel_proto_conf(chan, skb)))
+                       pcbit_fsm_event(dev, chan, EV_NET_SELP_RESP, NULL);
+               else {
+                       /* Error */
+                       printk("error %d - capi_decode_sel_proto_conf\n", err);
+               }
+               break;
+       case MSG_ACT_TRANSP_CONF:
+               if (!(chan = capi_channel(dev, skb))) {
+                       printk(KERN_WARNING
+                              "CAPI header: unknown channel id\n");
+                       break;
+               }
+
+               if (!capi_decode_actv_trans_conf(chan, skb))
+                       pcbit_fsm_event(dev, chan, EV_NET_ACTV_RESP, NULL);
+               break;
+
+       case MSG_DISC_IND:
+
+               if (!(chan = capi_channel(dev, skb))) {
+                       printk(KERN_WARNING
+                              "CAPI header: unknown channel id\n");
+                       break;
+               }
+
+               if (!capi_decode_disc_ind(chan, skb))
+                       pcbit_fsm_event(dev, chan, EV_NET_DISC, NULL);
+               else
+                       printk(KERN_WARNING "capi_decode_disc_ind - error\n");
+               break;
+       case MSG_DISC_CONF:
+               if (!(chan = capi_channel(dev, skb))) {
+                       printk(KERN_WARNING
+                              "CAPI header: unknown channel id\n");
+                       break;
+               }
+
+               if (!capi_decode_disc_ind(chan, skb))
+                       pcbit_fsm_event(dev, chan, EV_NET_RELEASE, NULL);
+               else
+                       printk(KERN_WARNING "capi_decode_disc_conf - error\n");
+               break;
+       case MSG_INFO_IND:
+#ifdef DEBUG
+               printk(KERN_DEBUG "received Info Indication - discarded\n");
+#endif
+               break;
+#ifdef DEBUG
+       case MSG_DEBUG_188:
+               capi_decode_debug_188(skb->data, skb->len);
+               break;
+
+       default:
+               printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n",
+                      msg);
+               break;
+#endif
+       }
+
+       kfree_skb(skb);
+
+}
+
+/*
+ *   Single statbuf
+ *   should be a statbuf per device
+ */
+
+static char statbuf[STATBUF_LEN];
+static int stat_st = 0;
+static int stat_end = 0;
+
+static int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
+{
+       int stat_count;
+       stat_count = stat_end - stat_st;
+
+       if (stat_count < 0)
+               stat_count = STATBUF_LEN - stat_st + stat_end;
+
+       /* FIXME: should we sleep and wait for more cookies ? */
+       if (len > stat_count)
+               len = stat_count;
+
+       if (stat_st < stat_end)
+       {
+               if (copy_to_user(buf, statbuf + stat_st, len))
+                       return -EFAULT;
+               stat_st += len;
+       }
+       else
+       {
+               if (len > STATBUF_LEN - stat_st)
+               {
+                       if (copy_to_user(buf, statbuf + stat_st,
+                                        STATBUF_LEN - stat_st))
+                               return -EFAULT;
+                       if (copy_to_user(buf, statbuf,
+                                        len - (STATBUF_LEN - stat_st)))
+                               return -EFAULT;
+
+                       stat_st = len - (STATBUF_LEN - stat_st);
+               }
+               else
+               {
+                       if (copy_to_user(buf, statbuf + stat_st, len))
+                               return -EFAULT;
+
+                       stat_st += len;
+
+                       if (stat_st == STATBUF_LEN)
+                               stat_st = 0;
+               }
+       }
+
+       if (stat_st == stat_end)
+               stat_st = stat_end = 0;
+
+       return len;
+}
+
+static void pcbit_logstat(struct pcbit_dev *dev, char *str)
+{
+       int i;
+       isdn_ctrl ictl;
+
+       for (i = stat_end; i < strlen(str); i++)
+       {
+               statbuf[i] = str[i];
+               stat_end = (stat_end + 1) % STATBUF_LEN;
+               if (stat_end == stat_st)
+                       stat_st = (stat_st + 1) % STATBUF_LEN;
+       }
+
+       ictl.command = ISDN_STAT_STAVAIL;
+       ictl.driver = dev->id;
+       ictl.arg = strlen(str);
+       dev->dev_if->statcallb(&ictl);
+}
+
+void pcbit_state_change(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                       unsigned short i, unsigned short ev, unsigned short f)
+{
+       char buf[256];
+
+       sprintf(buf, "change on device: %d channel:%d\n%s -> %s -> %s\n",
+               dev->id, chan->id,
+               isdn_state_table[i], strisdnevent(ev), isdn_state_table[f]
+               );
+
+#ifdef DEBUG
+       printk("%s", buf);
+#endif
+
+       pcbit_logstat(dev, buf);
+}
+
+static void set_running_timeout(unsigned long ptr)
+{
+       struct pcbit_dev *dev;
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "set_running_timeout\n");
+#endif
+       dev = (struct pcbit_dev *) ptr;
+
+       dev->l2_state = L2_DOWN;
+       wake_up_interruptible(&dev->set_running_wq);
+}
+
+static int set_protocol_running(struct pcbit_dev *dev)
+{
+       isdn_ctrl ctl;
+
+       init_timer(&dev->set_running_timer);
+
+       dev->set_running_timer.function = &set_running_timeout;
+       dev->set_running_timer.data = (ulong) dev;
+       dev->set_running_timer.expires = jiffies + SET_RUN_TIMEOUT;
+
+       /* kick it */
+
+       dev->l2_state = L2_STARTING;
+
+       writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
+              dev->sh_mem + BANK4);
+
+       add_timer(&dev->set_running_timer);
+
+       wait_event(dev->set_running_wq, dev->l2_state == L2_RUNNING ||
+                                       dev->l2_state == L2_DOWN);
+
+       del_timer(&dev->set_running_timer);
+
+       if (dev->l2_state == L2_RUNNING)
+       {
+               printk(KERN_DEBUG "pcbit: running\n");
+
+               dev->unack_seq = dev->send_seq;
+
+               dev->writeptr = dev->sh_mem;
+               dev->readptr = dev->sh_mem + BANK2;
+
+               /* tell the good news to the upper layer */
+               ctl.driver = dev->id;
+               ctl.command = ISDN_STAT_RUN;
+
+               dev->dev_if->statcallb(&ctl);
+       }
+       else
+       {
+               printk(KERN_DEBUG "pcbit: initialization failed\n");
+               printk(KERN_DEBUG "pcbit: firmware not loaded\n");
+
+#ifdef DEBUG
+               printk(KERN_DEBUG "Bank3 = %02x\n",
+                      readb(dev->sh_mem + BANK3));
+#endif
+               writeb(0x40, dev->sh_mem + BANK4);
+
+               /* warn the upper layer */
+               ctl.driver = dev->id;
+               ctl.command = ISDN_STAT_STOP;
+
+               dev->dev_if->statcallb(&ctl);
+
+               return -EL2HLT; /* Level 2 halted */
+       }
+
+       return 0;
+}
+
+static int pcbit_ioctl(isdn_ctrl *ctl)
+{
+       struct pcbit_dev *dev;
+       struct pcbit_ioctl *cmd;
+
+       dev = finddev(ctl->driver);
+
+       if (!dev)
+       {
+               printk(KERN_DEBUG "pcbit_ioctl: unknown device\n");
+               return -ENODEV;
+       }
+
+       cmd = (struct pcbit_ioctl *) ctl->parm.num;
+
+       switch (ctl->arg) {
+       case PCBIT_IOCTL_GETSTAT:
+               cmd->info.l2_status = dev->l2_state;
+               break;
+
+       case PCBIT_IOCTL_STRLOAD:
+               if (dev->l2_state == L2_RUNNING)
+                       return -EBUSY;
+
+               dev->unack_seq = dev->send_seq = dev->rcv_seq = 0;
+
+               dev->writeptr = dev->sh_mem;
+               dev->readptr = dev->sh_mem + BANK2;
+
+               dev->l2_state = L2_LOADING;
+               break;
+
+       case PCBIT_IOCTL_LWMODE:
+               if (dev->l2_state != L2_LOADING)
+                       return -EINVAL;
+
+               dev->l2_state = L2_LWMODE;
+               break;
+
+       case PCBIT_IOCTL_FWMODE:
+               if (dev->l2_state == L2_RUNNING)
+                       return -EBUSY;
+               dev->loadptr = LOAD_ZONE_START;
+               dev->l2_state = L2_FWMODE;
+
+               break;
+       case PCBIT_IOCTL_ENDLOAD:
+               if (dev->l2_state == L2_RUNNING)
+                       return -EBUSY;
+               dev->l2_state = L2_DOWN;
+               break;
+
+       case PCBIT_IOCTL_SETBYTE:
+               if (dev->l2_state == L2_RUNNING)
+                       return -EBUSY;
+
+               /* check addr */
+               if (cmd->info.rdp_byte.addr > BANK4)
+                       return -EFAULT;
+
+               writeb(cmd->info.rdp_byte.value, dev->sh_mem + cmd->info.rdp_byte.addr);
+               break;
+       case PCBIT_IOCTL_GETBYTE:
+               if (dev->l2_state == L2_RUNNING)
+                       return -EBUSY;
+
+               /* check addr */
+
+               if (cmd->info.rdp_byte.addr > BANK4)
+               {
+                       printk("getbyte: invalid addr %04x\n", cmd->info.rdp_byte.addr);
+                       return -EFAULT;
+               }
+
+               cmd->info.rdp_byte.value = readb(dev->sh_mem + cmd->info.rdp_byte.addr);
+               break;
+       case PCBIT_IOCTL_RUNNING:
+               if (dev->l2_state == L2_RUNNING)
+                       return -EBUSY;
+               return set_protocol_running(dev);
+               break;
+       case PCBIT_IOCTL_WATCH188:
+               if (dev->l2_state != L2_LOADING)
+                       return -EINVAL;
+               pcbit_l2_write(dev, MSG_WATCH188, 0x0001, NULL, 0);
+               break;
+       case PCBIT_IOCTL_PING188:
+               if (dev->l2_state != L2_LOADING)
+                       return -EINVAL;
+               pcbit_l2_write(dev, MSG_PING188_REQ, 0x0001, NULL, 0);
+               break;
+       case PCBIT_IOCTL_APION:
+               if (dev->l2_state != L2_LOADING)
+                       return -EINVAL;
+               pcbit_l2_write(dev, MSG_API_ON, 0x0001, NULL, 0);
+               break;
+       case PCBIT_IOCTL_STOP:
+               dev->l2_state = L2_DOWN;
+               writeb(0x40, dev->sh_mem + BANK4);
+               dev->rcv_seq = 0;
+               dev->send_seq = 0;
+               dev->unack_seq = 0;
+               break;
+       default:
+               printk("error: unknown ioctl\n");
+               break;
+       };
+       return 0;
+}
+
+/*
+ *        MSN list handling
+ *
+ *        if null reject all calls
+ *        if first entry has null MSN accept all calls
+ */
+
+static void pcbit_clear_msn(struct pcbit_dev *dev)
+{
+       struct msn_entry *ptr, *back;
+
+       for (ptr = dev->msn_list; ptr;)
+       {
+               back = ptr->next;
+               kfree(ptr);
+               ptr = back;
+       }
+
+       dev->msn_list = NULL;
+}
+
+static void pcbit_set_msn(struct pcbit_dev *dev, char *list)
+{
+       struct msn_entry *ptr;
+       struct msn_entry *back = NULL;
+       char *cp, *sp;
+       int len;
+
+       if (strlen(list) == 0) {
+               ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
+               if (!ptr) {
+                       printk(KERN_WARNING "kmalloc failed\n");
+                       return;
+               }
+
+               ptr->msn = NULL;
+
+               ptr->next = dev->msn_list;
+               dev->msn_list = ptr;
+
+               return;
+       }
+
+       if (dev->msn_list)
+               for (back = dev->msn_list; back->next; back = back->next);
+
+       sp = list;
+
+       do {
+               cp = strchr(sp, ',');
+               if (cp)
+                       len = cp - sp;
+               else
+                       len = strlen(sp);
+
+               ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
+
+               if (!ptr) {
+                       printk(KERN_WARNING "kmalloc failed\n");
+                       return;
+               }
+               ptr->next = NULL;
+
+               ptr->msn = kmalloc(len + 1, GFP_ATOMIC);
+               if (!ptr->msn) {
+                       printk(KERN_WARNING "kmalloc failed\n");
+                       kfree(ptr);
+                       return;
+               }
+
+               memcpy(ptr->msn, sp, len);
+               ptr->msn[len] = 0;
+
+#ifdef DEBUG
+               printk(KERN_DEBUG "msn: %s\n", ptr->msn);
+#endif
+               if (dev->msn_list == NULL)
+                       dev->msn_list = ptr;
+               else
+                       back->next = ptr;
+               back = ptr;
+               sp += len;
+       } while (cp);
+}
+
+/*
+ *  check if we do signal or reject an incoming call
+ */
+static int pcbit_check_msn(struct pcbit_dev *dev, char *msn)
+{
+       struct msn_entry *ptr;
+
+       for (ptr = dev->msn_list; ptr; ptr = ptr->next) {
+
+               if (ptr->msn == NULL)
+                       return 1;
+
+               if (strcmp(ptr->msn, msn) == 0)
+                       return 1;
+       }
+
+       return 0;
+}
diff --git a/drivers/staging/i4l/pcbit/edss1.c b/drivers/staging/i4l/pcbit/edss1.c
new file mode 100644 (file)
index 0000000..b2262ba
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * DSS.1 Finite State Machine
+ * base: ITU-T Rec Q.931
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ *        TODO: complete the FSM
+ *              move state/event descriptions to a user space logger
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+
+#include <linux/timer.h>
+#include <asm/io.h>
+
+#include <linux/isdnif.h>
+
+#include "pcbit.h"
+#include "edss1.h"
+#include "layer2.h"
+#include "callbacks.h"
+
+
+const char * const isdn_state_table[] = {
+       "Closed",
+       "Call initiated",
+       "Overlap sending",
+       "Outgoing call proceeding",
+       "NOT DEFINED",
+       "Call delivered",
+       "Call present",
+       "Call received",
+       "Connect request",
+       "Incoming call proceeding",
+       "Active",
+       "Disconnect request",
+       "Disconnect indication",
+       "NOT DEFINED",
+       "NOT DEFINED",
+       "Suspend request",
+       "NOT DEFINED",
+       "Resume request",
+       "NOT DEFINED",
+       "Release Request",
+       "NOT DEFINED",
+       "NOT DEFINED",
+       "NOT DEFINED",
+       "NOT DEFINED",
+       "NOT DEFINED",
+       "Overlap receiving",
+       "Select protocol on B-Channel",
+       "Activate B-channel protocol"
+};
+
+#ifdef DEBUG_ERRS
+static
+struct CauseValue {
+       byte nr;
+       char *descr;
+} cvlist[] = {
+       {0x01, "Unallocated (unassigned) number"},
+       {0x02, "No route to specified transit network"},
+       {0x03, "No route to destination"},
+       {0x04, "Send special information tone"},
+       {0x05, "Misdialled trunk prefix"},
+       {0x06, "Channel unacceptable"},
+       {0x07, "Channel awarded and being delivered in an established channel"},
+       {0x08, "Preemption"},
+       {0x09, "Preemption - circuit reserved for reuse"},
+       {0x10, "Normal call clearing"},
+       {0x11, "User busy"},
+       {0x12, "No user responding"},
+       {0x13, "No answer from user (user alerted)"},
+       {0x14, "Subscriber absent"},
+       {0x15, "Call rejected"},
+       {0x16, "Number changed"},
+       {0x1a, "non-selected user clearing"},
+       {0x1b, "Destination out of order"},
+       {0x1c, "Invalid number format (address incomplete)"},
+       {0x1d, "Facility rejected"},
+       {0x1e, "Response to Status enquiry"},
+       {0x1f, "Normal, unspecified"},
+       {0x22, "No circuit/channel available"},
+       {0x26, "Network out of order"},
+       {0x27, "Permanent frame mode connection out-of-service"},
+       {0x28, "Permanent frame mode connection operational"},
+       {0x29, "Temporary failure"},
+       {0x2a, "Switching equipment congestion"},
+       {0x2b, "Access information discarded"},
+       {0x2c, "Requested circuit/channel not available"},
+       {0x2e, "Precedence call blocked"},
+       {0x2f, "Resource unavailable, unspecified"},
+       {0x31, "Quality of service unavailable"},
+       {0x32, "Requested facility not subscribed"},
+       {0x35, "Outgoing calls barred within CUG"},
+       {0x37, "Incoming calls barred within CUG"},
+       {0x39, "Bearer capability not authorized"},
+       {0x3a, "Bearer capability not presently available"},
+       {0x3e, "Inconsistency in designated outgoing access information and subscriber class"},
+       {0x3f, "Service or option not available, unspecified"},
+       {0x41, "Bearer capability not implemented"},
+       {0x42, "Channel type not implemented"},
+       {0x43, "Requested facility not implemented"},
+       {0x44, "Only restricted digital information bearer capability is available"},
+       {0x4f, "Service or option not implemented"},
+       {0x51, "Invalid call reference value"},
+       {0x52, "Identified channel does not exist"},
+       {0x53, "A suspended call exists, but this call identity does not"},
+       {0x54, "Call identity in use"},
+       {0x55, "No call suspended"},
+       {0x56, "Call having the requested call identity has been cleared"},
+       {0x57, "User not member of CUG"},
+       {0x58, "Incompatible destination"},
+       {0x5a, "Non-existent CUG"},
+       {0x5b, "Invalid transit network selection"},
+       {0x5f, "Invalid message, unspecified"},
+       {0x60, "Mandatory information element is missing"},
+       {0x61, "Message type non-existent or not implemented"},
+       {0x62, "Message not compatible with call state or message type non-existent or not implemented"},
+       {0x63, "Information element/parameter non-existent or not implemented"},
+       {0x64, "Invalid information element contents"},
+       {0x65, "Message not compatible with call state"},
+       {0x66, "Recovery on timer expiry"},
+       {0x67, "Parameter non-existent or not implemented - passed on"},
+       {0x6e, "Message with unrecognized parameter discarded"},
+       {0x6f, "Protocol error, unspecified"},
+       {0x7f, "Interworking, unspecified"}
+};
+
+#endif
+
+static struct isdn_event_desc {
+       unsigned short ev;
+       char *desc;
+} isdn_event_table[] = {
+       {EV_USR_SETUP_REQ,     "CC->L3: Setup Request"},
+       {EV_USR_SETUP_RESP,    "CC->L3: Setup Response"},
+       {EV_USR_PROCED_REQ,    "CC->L3: Proceeding Request"},
+       {EV_USR_RELEASE_REQ,   "CC->L3: Release Request"},
+
+       {EV_NET_SETUP,        "NET->TE: setup "},
+       {EV_NET_CALL_PROC,    "NET->TE: call proceeding"},
+       {EV_NET_SETUP_ACK,    "NET->TE: setup acknowledge (more info needed)"},
+       {EV_NET_CONN,         "NET->TE: connect"},
+       {EV_NET_CONN_ACK,     "NET->TE: connect acknowledge"},
+       {EV_NET_DISC,         "NET->TE: disconnect indication"},
+       {EV_NET_RELEASE,      "NET->TE: release"},
+       {EV_NET_RELEASE_COMP, "NET->TE: release complete"},
+       {EV_NET_SELP_RESP,    "Board: Select B-channel protocol ack"},
+       {EV_NET_ACTV_RESP,    "Board: Activate B-channel protocol ack"},
+       {EV_TIMER,            "Timeout"},
+       {0, "NULL"}
+};
+
+char *strisdnevent(ushort ev)
+{
+       struct isdn_event_desc *entry;
+
+       for (entry = isdn_event_table; entry->ev; entry++)
+               if (entry->ev == ev)
+                       break;
+
+       return entry->desc;
+}
+
+/*
+ * Euro ISDN finite state machine
+ */
+
+static struct fsm_timer_entry fsm_timers[] = {
+       {ST_CALL_PROC, 10},
+       {ST_DISC_REQ, 2},
+       {ST_ACTIVE_SELP, 5},
+       {ST_ACTIVE_ACTV, 5},
+       {ST_INCM_PROC, 10},
+       {ST_CONN_REQ, 2},
+       {0xff, 0}
+};
+
+static struct fsm_entry fsm_table[] = {
+/* Connect Phase */
+       /* Outgoing */
+       {ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1},
+
+       {ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone},
+       {ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL},
+       {ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2},
+
+       {ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2},
+       {ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1},
+       {ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+       /* Incoming */
+       {ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL},
+
+       {ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1},
+       {ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+       {ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2},
+       {ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+       {ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3},
+
+       /* Active */
+       {ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1},
+       {ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+       {ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3},
+
+       /* Disconnect */
+
+       {ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1},
+       {ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3},
+
+       /* protocol selection */
+       {ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1},
+       {ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+       {ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open},
+       {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+       /* Timers */
+       {ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
+       {ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3},
+       {ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2},
+       {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2},
+       {ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
+       {ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2},
+
+       {0xff, 0, 0, NULL}
+};
+
+
+static void pcbit_fsm_timer(unsigned long data)
+{
+       struct pcbit_dev *dev;
+       struct pcbit_chan *chan;
+
+       chan = (struct pcbit_chan *) data;
+
+       del_timer(&chan->fsm_timer);
+       chan->fsm_timer.function = NULL;
+
+       dev = chan2dev(chan);
+
+       if (dev == NULL) {
+               printk(KERN_WARNING "pcbit: timer for unknown device\n");
+               return;
+       }
+
+       pcbit_fsm_event(dev, chan, EV_TIMER, NULL);
+}
+
+
+void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                    unsigned short event, struct callb_data *data)
+{
+       struct fsm_entry *action;
+       struct fsm_timer_entry *tentry;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       for (action = fsm_table; action->init != 0xff; action++)
+               if (action->init == chan->fsm_state && action->event == event)
+                       break;
+
+       if (action->init == 0xff) {
+
+               spin_unlock_irqrestore(&dev->lock, flags);
+               printk(KERN_DEBUG "fsm error: event %x on state %x\n",
+                      event, chan->fsm_state);
+               return;
+       }
+
+       if (chan->fsm_timer.function) {
+               del_timer(&chan->fsm_timer);
+               chan->fsm_timer.function = NULL;
+       }
+
+       chan->fsm_state = action->final;
+
+       pcbit_state_change(dev, chan, action->init, event, action->final);
+
+       for (tentry = fsm_timers; tentry->init != 0xff; tentry++)
+               if (tentry->init == chan->fsm_state)
+                       break;
+
+       if (tentry->init != 0xff) {
+               init_timer(&chan->fsm_timer);
+               chan->fsm_timer.function = &pcbit_fsm_timer;
+               chan->fsm_timer.data = (ulong) chan;
+               chan->fsm_timer.expires = jiffies + tentry->timeout * HZ;
+               add_timer(&chan->fsm_timer);
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (action->callb)
+               action->callb(dev, chan, data);
+
+}
diff --git a/drivers/staging/i4l/pcbit/edss1.h b/drivers/staging/i4l/pcbit/edss1.h
new file mode 100644 (file)
index 0000000..2f6b3a8
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * DSS.1 module definitions
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef EDSS1_H
+#define EDSS1_H
+
+/* ISDN states */
+
+#define ST_NULL      0
+#define ST_CALL_INIT 1    /* Call initiated */
+#define ST_OVER_SEND 2    /* Overlap sending - Requests More Info 4 call */
+#define ST_CALL_PROC 3    /* Call Proceeding */
+#define ST_CALL_DELV 4
+#define ST_CALL_PRES 6    /* Call Present - Received CONN.IND */
+#define ST_CALL_RECV 7    /* Alerting sent */
+#define ST_CONN_REQ  8    /* Answered - waiting 4 CONN.CONF */
+#define ST_INCM_PROC 9
+#define ST_ACTIVE    10
+#define ST_DISC_REQ  11
+#define ST_DISC_IND  12
+#define ST_SUSP_REQ  15
+#define ST_RESM_REQ  17
+#define ST_RELS_REQ  19
+#define ST_OVER_RECV 25
+
+#define ST_ACTIVE_SELP 26 /* Select protocol on B-Channel */
+#define ST_ACTIVE_ACTV 27 /* Activate B-channel protocol  */
+
+#define MAX_STATE ST_ACTIVE_ACTV
+
+#define EV_NULL               0
+#define EV_USR_SETUP_REQ      1
+#define EV_USR_SETUP_RESP     2
+#define EV_USR_PROCED_REQ     3
+#define EV_USR_RELEASE_REQ    4
+#define EV_USR_REJECT_REQ     4
+
+#define EV_NET_SETUP          16
+#define EV_NET_CALL_PROC      17
+#define EV_NET_SETUP_ACK      18
+#define EV_NET_CONN           19
+#define EV_NET_CONN_ACK       20
+
+#define EV_NET_SELP_RESP      21
+#define EV_NET_ACTV_RESP      22
+
+#define EV_NET_DISC           23
+#define EV_NET_RELEASE        24
+#define EV_NET_RELEASE_COMP   25
+
+#define EV_TIMER              26
+#define EV_ERROR              32
+
+/*
+ *  Cause values
+ *  only the ones we use
+ */
+
+#define CAUSE_NORMAL          0x10U
+#define CAUSE_NOCHAN          0x22U
+
+struct callb_data {
+       unsigned short type;
+       union {
+               struct ConnInfo {
+                       char *CalledPN;
+                       char *CallingPN;
+               } setup;
+               unsigned short cause;
+       } data;
+};
+
+struct fsm_entry {
+       unsigned short init;
+       unsigned short final;
+       unsigned short event;
+       void (*callb)(struct pcbit_dev *, struct pcbit_chan *, struct callb_data*);
+};
+
+struct fsm_timer_entry {
+       unsigned short init;
+       unsigned long timeout;          /* in seconds */
+};
+
+extern const char * const isdn_state_table[];
+
+void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
+                    unsigned short event, struct callb_data *);
+char *strisdnevent(ushort ev);
+
+#endif
diff --git a/drivers/staging/i4l/pcbit/layer2.c b/drivers/staging/i4l/pcbit/layer2.c
new file mode 100644 (file)
index 0000000..46e1240
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+ * PCBIT-D low-layer interface
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ * 19991203 - Fernando Carvalho - takion@superbofh.org
+ * Hacked to compile with egcs and run with current version of isdn modules
+ */
+
+/*
+ *        Based on documentation provided by Inesc:
+ *        - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93
+ */
+
+/*
+ *        TODO: better handling of errors
+ *              re-write/remove debug printks
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+
+#include <asm/io.h>
+
+
+#include "pcbit.h"
+#include "layer2.h"
+#include "edss1.h"
+
+#undef DEBUG_FRAG
+
+
+/*
+ *  Prototypes
+ */
+
+static void pcbit_transmit(struct pcbit_dev *dev);
+
+static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
+
+static void pcbit_l2_error(struct pcbit_dev *dev);
+static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
+static void pcbit_l2_err_recover(unsigned long data);
+
+static void pcbit_firmware_bug(struct pcbit_dev *dev);
+
+static __inline__ void
+pcbit_sched_delivery(struct pcbit_dev *dev)
+{
+       schedule_work(&dev->qdelivery);
+}
+
+
+/*
+ *  Called from layer3
+ */
+
+int
+pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
+              struct sk_buff *skb, unsigned short hdr_len)
+{
+       struct frame_buf *frame,
+               *ptr;
+       unsigned long flags;
+
+       if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
+               dev_kfree_skb(skb);
+               return -1;
+       }
+       if ((frame = kmalloc(sizeof(struct frame_buf),
+                            GFP_ATOMIC)) == NULL) {
+               dev_kfree_skb(skb);
+               return -1;
+       }
+       frame->msg = msg;
+       frame->refnum = refnum;
+       frame->copied = 0;
+       frame->hdr_len = hdr_len;
+
+       if (skb)
+               frame->dt_len = skb->len - hdr_len;
+       else
+               frame->dt_len = 0;
+
+       frame->skb = skb;
+
+       frame->next = NULL;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       if (dev->write_queue == NULL) {
+               dev->write_queue = frame;
+               spin_unlock_irqrestore(&dev->lock, flags);
+               pcbit_transmit(dev);
+       } else {
+               for (ptr = dev->write_queue; ptr->next; ptr = ptr->next);
+               ptr->next = frame;
+
+               spin_unlock_irqrestore(&dev->lock, flags);
+       }
+       return 0;
+}
+
+static __inline__ void
+pcbit_tx_update(struct pcbit_dev *dev, ushort len)
+{
+       u_char info;
+
+       dev->send_seq = (dev->send_seq + 1) % 8;
+
+       dev->fsize[dev->send_seq] = len;
+       info = 0;
+       info |= dev->rcv_seq << 3;
+       info |= dev->send_seq;
+
+       writeb(info, dev->sh_mem + BANK4);
+
+}
+
+/*
+ * called by interrupt service routine or by write_2
+ */
+
+static void
+pcbit_transmit(struct pcbit_dev *dev)
+{
+       struct frame_buf *frame = NULL;
+       unsigned char unacked;
+       int flen;               /* fragment frame length including all headers */
+       int free;
+       int count,
+               cp_len;
+       unsigned long flags;
+       unsigned short tt;
+
+       if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
+               return;
+
+       unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       if (dev->free > 16 && dev->write_queue && unacked < 7) {
+
+               if (!dev->w_busy)
+                       dev->w_busy = 1;
+               else {
+                       spin_unlock_irqrestore(&dev->lock, flags);
+                       return;
+               }
+
+
+               frame = dev->write_queue;
+               free = dev->free;
+
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               if (frame->copied == 0) {
+
+                       /* Type 0 frame */
+
+                       ulong   msg;
+
+                       if (frame->skb)
+                               flen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
+                       else
+                               flen = FRAME_HDR_LEN + PREHDR_LEN;
+
+                       if (flen > free)
+                               flen = free;
+
+                       msg = frame->msg;
+
+                       /*
+                        *  Board level 2 header
+                        */
+
+                       pcbit_writew(dev, flen - FRAME_HDR_LEN);
+
+                       pcbit_writeb(dev, GET_MSG_CPU(msg));
+
+                       pcbit_writeb(dev, GET_MSG_PROC(msg));
+
+                       /* TH */
+                       pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
+
+                       /* TD */
+                       pcbit_writew(dev, frame->dt_len);
+
+
+                       /*
+                        *  Board level 3 fixed-header
+                        */
+
+                       /* LEN = TH */
+                       pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
+
+                       /* XX */
+                       pcbit_writew(dev, 0);
+
+                       /* C + S */
+                       pcbit_writeb(dev, GET_MSG_CMD(msg));
+                       pcbit_writeb(dev, GET_MSG_SCMD(msg));
+
+                       /* NUM */
+                       pcbit_writew(dev, frame->refnum);
+
+                       count = FRAME_HDR_LEN + PREHDR_LEN;
+               } else {
+                       /* Type 1 frame */
+
+                       flen = 2 + (frame->skb->len - frame->copied);
+
+                       if (flen > free)
+                               flen = free;
+
+                       /* TT */
+                       tt = ((ushort) (flen - 2)) | 0x8000U;   /* Type 1 */
+                       pcbit_writew(dev, tt);
+
+                       count = 2;
+               }
+
+               if (frame->skb) {
+                       cp_len = frame->skb->len - frame->copied;
+                       if (cp_len > flen - count)
+                               cp_len = flen - count;
+
+                       memcpy_topcbit(dev, frame->skb->data + frame->copied,
+                                      cp_len);
+                       frame->copied += cp_len;
+               }
+               /* bookkeeping */
+               dev->free -= flen;
+               pcbit_tx_update(dev, flen);
+
+               spin_lock_irqsave(&dev->lock, flags);
+
+               if (frame->skb == NULL || frame->copied == frame->skb->len) {
+
+                       dev->write_queue = frame->next;
+
+                       if (frame->skb != NULL) {
+                               /* free frame */
+                               dev_kfree_skb(frame->skb);
+                       }
+                       kfree(frame);
+               }
+               dev->w_busy = 0;
+               spin_unlock_irqrestore(&dev->lock, flags);
+       } else {
+               spin_unlock_irqrestore(&dev->lock, flags);
+#ifdef DEBUG
+               printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
+                      unacked, dev->free, dev->write_queue ? "not empty" :
+                      "empty");
+#endif
+       }
+}
+
+
+/*
+ *  deliver a queued frame to the upper layer
+ */
+
+void
+pcbit_deliver(struct work_struct *work)
+{
+       struct frame_buf *frame;
+       unsigned long flags, msg;
+       struct pcbit_dev *dev =
+               container_of(work, struct pcbit_dev, qdelivery);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       while ((frame = dev->read_queue)) {
+               dev->read_queue = frame->next;
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               msg = 0;
+               SET_MSG_CPU(msg, 0);
+               SET_MSG_PROC(msg, 0);
+               SET_MSG_CMD(msg, frame->skb->data[2]);
+               SET_MSG_SCMD(msg, frame->skb->data[3]);
+
+               frame->refnum = *((ushort *)frame->skb->data + 4);
+               frame->msg = *((ulong *)&msg);
+
+               skb_pull(frame->skb, 6);
+
+               pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
+                                frame->refnum);
+
+               kfree(frame);
+
+               spin_lock_irqsave(&dev->lock, flags);
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/*
+ * Reads BANK 2 & Reassembles
+ */
+
+static void
+pcbit_receive(struct pcbit_dev *dev)
+{
+       unsigned short tt;
+       u_char cpu,
+               proc;
+       struct frame_buf *frame = NULL;
+       unsigned long flags;
+       u_char type1;
+
+       if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
+               return;
+
+       tt = pcbit_readw(dev);
+
+       if ((tt & 0x7fffU) > 511) {
+               printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
+                      tt);
+               pcbit_l2_error(dev);
+               return;
+       }
+       if (!(tt & 0x8000U)) {  /* Type 0 */
+               type1 = 0;
+
+               if (dev->read_frame) {
+                       printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
+                       /* discard previous queued frame */
+                       kfree_skb(dev->read_frame->skb);
+                       kfree(dev->read_frame);
+                       dev->read_frame = NULL;
+               }
+               frame = kzalloc(sizeof(struct frame_buf), GFP_ATOMIC);
+
+               if (frame == NULL) {
+                       printk(KERN_WARNING "kmalloc failed\n");
+                       return;
+               }
+
+               cpu = pcbit_readb(dev);
+               proc = pcbit_readb(dev);
+
+
+               if (cpu != 0x06 && cpu != 0x02) {
+                       printk(KERN_DEBUG "pcbit: invalid cpu value\n");
+                       kfree(frame);
+                       pcbit_l2_error(dev);
+                       return;
+               }
+               /*
+                * we discard cpu & proc on receiving
+                * but we read it to update the pointer
+                */
+
+               frame->hdr_len = pcbit_readw(dev);
+               frame->dt_len = pcbit_readw(dev);
+
+               /*
+                * 0 sized packet
+                * I don't know if they are an error or not...
+                * But they are very frequent
+                * Not documented
+                */
+
+               if (frame->hdr_len == 0) {
+                       kfree(frame);
+#ifdef DEBUG
+                       printk(KERN_DEBUG "0 sized frame\n");
+#endif
+                       pcbit_firmware_bug(dev);
+                       return;
+               }
+               /* sanity check the length values */
+               if (frame->hdr_len > 1024 || frame->dt_len > 2048) {
+#ifdef DEBUG
+                       printk(KERN_DEBUG "length problem: ");
+                       printk(KERN_DEBUG "TH=%04x TD=%04x\n",
+                              frame->hdr_len,
+                              frame->dt_len);
+#endif
+                       pcbit_l2_error(dev);
+                       kfree(frame);
+                       return;
+               }
+               /* minimum frame read */
+
+               frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
+                                          ((frame->hdr_len + 15) & ~15));
+
+               if (!frame->skb) {
+                       printk(KERN_DEBUG "pcbit_receive: out of memory\n");
+                       kfree(frame);
+                       return;
+               }
+               /* 16 byte alignment for IP */
+               if (frame->dt_len)
+                       skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
+
+       } else {
+               /* Type 1 */
+               type1 = 1;
+               tt &= 0x7fffU;
+
+               if (!(frame = dev->read_frame)) {
+                       printk("Type 1 frame and no frame queued\n");
+                       /* usually after an error: toss frame */
+                       dev->readptr += tt;
+                       if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
+                               dev->readptr -= BANKLEN;
+                       return;
+
+               }
+       }
+
+       memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
+
+       frame->copied += tt;
+       spin_lock_irqsave(&dev->lock, flags);
+       if (frame->copied == frame->hdr_len + frame->dt_len) {
+
+               if (type1) {
+                       dev->read_frame = NULL;
+               }
+               if (dev->read_queue) {
+                       struct frame_buf *ptr;
+                       for (ptr = dev->read_queue; ptr->next; ptr = ptr->next);
+                       ptr->next = frame;
+               } else
+                       dev->read_queue = frame;
+
+       } else {
+               dev->read_frame = frame;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/*
+ *  The board sends 0 sized frames
+ *  They are TDATA_CONFs that get messed up somehow
+ *  gotta send a fake acknowledgment to the upper layer somehow
+ */
+
+static __inline__ void
+pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan)
+{
+       isdn_ctrl ictl;
+
+       if (chan->queued) {
+               chan->queued--;
+
+               ictl.driver = dev->id;
+               ictl.command = ISDN_STAT_BSENT;
+               ictl.arg = chan->id;
+               dev->dev_if->statcallb(&ictl);
+       }
+}
+
+static void
+pcbit_firmware_bug(struct pcbit_dev *dev)
+{
+       struct pcbit_chan *chan;
+
+       chan = dev->b1;
+
+       if (chan->fsm_state == ST_ACTIVE) {
+               pcbit_fake_conf(dev, chan);
+       }
+       chan = dev->b2;
+
+       if (chan->fsm_state == ST_ACTIVE) {
+               pcbit_fake_conf(dev, chan);
+       }
+}
+
+irqreturn_t
+pcbit_irq_handler(int interrupt, void *devptr)
+{
+       struct pcbit_dev *dev;
+       u_char info,
+               ack_seq,
+               read_seq;
+
+       dev = (struct pcbit_dev *) devptr;
+
+       if (!dev) {
+               printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
+               return IRQ_NONE;
+       }
+       if (dev->interrupt) {
+               printk(KERN_DEBUG "pcbit: reentering interrupt handler\n");
+               return IRQ_HANDLED;
+       }
+       dev->interrupt = 1;
+
+       info = readb(dev->sh_mem + BANK3);
+
+       if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) {
+               pcbit_l2_active_conf(dev, info);
+               dev->interrupt = 0;
+               return IRQ_HANDLED;
+       }
+       if (info & 0x40U) {     /* E bit set */
+#ifdef DEBUG
+               printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n");
+#endif
+               pcbit_l2_error(dev);
+               dev->interrupt = 0;
+               return IRQ_HANDLED;
+       }
+       if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
+               dev->interrupt = 0;
+               return IRQ_HANDLED;
+       }
+       ack_seq = (info >> 3) & 0x07U;
+       read_seq = (info & 0x07U);
+
+       dev->interrupt = 0;
+
+       if (read_seq != dev->rcv_seq) {
+               while (read_seq != dev->rcv_seq) {
+                       pcbit_receive(dev);
+                       dev->rcv_seq = (dev->rcv_seq + 1) % 8;
+               }
+               pcbit_sched_delivery(dev);
+       }
+       if (ack_seq != dev->unack_seq) {
+               pcbit_recv_ack(dev, ack_seq);
+       }
+       info = dev->rcv_seq << 3;
+       info |= dev->send_seq;
+
+       writeb(info, dev->sh_mem + BANK4);
+       return IRQ_HANDLED;
+}
+
+
+static void
+pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
+{
+       u_char state;
+
+       state = dev->l2_state;
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "layer2_active_confirm\n");
+#endif
+
+
+       if (info & 0x80U) {
+               dev->rcv_seq = info & 0x07U;
+               dev->l2_state = L2_RUNNING;
+       } else
+               dev->l2_state = L2_DOWN;
+
+       if (state == L2_STARTING)
+               wake_up_interruptible(&dev->set_running_wq);
+
+       if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
+               pcbit_transmit(dev);
+       }
+}
+
+static void
+pcbit_l2_err_recover(unsigned long data)
+{
+
+       struct pcbit_dev *dev;
+       struct frame_buf *frame;
+
+       dev = (struct pcbit_dev *) data;
+
+       del_timer(&dev->error_recover_timer);
+       if (dev->w_busy || dev->r_busy) {
+               init_timer(&dev->error_recover_timer);
+               dev->error_recover_timer.expires = jiffies + ERRTIME;
+               add_timer(&dev->error_recover_timer);
+               return;
+       }
+       dev->w_busy = dev->r_busy = 1;
+
+       if (dev->read_frame) {
+               kfree_skb(dev->read_frame->skb);
+               kfree(dev->read_frame);
+               dev->read_frame = NULL;
+       }
+       if (dev->write_queue) {
+               frame = dev->write_queue;
+#ifdef FREE_ON_ERROR
+               dev->write_queue = dev->write_queue->next;
+
+               if (frame->skb) {
+                       dev_kfree_skb(frame->skb);
+               }
+               kfree(frame);
+#else
+               frame->copied = 0;
+#endif
+       }
+       dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
+       dev->free = 511;
+       dev->l2_state = L2_ERROR;
+
+       /* this is an hack... */
+       pcbit_firmware_bug(dev);
+
+       dev->writeptr = dev->sh_mem;
+       dev->readptr = dev->sh_mem + BANK2;
+
+       writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
+              dev->sh_mem + BANK4);
+       dev->w_busy = dev->r_busy = 0;
+
+}
+
+static void
+pcbit_l2_error(struct pcbit_dev *dev)
+{
+       if (dev->l2_state == L2_RUNNING) {
+
+               printk(KERN_INFO "pcbit: layer 2 error\n");
+
+#ifdef DEBUG
+               log_state(dev);
+#endif
+
+               dev->l2_state = L2_DOWN;
+
+               init_timer(&dev->error_recover_timer);
+               dev->error_recover_timer.function = &pcbit_l2_err_recover;
+               dev->error_recover_timer.data = (ulong) dev;
+               dev->error_recover_timer.expires = jiffies + ERRTIME;
+               add_timer(&dev->error_recover_timer);
+       }
+}
+
+/*
+ * Description:
+ * if board acks frames
+ *   update dev->free
+ *   call pcbit_transmit to write possible queued frames
+ */
+
+static void
+pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
+{
+       int i,
+               count;
+       int unacked;
+
+       unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
+
+       /* dev->unack_seq < ack <= dev->send_seq; */
+
+       if (unacked) {
+
+               if (dev->send_seq > dev->unack_seq) {
+                       if (ack <= dev->unack_seq || ack > dev->send_seq) {
+                               printk(KERN_DEBUG
+                                      "layer 2 ack unacceptable - dev %d",
+                                      dev->id);
+
+                               pcbit_l2_error(dev);
+                       } else if (ack > dev->send_seq && ack <= dev->unack_seq) {
+                               printk(KERN_DEBUG
+                                      "layer 2 ack unacceptable - dev %d",
+                                      dev->id);
+                               pcbit_l2_error(dev);
+                       }
+               }
+               /* ack is acceptable */
+
+
+               i = dev->unack_seq;
+
+               do {
+                       dev->unack_seq = i = (i + 1) % 8;
+                       dev->free += dev->fsize[i];
+               } while (i != ack);
+
+               count = 0;
+               while (count < 7 && dev->write_queue) {
+                       u8 lsend_seq = dev->send_seq;
+
+                       pcbit_transmit(dev);
+
+                       if (dev->send_seq == lsend_seq)
+                               break;
+                       count++;
+               }
+       } else
+               printk(KERN_DEBUG "recv_ack: unacked = 0\n");
+}
diff --git a/drivers/staging/i4l/pcbit/layer2.h b/drivers/staging/i4l/pcbit/layer2.h
new file mode 100644 (file)
index 0000000..be1327b
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * PCBIT-D low-layer interface definitions
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ * 19991203 - Fernando Carvalho - takion@superbofh.org
+ * Hacked to compile with egcs and run with current version of isdn modules
+ */
+
+#ifndef LAYER2_H
+#define LAYER2_H
+
+#include <linux/interrupt.h>
+
+#include <asm/byteorder.h>
+
+#define BANK1 0x0000U /* PC -> Board */
+#define BANK2 0x01ffU /* Board -> PC */
+#define BANK3 0x03feU /* Att Board */
+#define BANK4 0x03ffU /* Att PC */
+
+#define BANKLEN 0x01FFU
+
+#define LOAD_ZONE_START 0x03f8U
+#define LOAD_ZONE_END   0x03fdU
+
+#define LOAD_RETRY      18000000
+
+
+
+/* TAM - XX - C - S  - NUM */
+#define PREHDR_LEN 8
+/* TT  - M  - I - TH - TD  */
+#define FRAME_HDR_LEN  8
+
+#define MSG_CONN_REQ           0x08000100
+#define MSG_CONN_CONF          0x00000101
+#define MSG_CONN_IND           0x00000102
+#define MSG_CONN_RESP          0x08000103
+
+#define MSG_CONN_ACTV_REQ      0x08000300
+#define MSG_CONN_ACTV_CONF     0x00000301
+#define MSG_CONN_ACTV_IND      0x00000302
+#define MSG_CONN_ACTV_RESP     0x08000303
+
+#define MSG_DISC_REQ           0x08000400
+#define MSG_DISC_CONF          0x00000401
+#define MSG_DISC_IND           0x00000402
+#define MSG_DISC_RESP          0x08000403
+
+#define MSG_TDATA_REQ          0x0908E200
+#define MSG_TDATA_CONF         0x0000E201
+#define MSG_TDATA_IND          0x0000E202
+#define MSG_TDATA_RESP         0x0908E203
+
+#define MSG_SELP_REQ           0x09004000
+#define MSG_SELP_CONF          0x00004001
+
+#define MSG_ACT_TRANSP_REQ      0x0908E000
+#define MSG_ACT_TRANSP_CONF     0x0000E001
+
+#define MSG_STPROT_REQ         0x09004100
+#define MSG_STPROT_CONF                0x00004101
+
+#define MSG_PING188_REQ                0x09030500
+#define MSG_PING188_CONF        0x000005bc
+
+#define MSG_WATCH188           0x09030400
+
+#define MSG_API_ON              0x08020102
+#define MSG_POOL_PCBIT          0x08020400
+#define MSG_POOL_PCBIT_CONF     0x00000401
+
+#define MSG_INFO_IND            0x00002602
+#define MSG_INFO_RESP           0x08002603
+
+#define MSG_DEBUG_188           0x0000ff00
+
+/*
+
+  long  4 3 2 1
+  Intel 1 2 3 4
+*/
+
+#ifdef __LITTLE_ENDIAN
+#define SET_MSG_SCMD(msg, ch)  (msg = (msg & 0xffffff00) | (((ch) & 0xff)))
+#define SET_MSG_CMD(msg, ch)   (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8))
+#define SET_MSG_PROC(msg, ch)  (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16))
+#define SET_MSG_CPU(msg, ch)   (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24))
+
+#define GET_MSG_SCMD(msg)      ((msg) & 0xFF)
+#define GET_MSG_CMD(msg)       ((msg) >> 8 & 0xFF)
+#define GET_MSG_PROC(msg)      ((msg) >> 16 & 0xFF)
+#define GET_MSG_CPU(msg)       ((msg) >> 24)
+
+#else
+#error "Non-Intel CPU"
+#endif
+
+#define MAX_QUEUED 7
+
+#define SCHED_READ    0x01
+#define SCHED_WRITE   0x02
+
+#define SET_RUN_TIMEOUT 2 * HZ /* 2 seconds */
+
+struct frame_buf {
+       ulong msg;
+       unsigned int refnum;
+       unsigned int dt_len;
+       unsigned int hdr_len;
+       struct sk_buff *skb;
+       unsigned int copied;
+       struct frame_buf *next;
+};
+
+extern int pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
+                         struct sk_buff *skb, unsigned short hdr_len);
+
+extern irqreturn_t pcbit_irq_handler(int interrupt, void *);
+
+extern struct pcbit_dev *dev_pcbit[MAX_PCBIT_CARDS];
+
+#ifdef DEBUG
+static __inline__ void log_state(struct pcbit_dev *dev) {
+       printk(KERN_DEBUG "writeptr = %ld\n",
+              (ulong) (dev->writeptr - dev->sh_mem));
+       printk(KERN_DEBUG "readptr  = %ld\n",
+              (ulong) (dev->readptr - (dev->sh_mem + BANK2)));
+       printk(KERN_DEBUG "{rcv_seq=%01x, send_seq=%01x, unack_seq=%01x}\n",
+              dev->rcv_seq, dev->send_seq, dev->unack_seq);
+}
+#endif
+
+static __inline__ struct pcbit_dev *chan2dev(struct pcbit_chan *chan)
+{
+       struct pcbit_dev *dev;
+       int i;
+
+
+       for (i = 0; i < MAX_PCBIT_CARDS; i++)
+               if ((dev = dev_pcbit[i]))
+                       if (dev->b1 == chan || dev->b2 == chan)
+                               return dev;
+       return NULL;
+
+}
+
+static __inline__ struct pcbit_dev *finddev(int id)
+{
+       struct pcbit_dev *dev;
+       int i;
+
+       for (i = 0; i < MAX_PCBIT_CARDS; i++)
+               if ((dev = dev_pcbit[i]))
+                       if (dev->id == id)
+                               return dev;
+       return NULL;
+}
+
+
+/*
+ *  Support routines for reading and writing in the board
+ */
+
+static __inline__ void pcbit_writeb(struct pcbit_dev *dev, unsigned char dt)
+{
+       writeb(dt, dev->writeptr++);
+       if (dev->writeptr == dev->sh_mem + BANKLEN)
+               dev->writeptr = dev->sh_mem;
+}
+
+static __inline__ void pcbit_writew(struct pcbit_dev *dev, unsigned short dt)
+{
+       int dist;
+
+       dist = BANKLEN - (dev->writeptr - dev->sh_mem);
+       switch (dist) {
+       case 2:
+               writew(dt, dev->writeptr);
+               dev->writeptr = dev->sh_mem;
+               break;
+       case 1:
+               writeb((u_char) (dt & 0x00ffU), dev->writeptr);
+               dev->writeptr = dev->sh_mem;
+               writeb((u_char) (dt >> 8), dev->writeptr++);
+               break;
+       default:
+               writew(dt, dev->writeptr);
+               dev->writeptr += 2;
+               break;
+       };
+}
+
+static __inline__ void memcpy_topcbit(struct pcbit_dev *dev, u_char *data,
+                                     int len)
+{
+       int diff;
+
+       diff = len - (BANKLEN - (dev->writeptr - dev->sh_mem));
+
+       if (diff > 0)
+       {
+               memcpy_toio(dev->writeptr, data, len - diff);
+               memcpy_toio(dev->sh_mem, data + (len - diff), diff);
+               dev->writeptr = dev->sh_mem + diff;
+       }
+       else
+       {
+               memcpy_toio(dev->writeptr, data, len);
+
+               dev->writeptr += len;
+               if (diff == 0)
+                       dev->writeptr = dev->sh_mem;
+       }
+}
+
+static __inline__ unsigned char pcbit_readb(struct pcbit_dev *dev)
+{
+       unsigned char val;
+
+       val = readb(dev->readptr++);
+       if (dev->readptr == dev->sh_mem + BANK2 + BANKLEN)
+               dev->readptr = dev->sh_mem + BANK2;
+
+       return val;
+}
+
+static __inline__ unsigned short pcbit_readw(struct pcbit_dev *dev)
+{
+       int dist;
+       unsigned short val;
+
+       dist = BANKLEN - (dev->readptr - (dev->sh_mem + BANK2));
+       switch (dist) {
+       case 2:
+               val = readw(dev->readptr);
+               dev->readptr = dev->sh_mem + BANK2;
+               break;
+       case 1:
+               val = readb(dev->readptr);
+               dev->readptr = dev->sh_mem + BANK2;
+               val = (readb(dev->readptr++) << 8) | val;
+               break;
+       default:
+               val = readw(dev->readptr);
+               dev->readptr += 2;
+               break;
+       };
+       return val;
+}
+
+static __inline__ void memcpy_frompcbit(struct pcbit_dev *dev, u_char *data, int len)
+{
+       int diff;
+
+       diff = len - (BANKLEN - (dev->readptr - (dev->sh_mem + BANK2)));
+       if (diff > 0)
+       {
+               memcpy_fromio(data, dev->readptr, len - diff);
+               memcpy_fromio(data + (len - diff), dev->sh_mem + BANK2 , diff);
+               dev->readptr = dev->sh_mem + BANK2 + diff;
+       }
+       else
+       {
+               memcpy_fromio(data, dev->readptr, len);
+               dev->readptr += len;
+               if (diff == 0)
+                       dev->readptr = dev->sh_mem + BANK2;
+       }
+}
+
+
+#endif
diff --git a/drivers/staging/i4l/pcbit/module.c b/drivers/staging/i4l/pcbit/module.c
new file mode 100644 (file)
index 0000000..0a59bd0
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * PCBIT-D module support
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+#include "pcbit.h"
+
+MODULE_DESCRIPTION("ISDN4Linux: Driver for PCBIT-T card");
+MODULE_AUTHOR("Pedro Roque Marques");
+MODULE_LICENSE("GPL");
+
+static int mem[MAX_PCBIT_CARDS];
+static int irq[MAX_PCBIT_CARDS];
+
+module_param_array(mem, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+
+static int num_boards;
+struct pcbit_dev *dev_pcbit[MAX_PCBIT_CARDS];
+
+static int __init pcbit_init(void)
+{
+       int board;
+
+       num_boards = 0;
+
+       printk(KERN_NOTICE
+              "PCBIT-D device driver v 0.5-fjpc0 19991204 - "
+              "Copyright (C) 1996 Universidade de Lisboa\n");
+
+       if (mem[0] || irq[0])
+       {
+               for (board = 0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++)
+               {
+                       if (!mem[board])
+                               mem[board] = 0xD0000;
+                       if (!irq[board])
+                               irq[board] = 5;
+
+                       if (pcbit_init_dev(board, mem[board], irq[board]) == 0)
+                               num_boards++;
+
+                       else
+                       {
+                               printk(KERN_WARNING
+                                      "pcbit_init failed for dev %d",
+                                      board + 1);
+                               return -EIO;
+                       }
+               }
+       }
+
+       /* Hardcoded default settings detection */
+
+       if (!num_boards)
+       {
+               printk(KERN_INFO
+                      "Trying to detect board using default settings\n");
+               if (pcbit_init_dev(0, 0xD0000, 5) == 0)
+                       num_boards++;
+               else
+                       return -EIO;
+       }
+       return 0;
+}
+
+static void __exit pcbit_exit(void)
+{
+#ifdef MODULE
+       int board;
+
+       for (board = 0; board < num_boards; board++)
+               pcbit_terminate(board);
+       printk(KERN_NOTICE
+              "PCBIT-D module unloaded\n");
+#endif
+}
+
+#ifndef MODULE
+#define MAX_PARA       (MAX_PCBIT_CARDS * 2)
+static int __init pcbit_setup(char *line)
+{
+       int i, j, argc;
+       char *str;
+       int ints[MAX_PARA + 1];
+
+       str = get_options(line, MAX_PARA, ints);
+       argc = ints[0];
+       i = 0;
+       j = 1;
+
+       while (argc && (i < MAX_PCBIT_CARDS)) {
+
+               if (argc) {
+                       mem[i]  = ints[j];
+                       j++; argc--;
+               }
+
+               if (argc) {
+                       irq[i]  = ints[j];
+                       j++; argc--;
+               }
+
+               i++;
+       }
+       return (1);
+}
+__setup("pcbit=", pcbit_setup);
+#endif
+
+module_init(pcbit_init);
+module_exit(pcbit_exit);
diff --git a/drivers/staging/i4l/pcbit/pcbit.h b/drivers/staging/i4l/pcbit/pcbit.h
new file mode 100644 (file)
index 0000000..0a5a994
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * PCBIT-D device driver definitions
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef PCBIT_H
+#define PCBIT_H
+
+#include <linux/workqueue.h>
+
+#define MAX_PCBIT_CARDS 4
+
+
+#define BLOCK_TIMER
+
+#ifdef __KERNEL__
+
+struct pcbit_chan {
+       unsigned short id;
+       unsigned short callref;                   /* Call Reference */
+       unsigned char  proto;                     /* layer2protocol  */
+       unsigned char  queued;                    /* unacked data messages */
+       unsigned char  layer2link;                /* used in TData */
+       unsigned char  snum;                      /* used in TData */
+       unsigned short s_refnum;
+       unsigned short r_refnum;
+       unsigned short fsm_state;
+       struct timer_list fsm_timer;
+#ifdef BLOCK_TIMER
+       struct timer_list block_timer;
+#endif
+};
+
+struct msn_entry {
+       char *msn;
+       struct msn_entry *next;
+};
+
+struct pcbit_dev {
+       /* board */
+
+       volatile unsigned char __iomem *sh_mem;         /* RDP address  */
+       unsigned long ph_mem;
+       unsigned int irq;
+       unsigned int id;
+       unsigned int interrupt;                 /* set during interrupt
+                                                  processing */
+       spinlock_t lock;
+       /* isdn4linux */
+
+       struct msn_entry *msn_list;             /* ISDN address list */
+
+       isdn_if *dev_if;
+
+       ushort ll_hdrlen;
+       ushort hl_hdrlen;
+
+       /* link layer */
+       unsigned char l2_state;
+
+       struct frame_buf *read_queue;
+       struct frame_buf *read_frame;
+       struct frame_buf *write_queue;
+
+       /* Protocol start */
+       wait_queue_head_t set_running_wq;
+       struct timer_list set_running_timer;
+
+       struct timer_list error_recover_timer;
+
+       struct work_struct qdelivery;
+
+       u_char w_busy;
+       u_char r_busy;
+
+       volatile unsigned char __iomem *readptr;
+       volatile unsigned char __iomem *writeptr;
+
+       ushort loadptr;
+
+       unsigned short fsize[8];                /* sent layer2 frames size */
+
+       unsigned char send_seq;
+       unsigned char rcv_seq;
+       unsigned char unack_seq;
+
+       unsigned short free;
+
+       /* channels */
+
+       struct pcbit_chan *b1;
+       struct pcbit_chan *b2;
+};
+
+#define STATS_TIMER (10 * HZ)
+#define ERRTIME     (HZ / 10)
+
+/* MRU */
+#define MAXBUFSIZE  1534
+#define MRU   MAXBUFSIZE
+
+#define STATBUF_LEN 2048
+/*
+ *
+ */
+
+#endif /* __KERNEL__ */
+
+/* isdn_ctrl only allows a long sized argument */
+
+struct pcbit_ioctl {
+       union {
+               struct byte_op {
+                       ushort addr;
+                       ushort value;
+               } rdp_byte;
+               unsigned long l2_status;
+       } info;
+};
+
+
+
+#define PCBIT_IOCTL_GETSTAT  0x01    /* layer2 status */
+#define PCBIT_IOCTL_LWMODE   0x02    /* linear write mode */
+#define PCBIT_IOCTL_STRLOAD  0x03    /* start load mode */
+#define PCBIT_IOCTL_ENDLOAD  0x04    /* end load mode */
+#define PCBIT_IOCTL_SETBYTE  0x05    /* set byte */
+#define PCBIT_IOCTL_GETBYTE  0x06    /* get byte */
+#define PCBIT_IOCTL_RUNNING  0x07    /* set protocol running */
+#define PCBIT_IOCTL_WATCH188 0x08    /* set watch 188 */
+#define PCBIT_IOCTL_PING188  0x09    /* ping 188 */
+#define PCBIT_IOCTL_FWMODE   0x0A    /* firmware write mode */
+#define PCBIT_IOCTL_STOP     0x0B    /* stop protocol */
+#define PCBIT_IOCTL_APION    0x0C    /* issue API_ON  */
+
+#ifndef __KERNEL__
+
+#define PCBIT_GETSTAT  (PCBIT_IOCTL_GETSTAT  + IIOCDRVCTL)
+#define PCBIT_LWMODE   (PCBIT_IOCTL_LWMODE   + IIOCDRVCTL)
+#define PCBIT_STRLOAD  (PCBIT_IOCTL_STRLOAD  + IIOCDRVCTL)
+#define PCBIT_ENDLOAD  (PCBIT_IOCTL_ENDLOAD  + IIOCDRVCTL)
+#define PCBIT_SETBYTE  (PCBIT_IOCTL_SETBYTE  + IIOCDRVCTL)
+#define PCBIT_GETBYTE  (PCBIT_IOCTL_GETBYTE  + IIOCDRVCTL)
+#define PCBIT_RUNNING  (PCBIT_IOCTL_RUNNING  + IIOCDRVCTL)
+#define PCBIT_WATCH188 (PCBIT_IOCTL_WATCH188 + IIOCDRVCTL)
+#define PCBIT_PING188  (PCBIT_IOCTL_PING188  + IIOCDRVCTL)
+#define PCBIT_FWMODE   (PCBIT_IOCTL_FWMODE   + IIOCDRVCTL)
+#define PCBIT_STOP     (PCBIT_IOCTL_STOP     + IIOCDRVCTL)
+#define PCBIT_APION    (PCBIT_IOCTL_APION    + IIOCDRVCTL)
+
+#define MAXSUPERLINE 3000
+
+#endif
+
+#define L2_DOWN     0
+#define L2_LOADING  1
+#define L2_LWMODE   2
+#define L2_FWMODE   3
+#define L2_STARTING 4
+#define L2_RUNNING  5
+#define L2_ERROR    6
+
+void pcbit_deliver(struct work_struct *work);
+int pcbit_init_dev(int board, int mem_base, int irq);
+void pcbit_terminate(int board);
+void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, struct sk_buff *skb,
+                     ushort hdr_len, ushort refnum);
+void pcbit_state_change(struct pcbit_dev *dev, struct pcbit_chan *chan,
+                       unsigned short i, unsigned short ev, unsigned short f);
+
+#endif
This page took 0.275917 seconds and 5 git commands to generate.