mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
staging: i4l: delete the whole thing
It's now 2017, and a new LTS kernel has been chosen, so let's do what we said we would do in the TODO file and delete this code. If it's still needed, and a maintainer steps up to take it over, we will easily revert it. Cc: Arnd Bergmann <arnd@arndb.de> Cc: Karsten Keil <isdn@linux-pingi.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
457c005aaf
commit
02bbd9802d
@ -96,8 +96,6 @@ source "drivers/staging/wilc1000/Kconfig"
|
||||
|
||||
source "drivers/staging/most/Kconfig"
|
||||
|
||||
source "drivers/staging/i4l/Kconfig"
|
||||
|
||||
source "drivers/staging/ks7010/Kconfig"
|
||||
|
||||
source "drivers/staging/greybus/Kconfig"
|
||||
|
@ -37,7 +37,6 @@ 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/
|
||||
obj-$(CONFIG_KS7010) += ks7010/
|
||||
obj-$(CONFIG_GREYBUS) += greybus/
|
||||
obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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>
|
@ -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.
|
||||
|
@ -1,13 +0,0 @@
|
||||
#
|
||||
# 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
|
@ -1,5 +0,0 @@
|
||||
# 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/
|
@ -1,3 +0,0 @@
|
||||
* 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.
|
@ -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.
|
@ -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
|
@ -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 */
|
@ -1,444 +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;
|
||||
reg = inb(portbase + ISA_COR);
|
||||
if (reg != 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))
|
||||
return -EBUSY;
|
||||
else {
|
||||
card->port = portbase;
|
||||
card->flags |= ACT2000_FLAGS_PVALID;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Release resources, 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) {
|
||||
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)) {
|
||||
card->sbuf = skb_dequeue(&card->sndq);
|
||||
if (card->sbuf) {
|
||||
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;
|
||||
}
|
||||
p = strchr(fid.revision, '\n');
|
||||
if (p)
|
||||
*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;
|
||||
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;
|
||||
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);
|
||||
}
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
@ -1,357 +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, ncci) { \
|
||||
plci = fakencci & 0x1f; \
|
||||
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)
|
||||
*/
|
||||
|
||||
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
|
@ -1,816 +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;
|
||||
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;
|
||||
ret = act2000_set_msn(card, tmp);
|
||||
if (ret)
|
||||
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);
|
@ -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.
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -1,252 +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) {pr_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 */
|
@ -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.
|
@ -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
|
@ -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 <linux/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);
|
||||
}
|
@ -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
|
@ -1,646 +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/kernel.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/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
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -1,310 +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 <linux/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) {
|
||||
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) {
|
||||
setup_timer(&chan->fsm_timer, &pcbit_fsm_timer, (ulong)chan);
|
||||
mod_timer(&chan->fsm_timer, jiffies + tentry->timeout * HZ);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
if (action->callb)
|
||||
action->callb(dev, chan, data);
|
||||
|
||||
}
|
@ -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
|
@ -1,710 +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 <linux/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;
|
||||
|
||||
setup_timer(&dev->error_recover_timer, &pcbit_l2_err_recover,
|
||||
(ulong)dev);
|
||||
mod_timer(&dev->error_recover_timer, jiffies + ERRTIME);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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");
|
||||
}
|
@ -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
|
@ -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);
|
@ -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
|
Loading…
Reference in New Issue
Block a user