This commit was manufactured by cvs2git to create tag 'T4'.

This commit is contained in:
cvs2git 2000-03-04 17:13:14 +00:00
parent d22cbc3d2d
commit fdea602bfa
169 changed files with 0 additions and 76689 deletions

View File

@ -1,8 +0,0 @@
#
# defines for standalone build
#
# WARNING, You can NOT override FEATURES which are disabled in the
# kernel configuration here, only add Drivers here.
#
CONFIG_ISDN_DRV_LOOP=m
CONFIG_ISDN_DRV_ACT2000=m

View File

@ -1,132 +0,0 @@
--- linux-2.0.29.org/Documentation/Configure.help Tue Mar 25 23:24:33 1997
+++ /usr/src/linux/Documentation/Configure.help Tue Mar 25 22:52:13 1997
@@ -1671,6 +1671,15 @@
available via ftp (user: anonymous) at
sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you.
+GDT SCSI Disk Array Controller support
+CONFIG_SCSI_GDTH
+ This is a driver for all SCSI Disk Array Controllers (EISA/ISA/PCI)
+ manufactured by ICP vortex. It is documented in the kernel source in
+ drivers/scsi/gdth.c and drivers/scsi/gdth.h. This driver is also
+ available as a module ( = code which can be inserted in and removed
+ from the running kernel whenever you want). If you want to compile
+ it as a module, say M here and read Documentation/modules.txt.
+
IOMEGA Parallel Port ZIP drive SCSI support
CONFIG_SCSI_PPA
This driver supports the parallel port version of IOMEGA's ZIP drive
@@ -2734,6 +2743,14 @@
change a setting in the file include/linux/gscd.h before compiling
the kernel.
+MicroSolutions backup CDROM support
+CONFIG_BPCD
+ MicroSolutions' backup CDROM is an external drive that connects to
+ the parallel port. Say Y if you have one of these, and read the
+ file linux/Documentation/cdrom/bpcd. If you have several different
+ devices that will share a common parallel port, say M and build them
+ as modules.
+
Philips/LMS CM206 CDROM support
CONFIG_CM206
If you have a Philips/LMS CDROM drive cm206 in combination with a
@@ -3258,6 +3275,7 @@
module load time.
+
Mouse Support (not serial mice)
CONFIG_MOUSE
This is for machines with a bus mouse or a PS/2 mouse as opposed to
@@ -3775,6 +3793,90 @@
Documentation/isdn/README on how to configure it using 16.3, a
different D-channel protocol, or non-standard irq/port/shmem
settings.
+
+HiSax SiemensChipSet driver support
+CONFIG_ISDN_DRV_HISAX
+ This is an alternative driver supporting the Siemens chipset on
+ various ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0,
+ Teles S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and
+ many compatibles).It's a complete rewrite of the original Teles
+ driver. So you either say M or Y here and N in the above Teles
+ section.
+ See Documentation/isdn/README.HiSax for further informations on
+ using this driver.
+
+HiSax Support for Teles 16.0/8.0
+CONFIG_HISAX_16_0
+ This enables HiSax support for the Teles ISDN-cards S0-16.0,
+ S0-8 and many compatibles.
+ See Documentation/isdn/README.HiSax on how to configure it
+ using the different cards, a different D-channel protocol, or
+ non-standard irq/port/shmem settings.
+
+HiSax Support for Teles 16.3 or PNP or PCMCIA
+CONFIG_HISAX_16_3
+ This enables HiSax support for the Teles ISDN-cards S0-16.3
+ the Teles/Creatix PnP and the Teles PCMCIA.
+ See Documentation/isdn/README.HiSax on how to configure it
+ using the different cards, a different D-channel protocol, or
+ non-standard irq/port/shmem settings.
+
+HiSax Support for AVM A1 (Fritz)
+CONFIG_HISAX_AVM_A1
+ This enables HiSax support for the AVM A1 (aka "Fritz").
+ See Documentation/isdn/README.HiSax on how to configure it
+ using the different cards, a different D-channel protocol, or
+ non-standard irq/port/shmem settings.
+
+HiSax Support for Elsa ISA cards
+CONFIG_HISAX_ELSA_PCC
+ This enables HiSax support for the Elsa Mircolink cards and
+ for the Elsa Quickstep series cards for the ISA bus.
+ You don't have to select "HiSax Support for Elsa PCMCIA card"
+ at the same time.
+ See Documentation/isdn/README.HiSax on how to configure it
+ using the different cards, a different D-channel protocol, or
+ non-standard irq/port/shmem settings.
+
+HiSax Support for Elsa PCMCIA card
+CONFIG_HISAX_ELSA_PCMCIA
+ This enables HiSax support for the Elsa PCMCIA card.
+ You don't have to select "HiSax Support for Elsa ISA cards" at
+ the same time.
+ See Documentation/isdn/README.HiSax on how to configure it
+ using the different cards, a different D-channel protocol, or
+ non-standard irq/port/shmem settings.
+
+HiSax Support for ITK ix1-micro Revision 2
+CONFIG_HISAX_IX1MICROR2
+ This enables HiSax support for the ITK ix1-micro Revision 2 card.
+ See Documentation/isdn/README.HiSax on how to configure it
+ using the different cards, a different D-channel protocol, or
+ non-standard irq/port/shmem settings.
+
+HiSax Support for EURO/DSS1
+CONFIG_HISAX_EURO
+ You should choose your D-channel protocol your local
+ telephone service provider uses here by saying Y or N.
+ NOTE: This is mutually exclusive with HiSax Support for
+ german 1TR6 and US/NI-1 if you have only one ISDN card
+ installed.
+
+HiSax Support for US/NI-1
+CONFIG_HISAX_NI1
+ You should choose your D-channel protocol your local
+ telephone service provider uses here by saying Y or N.
+ NOTE: This is mutually exclusive with HiSax Support for
+ german 1TR6 and EURO/DSS1 if you have only one ISDN card
+ installed.
+
+HiSax Support for german 1TR6
+CONFIG_HISAX_1TR6
+ You should choose your D-channel protocol your local
+ telephone service provider uses here by saying Y or N.
+ NOTE: This is mutually exclusive with HiSax Support for
+ EURO/DSS1 and US/NI-1 if you have only one ISDN card
+ installed.
PCBIT-D support
CONFIG_ISDN_DRV_PCBIT

View File

@ -1,32 +0,0 @@
--- Configure.org Sat May 1 19:59:05 1999
+++ Configure.help Sat May 1 20:08:56 1999
@@ -4541,6 +4541,20 @@
driver is the only voice-supporting drivers. See
Documentation/isdn/README.audio for more information.
+ISDN diversion services support
+CONFIG_ISDN_DIVERSION
+ This option allows you to use some supplementary diversion
+ services in conjunction with the HiSax driver on an EURO/DSS1
+ line. Supported options are CD (call deflection), CFU (Call
+ forward unconditional), CFB (Call forward when busy) and CFNR
+ (call forward not reachable).
+ Additionally the actual CFU, CFB and CFNR state may be
+ interrogated. The use of CFU, CFB, CFNR and interrogation may
+ be limited to some countries. The keypad protocol is still not
+ implemented.
+ CD should work in all countries if this service has been sub-
+ scribed.
+
+HiSax driver for HFC-S+, HFC-SP and HFC-PCMCIA cards
+CONFIG_HISAX_HFC_SX
+ This option allows you to add support for for ISDN-cards supplied
+ with CCDs HFC-S+, HFC-SP and HFC-PCMCIA-cards with the SP chip.
+ Drivers for the very old HFC-S chip and the new busmaster HFC-PCI
+ are separate selectable drivers and not covered by this option.
+ Due to problems with cards only equipped with 8K of RAM this driver
+ only supports cards equipped with 32K RAM like CCD recommends.
+
ICN 2B and 4B support
CONFIG_ISDN_DRV_ICN
This enables support for two kinds of ISDN-cards made by a German

View File

@ -1,175 +0,0 @@
--- Configure.help.orig Wed Dec 15 20:35:10 1999
+++ Configure.help Wed Dec 15 20:35:33 1999
@@ -11317,6 +11317,172 @@
Please read the file Documentation/isdn/README.diversion.
+ISDN-ABC-DW Extension
+CONFIG_ISDN_WITH_ABC
+ These are many brand new Options and Features for the
+ ISDN SUBSYSTEM. Including Logical Device bindings,
+ Compression and other good stuff for Optimizing your
+ ISDN System.
+
+ To Use this Extensions you MUST HAVE THE NEWEST
+ ISDN4K-UTILS. You must have Version 3.1-Beta6 or
+ higher. Elsewhere you can not configure this Extensions.
+
+ WARNING ! THIS STUF IS NOT PRODUCTION RELEASE THE
+ FUNCTION ARE UNDER DEVELOPMENT. This ist BETA-CODE.
+ You can use it at you Own Risk.
+
+ For more Information on these Extensions take a look at
+ "linux/Documentation/isdn/dw-abc-extension-howto.txt or
+ Online at the Web "http://i4l.mediatronix.de"
+
+ Please Report Bugs to "mario@mediatronix.de" or
+ "delefw@isdn4linux.de"
+
+D-Channel-Callback with Channel in use check
+CONFIG_ISDN_WITH_ABC_CALLB
+ When a Interface is declared as an Callback Interface,
+ the Interface is checking that the other Side is not
+ Calling on the same time before the Interface is Dialing.
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+ In most case answer with "Yes" when you have Callback devices,
+ otherwise leave it "No"
+
+Outgoing-EAZ-Support
+CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
+ Enables the Feature to Define an other EAZ or MSN for
+ Outgoing calls on an Interface.
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+Least Cost Router Support
+CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
+ This is the final Kernel Code for configuring an Least
+ Cost Router Softwarebased. The other Job is to do the
+ action in ISDNLOG. You need the ISDNLOG to use this
+ function. Currently the ISDNLOG have not the Support for
+ this Option.
+ So in most situations let the Option off.
+
+TCP keepalive detect and response
+CONFIG_ISDN_WITH_ABC_IPV4_TCP_KEEPALIVE
+ This Option works only with the TCP/IP V4. It enables
+ the Function that ISDN Devices are Answering TCP_KEEPALIVE Pakets
+ localy. So that TCP KEEPALIVE Pakets not longer takes the Line
+ open.
+
+Drop frames Sourceadresse is not Interfaceadress
+CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
+ This Option works only with the TCP/IP V4. It will allow only
+ the Transmitt of Pakets where the Sourceadresse is the Interface
+ adress. It is usefull when you have Lines with Dynamic IP.
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+Receive do not reset the Hanguptimer
+CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
+ When you activate this option than the reiceive of pakets do
+ not reset the Hanguptimer. It is very usefull because if the
+ Paket vor your Network your Network generate an Response and
+ the Transmit is reseting the HUPTIMER. But when the Paket is
+ Rejected at your firewall your network generate no Response
+ and no Sendtraffic is generated. So in this case there is no
+ need to Reset the Huptimer because you have only received Data.
+ With that option only Transmitted Data/Pakets will reset the
+ HUPTIMER.
+
+Support of (device-channel) and Binding Groups
+CONFIG_ISDN_WITH_ABC_ICALL_BIND
+ This Option enables the Feature to Bind logical ISDN Interfaces
+ to an prefered ISDN Card or ISDN Card plus Channel. So you have
+ the Chance to keep Channels exclusively for one (or more)
+ Connection. Very usefull when you have more channels and Use
+ Calling Line Identification, because you can organize that your
+ call is going out over the Line with the right EAZ for the CLI.
+
+Skip channel if used external (Dial Only)
+CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
+ When you have more than One ISDN Card in your System and you
+ will Dialout with an Interface you can become the Situation
+ that an External Device such a Telephone or Fax is Using the
+ B-Channels. Normaly ISDN4Linux does not detect this Situation
+ and dial everytime of the "External Busy" line out. With this
+ Option Enabled the I4L will detect that he can not dialout on
+ This Card and dial over the next Card out.
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+Interface autodisable if Config error
+CONFIG_ISDN_WITH_ABC_CONN_ERROR
+ This Option will detect an Device which generate Telephone
+ Cost but does not Function correctly because there are
+ Configerrors on one of the Site. In this Situation the
+ Interface will be marked as Unsuably for some time to do
+ not call every time this Site.
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+UDP-Info-Support
+CONFIG_ISDN_WITH_ABC_UDP_CHECK
+ This is the Mainoption to Enable or Disable the UDP
+ Info Support. An Option to Controll ISDN-Interfaces
+ Remotely. For this very Complex thing take a look at
+
+ "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information.
+
+UDP Hangup Support
+CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
+
+ Sorry no more Information!
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+UDP Dial Support
+CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
+
+ Sorry no more Information!
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+Limit on the line frames to two
+CONFIG_ISDN_WITH_ABC_FRAME_LIMIT
+
+ This Option enables support for sending only 2 Pakets on
+ the Fly to the ISDN Driver. It is very usefull when you
+ will use the new RAW-IP Compression. Because of sending
+ Only 2 Pakets on the Fly makes the risk of overflowing
+ the ISDN Driver very smaller.
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+Compression with RAWIP and X75I
+CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
+
+ With this Option you have the ability to make Datacompression
+ on RAW-IP Lines. It is function on HDLC and X75I Connection,
+ but the Prefered L2-Protocol for Compression is X75I because
+ the HDLC Protocol have no Errorcorrection.
+
+ To Use this Option YOU MUST HAVE ENABLED THE OPTION:
+ Support synchronous PPP
+ and must load after loading the main isdndrivers the
+ Modul "isdn_bsdcomp".
+
+ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
+ for more Information
+
+
ICN 2B and 4B support
CONFIG_ISDN_DRV_ICN
This enables support for two kinds of ISDN-cards made by a German

View File

@ -1,33 +0,0 @@
--- Configure.org Sat Jul 31 14:01:20 1999
+++ Configure.help Sat Jul 31 14:17:49 1999
@@ -9820,6 +9820,30 @@
you need to have access to a machine on the Internet that has a
program like lynx or netscape).
+Eicon.Diehl active card support
+CONFIG_ISDN_DRV_EICON
+ Say Y here if you have an Eicon active ISDN card. In order to use
+ this card, additional firmware is necessary, which has to be loaded
+ into the card using the eiconctrl utility which is part of the latest
+ isdn4k-utils package. Please read the file
+ Documentation/isdn/README.eicon for more information.
+
+Eicon old-type card support
+CONFIG_ISDN_DRV_EICON_ISA
+ Say Y here if you have an old-type Eicon active ISDN card. In order to
+ use this card, additional firmware is necessary, which has to be loaded
+ into the card using the eiconctrl utility which is part of the latest
+ isdn4k-utils package. Please read the file
+ Documentation/isdn/README.eicon for more information.
+
+Support AT-Fax Class 2 commands
+CONFIG_ISDN_TTY_FAX
+ If you say Y here, the modem-emulator will support a subset of the
+ Fax Class 2 commands. Using a getty with fax-support
+ (mgetty+sendfax, hylafax), you will be able to use your Linux box
+ as an ISDN-fax-machine. This must be supported by the lowlevel driver
+ also. See Documentation/isdn/README.fax for more information.
+
AVM-B1 with CAPI2.0 support
CONFIG_ISDN_DRV_AVMB1
This enables support for the AVM B1 ISDN networking cards. In

View File

@ -1,43 +0,0 @@
00-INDEX
- this file (info on ISDN implementation for Linux)
CREDITS
- list of the kind folks that brought you this stuff.
INTERFACE
- description of Linklevel and Hardwarelevel ISDN interface.
README
- general info on what you need and what to do for Linux ISDN.
README.FAQ
- general info for FAQ.
README.audio
- info for running audio over ISDN.
README.fax
- info for using Fax over ISDN.
README.icn
- info on the ICN-ISDN-card and its driver.
README.HiSax
- info on the HiSax driver which replaces the old teles.
README.hfc-pci
- info on hfc-pci based cards.
README.pcbit
- info on the PCBIT-D ISDN adapter and driver.
README.syncppp
- info on running Sync PPP over ISDN.
syncPPP.FAQ
- frequently asked questions about running PPP over ISDN.
README.avmb1
- info on driver for AVM-B1 ISDN card.
README.act2000
- info on driver for IBM ACT-2000 card.
README.eicon
- info on driver for Eicon active cards.
README.concap
- info on "CONCAP" ecapsulation protocol interface used for X.25.
README.diversion
- info on module for isdn diversion services.
README.sc
- info on driver for Spellcaster cards.
README.x25
_ info for running X.25 over ISDN.
README.hysdn
- info on driver for Hypercope active HYSDN cards

View File

@ -1,70 +0,0 @@
I want to thank all who contributed to this project and especially to:
(in alphabetical order)
Thomas Bogendörfer (tsbogend@bigbug.franken.de)
Tester, lots of bugfixes and hints.
Alan Cox (alan@redhat.com)
For help getting into standard-kernel.
Henner Eisen (eis@baty.hanse.de)
For X.25 implementation.
Volker Götz (volker@oops.franken.de)
For contribution of man-pages, the imontty-tool and a perfect
maintaining of the mailing-list at hub-wue.
Matthias Hessler (hessler@isdn4linux.de)
For creating and maintaining the FAQ.
Bernhard Hailer (Bernhard.Hailer@lrz.uni-muenchen.de)
For creating the FAQ, and the leafsite HOWTO.
Michael 'Ghandi' Herold (michael@abadonna.franken.de)
For contribution of the vbox answering machine.
Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
For his Sync-PPP-code.
Karsten Keil (keil@isdn4linux.de)
For adding 1TR6-support to the Teles-driver.
For the HiSax-driver.
Michael Knigge (knick@cove.han.de)
For contributing the imon-tool
Andreas Kool (akool@Kool.f.EUnet.de)
For contribution of the isdnlog/isdnrep-tool
Pedro Roque Marques (roque@di.fc.ul.pt)
For lot of new ideas and the pcbit driver.
Eberhard Moenkeberg (emoenke@gwdg.de)
For testing and help to get into kernel.
Thomas Neumann (tn@ruhr.de)
For help with Cisco-SLARP and keepalive
Jan den Ouden (denouden@groovin.xs4all.nl)
For contribution of the original teles-driver
Carsten Paeth (calle@calle.in-berlin.de)
For the AVM-B1-CAPI2.0 driver
Thomas Pfeiffer (pfeiffer@pds.de)
For V.110, extended T.70 and Hylafax extensions in isdn_tty.c
Max Riegel (riegel@max.franken.de)
For making the ICN hardware-documentation and test-equipment available.
Armin Schindler (mac@melware.de)
For the eicon active card driver.
Gerhard 'Fido' Schneider (fido@wuff.mayn.de)
For heavy-duty-beta-testing with his BBS ;)
Thomas Uhl (uhl@think.de)
For distributing the cards.
For pushing me to work ;-)

View File

@ -1,78 +0,0 @@
-----BEGIN PGP SIGNED MESSAGE-----
First:
HiSax is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
However, if you wish to modify the HiSax sources, please note the following:
HiSax has passed the ITU approval test suite with ELSA Quickstep ISDN cards
and Eicon Technology Diva 2.01 PCI card.
The certification is only valid for the combination of the tested software
version and the tested hardware. Any changes to the HiSax source code may
therefore affect the certification.
If you change the main files of the HiSax ISDN stack, the certification will
become invalid. Because in most countries it is illegal to connect
unapproved ISDN equipment to the public network, I have to guarantee that
changes in HiSax do not affect the certification.
In order to make a valid certification apparent to the user, I have built in
some validation checks that are made during the make process. The HiSax main
files are protected by md5 checksums and the md5sum file is pgp signed by
myself:
KeyID 1024/FF992F6D 1997/01/16 Karsten Keil <kkeil@suse.de>
Key fingerprint = 92 6B F7 58 EE 86 28 C8 C4 1A E6 DC 39 89 F2 AA
Only if the checksums are OK, and the signature of the file
"drivers/isdn/hisax/md5sums.asc" match, is the certification valid; a
message confirming this is then displayed during the hisax init process.
The affected files are:
drivers/isdn/hisax/isac.c
drivers/isdn/hisax/isdnl1.c
drivers/isdn/hisax/isdnl2.c
drivers/isdn/hisax/isdnl3.c
drivers/isdn/hisax/tei.c
drivers/isdn/hisax/callc.c
drivers/isdn/hisax/l3dss1.c
drivers/isdn/hisax/l3_1tr6.c
drivers/isdn/hisax/cert.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/diva.c
Please send any changes, bugfixes and patches to me rather than implementing
them directly into the HiSax sources.
This does not reduce your rights granted by the GNU General Public License.
If you wish to change the sources, go ahead; but note that then the
certification is invalid even if you use one of the approved cards.
Here are the certification registration numbers for ELSA Quickstep cards:
German D133361J CETECOM ICT Services GmbH 0682
European D133362J CETECOM ICT Services GmbH 0682
Karsten Keil
keil@isdn4linux.de
-----BEGIN PGP SIGNATURE-----
Version: 2.6.3i
Charset: noconv
iQCVAwUBOFAwqTpxHvX/mS9tAQFI2QP9GLDK2iy/KBhwReE3F7LeO+tVhffTVZ3a
20q5/z/WcIg/pnH0uTkl2UgDXBFXYl45zJyDGNpAposIFmT+Edd14o7Vj1w/BBdn
Y+5rBmJf+gyBu61da5d6bv0lpymwRa/um+ri+ilYnZ/XPfg5JKhdjGSBCJuJAElM
d2jFbTrsMYw=
=LNf9
-----END PGP SIGNATURE-----

View File

@ -1,783 +0,0 @@
$Id$
Description of the Interface between Linklevel and Hardwarelevel
of isdn4linux:
The Communication between Linklevel (LL) and Hardwarelevel (HL)
is based on the struct isdn_if (defined in isdnif.h).
An HL-driver can register itself at LL by calling the function
register_isdn() with a pointer to that struct. Prior to that, it has
to preset some of the fields of isdn_if. The LL sets the rest of
the fields. All further communication is done via callbacks using
the function-pointers defined in isdn_if.
Changes/Version numbering:
During development of the ISDN subsystem, several changes have been
made to the interface. Before it went into kernel, the package
had a unique version number. The last version, distributed separately
was 0.7.4. When the subsystem went into kernel, every functional unit
got a separate version number. These numbers are shown at initialization,
separated by slashes:
c.c/t.t/n.n/p.p/a.a/v.v
where
c.c is the revision of the common code.
t.t is the revision of the tty related code.
n.n is the revision of the network related code.
p.p is the revision of the ppp related code.
a.a is the revision of the audio related code.
v.v is the revision of the V.110 related code.
Changes in this document are marked with '***CHANGEx' where x representing
the version number. If that number starts with 0, it refers to the old,
separately distributed package. If it starts with one of the letters
above, it refers to the revision of the corresponding module.
***CHANGEIx refers to the revision number of the isdnif.h
1. Description of the fields of isdn_if:
int channels;
This field has to be set by the HL-driver to the number of channels
supported prior to calling register_isdn(). Upon return of the call,
the LL puts an id there, which has to be used by the HL-driver when
invoking the other callbacks.
int maxbufsize;
***CHANGE0.6: New since this version.
Also to be preset by the HL-driver. With this value the HL-driver
tells the LL the maximum size of a data-packet it will accept.
unsigned long features;
To be preset by the HL-driver. Using this field, the HL-driver
announces the features supported. At the moment this is limited to
report the supported layer2 and layer3-protocols. For setting this
field the constants ISDN_FEATURE..., declared in isdnif.h have to be
used.
***CHANGE0.7.1: The line type (1TR6, EDSS1) has to be set.
unsigned short hl_hdrlen;
***CHANGE0.7.4: New field.
To be preset by the HL-driver, if it supports sk_buff's. The driver
should put here the amount of additional space needed in sk_buff's for
its internal purposes. Drivers not supporting sk_buff's should
initialize this field to 0.
void (*rcvcallb_skb)(int, int, struct sk_buff *)
***CHANGE0.7.4: New field.
This field will be set by LL. The HL-driver delivers received data-
packets by calling this function. Upon calling, the HL-driver must
already have its private data pulled off the head of the sk_buff.
Parameter:
int driver-Id
int Channel-number locally to the driver. (starting with 0)
struct sk_buff * Pointer to sk_buff, containing received data.
int (*statcallb)(isdn_ctrl*);
This field will be set by LL. This function has to be called by the
HL-driver for signaling status-changes or other events to the LL.
Parameter:
isdn_ctrl*
The struct isdn_ctrl also defined in isdn_if. The exact meanings of its
fields are described together with the descriptions of the possible
events. Here is only a short description of the fields:
driver = driver Id.
command = event-type. (one of the constants ISDN_STAT_...)
arg = depends on event-type.
num = depends on event-type.
Returnvalue:
0 on success, else -1
int (*command)(isdn_ctrl*);
This field has to be preset by the HL-driver. It points to a function,
to be called by LL to perform functions like dialing, B-channel
setup, etc. The exact meaning of the parameters is described with the
descriptions of the possible commands.
Parameter:
isdn_ctrl*
driver = driver-Id
command = command to perform. (one of the constants ISDN_CMD_...)
arg = depends on command.
num = depends on command.
Returnvalue:
>=0 on success, else error-code (-ENODEV etc.)
int (*writebuf_skb)(int, int, int, struct sk_buff *)
***CHANGE0.7.4: New field.
***CHANGEI.1.21: New field.
This field has to be preset by the HL-driver. The given function will
be called by the LL for delivering data to be send via B-Channel.
Parameter:
int driver-Id ***CHANGE0.7.4: New parameter.
int channel-number locally to the HL-driver. (starts with 0)
int ack ***ChangeI1.21: New parameter
If this is !0, the driver has to signal the delivery
by sending an ISDN_STAT_BSENT. If this is 0, the driver
MUST NOT send an ISDN_STAT_BSENT.
struct sk_buff * Pointer to sk_buff containing data to be send via
B-channel.
Returnvalue:
Length of data accepted on success, else error-code (-EINVAL on
oversized packets etc.)
int (*writecmd)(u_char*, int, int, int, int);
This field has to be preset by the HL-driver. The given function will be
called to perform write-requests on /dev/isdnctrl (i.e. sending commands
to the card) The data-format is hardware-specific. This function is
intended for debugging only. It is not necessary for normal operation
and never will be called by the tty-emulation- or network-code. If
this function is not supported, the driver has to set NULL here.
Parameter:
u_char* pointer to data.
int length of data.
int flag: 0 = call from within kernel-space. (HL-driver must use
memcpy, may NOT use schedule())
1 = call from user-space. (HL-driver must use
memcpy_fromfs, use of schedule() allowed)
int driver-Id.
int channel-number locally to the HL-driver. (starts with 0)
***CHANGEI1.14: The driver-Id and channel-number are new since this revision.
Returnvalue:
Length of data accepted on success, else error-code (-EINVAL etc.)
int (*readstat)(u_char*, int, int, int, int);
This field has to be preset by the HL-driver. The given function will be
called to perform read-requests on /dev/isdnctrl (i.e. reading replies
from the card) The data-format is hardware-specific. This function is
intended for debugging only. It is not necessary for normal operation
and never will be called by the tty-emulation- or network-code. If
this function is not supported, the driver has to set NULL here.
Parameter:
u_char* pointer to data.
int length of data.
int flag: 0 = call from within kernel-space. (HL-driver must use
memcpy, may NOT use schedule())
1 = call from user-space. (HL-driver must use
memcpy_fromfs, use of schedule() allowed)
int driver-Id.
int channel-number locally to the HL-driver. (starts with 0)
***CHANGEI1.14: The driver-Id and channel-number are new since this revision.
Returnvalue:
Length of data on success, else error-code (-EINVAL etc.)
char id[20];
***CHANGE0.7: New since this version.
This string has to be preset by the HL-driver. Its purpose is for
identification of the driver by the user. Eg.: it is shown in the
status-info of /dev/isdninfo. Furthermore it is used as Id for binding
net-interfaces to a specific channel. If a string of length zero is
given, upon return, isdn4linux will replace it by a generic name. (line0,
line1 etc.) It is recommended to make this string configurable during
module-load-time. (copy a global variable to this string.) For doing that,
modules 1.2.8 or newer are necessary.
2. Description of the commands, a HL-driver has to support:
All commands will be performed by calling the function command() described
above from within the LL. The field command of the struct-parameter will
contain the desired command, the field driver is always set to the
appropriate driver-Id.
Until now, the following commands are defined:
***CHANGEI1.34: The parameter "num" has been replaced by a union "parm" containing
the old "num" and a new setup_type struct used for ISDN_CMD_DIAL
and ISDN_STAT_ICALL callback.
ISDN_CMD_IOCTL:
This command is intended for performing ioctl-calls for configuring
hardware or similar purposes (setting port-addresses, loading firmware
etc.) For this purpose, in the LL all ioctl-calls with an argument
>= IIOCDRVCTL (0x100) will be handed transparently to this
function after subtracting 0x100 and placing the result in arg.
Example:
If a userlevel-program calls ioctl(0x101,...) the function gets
called with the field command set to 1.
Parameter:
driver = driver-Id.
command = ISDN_CMD_IOCTL
arg = Original ioctl-cmd - IIOCDRVCTL
parm.num = first bytes filled with (unsigned long)arg
Returnvalue:
Depending on driver.
ISDN_CMD_DIAL:
This command is used to tell the HL-driver it should dial a given
number.
Parameter:
driver = driver-Id.
command = ISDN_CMD_DIAL
arg = channel-number locally to the driver. (starting with 0)
parm.setup.phone = An ASCII-String containing the number to dial.
parm.setup.eazmsn = An ASCII-Sting containing the own EAZ or MSN.
parm.setup.si1 = The Service-Indicator.
parm.setup.si2 = Additional Service-Indicator.
If the Line has been designed as SPV (a special german
feature, meaning semi-leased-line) the phone has to
start with an "S".
***CHANGE0.6: In previous versions the EAZ has been given in the
highbyte of arg.
***CHANGE0.7.1: New since this version: ServiceIndicator and AddInfo.
ISDN_CMD_ACCEPTD:
With this command, the HL-driver is told to accept a D-Channel-setup.
(Response to an incoming call)
Parameter:
driver = driver-Id.
command = ISDN_CMD_ACCEPTD
arg = channel-number locally to the driver. (starting with 0)
parm = unused.
ISDN_CMD_ACCEPTB:
With this command, the HL-driver is told to perform a B-Channel-setup.
(after establishing D-Channel-Connection)
Parameter:
driver = driver-Id.
command = ISDN_CMD_ACCEPTB
arg = channel-number locally to the driver. (starting with 0)
parm = unused.
ISDN_CMD_HANGUP:
With this command, the HL-driver is told to hangup (B-Channel if
established first, then D-Channel). This command is also used for
actively rejecting an incoming call.
Parameter:
driver = driver-Id.
command = ISDN_CMD_HANGUP
arg = channel-number locally to the driver. (starting with 0)
parm = unused.
ISDN_CMD_CLREAZ:
With this command, the HL-driver is told not to signal incoming
calls to the LL.
Parameter:
driver = driver-Id.
command = ISDN_CMD_CLREAZ
arg = channel-number locally to the driver. (starting with 0)
parm = unused.
ISDN_CMD_SETEAZ:
With this command, the HL-driver is told to signal incoming calls for
the given EAZs/MSNs to the LL.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETEAZ
arg = channel-number locally to the driver. (starting with 0)
parm.num = ASCII-String, containing the desired EAZ's/MSN's
(comma-separated). If an empty String is given, the
HL-driver should respond to ALL incoming calls,
regardless of the destination-address.
***CHANGE0.6: New since this version the "empty-string"-feature.
ISDN_CMD_GETEAZ: (currently unused)
With this command, the HL-driver is told to report the current setting
given with ISDN_CMD_SETEAZ.
Parameter:
driver = driver-Id.
command = ISDN_CMD_GETEAZ
arg = channel-number locally to the driver. (starting with 0)
parm.num = ASCII-String, containing the current EAZ's/MSN's
ISDN_CMD_SETSIL: (currently unused)
With this command, the HL-driver is told to signal only incoming
calls with the given Service-Indicators.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETSIL
arg = channel-number locally to the driver. (starting with 0)
parm.num = ASCII-String, containing the desired Service-Indicators.
ISDN_CMD_GETSIL: (currently unused)
With this command, the HL-driver is told to return the current
Service-Indicators it will respond to.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETSIL
arg = channel-number locally to the driver. (starting with 0)
parm.num = ASCII-String, containing the current Service-Indicators.
ISDN_CMD_SETL2:
With this command, the HL-driver is told to select the given Layer-2-
protocol. This command is issued by the LL prior to ISDN_CMD_DIAL or
ISDN_CMD_ACCEPTD.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETL2
arg = channel-number locally to the driver. (starting with 0)
logical or'ed with (protocol-Id << 8)
protocol-Id is one of the constants ISDN_PROTO_L2...
parm = unused.
ISDN_CMD_GETL2: (currently unused)
With this command, the HL-driver is told to return the current
setting of the Layer-2-protocol.
Parameter:
driver = driver-Id.
command = ISDN_CMD_GETL2
arg = channel-number locally to the driver. (starting with 0)
parm = unused.
Returnvalue:
current protocol-Id (one of the constants ISDN_L2_PROTO)
ISDN_CMD_SETL3:
With this command, the HL-driver is told to select the given Layer-3-
protocol. This command is issued by the LL prior to ISDN_CMD_DIAL or
ISDN_CMD_ACCEPTD.
Parameter:
driver = driver-Id.
command = ISDN_CMD_SETL3
arg = channel-number locally to the driver. (starting with 0)
logical or'ed with (protocol-Id << 8)
protocol-Id is one of the constants ISDN_PROTO_L3...
parm.fax = Pointer to T30_s fax struct. (fax usage only)
ISDN_CMD_GETL2: (currently unused)
With this command, the HL-driver is told to return the current
setting of the Layer-3-protocol.
Parameter:
driver = driver-Id.
command = ISDN_CMD_GETL3
arg = channel-number locally to the driver. (starting with 0)
parm = unused.
Returnvalue:
current protocol-Id (one of the constants ISDN_L3_PROTO)
ISDN_CMD_LOCK:
With this command the HL-driver is told, that it will be used by the
LL and therefore may not be unloaded. The HL-driver should use
MOD_INC_USE_COUNT to tell that to the kernel.
Parameter:
driver = driver-Id.
command = ISDN_CMD_LOCK
arg = unused.
parm = unused.
ISDN_CMD_UNLOCK:
With this command the HL-driver is told, that it is no more used by the
LL and therefore may be unloaded. The HL-driver should use
DEC_INC_USE_COUNT to tell that to the kernel.
Parameter:
driver = driver-Id.
command = ISDN_CMD_UNLOCK
arg = unused.
parm = unused.
ISDN_CMD_PROCEED:
With this command, the HL-driver is told to proceed with a incoming call.
Parameter:
driver = driver-Id.
command = ISDN_CMD_PROCEED
arg = channel-number locally to the driver. (starting with 0)
setup.eazmsn= empty string or string send as uus1 in DSS1 with
PROCEED message
ISDN_CMD_ALERT:
With this command, the HL-driver is told to alert a proceeding call.
Parameter:
driver = driver-Id.
command = ISDN_CMD_ALERT
arg = channel-number locally to the driver. (starting with 0)
setup.eazmsn= empty string or string send as uus1 in DSS1 with
ALERT message
ISDN_CMD_REDIR:
With this command, the HL-driver is told to redirect a call in proceeding
or alerting state.
Parameter:
driver = driver-Id.
command = ISDN_CMD_REDIR
arg = channel-number locally to the driver. (starting with 0)
setup.eazmsn= empty string or string send as uus1 in DSS1 protocol
setup.screen= screening indicator
setup.phone = redirected to party number
ISDN_CMD_PROT_IO:
With this call, the LL-driver invokes protocol specific features through
the LL.
The call is not implicitely bound to a connection.
Parameter:
driver = driver-Id
command = ISDN_CMD_PROT_IO
arg = The lower 8 Bits define the adressed protocol as defined
in ISDN_PTYPE..., the upper bits are used to differenciate
the protocol specific CMD.
para = protocol and function specific. See isdnif.h for detail.
ISDN_CMD_FAXCMD:
With this command the HL-driver receives a fax sub-command.
For details refer to INTERFACE.fax
Parameter:
driver = driver-Id.
command = ISDN_CMD_FAXCMD
arg = channel-number locally to the driver. (starting with 0)
parm = unused.
3. Description of the events to be signaled by the HL-driver to the LL.
All status-changes are signaled via calling the previously described
function statcallb(). The field command of the struct isdn_cmd has
to be set by the HL-driver with the appropriate Status-Id (event-number).
The field arg has to be set to the channel-number (locally to the driver,
starting with 0) to which this event applies. (Exception: STAVAIL-event)
Until now, the following Status-Ids are defined:
ISDN_STAT_AVAIL:
With this call, the HL-driver signals the availability of new data
for readstat(). Used only for debugging-purposes, see description
of readstat().
Parameter:
driver = driver-Id
command = ISDN_STAT_STAVAIL
arg = length of available data.
parm = unused.
ISDN_STAT_ICALL:
ISDN_STAT_ICALLW:
With this call, the HL-driver signals an incoming call to the LL.
If ICALLW is signalled the incoming call is a waiting call without
a available B-chan.
Parameter:
driver = driver-Id
command = ISDN_STAT_ICALL
arg = channel-number, locally to the driver. (starting with 0)
para.setup.phone = Callernumber.
para.setup.eazmsn = CalledNumber.
para.setup.si1 = Service Indicator.
para.setup.si2 = Additional Service Indicator.
para.setup.plan = octet 3 from Calling party number Information Element.
para.setup.screen = octet 3a from Calling party number Information Element.
Return:
0 = No device matching this call.
1 = At least one device matching this call (RING on ttyI).
HL-driver may send ALERTING on the D-channel in this case.
2 = Call will be rejected.
3 = Incoming called party number is currently incomplete.
Additional digits are required.
Used for signalling with PtP connections.
4 = Call will be held in a proceeding state
(HL driver sends PROCEEDING)
Used when a user space prog needs time to interpret a call
para.setup.eazmsn may be filled with an uus1 message of
30 octets maximum. Empty string if no uus.
5 = Call will be actively deflected to another party
Only available in DSS1/EURO protocol
para.setup.phone must be set to destination party number
para.setup.eazmsn may be filled with an uus1 message of
30 octets maximum. Empty string if no uus.
-1 = An error happened. (Invalid parameters for example.)
The keypad support now is included in the dial command.
ISDN_STAT_RUN:
With this call, the HL-driver signals availability of the ISDN-card.
(after initializing, loading firmware)
Parameter:
driver = driver-Id
command = ISDN_STAT_RUN
arg = unused.
parm = unused.
ISDN_STAT_STOP:
With this call, the HL-driver signals unavailability of the ISDN-card.
(before unloading, while resetting/reconfiguring the card)
Parameter:
driver = driver-Id
command = ISDN_STAT_STOP
arg = unused.
parm = unused.
ISDN_STAT_DCONN:
With this call, the HL-driver signals the successful establishment of
a D-Channel-connection. (Response to ISDN_CMD_ACCEPTD or ISDN_CMD_DIAL)
Parameter:
driver = driver-Id
command = ISDN_STAT_DCONN
arg = channel-number, locally to the driver. (starting with 0)
parm = unused.
ISDN_STAT_BCONN:
With this call, the HL-driver signals the successful establishment of
a B-Channel-connection. (Response to ISDN_CMD_ACCEPTB or because the
remote-station has initiated establishment)
The HL driver should call this when the logical l2/l3 protocol
connection on top of the physical B-channel is established.
Parameter:
driver = driver-Id
command = ISDN_STAT_BCONN
arg = channel-number, locally to the driver. (starting with 0)
parm.num = ASCII-String, containing type of connection (for analog
modem only). This will be appended to the CONNECT message
e.g. 14400/V.32bis
ISDN_STAT_DHUP:
With this call, the HL-driver signals the shutdown of a
D-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP,
or caused by a remote-hangup or if the remote-station has actively
rejected a call.
Parameter:
driver = driver-Id
command = ISDN_STAT_DHUP
arg = channel-number, locally to the driver. (starting with 0)
parm = unused.
ISDN_STAT_BHUP:
With this call, the HL-driver signals the shutdown of a
B-Channel-connection. This could be a response to a prior ISDN_CMD_HANGUP,
or caused by a remote-hangup.
The HL driver should call this as soon as the logical l2/l3 protocol
connection on top of the physical B-channel is released.
Parameter:
driver = driver-Id
command = ISDN_STAT_BHUP
arg = channel-number, locally to the driver. (starting with 0)
parm = unused.
ISDN_STAT_CINF:
With this call, the HL-driver delivers charge-unit information to the
LL.
Parameter:
driver = driver-Id
command = ISDN_STAT_CINF
arg = channel-number, locally to the driver. (starting with 0)
parm.num = ASCII string containing charge-units (digits only).
ISDN_STAT_LOAD: (currently unused)
ISDN_STAT_UNLOAD:
With this call, the HL-driver signals that it will be unloaded now. This
tells the LL to release all corresponding data-structures.
Parameter:
driver = driver-Id
command = ISDN_STAT_UNLOAD
arg = unused.
parm = unused.
ISDN_STAT_BSENT:
With this call the HL-driver signals the delivery of a data-packet.
This callback is used by the network-interfaces only, tty-Emulation
does not need this call.
Parameter:
driver = driver-Id
command = ISDN_STAT_BSENT
arg = channel-number, locally to the driver. (starting with 0)
parm.length = ***CHANGEI.1.21: New field.
the driver has to set this to the original length
of the skb at the time of receiving it from the linklevel.
ISDN_STAT_NODCH:
With this call, the driver has to respond to a prior ISDN_CMD_DIAL, if
no D-Channel is available.
Parameter:
driver = driver-Id
command = ISDN_STAT_NODCH
arg = channel-number, locally to the driver. (starting with 0)
parm = unused.
ISDN_STAT_ADDCH:
This call is for HL-drivers, which are unable to check card-type
or numbers of supported channels before they have loaded any firmware
using ioctl. Those HL-driver simply set the channel-parameter to a
minimum channel-number when registering, and later if they know
the real amount, perform this call, allocating additional channels.
Parameter:
driver = driver-Id
command = ISDN_STAT_ADDCH
arg = number of channels to be added.
parm = unused.
ISDN_STAT_CAUSE:
With this call, the HL-driver delivers CAUSE-messages to the LL.
Currently the LL does not use this messages. Their contents is simply
logged via kernel-messages. Therefore, currently the format of the
messages is completely free. However they should be printable.
Parameter:
driver = driver-Id
command = ISDN_STAT_NODCH
arg = channel-number, locally to the driver. (starting with 0)
parm.num = ASCII string containing CAUSE-message.
ISDN_STAT_DISPLAY:
With this call, the HL-driver delivers DISPLAY-messages to the LL.
Currently the LL does not use this messages.
Parameter:
driver = driver-Id
command = ISDN_STAT_DISPLAY
arg = channel-number, locally to the driver. (starting with 0)
para.display= string containing DISPLAY-message.
ISDN_STAT_PROT:
With this call, the HL-driver delivers protocol specific infos to the LL.
The call is not implicitely bound to a connection.
Parameter:
driver = driver-Id
command = ISDN_STAT_PROT
arg = The lower 8 Bits define the adressed protocol as defined
in ISDN_PTYPE..., the upper bits are used to differenciate
the protocol specific STAT.
para = protocol and function specific. See isdnif.h for detail.
ISDN_STAT_DISCH:
With this call, the HL-driver signals the LL to disable or enable the
use of supplied channel and driver.
The call may be used to reduce the available number of B-channels after
loading the driver. The LL has to ignore a disabled channel when searching
for free channels. The HL driver itself never delivers STAT callbacks for
disabled channels.
The LL returns a nonzero code if the operation was not successfull or the
selected channel is actually regarded as busy.
Parameter:
driver = driver-Id
command = ISDN_STAT_DISCH
arg = channel-number, locally to the driver. (starting with 0)
parm.num[0] = 0 if channel shall be disabled, else enabled.
ISDN_STAT_L1ERR:
***CHANGEI1.21 new status message.
A signal can be sent to the linklevel if an Layer1-error results in
packet-loss on receive or send. The field errcode of the cmd.parm
union describes the error more precisely.
Parameter:
driver = driver-Id
command = ISDN_STAT_L1ERR
arg = channel-number, locally to the driver. (starting with 0)
parm.errcode= ISDN_STAT_L1ERR_SEND: Packet lost while sending.
ISDN_STAT_L1ERR_RECV: Packet lost while receiving.
ISDN_STAT_FAXIND:
With this call the HL-driver signals a fax sub-command to the LL.
For details refer to INTERFACE.fax
Parameter:
driver = driver-Id.
command = ISDN_STAT_FAXIND
arg = channel-number, locally to the driver. (starting with 0)
parm = unused.

View File

@ -1,163 +0,0 @@
$Id$
Description of the fax-subinterface between linklevel and hardwarelevel of
isdn4linux.
The communication between linklevel (LL) and harwarelevel (HL) for fax
is based on the struct T30_s (defined in isdnif.h).
This struct is allocated in the LL.
In order to use fax, the LL provides the pointer to this struct with the
command ISDN_CMD_SETL3 (parm.fax). This pointer expires in case of hangup
and when a new channel to a new connection is assigned.
Data handling:
In send-mode the HL-driver has to handle the <DLE> codes and the bit-order
conversion by itself.
In receive-mode the LL-driver takes care of the bit-order conversion
(specified by +FBOR)
Structure T30_s description:
This structure stores the values (set by AT-commands), the remote-
capability-values and the command-codes between LL and HL.
If the HL-driver receives ISDN_CMD_FAXCMD, all needed information
is in this struct set by the LL.
To signal information to the LL, the HL-driver has to set the
the parameters and use ISDN_STAT_FAXIND.
(Please refer to INTERFACE)
Structure T30_s:
All members are 8-bit unsigned (__u8)
- resolution
- rate
- width
- length
- compression
- ecm
- binary
- scantime
- id[]
Local faxmachine's parameters, set by +FDIS, +FDCS, +FLID, ...
- r_resolution
- r_rate
- r_width
- r_length
- r_compression
- r_ecm
- r_binary
- r_scantime
- r_id[]
Remote faxmachine's parameters. To be set by HL-driver.
- phase
Defines the actual state of fax connection. Set by HL or LL
depending on progress and type of connection.
If the phase changes because of an AT command, the LL driver
changes this value. Otherwise the HL-driver takes care of it, but
only neccessary on call establishment (from IDLE to PHASE_A).
(one of the constants ISDN_FAX_PHASE_[IDLE,A,B,C,D,E])
- direction
Defines outgoing/send or incoming/receive connection.
(ISDN_TTY_FAX_CONN_[IN,OUT])
- code
Commands from LL to HL; possible constants :
ISDN_TTY_FAX_DR signals +FDR command to HL
ISDN_TTY_FAX_DT signals +FDT command to HL
ISDN_TTY_FAX_ET signals +FET command to HL
Other than that the "code" is set with the hangup-code value at
the end of connection for the +FHNG message.
- r_code
Commands from HL to LL; possible constants :
ISDN_TTY_FAX_CFR output of +FCFR message.
ISDN_TTY_FAX_RID output of remote ID set in r_id[]
(+FCSI/+FTSI on send/receive)
ISDN_TTY_FAX_DCS output of +FDCS and CONNECT message,
switching to phase C.
ISDN_TTY_FAX_ET signals end of data,
switching to phase D.
ISDN_TTY_FAX_FCON signals the established, outgoing connection,
switching to phase B.
ISDN_TTY_FAX_FCON_I signals the established, incoming connection,
switching to phase B.
ISDN_TTY_FAX_DIS output of +FDIS message and values.
ISDN_TTY_FAX_SENT signals that all data has been sent
and <DLE><ETX> is acknowledged,
OK message will be sent.
ISDN_TTY_FAX_PTS signals a msg-confirmation (page sent successful),
depending on fet value:
0: output OK message (more pages follow)
1: switching to phase B (next document)
ISDN_TTY_FAX_TRAIN_OK output of +FDCS and OK message (for receive mode).
ISDN_TTY_FAX_EOP signals end of data in receive mode,
switching to phase D.
ISDN_TTY_FAX_HNG output of the +FHNG and value set by code and
OK message, switching to phase E.
- badlin
Value of +FBADLIN
- badmul
Value of +FBADMUL
- bor
Value of +FBOR
- fet
Value of +FET command in send-mode.
Set by HL in receive-mode for +FET message.
- pollid[]
ID-string, set by +FCIG
- cq
Value of +FCQ
- cr
Value of +FCR
- ctcrty
Value of +FCTCRTY
- minsp
Value of +FMINSP
- phcto
Value of +FPHCTO
- rel
Value of +FREL
- nbc
Value of +FNBC (0,1)
(+FNBC is not a known class 2 fax command, I added this to change the
automatic "best capabilities" connection in the eicon HL-driver)
Armin
mac@melware.de

View File

@ -1,597 +0,0 @@
README for the ISDN-subsystem
1. Preface
1.1 Introduction
This README describes how to set up and how to use the different parts
of the ISDN-subsystem.
For using the ISDN-subsystem, some additional userlevel programs are
necessary. Those programs and some contributed utilities are available
at
ftp.isdn4linux.de
/pub/isdn4linux/isdn4k-utils-<VersionNumber>.tar.gz
We also have set up a mailing-list:
The isdn4linux-project originates in Germany, and therefore by historical
reasons, the mailing-list's primary language is german. However mails
written in english have been welcome all the time.
to subscribe: write a email to majordomo@listserv.isdn4linux.de,
Subject irrelevant, in the message body:
subscribe isdn4linux <your_email_address>
To write to the mailing-list, write to isdn4linux@listserv.isdn4linux.de
This mailinglist is bidirectionally gated to the newsgroup
de.alt.comm.isdn4linux
There is also a well maintained FAQ in English available at
http://www.mhessler.de/i4lfaq/
It can be viewed online, or downloaded in sgml/text/html format.
The FAQ can also be viewed online at
http://www.isdn4inux.de/faq/
or downloaded from
ftp://ftp.isdn4linux.de/pub/isdn4linux/FAQ/
1.1 Technical details
In the following Text, the terms MSN and EAZ are used.
MSN is the abbreviation for (M)ultiple(S)ubscriber(N)umber, and applies
to Euro(EDSS1)-type lines. Usually it is simply the phone number.
EAZ is the abbreviation of (E)ndgeraete(A)uswahl(Z)iffer and
applies to German 1TR6-type lines. This is a one-digit string,
simply appended to the base phone number
The internal handling is nearly identical, so replace the appropriate
term to that one, which applies to your local ISDN-environment.
When the link-level-module isdn.o is loaded, it supports up to 16
low-level-modules with up to 64 channels. (The number 64 is arbitrarily
chosen and can be configured at compile-time --ISDN_MAX in isdn.h).
A low-level-driver can register itself through an interface (which is
defined in isdnif.h) and gets assigned a slot.
The following char-devices are made available for each channel:
A raw-control-device with the following functions:
write: raw D-channel-messages (format: depends on driver).
read: raw D-channel-messages (format: depends on driver).
ioctl: depends on driver, i.e. for the ICN-driver, the base-address of
the ports and the shared memory on the card can be set and read
also the boot-code and the protocol software can be loaded into
the card.
O N L Y !!! for debugging (no locking against other devices):
One raw-data-device with the following functions:
write: data to B-channel.
read: data from B-channel.
In addition the following devices are made available:
128 tty-devices (64 cuix and 64 ttyIx) with integrated modem-emulator:
The functionality is almost the same as that of a serial device
(the line-discs are handled by the kernel), which lets you run
SLIP, CSLIP and asynchronous PPP through the devices. We have tested
Seyon, minicom, CSLIP (uri-dip) PPP, mgetty, XCept and Hylafax.
The modem-emulation supports the following:
1.3.1 Commands:
ATA Answer incoming call.
ATD<No.> Dial, the number may contain:
[0-9] and [,#.*WPT-S]
the latter are ignored until 'S'.
The 'S' must precede the number, if
the line is a SPV (German 1TR6).
ATE0 Echo off.
ATE1 Echo on (default).
ATH Hang-up.
ATH1 Off hook (ignored).
ATH0 Hang-up.
ATI Return "ISDN for Linux...".
ATI0 "
ATI1 "
ATI2 Report of last connection.
ATO On line (data mode).
ATQ0 Enable result codes (default).
ATQ1 Disable result codes (default).
ATSx=y Set register x to y.
ATSx? Show contents of register x.
ATV0 Numeric responses.
ATV1 English responses (default).
ATZ Load registers and EAZ/MSN from Profile.
AT&Bx Set Send-Packet-size to x (max. 4000)
The real packet-size may be limited by the
low-level-driver used. e.g. the HiSax-Module-
limit is 2000. You will get NO Error-Message,
if you set it to higher values, because at the
time of giving this command the corresponding
driver may not be selected (see "Automatic
Assignment") however the size of outgoing packets
will be limited correctly.
AT&D0 Ignore DTR
AT&D2 DTR-low-edge: Hang up and return to
command mode (default).
AT&D3 Same as AT&D2 but also resets all registers.
AT&Ex Set the EAZ/MSN for this channel to x.
AT&F Reset all registers and profile to "factory-defaults"
AT&Lx Set list of phone numbers to listen on. x is a
list of wildcard patterns separated by semicolon.
If this is set, it has precedence over the MSN set
by AT&E.
AT&Rx Select V.110 bitrate adaption.
This command enables V.110 protocol with 9600 baud
(x=9600), 19200 baud (x=19200) or 38400 baud
(x=38400). A value of x=0 disables V.110 switching
back to default X.75. This command sets the following
Registers:
Reg 14 (Layer-2 protocol):
x = 0: 0
x = 9600: 7
x = 19200: 8
x = 38400: 9
Reg 18.2 = 1
Reg 19 (Additional Service Indicator):
x = 0: 0
x = 9600: 197
x = 19200: 199
x = 38400: 198
Note on value in Reg 19:
There is _NO_ common convention for 38400 baud.
The value 198 is choosen arbitrarily. Users
_MUST_ negotiate this value before establishing
a connection.
AT&Sx Set window-size (x = 1..8) (not yet implemented)
AT&V Show all settings.
AT&W0 Write registers and EAZ/MSN to profile. See also
iprofd (5.c in this README).
AT&X0 BTX-mode and T.70-mode off (default)
AT&X1 BTX-mode on. (S13.1=1, S13.5=0 S14=0, S16=7, S18=7, S19=0)
AT&X2 T.70-mode on. (S13.1=1, S13.5=1, S14=0, S16=7, S18=7, S19=0)
AT+Rx Resume a suspended call with CallID x (x = 1,2,3...)
AT+Sx Suspend a call with CallID x (x = 1,2,3...)
For voice-mode commands refer to README.audio
1.3.2 Escape sequence:
During a connection, the emulation reacts just like
a normal modem to the escape sequence <DELAY>+++<DELAY>.
(The escape character - default '+' - can be set in the
register 2).
The DELAY must at least be 1.5 seconds long and delay
between the escape characters must not exceed 0.5 seconds.
1.3.3 Registers:
Nr. Default Description
0 0 Answer on ring number.
(no auto-answer if S0=0).
1 0 Count of rings.
2 43 Escape character.
(a value >= 128 disables the escape sequence).
3 13 Carriage return character (ASCII).
4 10 Line feed character (ASCII).
5 8 Backspace character (ASCII).
6 3 Delay in seconds before dialing.
7 60 Wait for carrier.
8 2 Pause time for comma (ignored)
9 6 Carrier detect time (ignored)
10 7 Carrier loss to disconnect time (ignored).
11 70 Touch tone timing (ignored).
12 69 Bit coded register:
Bit 0: 0 = Suppress response messages.
1 = Show response messages.
Bit 1: 0 = English response messages.
1 = Numeric response messages.
Bit 2: 0 = Echo off.
1 = Echo on.
Bit 3 0 = DCD always on.
1 = DCD follows carrier.
Bit 4 0 = CTS follows RTS
1 = Ignore RTS, CTS always on.
Bit 5 0 = return to command mode on DTR low.
1 = Same as 0 but also resets all
registers.
See also register 13, bit 2
Bit 6 0 = DSR always on.
1 = DSR only on if channel is available.
Bit 7 0 = Cisco-PPP-flag-hack off (default).
1 = Cisco-PPP-flag-hack on.
13 0 Bit coded register:
Bit 0: 0 = Use delayed tty-send-algorithm
1 = Direct tty-send.
Bit 1: 0 = T.70 protocol (Only for BTX!) off
1 = T.70 protocol (Only for BTX!) on
Bit 2: 0 = Don't hangup on DTR low.
1 = Hangup on DTR low.
Bit 3: 0 = Standard response messages
1 = Extended response messages
Bit 4: 0 = CALLER NUMBER before every RING.
1 = CALLER NUMBER after first RING.
Bit 5: 0 = T.70 extended protocol off
1 = T.70 extended protocol on
Bit 6: 0 = Special RUNG Message off
1 = Special RUNG Message on
"RUNG" is delivered on a ttyI, if
an incoming call happened (RING) and
the remote party hung up before any
local ATA was given.
Bit 7: 0 = Don't show display messages from net
1 = Show display messages from net
(S12 Bit 1 must be 0 too)
14 0 Layer-2 protocol:
0 = X75/LAPB with I-frames
1 = X75/LAPB with UI-frames
2 = X75/LAPB with BUI-frames
3 = HDLC
4 = Transparent (audio)
7 = V.110, 9600 baud
8 = V.110, 19200 baud
9 = V.110, 38400 baud
10 = Analog Modem (only if hardware supports this)
11 = Fax G3 (only if hardware supports this)
15 0 Layer-3 protocol:
0 = transparent
1 = transparent with audio features (e.g. DSP)
2 = Fax G3 Class 2 commands (S14 has to be set to 11)
2 = Fax G3 Class 1 commands (S14 has to be set to 11)
16 250 Send-Packet-size/16
17 8 Window-size (not yet implemented)
18 4 Bit coded register, Service-Octet-1 to accept,
or to be used on dialout:
Bit 0: Service 1 (audio) when set.
Bit 1: Service 5 (BTX) when set.
Bit 2: Service 7 (data) when set.
Note: It is possible to set more than one
bit. In this case, on incoming calls
the selected services are accepted,
and if the service is "audio", the
Layer-2-protocol is automatically
changed to 4 regardless of the setting
of register 14. On outgoing calls,
the most significant 1-bit is chosen to
select the outgoing service octet.
19 0 Service-Octet-2
20 0 Bit coded register (readonly)
Service-Octet-1 of last call.
Bit mapping is the same as register 18
21 0 Bit coded register (readonly)
Set on incoming call (during RING) to
octet 3 of calling party number IE (Numbering plan)
See section 4.5.10 of ITU Q.931
22 0 Bit coded register (readonly)
Set on incoming call (during RING) to
octet 3a of calling party number IE (Screening info)
See section 4.5.10 of ITU Q.931
23 0 Bit coded register:
Bit 0: 0 = Add CPN to RING message off
1 = Add CPN to RING message on
Bit 1: 0 = Add CPN to FCON message off
1 = Add CPN to FCON message on
Last but not least a (at the moment fairly primitive) device to request
the line-status (/dev/isdninfo) is made available.
Automatic assignment of devices to lines:
All inactive physical lines are listening to all EAZs for incoming
calls and are NOT assigned to a specific tty or network interface.
When an incoming call is detected, the driver looks first for a network
interface and then for an opened tty which:
1. is configured for the same EAZ.
2. has the same protocol settings for the B-channel.
3. (only for network interfaces if the security flag is set)
contains the caller number in its access list.
4. Either the channel is not bound exclusively to another Net-interface, or
it is bound AND the other checks apply to exactly this interface.
(For usage of the bind-features, refer to the isdnctrl-man-page)
Only when a matching interface or tty is found is the call accepted
and the "connection" between the low-level-layer and the link-level-layer
is established and kept until the end of the connection.
In all other cases no connection is established. Isdn4linux can be
configured to either do NOTHING in this case (which is useful, if
other, external devices with the same EAZ/MSN are connected to the bus)
or to reject the call actively. (isdnctrl busreject ...)
For an outgoing call, the inactive physical lines are searched.
The call is placed on the first physical line, which supports the
requested protocols for the B-channel. If a net-interface, however
is pre-bound to a channel, this channel is used directly.
This makes it possible to configure several network interfaces and ttys
for one EAZ, if the network interfaces are set to secure operation.
If an incoming call matches one network interface, it gets connected to it.
If another incoming call for the same EAZ arrives, which does not match
a network interface, the first tty gets a "RING" and so on.
2 System prerequisites:
ATTENTION!
Always use the latest module utilities. The current version is
named in Documentation/Changes. Some old versions of insmod
are not capable of setting the driver-Ids correctly.
3. Lowlevel-driver configuration.
Configuration depends on how the drivers are built. See the
README.<yourDriver> for information on driver-specific setup.
4. Device-inodes
The major and minor numbers and their names are described in
Documentation/devices.txt. The major numbers are:
43 for the ISDN-tty's.
44 for the ISDN-callout-tty's.
45 for control/info/debug devices.
5. Application
a) For some card-types, firmware has to be loaded into the cards, before
proceeding with device-independent setup. See README.<yourDriver>
for how to do that.
b) If you only intend to use ttys, you are nearly ready now.
c) If you want to have really permanent "Modem"-settings on disk, you
can start the daemon iprofd. Give it a path to a file at the command-
line. It will store the profile-settings in this file every time
an AT&W0 is performed on any ISDN-tty. If the file already exists,
all profiles are initialized from this file. If you want to unload
any of the modules, kill iprofd first.
d) For networking, continue: Create an interface:
isdnctrl addif isdn0
e) Set the EAZ (or MSN for Euro-ISDN):
isdnctrl eaz isdn0 2
(For 1TR6 a single digit is allowed, for Euro-ISDN the number is your
real MSN e.g.: Phone-Number)
f) Set the number for outgoing calls on the interface:
isdnctrl addphone isdn0 out 1234567
... (this can be executed more than once, all assigned numbers are
tried in order)
and the number(s) for incoming calls:
isdnctrl addphone isdn0 in 1234567
g) Set the timeout for hang-up:
isdnctrl huptimeout isdn0 <timeout_in_seconds>
h) additionally you may activate charge-hang-up (= Hang up before
next charge-info, this only works, if your isdn-provider transmits
the charge-info during and after the connection):
isdnctrl chargehup isdn0 on
i) Set the dial mode of the interface:
isdnctrl dialmode isdn0 auto
"off" means that you (or the system) cannot make any connection
(neither incoming or outgoing connections are possible). Use
this if you want to be sure that no connections will be made.
"auto" means that the interface is in auto-dial mode, and will
attempt to make a connection whenever a network data packet needs
the interface's link. Note that this can cause unexpected dialouts,
and lead to a high phone bill! Some daemons or other pc's that use
this interface can cause this.
Incoming connections are also possible.
"manual" is a dial mode created to prevent the unexpected dialouts.
In this mode, the interface will never make any connections on its
own. You must explicitly initiate a connection with "isdnctrl dial
isdn0". However, after an idle time of no traffic as configured for
the huptimeout value with isdnctrl, the connection _will_ be ended.
If you don't want any automatic hangup, set the huptimeout value to 0.
"manual" is the default.
j) Setup the interface with ifconfig as usual, and set a route to it.
k) (optional) If you run X11 and have Tcl/Tk-wish version 4.0, you can use
the script tools/tcltk/isdnmon. You can add actions for line-status
changes. See the comments at the beginning of the script for how to
do that. There are other tty-based tools in the tools-subdirectory
contributed by Michael Knigge (imon), Volker Götz (imontty) and
Andreas Kool (isdnmon).
l) For initial testing, you can set the verbose-level to 2 (default: 0).
Then all incoming calls are logged, even if they are not addressed
to one of the configured net-interfaces:
isdnctrl verbose 2
Now you are ready! A ping to the set address should now result in an
automatic dial-out (look at syslog kernel-messages).
The phone numbers and EAZs can be assigned at any time with isdnctrl.
You can add as many interfaces as you like with addif following the
directions above. Of course, there may be some limitations. But we have
tested as many as 20 interfaces without any problem. However, if you
don't give an interface name to addif, the kernel will assign a name
which starts with "eth". The number of "eth"-interfaces is limited by
the kernel.
5. Additional options for isdnctrl:
"isdnctrl secure <InterfaceName> on"
Only incoming calls, for which the caller-id is listed in the access
list of the interface are accepted. You can add caller-id's With the
command "isdnctrl addphone <InterfaceName> in <caller-id>"
Euro-ISDN does not transmit the leading '0' of the caller-id for an
incoming call, therefore you should configure it accordingly.
If the real number for the dialout e.g. is "09311234567" the number
to configure here is "9311234567". The pattern-match function
works similar to the shell mechanism.
? one arbitrary digit
* zero or arbitrary many digits
[123] one of the digits in the list
[1-5] one digit between '1' and '5'
a '^' as the first character in a list inverts the list
"isdnctrl secure <InterfaceName> off"
Switch off secure operation (default).
"isdnctrl ihup <InterfaceName> [on|off]"
Switch the hang-up-timer for incoming calls on or off.
"isdnctrl eaz <InterfaceName>"
Returns the EAZ of an interface.
"isdnctrl delphone <InterfaceName> in|out <number>"
Deletes a number from one of the access-lists of the interface.
"isdnctrl delif <InterfaceName>"
Removes the interface (and possible slaves) from the kernel.
(You have to unregister it with "ifconfig <InterfaceName> down" before).
"isdnctrl callback <InterfaceName> [on|off]"
Switches an interface to callback-mode. In this mode, an incoming call
will be rejected and after this the remote-station will be called. If
you test this feature by using ping, some routers will re-dial very
quickly, so that the callback from isdn4linux may not be recognized.
In this case use ping with the option -i <sec> to increase the interval
between echo-packets.
"isdnctrl cbdelay <InterfaceName> [seconds]"
Sets the delay (default 5 sec) between an incoming call and start of
dialing when callback is enabled.
"isdnctrl cbhup <InterfaceName> [on|off]"
This enables (default) or disables an active hangup (reject) when getting an
incoming call for an interface which is configured for callback.
"isdnctrl encap <InterfaceName> <EncapType>"
Selects the type of packet-encapsulation. The encapsulation can be changed
only while an interface is down.
At the moment the following values are supported:
rawip (Default) Selects raw-IP-encapsulation. This means, MAC-headers
are stripped off.
ip IP with type-field. Same as IP but the type-field of the MAC-header
is preserved.
x25iface X.25 interface encapsulation (first byte semantics as defined in
../networking/x25-iface.txt). Use this for running the linux
X.25 network protocol stack (AF_X25 sockets) on top of isdn.
cisco-h A special-mode for communicating with a Cisco, which is configured
to do "hdlc"
ethernet No stripping. Packets are sent with full MAC-header.
The Ethernet-address of the interface is faked, from its
IP-address: fc:fc:i1:i2:i3:i4, where i1-4 are the IP-addr.-values.
syncppp Synchronous PPP
uihdlc HDLC with UI-frame-header (for use with DOS ISPA, option -h1)
NOTE: x25iface encapsulation is currently experimental. Please
read README.x25 for further details
Watching packets, using standard-tcpdump will fail for all encapsulations
except ethernet because tcpdump does not know how to handle packets
without MAC-header. A patch for tcpdump is included in the utility-package
mentioned above.
"isdnctrl l2_prot <InterfaceName> <L2-ProtocolName>"
Selects a layer-2-protocol.
(With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available.
With other drivers, "x75ui", "x75bui", "x25dte", "x25dce" may be
possible too. See README.x25 for x25 related l2 protocols.)
isdnctrl l3_prot <InterfaceName> <L3-ProtocolName>
The same for layer-3. (At the moment only "trans" is allowed)
"isdnctrl list <InterfaceName>"
Shows all parameters of an interface and the charge-info.
Try "all" as the interface name.
"isdnctrl hangup <InterfaceName>"
Forces hangup of an interface.
"isdnctrl bind <InterfaceName> <DriverId>,<ChannelNumber> [exclusive]"
If you are using more than one ISDN card, it is sometimes necessary to
dial out using a specific card or even preserve a specific channel for
dialout of a specific net-interface. This can be done with the above
command. Replace <DriverId> by whatever you assigned while loading the
module. The <ChannelNumber> is counted from zero. The upper limit
depends on the card used. At the moment no card supports more than
2 channels, so the upper limit is one.
"isdnctrl unbind <InterfaceName>"
unbinds a previously bound interface.
"isdnctrl busreject <DriverId> on|off"
If switched on, isdn4linux replies a REJECT to incoming calls, it
cannot match to any configured interface.
If switched off, nothing happens in this case.
You normally should NOT enable this feature, if the ISDN adapter is not
the only device connected to the S0-bus. Otherwise it could happen that
isdn4linux rejects an incoming call, which belongs to another device on
the bus.
"isdnctrl addslave <InterfaceName> <SlaveName>
Creates a slave interface for channel-bundling. Slave interfaces are
not seen by the kernel, but their ISDN-part can be configured with
isdnctrl as usual. (Phone numbers, EAZ/MSN, timeouts etc.) If more
than two channels are to be bundled, feel free to create as many as you
want. InterfaceName must be a real interface, NOT a slave. Slave interfaces
start dialing, if the master interface resp. the previous slave interface
has a load of more than 7000 cps. They hangup if the load goes under 7000
cps, according to their "huptimeout"-parameter.
"isdnctrl sdelay <InterfaceName> secs."
This sets the minimum time an Interface has to be fully loaded, until
it sends a dial-request to its slave.
"isdnctrl dial <InterfaceName>"
Forces an interface to start dialing even if no packets are to be
transferred.
"isdnctrl mapping <DriverId> MSN0,MSN1,MSN2,...MSN9"
This installs a mapping table for EAZ<->MSN-mapping for a single line.
Missing MSN's have to be given as "-" or can be omitted, if at the end
of the commandline.
With this command, it's now possible to have an interface listening to
mixed 1TR6- and Euro-Type lines. In this case, the interface has to be
configured to a 1TR6-type EAZ (one digit). The mapping is also valid
for tty-emulation. Seen from the interface/tty-level the mapping
CAN be used, however it's possible to use single tty's/interfaces with
real MSN's (more digits) also, in which case the mapping will be ignored.
Here is an example:
You have a 1TR6-type line with base-nr. 1234567 and a Euro-line with
MSN's 987654, 987655 and 987656. The DriverId for the Euro-line is "EURO".
isdnctrl mapping EURO -,987654,987655,987656,-,987655
...
isdnctrl eaz isdn0 1 # listen on 12345671(1tr6) and 987654(euro)
...
isdnctrl eaz isdn1 4 # listen on 12345674(1tr6) only.
...
isdnctrl eaz isdn2 987654 # listen on 987654(euro) only.
Same scheme is used with AT&E... at the tty's.
6. If you want to write a new low-level-driver, you are welcome.
The interface to the link-level-module is described in the file INTERFACE.
If the interface should be expanded for any reason, don't do it
on your own, send me a mail containing the proposed changes and
some reasoning about them.
If other drivers will not be affected, I will include the changes
in the next release.
For developers only, there is a second mailing-list. Write to me
(fritz@isdn4linux.de), if you want to join that list.
Have fun!
-Fritz

View File

@ -1,26 +0,0 @@
The FAQ for isdn4linux
======================
Please note that there is a big FAQ available in the isdn4k-utils.
You find it in:
isdn4k-utils/FAQ/i4lfaq.sgml
In case you just want to see the FAQ online, or download the newest version,
you can have a look at my website:
http://www.mhessler.de/i4lfaq/ (view + download)
or:
http://www.isdn4linux.de/faq/ (view)
As the extension tells, the FAQ is in SGML format, and you can convert it
into text/html/... format by using the sgml2txt/sgml2html/... tools.
Alternatively, you can also do a 'configure; make all' in the FAQ directory.
Please have a look at the FAQ before posting anything in the Mailinglist,
or the newsgroup!
Matthias Hessler
hessler@isdn4linux.de

View File

@ -1,633 +0,0 @@
HiSax is a Linux hardware-level driver for passive ISDN cards with Siemens
chipset (ISAC_S 2085/2086/2186, HSCX SAB 82525). It is based on the Teles
driver from Jan den Ouden.
It is meant to be used with isdn4linux, an ISDN link-level module for Linux
written by Fritz Elfert.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Supported cards
---------------
Teles 8.0/16.0/16.3 and compatible ones
Teles 16.3c
Teles S0/PCMCIA
Teles PCI
Teles S0Box
Creatix S0Box
Creatix PnP S0
Compaq ISDN S0 ISA card
AVM A1 (Fritz, Teledat 150)
AVM Fritz PCMCIA
AVM Fritz PnP
AVM Fritz PCI
ELSA Microlink PCC-16, PCF, PCF-Pro, PCC-8
ELSA Quickstep 1000
ELSA Quickstep 1000PCI
ELSA Quickstep 3000 (same settings as QS1000)
ELSA Quickstep 3000PCI
ELSA PCMCIA
ITK ix1-micro Rev.2
Eicon.Diehl Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
Eicon.Diehl Diva 2.01 ISA and PCI
Eicon.Diehl Diva Piccola
ASUSCOM NETWORK INC. ISDNLink 128K PC adapter (order code I-IN100-ST-D)
Dynalink IS64PH (OEM version of ASUSCOM NETWORK INC. ISDNLink 128K adapter)
PCBIT-DP (OEM version of ASUSCOM NETWORK INC. ISDNLink)
HFC-2BS0 based cards (TeleInt SA1)
Sedlbauer Speed Card (Speed Win, Teledat 100, PCI, Fax+)
Sedlbauer Speed Star/Speed Star2 (PCMCIA)
Sedlbauer ISDN-Controller PC/104
USR Sportster internal TA (compatible Stollmann tina-pp V3)
ith Kommunikationstechnik GmbH MIC 16 ISA card
Traverse Technologie NETjet PCI S0 card
Dr. Neuhaus Niccy PnP/PCI
Siemens I-Surf 1.0
Siemens I-Surf 2.0 (with IPAC, try type 12 asuscom)
ACER P10
HST Saphir
Berkom Telekom A4T
Scitel Quadro
Gazel ISDN cards
HFC-PCI based cards
Winbond W6692 based cards
HFC-S+, HFC-SP/PCMCIA cards
Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
PCC-8: not tested yet
Teles PCMCIA is EXPERIMENTAL
Teles 16.3c is EXPERIMENTAL
Teles PCI is EXPERIMENTAL
Teles S0Box is EXPERIMENTAL
Eicon.Diehl Diva U interface not tested
HFC-S+, HFC-SP/PCMCIA are experimental
If you know other passive cards with the Siemens chipset, please let me know.
To use the PNP cards you need the isapnptools.
You can combine any card, if there is no conflict between the ressources
(io, mem, irq).
Configuring the driver
----------------------
The HiSax driver can either be built directly into the kernel or as a module.
It can be configured using the command line feature while loading the kernel
with LILO or LOADLIN or, if built as a module, using insmod/modprobe with
parameters.
There is also some config needed before you compile the kernel and/or
modules. It is included in the normal "make [menu]config" target at the
kernel. Don't forget it, especially to select the right D-channel protocol.
Please note: All PnP cards need to be configured with isapnp and will work
only with the HiSax driver used as a module.
a) when built as a module
-------------------------
insmod/modprobe hisax.o \
io=iobase irq=IRQ mem=membase type=card_type \
protocol=D_channel_protocol id=idstring
or, if several cards are installed:
insmod/modprobe hisax.o \
io=iobase1,iobase2,... irq=IRQ1,IRQ2,... mem=membase1,membase2,... \
type=card_type1,card_type2,... \
protocol=D_channel_protocol1,D_channel_protocol2,... \
id=idstring1%idstring2 ...
where "iobaseN" represents the I/O base address of the Nth card, "membaseN"
the memory base address of the Nth card, etc.
The reason for the delimiter "%" being used in the idstrings is that ","
won't work with the current modules package.
The parameters may be specified in any order. For example, the "io"
parameter may precede the "irq" parameter, or vice versa. If several
cards are installed, the ordering within the comma separated parameter
lists must of course be consistent.
Only parameters applicable to the card type need to be specified. For
example, the Teles 16.3 card is not memory-mapped, so the "mem"
parameter may be omitted for this card. Sometimes it may be necessary
to specify a dummy parameter, however. This is the case when there is
a card of a different type later in the list that needs a parameter
which the preceding card does not. For instance, if a Teles 16.0 card
is listed after a Teles 16.3 card, a dummy memory base parameter of 0
must be specified for the 16.3. Instead of a dummy value, the parameter
can also be skipped by simply omitting the value. For example:
mem=,0xd0000. See example 6 below.
The parameter for the D-Channel protocol may be omitted if you selected the
correct one during kernel config. Valid values are "1" for German 1TR6,
"2" for EDSS1 (Euro ISDN) and "3" for leased lines (no D-Channel).
The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying
the I/O addresses of the ISAC and HSCX chips, respectively.
Card types:
Type Required parameters (in addition to type and protocol)
1 Teles 16.0 irq, mem, io
2 Teles 8.0 irq, mem
3 Teles 16.3 (non PnP) irq, io
4 Creatix/Teles PnP irq, io0 (ISAC), io1 (HSCX)
5 AVM A1 (Fritz) irq, io
6 ELSA PCC/PCF cards io or nothing for autodetect (the iobase is
required only if you have more than one ELSA
card in your PC)
7 ELSA Quickstep 1000 irq, io (from isapnp setup)
8 Teles 16.3 PCMCIA irq, io
9 ITK ix1-micro Rev.2 irq, io
10 ELSA PCMCIA irq, io (set with card manager)
11 Eicon.Diehl Diva ISA PnP irq, io
11 Eicon.Diehl Diva PCI no parameter
12 ASUS COM ISDNLink irq, io (from isapnp setup)
13 HFC-2BS0 based cards irq, io
14 Teles 16.3c PnP irq, io
15 Sedlbauer Speed Card irq, io
15 Sedlbauer PC/104 irq, io
15 Sedlbauer Speed PCI no parameter
16 USR Sportster internal irq, io
17 MIC card irq, io
18 ELSA Quickstep 1000PCI no parameter
19 Compaq ISDN S0 ISA card irq, io0, io1, io (from isapnp setup io=IO2)
20 NETjet PCI card no parameter
21 Teles PCI no parameter
22 Sedlbauer Speed Star (PCMCIA) irq, io (set with card manager)
24 Dr. Neuhaus Niccy PnP irq, io0, io1 (from isapnp setup)
24 Dr. Neuhaus Niccy PCI no parameter
25 Teles S0Box irq, io (of the used lpt port)
26 AVM A1 PCMCIA (Fritz!) irq, io (set with card manager)
27 AVM PnP (Fritz!PnP) irq, io (from isapnp setup)
27 AVM PCI (Fritz!PCI) no parameter
28 Sedlbauer Speed Fax+ irq, io (from isapnp setup)
29 Siemens I-Surf 1.0 irq, io, memory (from isapnp setup)
30 ACER P10 irq, io (from isapnp setup)
31 HST Saphir irq, io
32 Telekom A4T none
33 Scitel Quadro subcontroller (4*S0, subctrl 1...4)
34 Gazel ISDN cards (ISA) irq,io
34 Gazel ISDN cards (PCI) none
35 HFC 2BDS0 PCI none
36 W6692 based PCI cards none
37 HFC 2BDS0 S+, SP/PCMCIA irq,io (pcmcia must be set with cardmgr)
At the moment IRQ sharing is only possible with PCI cards. Please make sure
that your IRQ is free and enabled for ISA use.
Examples for module loading
1. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 10
modprobe hisax type=3 protocol=2 io=0x280 irq=10
2. Teles 16.0, 1TR6 ISDN, I/O base d80 hex, IRQ 5, Memory d0000 hex
modprobe hisax protocol=1 type=1 io=0xd80 mem=0xd0000 irq=5
3. Fritzcard, Euro ISDN, I/O base 340 hex, IRQ 10 and ELSA PCF, Euro ISDN
modprobe hisax type=5,6 protocol=2,2 io=0x340 irq=10 id=Fritz%Elsa
4. Any ELSA PCC/PCF card, Euro ISDN
modprobe hisax type=6 protocol=2
5. Teles 16.3 PnP, Euro ISDN, with isapnp configured
isapnp config: (INT 0 (IRQ 10 (MODE +E)))
(IO 0 (BASE 0x0580))
(IO 1 (BASE 0x0180))
modprobe hisax type=4 protocol=2 irq=10 io0=0x580 io1=0x180
6. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 12 and
Teles 16.0, 1TR6, IRQ 5, Memory d0000 hex
modprobe hisax type=3,1 protocol=2,1 io=0x280 mem=0,0xd0000
Please note the dummy 0 memory address for the Teles 16.3, used as a
placeholder as described above, in the last example.
7. Teles PCMCIA, Euro ISDN, I/O base 180 hex, IRQ 15 (default values)
modprobe hisax type=8 protocol=2 io=0x180 irq=15
b) using LILO/LOADLIN, with the driver compiled directly into the kernel
------------------------------------------------------------------------
hisax=typ1,dp1,pa_1,pb_1,pc_1[,typ2,dp2,pa_2 ... \
typn,dpn,pa_n,pb_n,pc_n][,idstring1[,idstring2,...,idstringn]]
where
typ1 = type of 1st card (default depends on kernel settings)
dp1 = D-Channel protocol of 1st card. 1=1TR6, 2=EDSS1, 3=leased
pa_1 = 1st parameter (depending on the type of the card)
pb_1 = 2nd parameter ( " " " " " " " )
pc_1 = 3rd parameter ( " " " " " " " )
typ2,dp2,pa_2,pb_2,pc_2 = Parameters of the second card (defaults: none)
typn,dpn,pa_n,pb_n,pc_n = Parameters of the n'th card (up to 16 cards are
supported)
idstring = Driver ID for accessing the particular card with utility
programs and for identification when using a line monitor
(default: "HiSax")
Note: the ID string must start with an alphabetical character!
Card types:
type
1 Teles 16.0 pa=irq pb=membase pc=iobase
2 Teles 8.0 pa=irq pb=membase
3 Teles 16.3 pa=irq pb=iobase
4 Creatix/Teles PNP ONLY WORKS AS A MODULE !
5 AVM A1 (Fritz) pa=irq pb=iobase
6 ELSA PCC/PCF cards pa=iobase or nothing for autodetect
7 ELSA Quickstep 1000 ONLY WORKS AS A MODULE !
8 Teles S0 PCMCIA pa=irq pb=iobase
9 ITK ix1-micro Rev.2 pa=irq pb=iobase
10 ELSA PCMCIA pa=irq, pb=io (set with card manager)
11 Eicon.Diehl Diva ISAPnP ONLY WORKS AS A MODULE !
11 Eicon.Diehl Diva PCI no parameter
12 ASUS COM ISDNLink ONLY WORKS AS A MODULE !
13 HFC-2BS0 based cards pa=irq pb=io
14 Teles 16.3c PnP ONLY WORKS AS A MODULE !
15 Sedlbauer Speed Card pa=irq pb=io (Speed Win only as module !)
15 Sedlbauer PC/104 pa=irq pb=io
15 Sedlbauer Speed PCI no parameter
16 USR Sportster internal pa=irq pb=io
17 MIC card pa=irq pb=io
18 ELSA Quickstep 1000PCI no parameter
19 Compaq ISDN S0 ISA card ONLY WORKS AS A MODULE !
20 NETjet PCI card no parameter
21 Teles PCI no parameter
22 Sedlbauer Speed Star (PCMCIA) pa=irq, pb=io (set with card manager)
24 Dr. Neuhaus Niccy PnP ONLY WORKS AS A MODULE !
24 Dr. Neuhaus Niccy PCI no parameter
25 Teles S0Box pa=irq, pb=io (of the used lpt port)
26 AVM A1 PCMCIA (Fritz!) pa=irq, pb=io (set with card manager)
27 AVM PnP (Fritz!PnP) ONLY WORKS AS A MODULE !
27 AVM PCI (Fritz!PCI) no parameter
28 Sedlbauer Speed Fax+ ONLY WORKS AS A MODULE !
29 Siemens I-Surf 1.0 ONLY WORKS AS A MODULE !
30 ACER P10 ONLY WORKS AS A MODULE !
31 HST Saphir pa=irq, pb=io
32 Telekom A4T no parameter
33 Scitel Quadro subcontroller (4*S0, subctrl 1...4)
34 Gazel ISDN cards (ISA) pa=irq, pb=io
34 Gazel ISDN cards (PCI) no parameter
35 HFC 2BDS0 PCI no parameter
36 W6692 based PCI cards none
37 HFC 2BDS0 S+,SP/PCMCIA pa=irq, pb=io
Running the driver
------------------
When you insmod isdn.o and hisax.o (or with the in-kernel version, during
boot time), a few lines should appear in your syslog. Look for something like:
Apr 13 21:01:59 kke01 kernel: HiSax: Driver for Siemens chip set ISDN cards
Apr 13 21:01:59 kke01 kernel: HiSax: Version 2.9
Apr 13 21:01:59 kke01 kernel: HiSax: Revisions 1.14/1.9/1.10/1.25/1.8
Apr 13 21:01:59 kke01 kernel: HiSax: Total 1 card defined
Apr 13 21:01:59 kke01 kernel: HiSax: Card 1 Protocol EDSS1 Id=HiSax1 (0)
Apr 13 21:01:59 kke01 kernel: HiSax: Elsa driver Rev. 1.13
...
Apr 13 21:01:59 kke01 kernel: Elsa: PCF-Pro found at 0x360 Rev.:C IRQ 10
Apr 13 21:01:59 kke01 kernel: Elsa: timer OK; resetting card
Apr 13 21:01:59 kke01 kernel: Elsa: HSCX version A: V2.1 B: V2.1
Apr 13 21:01:59 kke01 kernel: Elsa: ISAC 2086/2186 V1.1
...
Apr 13 21:01:59 kke01 kernel: HiSax: DSS1 Rev. 1.14
Apr 13 21:01:59 kke01 kernel: HiSax: 2 channels added
This means that the card is ready for use.
Cabling problems or line-downs are not detected, and only some ELSA cards can
detect the S0 power.
Remember that, according to the new strategy for accessing low-level drivers
from within isdn4linux, you should also define a driver ID while doing
insmod: Simply append hisax_id=<SomeString> to the insmod command line. This
string MUST NOT start with a digit or a small 'x'!
At this point you can run a 'cat /dev/isdnctrl0' and view debugging messages.
At the moment, debugging messages are enabled with the hisaxctrl tool:
hisaxctrl <DriverId> DebugCmd <debugging_flags>
<DriverId> default is HiSax, if you didn't specify one.
DebugCmd is 1 for generic debugging
11 for layer 1 development debugging
13 for layer 3 development debugging
where <debugging_flags> is the integer sum of the following debugging
options you wish enabled:
With DebugCmd set to 1:
0x0001 Link-level <--> hardware-level communication
0x0002 Top state machine
0x0004 D-Channel Frames for isdnlog
0x0008 D-Channel Q.921
0x0010 B-Channel X.75
0x0020 D-Channel l2
0x0040 B-Channel l2
0x0080 D-Channel link state debugging
0x0100 B-Channel link state debugging
0x0200 TEI debug
0x0400 LOCK debug in callc.c
0x0800 More paranoid debug in callc.c (not for normal use)
0x1000 D-Channel l1 state debugging
0x2000 B-Channel l1 state debugging
With DebugCmd set to 11:
0x0001 Warnings (default: on)
0x0002 IRQ status
0x0004 ISAC
0x0008 ISAC FIFO
0x0010 HSCX
0x0020 HSCX FIFO (attention: full B-Channel output!)
0x0040 D-Channel LAPD frame types
0x0080 IPAC debug
0x0100 HFC receive debug
0x0200 ISAC monitor debug
0x0400 D-Channel frames for isdnlog (set with 1 0x4 too)
0x0800 D-Channel message verbose
With DebugCmd set to 13:
1 Warnings (default: on)
2 l3 protocol descriptor errors
4 l3 state machine
8 charge info debugging (1TR6)
For example, 'hisaxctrl HiSax 1 0x3ff' enables full generic debugging.
Because of some obscure problems with some switch equipment, the delay
between the CONNECT message and sending the first data on the B-channel is now
configurable with
hisaxctrl <DriverId> 2 <delay>
<delay> in ms Value between 50 and 800 ms is recommended.
Downloading Firmware
--------------------
At the moment, the Sedlbauer speed fax+ is the only card, which
needs to download firmware.
The firmware is downloaded with the hisaxctrl tool:
hisaxctrl <DriverId> 9 <firmware_filename>
<DriverId> default is HiSax, if you didn't specify one,
where <firmware_filename> is the filename of the firmware file.
For example, 'hisaxctrl HiSax 9 ISAR.BIN' downloads the firmware for
ISAR based cards (like the Sedlbauer speed fax+).
Warning
-------
HiSax is a work in progress and may crash your machine.
For certification look at HiSax.cert file.
Limitations
-----------
At this time, HiSax only works on Euro ISDN lines and German 1TR6 lines.
For leased lines see appendix.
Bugs
----
If you find any, please let me know.
Thanks
------
Special thanks to:
Emil Stephan for the name HiSax which is a mix of HSCX and ISAC.
Fritz Elfert, Jan den Ouden, Michael Hipp, Michael Wein,
Andreas Kool, Pekka Sarnila, Sim Yskes, Johan Myrre'en,
Klaus-Peter Nischke (ITK AG), Christof Petig, Werner Fehn (ELSA GmbH),
Volker Schmidt
Edgar Toernig and Marcus Niemann for the Sedlbauer driver
Stephan von Krawczynski
Juergen Quade for the Leased Line part
Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE), for ELSA PCMCIA support
Enrik Berkhan (enrik@starfleet.inka.de) for S0BOX specific stuff
Ton van Rosmalen for Teles PCI
Petr Novak <petr.novak@i.cz> for Winbond W6692 support
and more people who are hunting bugs. (If I forgot somebody, please
send me a mail).
Firma ELSA GmbH
Firma Eicon.Diehl GmbH
Firma Dynalink NL
Firma ASUSCOM NETWORK INC. Taiwan
Firma S.u.S.E
Firma ith Kommunikationstechnik GmbH
Firma Traverse Technologie Australia
Firma Medusa GmbH (www.medusa.de).
Firma Quant-X Austria for sponsoring a DEC Alpha board+CPU
Firma Cologne Chip Designs GmbH
My girl friend and partner in life Ute for her patience with me.
Enjoy,
Karsten Keil
keil@isdn4linux.de
Appendix: Teles PCMCIA driver
-----------------------------
See
http://www.stud.uni-wuppertal.de/~ea0141/pcmcia.html
for instructions.
Appendix: Linux and ISDN-leased lines
-------------------------------------
Original from Juergen Quade, new version KKe.
Attention NEW VERSION, the old leased line syntax won't work !!!
You can use HiSax to connect your Linux-Box via an ISDN leased line
to e.g. the Internet:
1. Build a kernel which includes the HiSax driver either as a module
or as part of the kernel.
cd /usr/src/linux
make menuconfig
<ISDN subsystem - ISDN support -- HiSax>
make clean; make dep; make zImage; make modules; make modules_install
2. Install the new kernel
cp /usr/src/linux/arch/i386/boot/zImage /etc/kernel/linux.isdn
vi /etc/lilo.conf
<add new kernel in the bootable image section>
lilo
3. in case the hisax driver is a "fixed" part of the kernel, configure
the driver with lilo:
vi /etc/lilo.conf
<add HiSax driver parameter in the global section (see below)>
lilo
Your lilo.conf _might_ look like the following:
# LILO configuration-file
# global section
# teles 16.0 on IRQ=5, MEM=0xd8000, PORT=0xd80
append="hisax=1,3,5,0xd8000,0xd80,HiSax"
# teles 16.3 (non pnp) on IRQ=15, PORT=0xd80
# append="hisax=3,3,5,0xd8000,0xd80,HiSax"
boot=/dev/sda
compact # faster, but won't work on all systems.
linear
read-only
prompt
timeout=100
vga = normal # force sane state
# Linux bootable partition config begins
image = /etc/kernel/linux.isdn
root = /dev/sda1
label = linux.isdn
#
image = /etc/kernel/linux-2.0.30
root = /dev/sda1
label = linux.secure
In the line starting with "append" you have to adapt the parameters
according to your card (see above in this file)
3. boot the new linux.isdn kernel
4. start the ISDN subsystem:
a) load - if necessary - the modules (depends, whether you compiled
the ISDN driver as module or not)
According to the type of card you have to specify the necessary
driver parameter (irq, io, mem, type, protocol).
For the leased line the protocol is "3". See the table above for
the parameters, which you have to specify depending on your card.
b) configure i4l
/sbin/isdnctrl addif isdn0
# EAZ 1 -- B1 channel 2 --B2 channel
/sbin/isdnctrl eaz isdn0 1
/sbin/isdnctrl secure isdn0 on
/sbin/isdnctrl huptimeout isdn0 0
/sbin/isdnctrl l2_prot isdn0 hdlc
# Attention you must not set an outgoing number !!! This won't work !!!
# The incomming number is LEASED0 for the first card, LEASED1 for the
# second and so on.
/sbin/isdnctrl addphone isdn0 in LEASED0
# Here is no need to bind the channel.
c) in case the remote partner is a CISCO:
/sbin/isdnctrl encap isdn0 cisco-h
d) configure the interface
/sbin/ifconfig isdn0 ${LOCAL_IP} pointopoint ${REMOTE_IP}
e) set the routes
/sbin/route add -host ${REMOTE_IP} isdn0
/sbin/route add default gw ${REMOTE_IP}
f) switch the card into leased mode for each used B-channel
/sbin/hisaxctrl HiSax 5 1
Remarks:
a) Use state of the art isdn4k-utils
Here an example script:
#!/bin/sh
# Start/Stop ISDN lesaed line connection
I4L_AS_MODULE=yes
I4L_REMOTE_IS_CISCO=no
I4L_MODULE_PARAMS="type=16 io=0x268 irq=7 "
I4L_DEBUG=no
I4L_LEASED_128K=yes
LOCAL_IP=192.168.1.1
REMOTE_IP=192.168.2.1
case "$1" in
start)
echo "Starting ISDN ..."
if [ ${I4L_AS_MODULE} = "yes" ]; then
echo "loading modules..."
/sbin/modprobe hisax ${I4L_MODULE_PARAMS}
fi
# configure interface
/sbin/isdnctrl addif isdn0
/sbin/isdnctrl secure isdn0 on
if [ ${I4L_DEBUG} = "yes" ]; then
/sbin/isdnctrl verbose 7
/sbin/hisaxctrl HiSax 1 0xffff
/sbin/hisaxctrl HiSax 11 0xff
cat /dev/isdnctrl >/tmp/lea.log &
fi
if [ ${I4L_REMOTE_IS_CISCO} = "yes" ]; then
/sbin/isdnctrl encap isdn0 cisco-h
fi
/sbin/isdnctrl huptimeout isdn0 0
# B-CHANNEL 1
/sbin/isdnctrl eaz isdn0 1
/sbin/isdnctrl l2_prot isdn0 hdlc
# 1. card
/sbin/isdnctrl addphone isdn0 in LEASED0
if [ ${I4L_LEASED_128K} = "yes" ]; then
/sbin/isdnctrl addslave isdn0 isdn0s
/sbin/isdnctrl secure isdn0s on
/sbin/isdnctrl huptimeout isdn0s 0
# B-CHANNEL 2
/sbin/isdnctrl eaz isdn0s 2
/sbin/isdnctrl l2_prot isdn0s hdlc
# 1. card
/sbin/isdnctrl addphone isdn0s in LEASED0
if [ ${I4L_REMOTE_IS_CISCO} = "yes" ]; then
/sbin/isdnctrl encap isdn0s cisco-h
fi
fi
/sbin/isdnctrl dialmode isdn0 manual
# configure tcp/ip
/sbin/ifconfig isdn0 ${LOCAL_IP} pointopoint ${REMOTE_IP}
/sbin/route add -host ${REMOTE_IP} isdn0
/sbin/route add default gw ${REMOTE_IP}
# switch to leased mode
# B-CHANNEL 1
/sbin/hisaxctrl HiSax 5 1
if [ ${I4L_LEASED_128K} = "yes" ]; then
# B-CHANNEL 2
sleep 10; /* Wait for master */
/sbin/hisaxctrl HiSax 5 2
fi
;;
stop)
/sbin/ifconfig isdn0 down
/sbin/isdnctrl delif isdn0
if [ ${I4L_DEBUG} = "yes" ]; then
killall cat
fi
if [ ${I4L_AS_MODULE} = "yes" ]; then
/sbin/rmmod hisax
/sbin/rmmod isdn
/sbin/rmmod ppp
/sbin/rmmod slhc
fi
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
exit 0

View File

@ -1,104 +0,0 @@
$Id$
This document describes the ACT2000 driver for the
IBM Active 2000 ISDN card.
There are 3 Types of this card available. A ISA-, MCA-, and PCMCIA-Bus
Version. Currently, only the ISA-Bus version of the card is supported.
However MCA and PCMCIA will follow soon.
The ISA-Bus Version uses 8 IO-ports. The base port adress has to be set
manually using the DIP switches.
Setting up the DIP switches for the IBM Active 2000 ISDN card:
Note: S5 and S6 always set off!
S1 S2 S3 S4 Base-port
on on on on 0x0200 (Factory default)
off on on on 0x0240
on off on on 0x0280
off off on on 0x02c0
on on off on 0x0300
off on off on 0x0340
on off off on 0x0380
on on on off 0xcfe0
off on on off 0xcfa0
on off on off 0xcf60
off off on off 0xcf20
on on off off 0xcee0
off on off off 0xcea0
on off off off 0xce60
off off off off Card disabled
IRQ is configured by software. Possible values are:
3, 5, 7, 10, 11, 12, 15 and none (polled mode)
The ACT2000 driver 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.

View File

@ -1,138 +0,0 @@
$Id$
ISDN subsystem for Linux.
Description of audio mode.
When enabled during kernel configuration, the tty emulator of the ISDN
subsystem is capable of a reduced set of commands to support audio.
This document describes the commands supported and the format of
audio data.
Commands for enabling/disabling audio mode:
AT+FCLASS=8 Enable audio mode.
This affects the following registers:
S18: Bits 0 and 2 are set.
S16: Set to 48 and any further change to
larger values is blocked.
AT+FCLASS=0 Disable audio mode.
Register 18 is set to 4.
AT+FCLASS=? Show possible modes.
AT+FCLASS? Report current mode (0 or 8).
Commands supported in audio mode:
All audio mode commands have one of the following forms:
AT+Vxx? Show current setting.
AT+Vxx=? Show possible settings.
AT+Vxx=v Set simple parameter.
AT+Vxx=v,v ... Set complex parameter.
where xx is a two-character code and v are alphanumerical parameters.
The following commands are supported:
AT+VNH=x Auto hangup setting. NO EFFECT, supported
for compatibility only.
AT+VNH? Always reporting "1"
AT+VNH=? Always reporting "1"
AT+VIP Reset all audio parameters.
AT+VLS=x Line select. x is one of the following:
0 = No device.
2 = Phone line.
AT+VLS=? Always reporting "0,2"
AT+VLS? Show current line.
AT+VRX Start recording. Emulator responds with
CONNECT and starts sending audio data to
the application. See below for data format
AT+VSD=x,y Set silence-detection parameters.
Possible parameters:
x = 0 ... 31 sensitivity threshold level.
(default 0 , deactivated)
y = 0 ... 255 range of interval in units
of 0.1 second. (default 70)
AT+VSD=? Report possible parameters.
AT+VSD? Show current parameters.
AT+VDD=x,y Set DTMF-detection parameters.
Only possible if online and during this connection.
Possible parameters:
x = 0 ... 15 sensitivity threshold level.
(default 0 , I4L soft-decode)
(1-15 soft-decode off, hardware on)
y = 0 ... 255 tone duration in units of 5ms.
Not for I4L soft decode (default 8, 40ms)
AT+VDD=? Report possible parameters.
AT+VDD? Show current parameters.
AT+VSM=x Select audio data format.
Possible parameters:
2 = ADPCM-2
3 = ADPCM-3
4 = ADPCM-4
5 = aLAW
6 = uLAW
AT+VSM=? Show possible audio formats.
AT+VTX Start audio playback. Emulator responds
with CONNECT and starts sending audio data
received from the application via phone line.
General behavior and description of data formats/protocol.
when a connection is made:
On incoming calls, if the application responds to a RING
with ATA, depending on the calling service, the emulator
responds with either CONNECT (data call) or VCON (voice call).
On outgoing voice calls, the emulator responds with VCON
upon connection setup.
Audio recording.
When receiving audio data, a kind of bisync protocol is used.
Upon AT+VRX command, the emulator responds with CONNECT, and
starts sending audio data to the application. There are several
escape sequences defined, all using DLE (0x10) as Escape char:
<DLE><ETX> End of audio data. (i.e. caused by a
hangup of the remote side) Emulator stops
recording, responding with VCON.
<DLE><DC4> Abort recording, (send by appl.) Emulator
stops recording, sends DLE,ETX.
<DLE><DLE> Escape sequence for DLE in data stream.
<DLE>0 Touchtone "0" received.
...
<DLE>9 Touchtone "9" received.
<DLE># Touchtone "#" received.
<DLE>* Touchtone "*" received.
<DLE>A Touchtone "A" received.
<DLE>B Touchtone "B" received.
<DLE>C Touchtone "C" received.
<DLE>D Touchtone "D" received.
<DLE>q quiet. Silence detected after non-silence.
<DLE>s silence. Silence detected from the
start of recording.
Currently unsupported DLE sequences:
<DLE>c FAX calling tone received.
<DLE>b busy tone received.
Audio playback.
When sending audio data, upon AT+VTX command, emulator responds with
CONNECT, and starts transferring data from application to the phone line.
The same DLE sequences apply to this mode.
Full-Duplex-Audio:
When _both_ commands for recording and playback are given in _one_
AT-command-line (i.e.: "AT+VTX+VRX"), full-duplex-mode is selected.
In this mode, the only way to stop recording is sending <DLE><DC4>
and the only way to stop playback is to send <DLE><ETX>.

View File

@ -1,187 +0,0 @@
Driver for active AVM Controller.
The driver provides a kernel capi2.0 Interface (kernelcapi) and
on top of this a User-Level-CAPI2.0-interface (capi)
and a driver to connect isdn4linux with CAPI2.0 (capidrv).
The lowlevel interface can be used to implement a CAPI2.0
also for passive cards since July 1999.
The author can be reached at calle@calle.in-berlin.de.
The command avmcapictrl is part of the isdn4k-utils.
t4-files can be found at ftp://ftp.avm.de/cardware/b1/linux/firmware
Currently supported cards:
B1 ISA (all versions)
B1 PCI
T1/T1B (HEMA card)
M1
M2
B1 PCMCIA
Installing
----------
You need at least /dev/capi20 to load the firmware.
mknod /dev/capi20 c 68 0
mknod /dev/capi20.00 c 68 1
mknod /dev/capi20.01 c 68 2
.
.
.
mknod /dev/capi20.19 c 68 20
Running
-------
To use the card you need the t4-files to download the firmware.
AVM GmbH provides several t4-files for the different D-channel
protocols (b1.t4 for Euro-ISDN). Install these file in /lib/isdn.
if you configure as modules load the modules this way:
insmod /lib/modules/current/misc/capiutil.o
insmod /lib/modules/current/misc/b1.o
insmod /lib/modules/current/misc/kernelcapi.o
insmod /lib/modules/current/misc/capidrv.o
insmod /lib/modules/current/misc/capi.o
if you have an B1-PCI card load the module b1pci.o
insmod /lib/modules/current/misc/b1pci.o
and load the firmware with
avmcapictrl load /lib/isdn/b1.t4 1
if you have an B1-ISA card load the module b1isa.o
and add the card by calling
avmcapictrl add 0x150 15
and load the firmware by calling
avmcapictrl load /lib/isdn/b1.t4 1
if you have an T1-ISA card load the module t1isa.o
and add the card by calling
avmcapictrl add 0x450 15 T1 0
and load the firmware by calling
avmcapictrl load /lib/isdn/t1.t4 1
if you have an PCMCIA card (B1/M1/M2) load the module b1pcmcia.o
before you insert the card.
Leased Lines with B1
--------------------
Init card and load firmware.
For an D64S use "FV: 1" as phone number
For an D64S2 use "FV: 1" and "FV: 2" for multilink
or "FV: 1,2" to use CAPI channel bundling.
/proc-Interface
-----------------
/proc/capi:
dr-xr-xr-x 2 root root 0 Jul 1 14:03 .
dr-xr-xr-x 82 root root 0 Jun 30 19:08 ..
-r--r--r-- 1 root root 0 Jul 1 14:03 applications
-r--r--r-- 1 root root 0 Jul 1 14:03 applstats
-r--r--r-- 1 root root 0 Jul 1 14:03 capi20
-r--r--r-- 1 root root 0 Jul 1 14:03 capidrv
-r--r--r-- 1 root root 0 Jul 1 14:03 controller
-r--r--r-- 1 root root 0 Jul 1 14:03 contrstats
-r--r--r-- 1 root root 0 Jul 1 14:03 driver
-r--r--r-- 1 root root 0 Jul 1 14:03 ncci
-r--r--r-- 1 root root 0 Jul 1 14:03 users
/proc/capi/applications:
applid level3cnt datablkcnt datablklen ncci-cnt recvqueuelen
level3cnt: capi_register parameter
datablkcnt: capi_register parameter
ncci-cnt: current number of nccis (connections)
recvqueuelen: number of messages on receive queue
for example:
1 -2 16 2048 1 0
2 2 7 2048 1 0
/proc/capi/applstats:
applid recvctlmsg nrecvdatamsg nsentctlmsg nsentdatamsg
recvctlmsg: capi messages received without DATA_B3_IND
recvdatamsg: capi DATA_B3_IND received
sentctlmsg: capi messages sent without DATA_B3_REQ
sentdatamsg: capi DATA_B3_REQ sent
for example:
1 2057 1699 1721 1699
/proc/capi/capi20: statistics of capi.o (/dev/capi20)
minor nopen nrecvdropmsg nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg
minor: minor device number of capi device
nopen: number of calls to devices open
nrecvdropmsg: capi messages dropped (messages in recvqueue in close)
nrecvctlmsg: capi messages received without DATA_B3_IND
nrecvdatamsg: capi DATA_B3_IND received
nsentctlmsg: capi messages sent without DATA_B3_REQ
nsentdatamsg: capi DATA_B3_REQ sent
for example:
1 2 18 0 16 2
/proc/capi/capidrv: statistics of capidrv.o (capi messages)
nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg
nrecvctlmsg: capi messages received without DATA_B3_IND
nrecvdatamsg: capi DATA_B3_IND received
nsentctlmsg: capi messages sent without DATA_B3_REQ
nsentdatamsg: capi DATA_B3_REQ sent
for example:
2780 2226 2256 2226
/proc/capi/controller:
controller drivername state cardname controllerinfo
for example:
1 b1pci running b1pci-e000 B1 3.07-01 0xe000 19
2 t1isa running t1isa-450 B1 3.07-01 0x450 11 0
3 b1pcmcia running m2-150 B1 3.07-01 0x150 5
/proc/capi/contrstats:
controller nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg
nrecvctlmsg: capi messages received without DATA_B3_IND
nrecvdatamsg: capi DATA_B3_IND received
nsentctlmsg: capi messages sent without DATA_B3_REQ
nsentdatamsg: capi DATA_B3_REQ sent
for example:
1 2845 2272 2310 2274
2 2 0 2 0
3 2 0 2 0
/proc/capi/driver:
drivername ncontroller
for example:
b1pci 1
t1isa 1
b1pcmcia 1
b1isa 0
/proc/capi/ncci:
apllid ncci winsize sendwindow
for example:
1 0x10101 8 0
/proc/capi/users: kernelmodules that use the kernelcapi.
name
for example:
capidrv
capi20
Questions
---------
Check out the FAQ (ftp.isdn4linux.de) or subscribe to the
linux-avmb1@calle.in-berlin.de mailing list by sending
a mail to majordomo@calle.in-berlin.de with
subscribe linux-avmb1
in the body.
German documentaion and several scripts can be found at
ftp://ftp.avm.de/cardware/b1/linux/
Bugs
----
If you find any please let me know.
Enjoy,
Carsten Paeth (calle@calle.in-berlin.de)

View File

@ -1,259 +0,0 @@
Description of the "concap" encapsulation protocol interface
============================================================
The "concap" interface is intended to be used by network device
drivers that need to process an encapsulation protocol.
It is assumed that the protocol interacts with a linux network device by
- data transmission
- connection control (establish, release)
Thus, the mnemonic: "CONnection CONtrolling eNCAPsulation Protocol".
This is currently only used inside the isdn subsystem. But it might
also be useful to other kinds of network devices. Thus, if you want
to suggest changes that improve usability or performance of the
interface, please let me know. I'm willing to include them in future
releases (even if I needed to adapt the current isdn code to the
changed interface).
Why is this useful?
===================
The encapsulation protocol used on top of WAN connections or permanent
point-to-point links are frequently chosen upon bilateral agreement.
Thus, a device driver for a certain type of hardware must support
several different encapsulation protocols at once.
The isdn device driver did already support several different
encapsulation protocols. The encapsulation protocol is configured by a
user space utility (isdnctrl). The isdn network interface code then
uses several case statements which select appropriate actions
depending on the currently configured encapsulation protocol.
In contrast, LAN network interfaces always used a single encapsulation
protocol which is unique to the hardware type of the interface. The LAN
encapsulation is usually done by just sticking a header on the data. Thus,
traditional linux network device drivers used to process the
encapsulation protocol directly (usually by just providing a hard_header()
method in the device structure) using some hardware type specific support
functions. This is simple, direct and efficient. But it doesn't fit all
the requirements for complex WAN encapsulations.
The configurability of the encapsulation protocol to be used
makes isdn network interfaces more flexible, but also much more
complex than traditional lan network interfaces.
Many Encapsulation protocols used on top of WAN connections will not just
stick a header on the data. They also might need to set up or release
the WAN connection. They also might want to send other data for their
private purpose over the wire, e.g. ppp does a lot of link level
negotiation before the first piece of user data can be transmitted.
Such encapsulation protocols for WAN devices are typically more complex
than encapsulation protocols for lan devices. Thus, network interface
code for typical WAN devices also tends to be more complex.
In order to support Linux' x25 PLP implementation on top of
isdn network interfaces I could have introduced yet another branch to
the various case statements inside drivers/isdn/isdn_net.c.
This eventually made isdn_net.c even more complex. In addition, it made
isdn_net.c harder to maintain. Thus, by identifying an abstract
interface between the network interface code and the encapsulation
protocol, complexity could be reduced and maintainability could be
increased.
Likewise, a similar encapsulation protocol will frequently be needed by
several different interfaces of even different hardware type, e.g. the
synchronous ppp implementation used by the isdn driver and the
asyncronous ppp implementation used by the ppp driver have a lot of
similar code in them. By cleanly separating the encapsulation protocol
from the hardware specific interface stuff such code could be shared
better in future.
When operating over dial-up-connections (e.g. telephone lines via modem,
non-permanent virtual circuits of wide area networks, ISDN) many
encapsulation protocols will need to control the connection. Therefore,
some basic connection control primitives are supported. The type and
semantics of the connection (i.e the ISO layer where connection service
is provided) is outside our scope and might be different depending on
the encapsulation protocol used, e.g. for a ppp module using our service
on top of a modem connection a connect_request will result in dialing
a (somewhere else configured) remote phone number. For an X25-interface
module (LAPB semantics, as defined in Documentation/networking/x25-iface.txt)
a connect_request will ask for establishing a reliable lapb
datalink connection.
The encapsulation protocol currently provides the following
service primitives to the network device.
- create a new encapsulation protocol instance
- delete encapsulation protocol instance and free all its resources
- initialize (open) the encapsulation protocol instance for use.
- deactivate (close) an encapsulation protocol instance.
- process (xmit) data handed down by upper protocol layer
- receive data from lower (hardware) layer
- process connect indication from lower (hardware) layer
- process disconnect indication from lower (hardware) layer
The network interface driver accesses those primitives via callbacks
provided by the encapsulation protocol instance within a
struct concap_proto_ops.
struct concap_proto_ops{
/* create a new encapsulation protocol instance of same type */
struct concap_proto * (*proto_new) (void);
/* delete encapsulation protocol instance and free all its resources.
cprot may no loger be referenced after calling this */
void (*proto_del)(struct concap_proto *cprot);
/* initialize the protocol's data. To be called at interface startup
or when the device driver resets the interface. All services of the
encapsulation protocol may be used after this*/
int (*restart)(struct concap_proto *cprot,
struct net_device *ndev,
struct concap_device_ops *dops);
/* deactivate an encapsulation protocol instance. The encapsulation
protocol may not call any *dops methods after this. */
int (*close)(struct concap_proto *cprot);
/* process a frame handed down to us by upper layer */
int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
/* to be called for each data entity received from lower layer*/
int (*data_ind)(struct concap_proto *cprot, struct sk_buff *skb);
/* to be called when a connection was set up/down.
Protocols that don't process these primitives might fill in
dummy methods here */
int (*connect_ind)(struct concap_proto *cprot);
int (*disconn_ind)(struct concap_proto *cprot);
};
The data structures are defined in the header file include/linux/concap.h.
A Network interface using encapsulation protocols must also provide
some service primitives to the encapsulation protocol:
- request data being submitted by lower layer (device hardware)
- request a connection being set up by lower layer
- request a connection being released by lower layer
The encapsulation protocol accesses those primitives via callbacks
provided by the network interface within a struct concap_device_ops.
struct concap_device_ops{
/* to request data be submitted by device */
int (*data_req)(struct concap_proto *, struct sk_buff *);
/* Control methods must be set to NULL by devices which do not
support connection control. */
/* to request a connection be set up */
int (*connect_req)(struct concap_proto *);
/* to request a connection be released */
int (*disconn_req)(struct concap_proto *);
};
The network interface does not explicitly provide a receive service
because the encapsulation protocol directly calls netif_rx().
An encapsulation protocol itself is actually the
struct concap_proto{
struct net_device *net_dev; /* net device using our service */
struct concap_device_ops *dops; /* callbacks provided by device */
struct concap_proto_ops *pops; /* callbacks provided by us */
int flags;
void *proto_data; /* protocol specific private data, to
be accessed via *pops methods only*/
/*
:
whatever
:
*/
};
Most of this is filled in when the device requests the protocol to
be reset (opend). The network interface must provide the net_dev and
dops pointers. Other concap_proto members should be considered private
data that are only accessed by the pops callback functions. Likewise,
a concap proto should access the network device's private data
only by means of the callbacks referred to by the dops pointer.
A possible extended device structure which uses the connection controlling
encapsulation services could look like this:
struct concap_device{
struct net_device net_dev;
struct my_priv /* device->local stuff */
/* the my_priv struct might contain a
struct concap_device_ops *dops;
to provide the device specific callbacks
*/
struct concap_proto *cprot; /* callbacks provided by protocol */
};
Misc Thoughts
=============
The concept of the concap proto might help to reuse protocol code and
reduce the complexity of certain network interface implementations.
The trade off is that it introduces yet another procedure call layer
when processing the protocol. This has of course some impact on
performance. However, typically the concap interface will be used by
devices attached to slow lines (like telephone, isdn, leased synchronous
lines). For such slow lines, the overhead is probably negligible.
This might no longer hold for certain high speed WAN links (like
ATM).
If general linux network interfaces explicitly supported concap
protocols (e.g. by a member struct concap_proto* in struct net_device)
then the interface of the service function could be changed
by passing a pointer of type (struct net_device*) instead of
type (struct concap_proto*). Doing so would make many of the service
functions compatible to network device support functions.
e.g. instead of the concap protocol's service function
int (*encap_and_xmit)(struct concap_proto *cprot, struct sk_buff *skb);
we could have
int (*encap_and_xmit)(struct net_device *ndev, struct sk_buff *skb);
As this is compatible to the dev->hard_start_xmit() method, the device
driver could directly register the concap protocol's encap_and_xmit()
function as its hard_start_xmit() method. This would eliminate one
procedure call layer.
The device's data request function could also be defined as
int (*data_req)(struct net_device *ndev, struct sk_buff *skb);
This might even allow for some protocol stacking. And the network
interface might even register the same data_req() function directly
as its hard_start_xmit() method when a zero layer encapsulation
protocol is configured. Thus, eliminating the performance penalty
of the concap interface when a trivial concap protocol is used.
Nevertheless, the device remains able to support encapsulation
protocol configuration.

View File

@ -1,127 +0,0 @@
The isdn diversion services are a supporting module working together with
the isdn4linux and the HiSax module for passive cards.
Active cards, TAs and cards using a own or other driver than the HiSax
module need to be adapted to the HL<->LL interface described in a separate
document. The diversion services may be used with all cards supported by
the HiSax driver.
The diversion kernel interface and controlling tool divertctrl were written
by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) under the
GNU Public License.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Table of contents
=================
1. Features of the i4l diversion services
(Or what can the i4l diversion services do for me)
2. Required hard- and software
3. Compiling, installing and loading/unloading the module
Tracing calling and diversion information
4. Tracing calling and diversion information
5. Format of the divert device ASCII output
1. Features of the i4l diversion services
(Or what can the i4l diversion services do for me)
The i4l diversion services offers call forwarding and logging normally
only supported by isdn phones. Incoming calls may be diverted
unconditionally (CFU), when not reachable (CFNR) or on busy condition
(CFB).
The diversions may be invoked statically in the providers exchange
as normally done by isdn phones. In this case all incoming calls
with a special (or all) service identifiers are forwarded if the
forwarding reason is met. Activated static services may also be
interrogated (queried).
The i4l diversion services additionally offers a dynamic version of
call forwarding which is not preprogrammed inside the providers exchange
but dynamically activated by i4l.
In this case all incoming calls are checked by rules that may be
compared to the mechanism of ipfwadm or ipchains. If a given rule matches
the checking process is finished and the rule matching will be applied
to the call.
The rules include primary and secondary service indentifiers, called
number and subaddress, callers number and subaddress and whether the rule
matches to all filtered calls or only those when all B-channel resources
are exhausted.
Actions that may be invoked by a rule are ignore, proceed, reject,
direct divert or delayed divert of a call.
All incoming calls matching a rule except the ignore rule a reported and
logged as ASCII via the proc filesystem (/proc/net/isdn/divert). If proceed
is selected the call will be held in a proceeding state (without ringing)
for a certain amount of time to let an external program or client decide
how to handle the call.
2. Required hard- and software
For using the i4l diversion services the isdn line must be of a EURO/DSS1
type. Additionally the i4l services only work together with the HiSax
driver for passive isdn cards. All HiSax supported cards may be used for
the diversion purposes.
The static diversion services require the provider having static services
CFU, CFNR, CFB activated on an MSN-line. The static services may not be
used on a point-to-point connection. Further the static services are only
available in some countries (for example germany). Countries requiring the
keypad protocol for activating static diversions (like the netherlands) are
not supported but may use the tty devices for this purpose.
The dynamic diversion servives may be used in all countries if the provider
enables the feature CF (call forwarding). This should work on both MSN- and
point-to-point lines.
To add and delete rules the additional divertctrl program is needed. This
program is part of the isdn4kutils package.
3. Compiling, installing and loading/unloading the module
Tracing calling and diversion information
To compile the i4l code with diversion support you need to say yes to the
DSS1 diversion services when selecting the i4l options in the kernel
config (menuconfig or config).
After having properly activated a make modules and make modules_install all
required modules will be correctly installed in the needed modules dirs.
As the diversion services are currently not included in the scripts of most
standard distributions you will have to add a "insmod dss1_divert" after
having loaded the global isdn module.
The module can be loaded without any command line parameters.
If the module is actually loaded and active may be checked with a
"cat /proc/modules" or "ls /proc/net/isdn/divert". The divert file is
dynamically created by the diversion module and removed when the module is
unloaded.
4. Tracing calling and diversion information
You also may put a "cat /proc/net/isdn/divert" in the background with the
output redirected to a file. Then all actions of the module are logged.
The divert file in the proc system may be opened more than once, so in
conjunction with inetd and a small remote client on other machines inside
your network incoming calls and reactions by the module may be shown on
every listening machine.
If a call is reported as proceeding an external program or client may
specify during a certain amount of time (normally 4 to 10 seconds) what
to do with that call.
To unload the module all open files to the device in the proc system must
be closed. Otherwise the module (and isdn.o) may not be unloaded.
5. Format of the divert device ASCII output
To be done later

View File

@ -1,111 +0,0 @@
$Id$
(c) 1999,2000 Armin Schindler (mac@melware.de)
(c) 1999,2000 Cytronics & Melware (info@melware.de)
This document describes the eicon driver for the
Eicon active ISDN cards.
It is meant to be used with isdn4linux, an ISDN link-level module for Linux.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Supported Cards
===============
Old ISA type
------------
- S-Card ISA
- SX-Card ISA
- SXn-Card ISA
- SCOM-Card ISA
- Quadro-Card ISA
- S2M-Card ISA
DIVA Server family
------------------
- DIVA Server BRI/PCI 2M
- DIVA Server PRI/PCI 2M (9M 23M 30M)
supported functions of onboard DSPs:
- analog modem
- fax group 2/3 (Fax Class 2 commands)
- DTMF detection
ISDN D-Channel Protocols
------------------------
- ETSI (Euro-DSS1)
- 1TR6 (German ISDN) *not testet*
- other protocols exist for the range of DIVA Server cards,
but they are not fully testet yet.
You can load the module simply by using the insmod or modprobe function :
insmod eicon [id=driverid] [membase=<membase>] [irq=<irq>]
The module will automatically probe the PCI-cards. If the id-option
is omitted, the driver will assume 'eicon0' for the first pci card and
increases the digit with each further card. With a given driver-id
the module appends a number starting with '0'.
For ISA-cards you have to specify membase, irq and id. If id or
membase is missing/invalid, the driver will not be loaded except
PCI-cards were found. Additional ISA-cards and irq/membase changes
can be done with the eiconctrl utility.
After loading the module, you have to download the protocol and
dsp-code by using the eiconctrl utility of isdn4k-utils.
Example for loading and starting a BRI card with E-DSS1 Protocol.
eiconctrl [-d DriverId] load etsi
Example for loading and starting a PRI card with E-DSS1 Protocol.
eiconctrl [-d DriverId] load etsi -s2 -n
Details about using the eiconctrl utility are in 'man eiconctrl'
or will be printed by starting eiconctrl without any parameters.
ISDNLOG:
With eicon driver version 1.77 or newer and the eiconctrl utility
of version 1.1 or better, you can use the isdnlog user program
with your DIVA Server BRI card.
Just use "eiconctrl isdnlog on" and the driver will generate
the necessary D-Channel traces for isdnlog.
Thanks to
Deutsche Mailbox Saar-Lor-Lux GmbH
for sponsoring and testing fax
capabilities with Diva Server cards.
Any reports about bugs, errors and even wishes are welcome.
Have fun !
Armin Schindler
mac@melware.de
http://www.melware.de

View File

@ -1,42 +0,0 @@
Fax with isdn4linux
===================
When enabled during kernel configuration, the tty emulator
of the ISDN subsystem is capable of the Fax Class 2 commands.
This only makes sense under the following conditions :
- You need the commands as dummy, because you are using
hylafax (with patch) for AVM capi.
- You want to use the fax capabilities of your isdn-card.
(supported cards are listed below)
NOTE: This implementation does *not* support fax with passive
ISDN-cards (known as softfax). The low-level driver of
the ISDN-card and/or the card itself must support this.
Supported ISDN-Cards
--------------------
Eicon DIVA Server BRI/PCI
- full support with both B-channels.
Eicon DIVA Server PRI/PCI
- full support on amount of B-channels
depending on DSPs on board.
The command set is known as Class 2 (not Class 2.0) and
can be activated by AT+FCLASS=2
The interface between the link-level-module and the hardware-level driver
is described in the files INTERFACE.fax and INTERFACE.
Armin
mac@melware.de

View File

@ -1,41 +0,0 @@
The driver for the HFC-PCI and HFC-PCI-A chips from CCD may be used
for many OEM cards using this chips.
Additionally the driver has a special feature which makes it possible
to read the echo-channel of the isdn bus. So all frames in both directions
may be logged.
When the echo logging feature is used the number of available B-channels
for a HFC-PCI card is reduced to 1. Of course this is only relevant to
the card, not to the isdn line.
To activate the echo mode the following ioctls must be entered:
hisaxctrl <driver/cardname> 10 1
This reduces the available channels to 1. There must not be open connections
through this card when entering the command.
And then:
hisaxctrl <driver/cardname> 12 1
This enables the echo mode. If Hex logging is activated the isdnctrlx
devices show a output with a line beginning of HEX: for the providers
exchange and ECHO: for isdn devices sending to the provider.
If more than one HFC-PCI cards are installed, a specific card may be selected
at the hisax module load command line. Supply the load command with the desired
IO-address of the desired card.
Example:
There tree cards installed in your machine at IO-base addresses 0xd000, 0xd400
and 0xdc00
If you want to use the card at 0xd400 standalone you should supply the insmod
or depmod with type=35 io=0xd400.
If you want to use all three cards, but the order needs to be at 0xdc00,0xd400,
0xd000 you may give the parameters type=35,35,35 io=0xdc00,0xd400,0xd00
Then the desired card will be the initialised in the desired order.
If the io parameter is used the io addresses of all used cards should be
supplied else the parameter is assumed 0 and a auto search for a free card is
invoked which may not give the wanted result.
Comments and reports to werner@isdn4linux.de or werner@titro.de .

View File

@ -1,177 +0,0 @@
$Id$
The hysdn driver has been written by
by Werner Cornelius (werner@isdn4linux.de or werner@titro.de)
for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver
under the GNU Public License.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Table of contents
=================
1. About the driver
2. Loading/Unloading the driver
3. Entries in the /proc filesystem
4. The /proc/net/hysdn/cardconfX file
5. The /proc/net/hysdn/cardlogX file
6. Where to get additional info and help
1. About the driver
The drivers/isdn/hysdn subdir contains a driver for HYPERCOPEs active
PCI isdn cards Champ, Ergo and Metro. To enable support for this cards
enable ISDN support in the kernel config and support for HYSDN cards in
the active cards submenu. The driver may only be compiled and used if
support for loadable modules and the process filesystem have been enabled.
No other ISDN options need to be enabled for these cards.
Up to now these cards do not use or require the standard isdn interface
module (isdn.o), but registers itself as an ethernet card. All necessary
handlers for various protocols like ppp and others as well as config info
and firmware may be fetched from Hypercopes WWW-Site www.hypercope.de.
The driver has been included in the i4l tree as a CAPI compliant module
is under development and will be connected to the standard i4l modules
additionally.
2. Loading/Unloading the driver
The module has no command line parameters and auto detects up to 10 cards
in the id-range 0-9.
If a loaded driver shall be unloaded all open files in the /proc/net/hysdn
subdir need to be closed and all ethernet interfaces allocated by this
driver must be shut down. Otherwise the module counter will avoid a module
unload.
3. Entries in the /proc filesystem
When the module has been loaded it adds the directory hysdn in the
/proc/net tree. This directory contains exactly 2 file entries for each
card. One is called cardconfX and the other cardlogX, where X is the
card id number from 0 to 9.
The cards are numbered in the order found in the PCI config data.
4. The /proc/net/hysdn/cardconfX file
This file may be read to get by everyone to get info about the cards type,
actual state, available features and used resources.
The first 3 entries (id, bus and slot) are PCI info fields, the following
type field gives the information about the cards type:
4 -> Ergo card (server card with 2 b-chans)
5 -> Metro card (server card with 4 or 8 b-chans)
6 -> Champ card (client card with 2 b-chans)
The following 3 fields show the hardware assignments for irq, iobase and the
dual ported memory (dp-mem).
The fields b-chans and fax-chans announce the available card resources of
this types for the user.
The state variable indicates the actual drivers state for this card with the
following assignments.
0 -> card has not been booted since driver load
1 -> card booting is actually in progess
2 -> card is in an error state due to a previous boot failure
3 -> card is booted and active
And the last field (device) shows the name of the ethernet device assigned
to this card. Up to the first successfull boot this field only shows a -
to tell that no net device has been allocated up to now. Once a net device
has been allocated it remains assigned to this card, even if a card is
rebooted and an boot error occurs.
Writing to the cardconfX file boots the card or transfers config lines to
the cards firmware. The type of data is automatically detected when the
first data is written. Only root has write access to this file.
The firmware boot files are normally called hyclient.pof for client cards
and hyserver.pof for server cards.
After successfully writing the boot file, complete config files or single
config lines may be copied to this file.
If an error occurs the return value given to the writing process has the
following additional codes (decimal):
1000 Another process is currently bootng the card
1001 Invalid firmware header
1002 Boards dual-port RAM test failed
1003 Internal firmware handler error
1004 Boot image size invalid
1005 First boot stage (bootstrap loader) failed
1006 Second boot stage failure
1007 Timeout waiting for card ready during boot
1008 Operation only allowed in booted state
1009 Config line to long
1010 Invalid channel number
1011 Timeout sending config data
Additional info about error reasons may be fetched from the log output.
5. The /proc/net/hysdn/cardlogX file
The cardlogX file entry may be opened multiple for reading by everyone to
get the cards and drivers log data. Card messages always start with the
keyword LOG. All other lines are output from the driver.
The driver log data may be redirected to the syslog by selecting the
approriate bitmask. The cards log messages will always be send to this
interface but never to the syslog.
A root user may write a decimal or hex (with 0x) value t this file to select
desired output options. As mentioned above the cards log dat is always
written to the cardlog file independant of the following options only used
to check and debug the driver itself:
For example:
echo "0x34560078" > /proc/net/hysdn/cardlog0
to output the hex log mask 34560078 for card 0.
The written value is regarded as an unsigned 32-Bit value, bit ored for
desired output. The following bits are already assigned:
0x80000000 All driver log data is alternatively via syslog
0x00000001 Log memory allocation errors
0x00000010 Firmware load start and close are logged
0x00000020 Log firmware record parser
0x00000040 Log every firmware write actions
0x00000080 Log all card related boot messages
0x00000100 Output all config data sent for debugging purposes
0x00000200 Only non comment config lines are shown wth channel
0x00000400 Additional conf log output
0x00001000 Log the asynchronous scheduler actions (config and log)
0x00100000 Log all open and close actions to /proc/net/hysdn/card files
0x00200000 Log all actions from /proc file entries
0x00010000 Log network interface init and deinit
6. Where to get additional info and help
If you have any problems concerning the driver or configuration contact
the Hypercope support team (www.hypercope.de) and or the author
Werner Cornelius (werner@isdn4linux or cornelius@titro.de)

View File

@ -1,148 +0,0 @@
$Id$
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 dowloading 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.

View File

@ -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>

View File

@ -1,58 +0,0 @@
Some additional information for setting up a syncPPP
connection using network interfaces.
---------------------------------------------------------------
You need one thing beside the isdn4linux package:
a patched pppd .. (I called it ipppd to show the difference)
Compiling isdn4linux with sync PPP:
-----------------------------------
To compile isdn4linux with the sync PPP part, you have
to answer the appropriate question when doing a "make config"
Don't forget to load the slhc.o
module before the isdn.o module, if VJ-compression support
is not compiled into your kernel. (e.g if you have no PPP or
CSLIP in the kernel)
Using isdn4linux with sync PPP:
-------------------------------
Sync PPP is just another encapsulation for isdn4linux. The
name to enable sync PPP encapsulation is 'syncppp' .. e.g:
/sbin/isdnctrl encap ippp0 syncppp
The name of the interface is here 'ippp0'. You need
one interface with the name 'ippp0' to saturate the
ipppd, which checks the ppp version via this interface.
Currently, all devices must have the name ipppX where
'X' is a decimal value.
To set up a PPP connection you need the ipppd .. You must start
the ipppd once after installing the modules. The ipppd
communicates with the isdn4linux link-level driver using the
/dev/ippp0 to /dev/ippp15 devices. One ipppd can handle
all devices at once. If you want to use two PPP connections
at the same time, you have to connect the ipppd to two
devices .. and so on.
I've implemented one additional option for the ipppd:
'useifip' will get (if set to not 0.0.0.0) the IP address
for the negotiation from the attached network-interface.
(also: ipppd will try to negotiate pointopoint IP as remote IP)
You must disable BSD-compression, this implementation can't
handle compressed packets.
Check the etc/rc.isdn.syncppp in the isdn4kernel-util package
for an example setup script.
To use the MPPP stuff, you must configure a slave device
with isdn4linux. Now call the ipppd with the '+mp' option.
To increase the number of links, you must use the
'addlink' option of the isdnctrl tool. (rc.isdn.syncppp.MPPP is
an example script)
enjoy it,
michael

View File

@ -1,184 +0,0 @@
X.25 support within isdn4linux
==============================
This is alpha/beta test code. Use it completely at your own risk.
As new versions appear, the stuff described here might suddenly change
or become invalid without notice.
Keep in mind:
You are using several new parts of the 2.2.x kernel series which
have not been tested in a large scale. Therefore, you might encounter
more bugs as usual.
- If you connect to an X.25 neighbour not operated by yourself, ASK the
other side first. Be prepared that bugs in the protocol implementation
might result in problems.
- This implementation has never wiped out my whole hard disk yet. But as
this is experimental code, don't blame me if that happened to you.
Backing up important data will never harm.
- Monitor your isdn connections while using this software. This should
prevent you from undesired phone bills in case of driver problems.
How to configure the kernel
===========================
The ITU-T (former CCITT) X.25 network protocol layer has been implemented
in the Linux source tree since version 2.1.16. The isdn subsystem might be
useful to run X.25 on top of ISDN. If you want to try it, select
"CCITT X.25 Packet Layer"
from the networking options as well as
"ISDN Support" and "X.25 PLP on Top of ISDN"
from the ISDN subsystem options when you configure your kernel for
compilation. You currently also need to enable
"Prompt for development and/or incomplete code/drivers" from the
"Code maturity level options" menu. For the x25trace utility to work
you also need to enable "Packet socket".
For local testing it is also recommended to enable the isdnloop driver
from the isdn subsystem's configuration menu.
For testing, it is recommended that all isdn drivers and the X.25 PLP
protocol are compiled as loadable modules. Like this, you can recover
from certain errors by simply unloading and reloading the modules.
What's it for? How to use it?
=============================
X.25 on top of isdn might be useful with two different scenarios:
- You might want to access a public X.25 data network from your Linux box.
You can use i4l if you were physically connected to the X.25 switch
by an ISDN B-channel (leased line as well as dial up connection should
work).
This corresponds to ITU-T recommendation X.31 Case A (circuit-mode
access to PSPDN [packet switched public data network]).
NOTE: X.31 also covers a Case B (access to PSPDN via virtual
circuit / packet mode service). The latter mode (which in theory
also allows using the D-channel) is not supported by isdn4linux.
It should however be possible to establish such packet mode connections
with certain active isdn cards provided that the firmware supports X.31
and the driver exports this functionality to the user. Currently,
the AVM B1 driver is the only driver which does so. (It should be
possible to access D-channel X.31 with active AVM cards using the
CAPI interface of the AVM-B1 driver).
- Or you might want to operate certain ISDN teleservices on your linux
box. A lot of those teleservices run on top of the ISO-8208
(DTE-DTE mode) network layer protocol. ISO-8208 is essentially the
same as ITU-T X.25.
Popular candidates of such teleservices are EUROfile transfer or any
teleservice applying ITU-T recommendation T.90.
To use the X.25 protocol on top of isdn, just create an isdn network
interface as usual, configure your own and/or peer's ISDN numbers,
and choose x25iface encapsulation by
isdnctrl encap <iface-name> x25iface.
Once encap is set like this, the device can be used by the X.25 packet layer.
All the stuff needed for X.25 is implemented inside the isdn link
level (mainly isdn_net.c and some new source files). Thus, it should
work with every existing HL driver. I was able to successfully open X.25
connections on top of the isdnloop driver and the hisax driver.
"x25iface"-encapsulation bypasses demand dialing. Dialing will be
initiated when the upper (X.25 packet) layer requests the lapb datalink to
be established. But hangup timeout is still active. Whenever a hangup
occurs, all existing X.25 connections on that link will be cleared
It is recommended to use sufficiently large hangup-timeouts for the
isdn interfaces.
In order to set up a conforming protocol stack you also need to
specify the proper l2_prot parameter:
To operate in ISO-8208 X.25 DTE-DTE mode, use
isdnctrl l2_prot <iface-name> x75i
To access an X.25 network switch via isdn (your linux box is the DTE), use
isdnctrl l2_prot <iface-name> x25dte
To mimic an X.25 network switch (DCE side of the connection), use
isdnctrl l2_prot <iface-name> x25dce
However, x25dte or x25dce is currently not supported by any real HL
level driver. The main difference between x75i and x25dte/dce is that
x25d[tc]e uses fixed lap_b addresses. With x75i, the side which
initiates the isdn connection uses the DTE's lap_b address while the
called side used the DCE's lap_b address. Thus, l2_prot x75i might
probably work if you access a public X.25 network as long as the
corresponding isdn connection is set up by you. At least one test
was successful to connect via isdn4linux to an X.25 switch using this
trick. At the switch side, a terminal adapter X.21 was used to connect
it to the isdn.
How to set up a test installation?
==================================
To test X.25 on top of isdn, you need to get
- a recent version of the "isdnctrl" program that supports setting the new
X.25 specific parameters.
- the x25-utils-2.X package from
ftp://ftp.hes.iki.fi/pub/ham/linux/ax25/x25utils-*
(don't confuse the x25-utils with the ax25-utils)
- an application program that uses linux PF_X25 sockets (some are
contained in the x25-util package).
Before compiling the user level utilities make sure that the compiler/
preprocessor will fetch the proper kernel header files of this kernel
source tree. Either make /usr/include/linux a symbolic link pointing to
this kernel's include/linux directory or set the appropriate compiler flags.
When all drivers and interfaces are loaded and configured you need to
ifconfig the network interfaces up and add X.25-routes to them. Use
the usual ifconfig tool.
ifconfig <iface-name> up
But a special x25route tool (distributed with the x25-util package)
is needed to set up X.25 routes. I.e.
x25route add 01 <iface-name>
will cause all x.25 connections to the destination X.25-address
"01" to be routed to your created isdn network interface.
There are currently no real X.25 applications available. However, for
tests, the x25-utils package contains a modified version of telnet
and telnetd that uses X.25 sockets instead of tcp/ip sockets. You can
use those for your first tests. Furthermore, you might check
ftp://ftp.hamburg.pop.de/pub/LOCAL/linux/i4l-eft/ which contains some
alpha-test implementation ("eftp4linux") of the EUROfile transfer
protocol.
The scripts distributed with the eftp4linux test releases might also
provide useful examples for setting up X.25 on top of isdn.
The x25-utility package also contains an x25trace tool that can be
used to monitor X.25 packets received by the network interfaces.
The /proc/net/x25* files also contain useful information.
- Henner

View File

@ -1,166 +0,0 @@
ISDN-ABC-DW Extension
CONFIG_ISDN_WITH_ABC
These are many brand new Options and Features for the
ISDN SUBSYSTEM. Including Logical Device bindings,
Compression and other good stuff for Optimizing your
ISDN System.
To Use this Extensions you MUST HAVE THE NEWEST
ISDN4K-UTILS. You must have Version 3.1-Beta6 or
higher. Elsewhere you can not configure this Extensions.
WARNING ! THIS STUF IS NOT PRODUCTION RELEASE THE
FUNCTION ARE UNDER DEVELOPMENT. This ist BETA-CODE.
You can use it at you Own Risk.
For more Information on these Extensions take a look at
"linux/Documentation/isdn/dw-abc-extension-howto.txt or
Online at the Web "http://www.mediatronix.de/i4l/index.html"
Please Report Bugs to "mario@mediatronix.de" or
"delefw@isdn4linux.de"
D-Channel-Callback with Channel in use check
CONFIG_ISDN_WITH_ABC_CALLB
When a Interface is declared as an Callback Interface,
the Interface is checking that the other Side is not
Calling on the same time before the Interface is Dialing.
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information
In most case answer with "Yes" when you have Callback devices,
otherwise leave it "No"
Outgoing-EAZ-Support
CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
Enables the Feature to Define an other EAZ or MSN for
Outgoing calls on an Interface.
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information
Least Cost Router Support
CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
This is the final Kernel Code for configuring an Least
Cost Router Softwarebased. The other Job is to do the
action in ISDNLOG. You need the ISDNLOG to use this
function. Currently the ISDNLOG have not the Support for
this Option.
So in most situations let the Option off.
TCP keepalive detect and response
CONFIG_ISDN_WITH_ABC_IPV4_TCP_KEEPALIVE
This Option works only with the TCP/IP V4. It enables
the Function that ISDN Devices are Answering TCP_KEEPALIVE Pakets
localy. So that TCP KEEPALIVE Pakets not longer takes the Line
open.
Drop frames Sourceadresse is not Interfaceadress
CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
This Option works only with the TCP/IP V4. It will allow only
the Transmitt of Pakets where the Sourceadresse is the Interface
adress. It is usefull when you have Lines with Dynamic IP.
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information
Receive do not reset the Hanguptimer
CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
When you activate this option than the reiceive of pakets do
not reset the Hanguptimer. It is very usefull because if the
Paket vor your Network your Network generate an Response and
the Transmit is reseting the HUPTIMER. But when the Paket is
Rejected at your firewall your network generate no Response
and no Sendtraffic is generated. So in this case there is no
need to Reset the Huptimer because you have only received Data.
With that option only Transmitted Data/Pakets will reset the
HUPTIMER.
Support of (device-channel) and Binding Groups
CONFIG_ISDN_WITH_ABC_ICALL_BIND
This Option enables the Feature to Bind logical ISDN Interfaces
to an prefered ISDN Card or ISDN Card plus Channel. So you have
the Chance to keep Channels exclusively for one (or more)
Connection. Very usefull when you have more channels and Use
Calling Line Identification, because you can organize that your
call is going out over the Line with the right EAZ for the CLI.
Skip channel if used external (Dial Only)
CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
When you have more than One ISDN Card in your System and you
will Dialout with an Interface you can become the Situation
that an External Device such a Telephone or Fax is Using the
B-Channels. Normaly ISDN4Linux does not detect this Situation
and dial everytime of the "External Busy" line out. With this
Option Enabled the I4L will detect that he can not dialout on
This Card and dial over the next Card out.
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information
Interface autodisable if Config error
CONFIG_ISDN_WITH_ABC_CONN_ERROR
This Option will detect an Device which generate Telephone
Cost but does not Function correctly because there are
Configerrors on one of the Site. In this Situation the
Interface will be marked as Unsuably for some time to do
not call every time this Site.
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information
UDP-Info-Support
CONFIG_ISDN_WITH_ABC_UDP_CHECK
This is the Mainoption to Enable or Disable the UDP
Info Support. An Option to Controll ISDN-Interfaces
Remotely. For this very Complex thing take a look at
"linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information.
UDP Hangup Support
CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
Sorry no more Information!
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information
UDP Dial Support
CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
Sorry no more Information!
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information
Limit on the line frames to two
CONFIG_ISDN_WITH_ABC_FRAME_LIMIT
This Option enables support for sending only 2 Pakets on
the Fly to the ISDN Driver. It is very usefull when you
will use the new RAW-IP Compression. Because of sending
Only 2 Pakets on the Fly makes the risk of overflowing
the ISDN Driver very smaller.
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information
Compression with RAWIP and X75I
CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
With this Option you have the ability to make Datacompression
on RAW-IP Lines. It is function on HDLC and X75I Connection,
but the Prefered L2-Protocol for Compression is X75I because
the HDLC Protocol have no Errorcorrection.
To Use this Option YOU MUST HAVE ENABLED THE OPTION:
Support synchronous PPP
and must load after loading the main isdndrivers the
Modul "isdn_bsdcomp".
See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
for more Information

View File

@ -1,224 +0,0 @@
simple isdn4linux PPP FAQ .. to be continued .. not 'debugged'
-------------------------------------------------------------------
Q01: what's pppd, ipppd, syncPPP, asyncPPP ??
Q02: error message "this system lacks PPP support"
Q03: strange information using 'ifconfig'
Q04: MPPP?? What's that and how can I use it ...
Q05: I tried MPPP but it doesn't work
Q06: can I use asynchronous PPP encapsulation with network devices
Q07: A SunISDN machine can't connect to my i4l system
Q08: I wanna talk to several machines, which need different configs
Q09: Starting the ipppd, I get only error messages from i4l
Q10: I wanna use dynamic IP address assignment
Q11: I can't connect. How can I check where the problem is.
Q12: How can I reduce login delay?
-------------------------------------------------------------------
Q01: pppd, ipppd, syncPPP, asyncPPP .. what is that ?
what should I use?
A: The pppd is for asynchronous PPP .. asynchronous means
here, the framing is character based. (e.g when
using ttyI* or tty* devices)
The ipppd handles PPP packets coming in HDLC
frames (bit based protocol) ... The PPP driver
in isdn4linux pushes all IP packets direct
to the network layer and all PPP protocol
frames to the /dev/ippp* device.
So, the ipppd is a simple external network
protocol handler.
If you login into a remote machine using the
/dev/ttyI* devices and then enable PPP on the
remote terminal server -> use the 'old' pppd
If your remote side immediately starts to send
frames ... you probably connect to a
syncPPP machine .. use the network device part
of isdn4linux with the 'syncppp' encapsulation
and make sure, that the ipppd is running and
connected to at least one /dev/ippp*. Check the
isdn4linux manual on how to configure a network device.
--
Q02: when I start the ipppd .. I only get the
error message "this system lacks PPP support"
A: check that at least the device 'ippp0' exists.
(you can check this e.g with the program 'ifconfig')
The ipppd NEEDS this device under THIS name ..
If this device doesn't exists, use:
isdnctrl addif ippp0
isdnctrl encap ippp0 syncppp
... (see isdn4linux doc for more) ...
A: Maybe you have compiled the ipppd with another
kernel source tree than the kernel you currently
run ...
--
Q03: when I list the netdevices with ifconfig I see, that
my ISDN interface has a HWaddr and IRQ=0 and Base
address = 0
A: The device is a fake ethernet device .. ignore IRQ and baseaddr
You need the HWaddr only for ethernet encapsulation.
--
Q04: MPPP?? What's that and how can I use it ...
A: MPPP or MP or MPP (Warning: MP is also an
acronym for 'Multi Processor') stands for
Multi Point to Point and means bundling
of several channels to one logical stream.
To enable MPPP negotiation you must call the
ipppd with the '+mp' option.
You must also configure a slave device for
every additional channel. (see the i4l manual
for more)
To use channel bundling you must first activate
the 'master' or initial call. Now you can add
the slave channels with the command:
isdnctrl addlink <device>
e.g:
isdnctrl addlink ippp0
This is different from other encapsulations of
isdn4linux! With syncPPP, there is no automatic
activation of slave devices.
--
Q05: I tried MPPP but it doesn't work .. the ipppd
writes in the debug log something like:
.. rcvd [0][proto=0x3d] c0 00 00 00 80 fd 01 01 00 0a ...
.. sent [0][LCP ProtRej id=0x2 00 3d c0 00 00 00 80 fd 01 ...
A: you forgot to compile MPPP/RFC1717 support into the
ISDN Subsystem. Recompile with this option enabled.
--
Q06: can I use asynchronous PPP encapsulation
over the network interface of isdn4linux ..
A: No .. that's not possible .. Use the standard
PPP package over the /dev/ttyI* devices. You
must not use the ipppd for this.
--
Q07: A SunISDN machine tries to connect my i4l system,
which doesn't work.
Checking the debug log I just saw garbage like:
!![ ... fill in the line ... ]!!
A: The Sun tries to talk asynchronous PPP ... i4l
can't understand this ... try to use the ttyI*
devices with the standard PPP/pppd package
A: (from Alexanter Strauss: )
!![ ... fill in mail ]!!
--
Q08: I wanna talk to remote machines, which need
a different configuration. The only way
I found to do this is to kill the ipppd and
start a new one with another config to connect
to the second machine.
A: you must bind a network interface explicitly to
an ippp device, where you can connect a (for this
interface) individually configured ipppd.
--
Q09: When I start the ipppd I only get error messages
from the i4l driver ..
A: When starting, the ipppd calls functions which may
trigger a network packet. (e.g gethostbyname()).
Without the ipppd (at this moment, it is not
fully started) we can't handle this network request.
Try to configure hostnames necessary for the ipppd
in your local /etc/hosts file or in a way, that
your system can resolve it without using an
isdn/ippp network-interface.
--
Q10: I wanna use dynamic IP address assignment ... How
must I configure the network device.
A: At least you must have a route which forwards
a packet to the ippp network-interface to trigger
the dial-on-demand.
A default route to the ippp-interface will work.
Now you must choose a dummy IP address for your
interface.
If for some reason you can't set the default
route to the ippp interface, you may take any
address of the subnet from which you expect your
dynamic IP number and set a 'network route' for
this subnet to the ippp interface.
To allow overriding of the dummy address you
must call the ipppd with the 'ipcp-accept-local' option.
A: You must know, how the ipppd gets the addresses it wanna
configure. If you don't give any option, the ipppd
tries to negotiate the local host address!
With the option 'noipdefault' it requests an address
from the remote machine. With 'useifip' it gets the
addresses from the net interface. Or you set the address
on the option line with the <a.b.c.d:e.f.g.h> option.
Note: the IP address of the remote machine must be configured
locally or the remote machine must send it in an IPCP request.
If your side doesn't know the IP address after negotiation, it
closes the connection!
You must allow overriding of address with the 'ipcp-accept-*'
options, if you have set your own or the remote address
explicitly.
A: Maybe you try these options .. e.g:
/sbin/ipppd :$REMOTE noipdefault /dev/ippp0
where REMOTE must be the address of the remote machine (the
machine, which gives you your address)
--
Q11: I can't connect. How can I check where the problem is.
A: A good help log is the debug output from the ipppd...
Check whether you can find there:
- only a few LCP-conf-req SENT messages (less then 10)
and then a Term-REQ:
-> check whether your ISDN card is well configured
it seems, that your machine doesn't dial
(IRQ,IO,Proto, etc problems)
Configure your ISDN card to print debug messages and
check the /dev/isdnctrl output next time. There
you can see, whether there is activity on the card/line.
- there are at least a few RECV messages in the log:
-> fine: your card is dialing and your remote machine
tries to talk with you. Maybe only a missing
authentication. Check your ipppd configuration again.
- the ipppd exits for some reason:
-> not good ... check /var/adm/syslog and /var/adm/daemon.
Could be a bug in the ipppd.
--
Q12: How can I reduce login delay?
A: Log a login session ('debug' log) and check which options
your remote side rejects. Next time configure your ipppd
to not negotiate these options. Another 'side effect' is, that
this increases redundancy. (e.g your remote side is buggy and
rejects options in a wrong way).

126
Makefile
View File

@ -1,126 +0,0 @@
I4LVERSION=2.1.88
KERNELDIR = /usr/src/linux
######### NOTHING TO CHANGE BELOW ################
.EXPORT_ALL_VARIABLES:
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
else if [ -x /bin/bash ]; then echo /bin/bash; \
else echo sh; fi ; fi)
KCONFIG = $(KERNELDIR)/.config
TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
ISDNINC := $(ISDNTOP)/include
#
# Get VERSION, PATCHLEVEL, SUBLEVEL, ARCH, SMP and SMP_PROF from Kerneltree
#
VERSION = $(shell head -9 $(KERNELDIR)/Makefile |grep VERSION |awk '{print $$3}')
PATCHLEVEL = $(shell head -9 $(KERNELDIR)/Makefile |grep PATCHLEVEL |awk '{print $$3}')
SUBLEVEL = $(shell head -9 $(KERNELDIR)/Makefile |grep SUBLEVEL |awk '{print $$3}')
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
ifneq ("$(shell egrep '^ *SMP *=.*' $(KERNELDIR)/Makefile)","")
SMP = 1
endif
ifneq ("$(shell egrep '^ *SMP_PROF *=.*' $(KERNELDIR)/Makefile)","")
SMP_PROF = 1
endif
ARCHMAKE := $(KERNELDIR)/arch/$(ARCH)/Makefile
MODDEST =/lib/modules/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)/misc
HPATH =$(KERNELDIR)/include
HOSTCC =gcc -I$(HPATH) -I$(ISDNINC)
HOSTCFLAGS =-O2 -fomit-frame-pointer
CROSS_COMPILE =
AS =$(CROSS_COMPILE)as
LD =$(CROSS_COMPILE)ld
CC =$(CROSS_COMPILE)gcc -g -D__KERNEL__ -I$(HPATH)
CPP =$(CC) -E
AR =$(CROSS_COMPILE)ar
NM =$(CROSS_COMPILE)nm
STRIP =$(CROSS_COMPILE)strip
MAKE =make
ifeq ($(KCONFIG),$(wildcard $(KCONFIG)))
include $(KCONFIG)
ifeq ($(CONFIG_ISDN),m)
include .config
do-it-all: modules
else
do-it-all: modconf-error
endif
else
do-it-all: unconf-error
endif
CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce
ifdef CONFIG_CPP
CFLAGS := $(CFLAGS) -x c++
endif
ifdef SMP
CFLAGS += -D__SMP__
AFLAGS += -D__SMP__
ifdef SMP_PROF
CFLAGS += -D__SMP_PROF__
AFLAGS += -D__SMP_PROF__
endif
endif
include $(ARCHMAKE)
SUBDIRS := drivers/isdn
MODFLAGS = -DMODULE
ifdef CONFIG_MODVERSIONS
MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h
endif
all: do-it-all
unconf-error:
@echo ""
@echo "Cannot find configured kernel."
@echo "Make sure, you have our kernel configured, and"
@echo "the definition of KERNELDIR points to the proper location."
@echo ""
modconf-error:
@echo ""
@echo "Your have disbled CONFIG_MODULES in your kernel configuration."
@echo "Without that option, this package cannot compile."
@echo "Reconfigure your kernel, then come back here and start again."
@echo ""
$(KERNELDIR)/linux/version.h: $(KERNELDIR)/Makefile
@cd $(KERNELDIR)
$(MAKE) include/linux/version.h
modules: $(KERNELDIR)/include/linux/version.h
@set -e; \
for i in $(SUBDIRS); do \
$(MAKE) -C $$i CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules; \
done
rootperm:
@echo 'main(int argc,char**argv){unlink(argv[0]);return(getuid()==0);}'>g
@if gcc -x c -o G g && rm -f g && ./G ; then \
echo -e "\n\n Need root permission for installation!\n\n"; \
exit 1; \
fi
modules_install: rootperm
@set -e; \
for i in $(SUBDIRS); do \
$(MAKE) -C $$i modules_install; \
done
depmod -a $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)
clean:
rm -f `find . -name '*.[iso]' -print`
rm -f `find . -type f -name '*~' -print`
rm -f core `find . -type f -name 'core' -print`
include Rules.make

View File

@ -1,61 +0,0 @@
"preparser" is a little tool to resolve special macros and conditional
preprocessor code in C files.
The special marcro and conditions are given in a control file.
The control file use the same syntax like the C preprocessor directives
"#define" and "#undef" plus a "#delete" command.
You can also use C-Comments in it.
Here are 2 implicit conditional defines in "preparser" for "#if 0"
and "#if 1" code segments.
Control file syntax:
#delete <item to delete>
#define <name> <value>
#undef <name>
<name> maybe also a function.
/* example control file */
#delete #include <linux/isdn_compat.h>
#define GET_USER get_user
#define PUT_USER put_user
#define idev_kfree_skb(a,b) dev_kfree_skb(a)
#define COMPAT_HAS_NEW_SYMTAB
#undef COMPAT_HAS_NEW_SETUP
/* end of example control file */
What does the Programm ?
1. It copies a input file into a output file (or stdout)
2. While copying it deletes all items given in #delete (exact string
matching).
3. While copying it resolve the marcros given in the control file.
4. It resolve any "#ifdef" "#ifndef" "#if" related to the marcros given in
the control file. Note: in the moment it don't calculate a value after
an "#if" directive, if here is a "#define" in the control file for
the string after "#if" and the value of that "#define" is empty, "#if" is
handled as false, if a value is given it is handled as true.
5. All items inside "strings" or C comments are not modified.
Usage
./preparser [options] <input file> [output file]
Valid options are:
-d increase debug level
-c,-C <controlfile> Use control file
-? Usage ; printout this information
"preparser" was written to write Linux portable Linux kernel code (portable
in the sense "portable between various kernel versions") and to remove
experimental code from C files. This avoid that contructs based on
KERNELVERSION are going into standard kernel.
Karsten Keil
keil@isdn4linux.de
PS: If you like to get the source, request it by mail.

View File

@ -1,189 +0,0 @@
#
# This file contains rules which are shared between multiple Makefiles.
#
#
# False targets.
#
.PHONY: dummy
#
# Special variables which should not be exported
#
unexport EXTRA_ASFLAGS
unexport EXTRA_CFLAGS
unexport EXTRA_LDFLAGS
unexport EXTRA_ARFLAGS
unexport SUBDIRS
unexport SUB_DIRS
unexport ALL_SUB_DIRS
unexport MOD_SUB_DIRS
unexport O_TARGET
unexport O_OBJS
unexport L_OBJS
unexport M_OBJS
unexport ALL_MOBJS
# objects that export symbol tables
unexport OX_OBJS
unexport LX_OBJS
unexport MX_OBJS
unexport SYMTAB_OBJS
unexport MOD_LIST_NAME
#
# Get things started.
#
first_rule: sub_dirs
$(MAKE) all_targets
#
# Common rules
#
%.s: %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o $@
%.o: %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
%.o: %.s
$(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $<
#
#
#
all_targets: $(O_TARGET) $(L_TARGET)
#
# Rule to compile a set of .o files into one .o file
#
ifdef O_TARGET
ALL_O = $(OX_OBJS) $(O_OBJS)
$(O_TARGET): $(ALL_O) $(KERNELDIR)/include/linux/config.h
rm -f $@
ifneq "$(strip $(ALL_O))" ""
$(LD) $(EXTRA_LDFLAGS) -r -o $@ $(ALL_O)
else
$(AR) rcs $@
endif
endif
#
# Rule to compile a set of .o files into one .a file
#
ifdef L_TARGET
$(L_TARGET): $(LX_OBJS) $(L_OBJS) $(KERNELDIR)/include/linux/config.h
rm -f $@
$(AR) $(EXTRA_ARFLAGS) rcs $@ $(LX_OBJS) $(L_OBJS)
endif
#
# This make dependencies quickly
#
fastdep: dummy
if [ -n "$(wildcard *.[chS])" ]; then \
$(TOPDIR)/scripts/mkdep *.[chS] > .depend; fi
ifdef ALL_SUB_DIRS
set -e; for i in $(ALL_SUB_DIRS); do $(MAKE) -C $$i fastdep; done
endif
#
# A rule to make subdirectories
#
sub_dirs: dummy
ifdef SUB_DIRS
set -e; for i in $(SUB_DIRS); do $(MAKE) -C $$i; done
endif
#
# A rule to make modules
#
ALL_MOBJS = $(MX_OBJS) $(M_OBJS)
modules: $(ALL_MOBJS) dummy
ifdef MOD_SUB_DIRS
set -e; for i in $(MOD_SUB_DIRS); do $(MAKE) -C $$i modules; done
endif
modules_install: $(ALL_MOBJS) dummy
ifdef MOD_SUB_DIRS
set -e; for i in $(MOD_SUB_DIRS); do $(MAKE) -C $$i modules_install; done
endif
ifneq "$(strip $(ALL_MOBJS))" ""
mkdir -p $(MODDEST)
cp -p $(ALL_MOBJS) $(MODDEST)
endif
#
# A rule to do nothing
#
dummy:
#
# This is useful for testing
#
script:
$(SCRIPT)
#
# This sets version suffixes on exported symbols
# Uses SYMTAB_OBJS
# Separate the object into "normal" objects and "exporting" objects
# Exporting objects are: all objects that define symbol tables
#
ifdef CONFIG_MODVERSIONS
SYMTAB_OBJS = $(LX_OBJS) $(OX_OBJS) $(MX_OBJS)
ifneq "$(strip $(SYMTAB_OBJS))" ""
MODINCL = $(KERNELDIR)/include/linux/modules
# The -w option (enable warnings) for /bin/genksyms will return here in 2.1
$(MODINCL)/%.ver: %.c
@if [ ! -x /sbin/genksyms ]; then echo "Please read: Documentation/modules.txt"; fi
$(CC) $(CFLAGS) -E -D__GENKSYMS__ $< | /sbin/genksyms $(MODINCL)
$(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver)): $(KERNELDIR)/include/linux/autoconf.h
$(KERNELDIR)/include/linux/modversions.h: $(addprefix $(MODINCL)/,$(SYMTAB_OBJS:.o=.ver))
@echo updating $(KERNELDIR)/include/linux/modversions.h
@(echo "#ifdef MODVERSIONS";\
echo "#undef CONFIG_MODVERSIONS";\
echo "#define CONFIG_MODVERSIONS";\
echo "#ifndef _set_ver";\
echo "#define _set_ver(sym,vers) sym ## _R ## vers";\
echo "#endif";\
cd $(KERNELDIR)/include/linux/modules; for f in *.ver;\
do echo "#include <linux/modules/$${f}>"; done; \
echo "#undef CONFIG_MODVERSIONS";\
echo "#endif") \
> $(KERNELDIR)/include/linux/modversions.h
$(MX_OBJS): $(KERNELDIR)/include/linux/modversions.h
$(CC) $(CFLAGS) -DEXPORT_SYMTAB -c $(@:.o=.c)
$(LX_OBJS) $(OX_OBJS): $(KERNELDIR)/include/linux/modversions.h
$(CC) $(CFLAGS) -DMODVERSIONS -DEXPORT_SYMTAB -c $(@:.o=.c)
dep fastdep: $(KERNELDIR)/include/linux/modversions.h
endif
$(M_OBJS): $(KERNELDIR)/include/linux/modversions.h
ifdef MAKING_MODULES
$(O_OBJS) $(L_OBJS): $(KERNELDIR)/include/linux/modversions.h
endif
# This is needed to ensure proper dependency for multipart modules such as
# fs/ext.o. (Otherwise, not all subobjects will be recompiled when
# version information changes.)
endif
#
# include dependency files they exist
#
ifeq (.depend,$(wildcard .depend))
include .depend
endif
ifeq ($(KERNELDIR)/.hdepend,$(wildcard $(KERNELDIR)/.hdepend))
include $(KERNELDIR)/.hdepend
endif

View File

@ -1,66 +0,0 @@
#!/bin/sh
INDENT=`which indent`
SED=`which sed`
if test "$INDENT" = "" ; then
echo programm indent missing
exit
fi
if test "$SED" = "" ; then
echo programm sed missing
exit
fi
BACKUP=false
CHECK=false
case "$1" in
-b)
BACKUP=true
shift
;;
-c)
CHECK=true
BACKUP=false
shift
;;
esac
formatiere() {
if $CHECK ; then
OUT=$1.idout
else
OUT=$1
fi
cp $1 $1\~
cat $1\~ | $INDENT -kr -i8 -cli8 -psl -lp | \
$SED -e 's/^ / /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/^\( \+\) /\1 /g' \
-e 's/[ ]\+$//g' > $OUT
if $CHECK ; then
diff -u $1\~ $OUT
rm $OUT
fi
if ! $BACKUP ; then
rm $1\~
fi
}
for f in $* ; do
formatiere $f
done

View File

@ -1,141 +0,0 @@
#
# ISDN device configuration
#
if [ "$CONFIG_INET" != "n" ]; then
bool ' Support synchronous PPP' CONFIG_ISDN_PPP
if [ "$CONFIG_ISDN_PPP" != "n" ]; then
bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
fi
fi
bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO
if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
bool ' Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
fi
if [ "$CONFIG_X25" != "n" ]; then
bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25
fi
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
mainmenu_option next_comment
comment 'ISDN abc-dw-extension'
bool 'Enable isdn-abc-dw-extension' CONFIG_ISDN_WITH_ABC
if [ "$CONFIG_ISDN_WITH_ABC" != "n" ]; then
bool ' Use D-Channel-Callback with Channel in use check' CONFIG_ISDN_WITH_ABC_CALLB
bool ' Enable Outgoing-EAZ-Support' CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
bool ' Enable LCR-Support (need isdnlog)' CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
bool ' TCP keepalive detect and response (ip4 only)' CONFIG_ISDN_WITH_ABC_IPV4_TCP_KEEPALIVE
bool ' Drop frames s_addr != iface_addr (ip4 only)' CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
if [ "$CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR" != "n" ]; then
bool ' Rewrite socket and frame saddr-field (tcp-ip4 only and very experimental)' CONFIG_ISDN_WITH_ABC_IPV4_RW_SOCKADDR
bool ' Rewrite socket and frame saddr-field (udp-ip4 only and very experimental)' CONFIG_ISDN_WITH_ABC_IPV4_RWUDP_SOCKADDR
fi
bool ' RX dont reset hanguptimeout' CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
bool ' Support (device-channel)<->(bind-groups)' CONFIG_ISDN_WITH_ABC_ICALL_BIND
bool ' Skip channel if used external (dial only)' CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
bool ' Support interface-auto-disble if config-error' CONFIG_ISDN_WITH_ABC_CONN_ERROR
bool ' Enable UDP-Info-Support' CONFIG_ISDN_WITH_ABC_UDP_CHECK
if [ "$CONFIG_ISDN_WITH_ABC_UDP_CHECK" != "n" ]; then
bool ' Enable Hangup-Support with UDP-INFO' CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
bool ' Enable Dial-Support with UDP-INFO' CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
fi
bool ' Limit on the line frames to 2' CONFIG_ISDN_WITH_ABC_FRAME_LIMIT
if [ "$CONFIG_ISDN_PPP" != "n" ]; then
bool ' Enable Compression with rawip and x75i' CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
fi
fi
endmenu
fi
mainmenu_option next_comment
comment 'ISDN feature submodules'
dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
endmenu
comment 'low-level hardware drivers'
mainmenu_option next_comment
comment 'Passive ISDN cards'
dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
comment ' D-channel protocol features'
bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
if [ "$CONFIG_HISAX_EURO" != "n" ]; then
bool ' Support for german chargeinfo' CONFIG_DE_AOC
bool ' Disable sending complete' CONFIG_HISAX_NO_SENDCOMPLETE
bool ' Disable sending low layer compatibility' CONFIG_HISAX_NO_LLC
bool ' Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
fi
bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
comment ' HiSax supported cards'
bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
bool ' Teles PCI' CONFIG_HISAX_TELESPCI
bool ' Teles S0Box' CONFIG_HISAX_S0BOX
bool ' AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
bool ' AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
bool ' AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
bool ' Elsa cards' CONFIG_HISAX_ELSA
bool ' ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
bool ' Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
bool ' ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
bool ' TELEINT cards' CONFIG_HISAX_TELEINT
bool ' HFC-S based cards' CONFIG_HISAX_HFCS
bool ' Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
bool ' MIC card' CONFIG_HISAX_MIC
bool ' NETjet card' CONFIG_HISAX_NETJET
bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY
bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF
bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR
bool ' Telekom A4T card' CONFIG_HISAX_BKM_A4T
bool ' Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
bool ' Gazel cards' CONFIG_HISAX_GAZEL
bool ' HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI
bool ' Winbond W6692 based cards' CONFIG_HISAX_W6692
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
bool ' HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
bool ' Am7930' CONFIG_HISAX_AMD7930
fi
fi
fi
endmenu
mainmenu_option next_comment
comment 'Active ISDN cards'
dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
fi
dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
fi
dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
bool ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
bool ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
bool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4
fi
fi
bool ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
bool ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
bool ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
bool ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4
fi
bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
fi
if [ "$CONFIG_PROC_FS" != "n" ]; then
if [ "$CONFIG_MODULES" != "n" ]; then
bool 'Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN
fi
fi
endmenu

View File

@ -1,151 +0,0 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert hysdn
L_OBJS :=
LX_OBJS :=
M_OBJS :=
MX_OBJS :=
O_OBJS :=
OX_OBJS :=
L_TARGET :=
O_TARGET :=
ifeq ($(CONFIG_ISDN),y)
L_TARGET := isdn.a
L_OBJS += isdn_net.o isdn_tty.o isdn_cards.o isdn_v110.o
LX_OBJS += isdn_common.o
ifdef CONFIG_ISDN_PPP
L_OBJS += isdn_ppp.o
endif
ifdef CONFIG_ISDN_X25
L_OBJS += isdn_x25iface.o
L_OBJS += isdn_concap.o
endif
ifdef CONFIG_ISDN_AUDIO
L_OBJS += isdn_audio.o
ifdef CONFIG_ISDN_TTY_FAX
L_OBJS += isdn_ttyfax.o
endif
endif
ifdef CONFIG_ISDN_WITH_ABC
L_OBJS += isdn_dwabc.o
endif
else
ifeq ($(CONFIG_ISDN),m)
M_OBJS += isdn.o
O_TARGET += isdn.o
O_OBJS += isdn_net.o isdn_tty.o isdn_v110.o
OX_OBJS += isdn_common.o
ifdef CONFIG_ISDN_PPP
O_OBJS += isdn_ppp.o
M_OBJS += isdn_bsdcomp.o
endif
ifdef CONFIG_ISDN_X25
O_OBJS += isdn_x25iface.o
O_OBJS += isdn_concap.o
endif
ifdef CONFIG_ISDN_AUDIO
O_OBJS += isdn_audio.o
ifdef CONFIG_ISDN_TTY_FAX
O_OBJS += isdn_ttyfax.o
endif
endif
ifdef CONFIG_ISDN_WITH_ABC
O_OBJS += isdn_dwabc.o
endif
endif
endif
ifeq ($(CONFIG_ISDN_DIVERSION),y)
ifeq ($(CONFIG_MODULES),y)
MOD_SUB_DIRS += divert
endif
endif
ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
L_OBJS += hisax/hisax.o
SUB_DIRS += hisax
MOD_SUB_DIRS += hisax
else
ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
MOD_SUB_DIRS += hisax
endif
endif
ifeq ($(CONFIG_ISDN_DRV_ICN),y)
L_OBJS += icn/icn_obj.o
SUB_DIRS += icn
MOD_SUB_DIRS += icn
else
ifeq ($(CONFIG_ISDN_DRV_ICN),m)
MOD_SUB_DIRS += icn
endif
endif
ifeq ($(CONFIG_ISDN_DRV_PCBIT),y)
L_OBJS += pcbit/pcbit.o
SUB_DIRS += pcbit
MOD_SUB_DIRS += pcbit
else
ifeq ($(CONFIG_ISDN_DRV_PCBIT),m)
MOD_SUB_DIRS += pcbit
endif
endif
ifeq ($(CONFIG_ISDN_DRV_SC),y)
L_OBJS += sc/sc.o
SUB_DIRS += sc
MOD_SUB_DIRS += sc
else
ifeq ($(CONFIG_ISDN_DRV_SC),m)
MOD_SUB_DIRS += sc
endif
endif
ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
L_OBJS += avmb1/avmb1.o
SUB_DIRS += avmb1
MOD_SUB_DIRS += avmb1
else
ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
MOD_SUB_DIRS += avmb1
endif
endif
ifeq ($(CONFIG_ISDN_DRV_LOOP),y)
L_OBJS += isdnloop/isdnloop.o
SUB_DIRS += isdnloop
MOD_SUB_DIRS += isdnloop
else
ifeq ($(CONFIG_ISDN_DRV_LOOP),m)
MOD_SUB_DIRS += isdnloop
endif
endif
ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
L_OBJS += act2000/act2000.o
SUB_DIRS += act2000
MOD_SUB_DIRS += act2000
else
ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
MOD_SUB_DIRS += act2000
endif
endif
ifeq ($(CONFIG_ISDN_DRV_EICON),y)
L_OBJS += eicon/eicon.o
SUB_DIRS += eicon
MOD_SUB_DIRS += eicon
else
ifeq ($(CONFIG_ISDN_DRV_EICON),m)
MOD_SUB_DIRS += eicon
endif
endif
ifeq ($(CONFIG_HYSDN),y)
MOD_SUB_DIRS += hysdn
endif
include $(TOPDIR)/Rules.make

View File

@ -1,15 +0,0 @@
L_OBJS :=
M_OBJS :=
O_OBJS := module.o capi.o act2000_isa.o
O_TARGET :=
ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
O_TARGET += act2000.o
else
ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
O_TARGET += act2000.o
M_OBJS = act2000.o
endif
endif
include $(TOPDIR)/Rules.make

View File

@ -1,240 +0,0 @@
/* $Id$
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
* Thanks to Friedemann Baitinger and IBM Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.6 1998/11/05 22:12:38 fritz
* Changed mail-address.
*
* Revision 1.5 1997/10/09 22:22:59 fritz
* New HL<->LL interface:
* New BSENT callback with nr. of bytes included.
* Sending without ACK.
*
* Revision 1.4 1997/09/25 17:25:37 fritz
* Support for adding cards at runtime.
* Support for new Firmware.
*
* Revision 1.3 1997/09/24 23:11:43 fritz
* Optimized IRQ load and polling-mode.
*
* Revision 1.2 1997/09/24 19:44:12 fritz
* Added MSN mapping support, some cleanup.
*
* Revision 1.1 1997/09/23 18:00:05 fritz
* New driver for IBM Active 2000.
*
*/
#ifndef act2000_h
#define act2000_h
#ifdef __KERNEL__
/* Kernel includes */
#include <linux/module.h>
#include <linux/version.h>
#endif
#define ACT2000_IOCTL_SETPORT 1
#define ACT2000_IOCTL_GETPORT 2
#define ACT2000_IOCTL_SETIRQ 3
#define ACT2000_IOCTL_GETIRQ 4
#define ACT2000_IOCTL_SETBUS 5
#define ACT2000_IOCTL_GETBUS 6
#define ACT2000_IOCTL_SETPROTO 7
#define ACT2000_IOCTL_GETPROTO 8
#define ACT2000_IOCTL_SETMSN 9
#define ACT2000_IOCTL_GETMSN 10
#define ACT2000_IOCTL_LOADBOOT 11
#define ACT2000_IOCTL_ADDCARD 12
#define ACT2000_IOCTL_TEST 98
#define ACT2000_IOCTL_DEBUGVAR 99
#define ACT2000_BUS_ISA 1
#define ACT2000_BUS_MCA 2
#define ACT2000_BUS_PCMCIA 3
/* Struct for adding new cards */
typedef struct act2000_cdef {
int bus;
int port;
int irq;
char id[10];
} act2000_cdef;
/* Struct for downloading firmware */
typedef struct act2000_ddef {
int length; /* Length of code */
char *buffer; /* Ptr. to code */
} act2000_ddef;
typedef struct act2000_fwid {
char isdn[4];
char revlen[2];
char revision[504];
} act2000_fwid;
#if defined(__KERNEL__) || defined(__DEBUGVAR__)
#ifdef __KERNEL__
/* Kernel includes */
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/tqueue.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/isdnif.h>
#endif /* __KERNEL__ */
#define ACT2000_PORTLEN 8
#define ACT2000_FLAGS_RUNNING 1 /* Cards driver activated */
#define ACT2000_FLAGS_PVALID 2 /* Cards port is valid */
#define ACT2000_FLAGS_IVALID 4 /* Cards irq is valid */
#define ACT2000_FLAGS_LOADED 8 /* Firmware loaded */
#define ACT2000_BCH 2 /* # of channels per card */
/* D-Channel states */
#define ACT2000_STATE_NULL 0
#define ACT2000_STATE_ICALL 1
#define ACT2000_STATE_OCALL 2
#define ACT2000_STATE_IWAIT 3
#define ACT2000_STATE_OWAIT 4
#define ACT2000_STATE_IBWAIT 5
#define ACT2000_STATE_OBWAIT 6
#define ACT2000_STATE_BWAIT 7
#define ACT2000_STATE_BHWAIT 8
#define ACT2000_STATE_BHWAIT2 9
#define ACT2000_STATE_DHWAIT 10
#define ACT2000_STATE_DHWAIT2 11
#define ACT2000_STATE_BSETUP 12
#define ACT2000_STATE_ACTIVE 13
#define ACT2000_MAX_QUEUED 8000 /* 2 * maxbuff */
#define ACT2000_LOCK_TX 0
#define ACT2000_LOCK_RX 1
typedef struct act2000_chan {
unsigned short callref; /* Call Reference */
unsigned short fsm_state; /* Current D-Channel state */
unsigned short eazmask; /* EAZ-Mask for this Channel */
short queued; /* User-Data Bytes in TX queue */
unsigned short plci;
unsigned short ncci;
unsigned char l2prot; /* Layer 2 protocol */
unsigned char l3prot; /* Layer 3 protocol */
} act2000_chan;
typedef struct msn_entry {
char eaz;
char msn[16];
struct msn_entry * next;
} msn_entry;
typedef struct irq_data_isa {
__u8 *rcvptr;
__u16 rcvidx;
__u16 rcvlen;
struct sk_buff *rcvskb;
__u8 rcvignore;
__u8 rcvhdr[8];
} irq_data_isa;
typedef union irq_data {
irq_data_isa isa;
} irq_data;
/*
* Per card driver data
*/
typedef struct act2000_card {
unsigned short port; /* Base-port-address */
unsigned short irq; /* Interrupt */
u_char ptype; /* Protocol type (1TR6 or Euro) */
u_char bus; /* Cardtype (ISA, MCA, PCMCIA) */
struct act2000_card *next; /* Pointer to next device struct */
int myid; /* Driver-Nr. assigned by linklevel */
unsigned long flags; /* Statusflags */
unsigned long ilock; /* Semaphores for IRQ-Routines */
struct sk_buff_head rcvq; /* Receive-Message queue */
struct sk_buff_head sndq; /* Send-Message queue */
struct sk_buff_head ackq; /* Data-Ack-Message queue */
u_char *ack_msg; /* Ptr to User Data in User skb */
__u16 need_b3ack; /* Flag: Need ACK for current skb */
struct sk_buff *sbuf; /* skb which is currently sent */
struct timer_list ptimer; /* Poll timer */
struct tq_struct snd_tq; /* Task struct for xmit bh */
struct tq_struct rcv_tq; /* Task struct for rcv bh */
struct tq_struct poll_tq; /* Task struct for polled rcv bh */
msn_entry *msn_list;
unsigned short msgnum; /* Message number fur sending */
act2000_chan bch[ACT2000_BCH]; /* B-Channel status/control */
char status_buf[256]; /* Buffer for status messages */
char *status_buf_read;
char *status_buf_write;
char *status_buf_end;
irq_data idat; /* Data used for IRQ handler */
isdn_if interface; /* Interface to upper layer */
char regname[35]; /* Name used for request_region */
} act2000_card;
extern __inline__ void act2000_schedule_tx(act2000_card *card)
{
queue_task(&card->snd_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
extern __inline__ void act2000_schedule_rx(act2000_card *card)
{
queue_task(&card->rcv_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
extern __inline__ void act2000_schedule_poll(act2000_card *card)
{
queue_task(&card->poll_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
extern char *act2000_find_eaz(act2000_card *, char);
#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
#endif /* act2000_h */

View File

@ -1,538 +0,0 @@
/* $Id$
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
* Thanks to Friedemann Baitinger and IBM Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.9 1999/09/04 06:20:04 keil
* Changes from kernel set_current_state()
*
* Revision 1.8 1999/01/05 18:29:25 he
* merged remaining schedule_timeout() changes from 2.1.127
*
* Revision 1.7 1998/11/05 22:12:41 fritz
* Changed mail-address.
*
* Revision 1.6 1998/06/17 19:51:09 he
* merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
* brute force fix to avoid Ugh's in isdn_tty_write()
* cleaned up some dead code
*
* Revision 1.5 1998/02/12 23:06:47 keil
* change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
* Revision 1.4 1997/10/09 22:23:00 fritz
* New HL<->LL interface:
* New BSENT callback with nr. of bytes included.
* Sending without ACK.
*
* Revision 1.3 1997/09/25 17:25:38 fritz
* Support for adding cards at runtime.
* Support for new Firmware.
*
* Revision 1.2 1997/09/24 23:11:44 fritz
* Optimized IRQ load and polling-mode.
*
* Revision 1.1 1997/09/23 18:00:05 fritz
* New driver for IBM Active 2000.
*
*/
#define __NO_VERSION__
#include "act2000.h"
#include "act2000_isa.h"
#include "capi.h"
static act2000_card *irq2card_map[16] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static int act2000_isa_irqs[] =
{
3, 5, 7, 10, 11, 12, 15
};
#define ISA_NRIRQS (sizeof(act2000_isa_irqs)/sizeof(int))
static void
act2000_isa_delay(long t)
{
sti();
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(t);
sti();
}
/*
* Reset Controller, then try to read the Card's signature.
+ Return:
* 1 = Signature found.
* 0 = Signature not found.
*/
static int
act2000_isa_reset(unsigned short portbase)
{
unsigned char reg;
int i;
int found;
int serial = 0;
found = 0;
if ((reg = inb(portbase + ISA_COR)) != 0xff) {
outb(reg | ISA_COR_RESET, portbase + ISA_COR);
mdelay(10);
outb(reg, portbase + ISA_COR);
mdelay(10);
for (i = 0; i < 16; i++) {
if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
serial |= 0x10000;
serial >>= 1;
}
if (serial == ISA_SER_ID)
found++;
}
return found;
}
int
act2000_isa_detect(unsigned short portbase)
{
int ret = 0;
unsigned long flags;
save_flags(flags);
cli();
if (!check_region(portbase, ISA_REGION))
ret = act2000_isa_reset(portbase);
restore_flags(flags);
return ret;
}
static void
act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
act2000_card *card = irq2card_map[irq];
u_char istatus;
if (!card) {
printk(KERN_WARNING
"act2000: Spurious interrupt!\n");
return;
}
istatus = (inb(ISA_PORT_ISR) & 0x07);
if (istatus & ISA_ISR_OUT) {
/* RX fifo has data */
istatus &= ISA_ISR_OUT_MASK;
outb(0, ISA_PORT_SIS);
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", irq, istatus);
}
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 explicitely.
*/
int
act2000_isa_config_irq(act2000_card * card, short irq)
{
int i;
unsigned long flags;
if (card->flags & ACT2000_FLAGS_IVALID) {
free_irq(card->irq, NULL);
irq2card_map[card->irq] = NULL;
}
card->flags &= ~ACT2000_FLAGS_IVALID;
outb(ISA_COR_IRQOFF, ISA_PORT_COR);
if (!irq)
return 0;
save_flags(flags);
cli();
if (irq == -1) {
/* Auto select */
for (i = 0; i < ISA_NRIRQS; i++) {
if (!request_irq(act2000_isa_irqs[i], &act2000_isa_interrupt, 0, card->regname, NULL)) {
card->irq = act2000_isa_irqs[i];
irq2card_map[card->irq] = card;
card->flags |= ACT2000_FLAGS_IVALID;
break;
}
}
} else {
/* Fixed irq */
if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) {
card->irq = irq;
irq2card_map[card->irq] = card;
card->flags |= ACT2000_FLAGS_IVALID;
}
}
restore_flags(flags);
if (!card->flags & ACT2000_FLAGS_IVALID) {
printk(KERN_WARNING
"act2000: Could not request irq\n");
return -EBUSY;
} else {
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 (!check_region(portbase, ISA_REGION)) {
request_region(portbase, ACT2000_PORTLEN, card->regname);
card->port = portbase;
card->flags |= ACT2000_FLAGS_PVALID;
return 0;
}
return -EBUSY;
}
/*
* Release ressources, used by an adaptor.
*/
void
act2000_isa_release(act2000_card * card)
{
unsigned long flags;
save_flags(flags);
cli();
if (card->flags & ACT2000_FLAGS_IVALID) {
free_irq(card->irq, NULL);
irq2card_map[card->irq] = NULL;
}
card->flags &= ~ACT2000_FLAGS_IVALID;
if (card->flags & ACT2000_FLAGS_PVALID)
release_region(card->port, ISA_REGION);
card->flags &= ~ACT2000_FLAGS_PVALID;
restore_flags(flags);
}
static int
act2000_isa_writeb(act2000_card * card, u_char data)
{
u_char timeout = 40;
while (timeout) {
if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
outb(data, ISA_PORT_SDO);
return 0;
} else {
timeout--;
udelay(10);
}
}
return 1;
}
static int
act2000_isa_readb(act2000_card * card, u_char * data)
{
u_char timeout = 40;
while (timeout) {
if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
*data = inb(ISA_PORT_SDI);
return 0;
} else {
timeout--;
udelay(10);
}
}
return 1;
}
void
act2000_isa_receive(act2000_card *card)
{
u_char c;
if (test_and_set_bit(ACT2000_LOCK_RX, (void *) &card->ilock) != 0)
return;
while (!act2000_isa_readb(card, &c)) {
if (card->idat.isa.rcvidx < 8) {
card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
if (card->idat.isa.rcvidx == 8) {
int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
if (valid) {
card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
if (card->idat.isa.rcvskb == NULL) {
card->idat.isa.rcvignore = 1;
printk(KERN_WARNING
"act2000_isa_receive: no memory\n");
test_and_clear_bit(ACT2000_LOCK_RX, (void *) &card->ilock);
return;
}
memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
} else {
card->idat.isa.rcvidx = 0;
printk(KERN_WARNING
"act2000_isa_receive: Invalid CAPI msg\n");
{
int i; __u8 *p; __u8 *c; __u8 tmp[30];
for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
c += sprintf(c, "%02x ", *(p++));
printk(KERN_WARNING "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) {
save_flags(flags);
cli();
if (!(card->sbuf)) {
if ((card->sbuf = skb_dequeue(&card->sndq))) {
card->ack_msg = card->sbuf->data;
msg = (actcapi_msg *)card->sbuf->data;
if ((msg->hdr.cmd.cmd == 0x86) &&
(msg->hdr.cmd.subcmd == 0) ) {
/* Save flags in message */
card->need_b3ack = msg->msg.data_b3_req.flags;
msg->msg.data_b3_req.flags = 0;
}
}
}
restore_flags(flags);
if (!(card->sbuf)) {
/* No more data to send */
test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
return;
}
skb = card->sbuf;
l = 0;
while (skb->len) {
if (act2000_isa_writeb(card, *(skb->data))) {
/* Fifo is full, but more data to send */
#if 0
printk(KERN_DEBUG "act2000_isa_send: %d bytes\n", l);
#endif
test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
/* Schedule myself */
act2000_schedule_tx(card);
return;
}
skb_pull(skb, 1);
l++;
}
msg = (actcapi_msg *)card->ack_msg;
if ((msg->hdr.cmd.cmd == 0x86) &&
(msg->hdr.cmd.subcmd == 0) ) {
/*
* If it's user data, reset data-ptr
* and put skb into ackq.
*/
skb->data = card->ack_msg;
/* Restore flags in message */
msg->msg.data_b3_req.flags = card->need_b3ack;
skb_queue_tail(&card->ackq, skb);
} else
dev_kfree_skb(skb);
card->sbuf = NULL;
#if 0
printk(KERN_DEBUG "act2000_isa_send: %d bytes\n", l);
#endif
}
}
/*
* Get firmware ID, check for 'ISDN' signature.
*/
static int
act2000_isa_getid(act2000_card * card)
{
act2000_fwid fid;
u_char *p = (u_char *) & fid;
int count = 0;
while (1) {
if (count > 510)
return -EPROTO;
if (act2000_isa_readb(card, p++))
break;
count++;
}
if (count <= 20) {
printk(KERN_WARNING "act2000: No Firmware-ID!\n");
return -ETIME;
}
*p = '\0';
fid.revlen[0] = '\0';
if (strcmp(fid.isdn, "ISDN")) {
printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
return -EPROTO;
}
if ((p = strchr(fid.revision, '\n')))
*p = '\0';
printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
if (card->flags & ACT2000_FLAGS_IVALID) {
printk(KERN_DEBUG "Enabling Interrupts ...\n");
act2000_isa_enable_irq(card);
}
return 0;
}
/*
* Download microcode into card, check Firmware signature.
*/
int
act2000_isa_download(act2000_card * card, act2000_ddef * cb)
{
int length;
int ret;
int l;
int c;
long timeout;
u_char *b;
u_char *p;
u_char *buf;
act2000_ddef cblock;
if (!act2000_isa_reset(card->port))
return -ENXIO;
act2000_isa_delay(HZ / 2);
if ((ret = verify_area(VERIFY_READ, (void *) cb, sizeof(cblock))))
return ret;
copy_from_user(&cblock, (char *) cb, sizeof(cblock));
length = cblock.length;
p = cblock.buffer;
if ((ret = verify_area(VERIFY_READ, (void *) p, length)))
return ret;
buf = (u_char *) kmalloc(1024, GFP_KERNEL);
if (!buf)
return -ENOMEM;
timeout = 0;
while (length) {
l = (length > 1024) ? 1024 : length;
c = 0;
b = buf;
copy_from_user(buf, p, l);
while (c < l) {
if (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);
act2000_isa_delay(HZ / 2);
return (act2000_isa_getid(card));
}

View File

@ -1,152 +0,0 @@
/* $Id$
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
* Thanks to Friedemann Baitinger and IBM Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.2 1998/11/05 22:12:43 fritz
* Changed mail-address.
*
* Revision 1.1 1997/09/23 18:00:07 fritz
* New driver for IBM Active 2000.
*
*/
#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 * 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

View File

@ -1,406 +0,0 @@
/* $Id$
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
* Thanks to Friedemann Baitinger and IBM Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.4 1997/10/01 09:21:04 fritz
* Removed old compatibility stuff for 2.0.X kernels.
* From now on, this code is for 2.1.X ONLY!
* Old stuff is still in the separate branch.
*
* Revision 1.3 1997/09/25 17:25:41 fritz
* Support for adding cards at runtime.
* Support for new Firmware.
*
* Revision 1.2 1997/09/24 19:44:15 fritz
* Added MSN mapping support, some cleanup.
*
* Revision 1.1 1997/09/23 18:00:10 fritz
* New driver for IBM Active 2000.
*
*/
#ifndef CAPI_H
#define CAPI_H
/* Command-part of a CAPI message */
typedef struct actcapi_msgcmd {
__u8 cmd;
__u8 subcmd;
} actcapi_msgcmd;
/* CAPI message header */
typedef struct actcapi_msghdr {
__u16 len;
__u16 applicationID;
actcapi_msgcmd cmd;
__u16 msgnum;
} actcapi_msghdr;
/* CAPI message description (for debugging) */
typedef struct actcapi_msgdsc {
actcapi_msgcmd cmd;
char *description;
} actcapi_msgdsc;
/* CAPI Adress */
typedef struct actcapi_addr {
__u8 len; /* Length of element */
__u8 tnp; /* Type/Numbering Plan */
__u8 num[20]; /* Caller ID */
} actcapi_addr;
/* CAPI INFO element mask */
typedef union actcapi_infonr { /* info number */
__u16 mask; /* info-mask field */
struct bmask { /* bit definitions */
unsigned codes : 3; /* code set */
unsigned rsvd : 5; /* reserved */
unsigned svind : 1; /* single, variable length ind. */
unsigned wtype : 7; /* W-element type */
} bmask;
} actcapi_infonr;
/* CAPI INFO element */
typedef union actcapi_infoel { /* info element */
__u8 len; /* length of info element */
__u8 display[40]; /* display contents */
__u8 uuinfo[40]; /* User-user info field */
struct cause { /* Cause information */
unsigned ext2 : 1; /* extension */
unsigned cod : 2; /* coding standard */
unsigned spare : 1; /* spare */
unsigned loc : 4; /* location */
unsigned ext1 : 1; /* extension */
unsigned cval : 7; /* Cause value */
} cause;
struct charge { /* Charging information */
__u8 toc; /* type of charging info */
__u8 unit[10]; /* charging units */
} charge;
__u8 date[20]; /* date fields */
__u8 stat; /* state of remote party */
} actcapi_infoel;
/* Message for EAZ<->MSN Mapping */
typedef struct actcapi_msn {
__u8 eaz;
__u8 len; /* Length of MSN */
__u8 msn[15] __attribute__ ((packed));
} actcapi_msn;
typedef struct actcapi_dlpd {
__u8 len; /* Length of structure */
__u16 dlen __attribute__ ((packed)); /* Data Length */
__u8 laa __attribute__ ((packed)); /* Link Address A */
__u8 lab; /* Link Address B */
__u8 modulo; /* Modulo Mode */
__u8 win; /* Window size */
__u8 xid[100]; /* XID Information */
} actcapi_dlpd;
typedef struct actcapi_ncpd {
__u8 len; /* Length of structure */
__u16 lic __attribute__ ((packed));
__u16 hic __attribute__ ((packed));
__u16 ltc __attribute__ ((packed));
__u16 htc __attribute__ ((packed));
__u16 loc __attribute__ ((packed));
__u16 hoc __attribute__ ((packed));
__u8 modulo __attribute__ ((packed));
} actcapi_ncpd;
#define actcapi_ncpi actcapi_ncpd
/*
* Layout of NCCI field in a B3 DATA CAPI message is different from
* standard at act2000:
*
* Bit 0-4 = PLCI
* Bit 5-7 = Controller
* Bit 8-15 = NCCI
*/
#define MAKE_NCCI(plci,contr,ncci) \
((plci & 0x1f) | ((contr & 0x7) << 5) | ((ncci & 0xff) << 8))
#define EVAL_NCCI(fakencci,plci,contr,ncci) { \
plci = fakencci & 0x1f; \
contr = (fakencci >> 5) & 0x7; \
ncci = (fakencci >> 8) & 0xff; \
}
/*
* Layout of PLCI field in a B3 DATA CAPI message is different from
* standard at act2000:
*
* Bit 0-4 = PLCI
* Bit 5-7 = Controller
* Bit 8-15 = reserved (must be 0)
*/
#define MAKE_PLCI(plci,contr) \
((plci & 0x1f) | ((contr & 0x7) << 5))
#define EVAL_PLCI(fakeplci,plci,contr) { \
plci = fakeplci & 0x1f; \
contr = (fakeplci >> 5) & 0x7; \
}
typedef struct actcapi_msg {
actcapi_msghdr hdr;
union msg {
__u16 manuf_msg;
struct manufacturer_req_net {
__u16 manuf_msg;
__u16 controller;
__u8 nettype;
} manufacturer_req_net;
struct manufacturer_req_v42 {
__u16 manuf_msg;
__u16 controller;
__u32 v42control;
} manufacturer_req_v42;
struct manufacturer_conf_v42 {
__u16 manuf_msg;
__u16 controller;
} manufacturer_conf_v42;
struct manufacturer_req_err {
__u16 manuf_msg;
__u16 controller;
} manufacturer_req_err;
struct manufacturer_ind_err {
__u16 manuf_msg;
__u16 controller;
__u32 errcode;
__u8 errstring; /* actually up to 160 */
} manufacturer_ind_err;
struct manufacturer_req_msn {
__u16 manuf_msg;
__u16 controller;
actcapi_msn msnmap;
} manufacturer_req_msn;
/* TODO: TraceInit-req/conf/ind/resp and
* TraceDump-req/conf/ind/resp
*/
struct connect_req {
__u8 controller;
__u8 bchan;
__u32 infomask __attribute__ ((packed));
__u8 si1;
__u8 si2;
__u8 eaz;
actcapi_addr addr;
} connect_req;
struct connect_conf {
__u16 plci;
__u16 info;
} connect_conf;
struct connect_ind {
__u16 plci;
__u8 controller;
__u8 si1;
__u8 si2;
__u8 eaz;
actcapi_addr addr;
} connect_ind;
struct connect_resp {
__u16 plci;
__u8 rejectcause;
} connect_resp;
struct connect_active_ind {
__u16 plci;
actcapi_addr addr;
} connect_active_ind;
struct connect_active_resp {
__u16 plci;
} connect_active_resp;
struct connect_b3_req {
__u16 plci;
actcapi_ncpi ncpi;
} connect_b3_req;
struct connect_b3_conf {
__u16 plci;
__u16 ncci;
__u16 info;
} connect_b3_conf;
struct connect_b3_ind {
__u16 ncci;
__u16 plci;
actcapi_ncpi ncpi;
} connect_b3_ind;
struct connect_b3_resp {
__u16 ncci;
__u8 rejectcause;
actcapi_ncpi ncpi __attribute__ ((packed));
} connect_b3_resp;
struct disconnect_req {
__u16 plci;
__u8 cause;
} disconnect_req;
struct disconnect_conf {
__u16 plci;
__u16 info;
} disconnect_conf;
struct disconnect_ind {
__u16 plci;
__u16 info;
} disconnect_ind;
struct disconnect_resp {
__u16 plci;
} disconnect_resp;
struct connect_b3_active_ind {
__u16 ncci;
actcapi_ncpi ncpi;
} connect_b3_active_ind;
struct connect_b3_active_resp {
__u16 ncci;
} connect_b3_active_resp;
struct disconnect_b3_req {
__u16 ncci;
actcapi_ncpi ncpi;
} disconnect_b3_req;
struct disconnect_b3_conf {
__u16 ncci;
__u16 info;
} disconnect_b3_conf;
struct disconnect_b3_ind {
__u16 ncci;
__u16 info;
actcapi_ncpi ncpi;
} disconnect_b3_ind;
struct disconnect_b3_resp {
__u16 ncci;
} disconnect_b3_resp;
struct info_ind {
__u16 plci;
actcapi_infonr nr;
actcapi_infoel el;
} info_ind;
struct info_resp {
__u16 plci;
} info_resp;
struct listen_b3_req {
__u16 plci;
} listen_b3_req;
struct listen_b3_conf {
__u16 plci;
__u16 info;
} listen_b3_conf;
struct select_b2_protocol_req {
__u16 plci;
__u8 protocol;
actcapi_dlpd dlpd __attribute__ ((packed));
} select_b2_protocol_req;
struct select_b2_protocol_conf {
__u16 plci;
__u16 info;
} select_b2_protocol_conf;
struct select_b3_protocol_req {
__u16 plci;
__u8 protocol;
actcapi_ncpd ncpd __attribute__ ((packed));
} select_b3_protocol_req;
struct select_b3_protocol_conf {
__u16 plci;
__u16 info;
} select_b3_protocol_conf;
#if 0
struct listen_req {
__u32 controller;
__u32 infomask;
__u32 cipmask;
__u32 cipmask2;
__u16 dummy; /* 2 Length-bytes of 2 Structs MUST always be 0!!! */
} listen_req;
struct listen_conf {
__u32 controller;
__u16 info;
} listen_conf;
#else
struct listen_req {
__u8 controller;
__u32 infomask __attribute__ ((packed));
__u16 eazmask __attribute__ ((packed));
__u16 simask __attribute__ ((packed));
} listen_req;
struct listen_conf {
__u8 controller;
__u16 info __attribute__ ((packed));
} listen_conf;
#endif
struct data_b3_req {
__u16 fakencci;
__u16 datalen;
__u32 unused;
__u8 blocknr;
__u16 flags __attribute__ ((packed));
} data_b3_req;
struct data_b3_ind {
__u16 fakencci;
__u16 datalen;
__u32 unused;
__u8 blocknr;
__u16 flags __attribute__ ((packed));
} data_b3_ind;
struct data_b3_resp {
__u16 ncci;
__u8 blocknr;
} data_b3_resp;
struct data_b3_conf {
__u16 ncci;
__u8 blocknr;
__u16 info __attribute__ ((packed));
} data_b3_conf;
} msg;
} actcapi_msg;
extern __inline__ unsigned short
actcapi_nextsmsg(act2000_card *card)
{
unsigned long flags;
unsigned short n;
save_flags(flags);
cli();
n = card->msgnum;
card->msgnum++;
card->msgnum &= 0x7fff;
restore_flags(flags);
return n;
}
#define DEBUG_MSG
#undef DEBUG_DATA_MSG
#undef DEBUG_DUMP_SKB
extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
extern int actcapi_listen_req(act2000_card *);
extern int actcapi_manufacturer_req_net(act2000_card *);
extern int actcapi_manufacturer_req_v42(act2000_card *, ulong);
extern int actcapi_manufacturer_req_errh(act2000_card *);
extern int actcapi_manufacturer_req_msn(act2000_card *);
extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *);
extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *);
extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8);
extern void actcapi_dispatch(act2000_card *);
#ifdef DEBUG_MSG
extern void actcapi_debug_msg(struct sk_buff *skb, int);
#else
#define actcapi_debug_msg(skb, len)
#endif
#endif

View File

@ -1,963 +0,0 @@
/* $Id$
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
* Thanks to Friedemann Baitinger and IBM Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.10 1999/10/24 18:46:05 fritz
* Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
* kernels.
*
* Revision 1.9 1999/04/12 13:13:56 fritz
* Made cards pointer static to avoid name-clash.
*
* Revision 1.8 1998/11/05 22:12:51 fritz
* Changed mail-address.
*
* Revision 1.7 1998/02/12 23:06:52 keil
* change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
*
* Revision 1.6 1998/01/31 22:10:42 keil
* changes for 2.1.82
*
* Revision 1.5 1997/10/09 22:23:04 fritz
* New HL<->LL interface:
* New BSENT callback with nr. of bytes included.
* Sending without ACK.
*
* Revision 1.4 1997/09/25 17:25:43 fritz
* Support for adding cards at runtime.
* Support for new Firmware.
*
* Revision 1.3 1997/09/24 23:11:45 fritz
* Optimized IRQ load and polling-mode.
*
* Revision 1.2 1997/09/24 19:44:17 fritz
* Added MSN mapping support, some cleanup.
*
* Revision 1.1 1997/09/23 18:00:13 fritz
* New driver for IBM Active 2000.
*
*/
#include "act2000.h"
#include "act2000_isa.h"
#include "capi.h"
static unsigned short act2000_isa_ports[] =
{
0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
};
#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short))
static act2000_card *cards = (act2000_card *) NULL;
/* Parameters to be set by insmod */
static int act_bus = 0;
static int act_port = -1; /* -1 = Autoprobe */
static int act_irq = -1; /* -1 = Autoselect */
static char *act_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
MODULE_DESCRIPTION( "Driver for IBM Active 2000 ISDN card");
MODULE_AUTHOR( "Fritz Elfert");
MODULE_SUPPORTED_DEVICE( "ISDN subsystem");
MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");
MODULE_PARM_DESC(membase, "Base port address of first card");
MODULE_PARM_DESC(act_irq, "IRQ of first card (-1 = grab next free IRQ)");
MODULE_PARM_DESC(act_id, "ID-String of first card");
MODULE_PARM(act_bus, "i");
MODULE_PARM(act_port, "i");
MODULE_PARM(act_irq, "i");
MODULE_PARM(act_id, "s");
static int act2000_addcard(int, int, int, char *);
static act2000_chan *
find_channel(act2000_card *card, int channel)
{
if ((channel >= 0) && (channel < ACT2000_BCH))
return &(card->bch[channel]);
printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);
return NULL;
}
/*
* Free MSN list
*/
static void
act2000_clear_msn(act2000_card *card)
{
struct msn_entry *p = card->msn_list;
struct msn_entry *q;
unsigned long flags;
save_flags(flags);
cli();
card->msn_list = NULL;
restore_flags(flags);
while (p) {
q = p->next;
kfree(p);
p = q;
}
}
/*
* Find an MSN entry in the list.
* If ia5 != 0, return IA5-encoded EAZ, else
* return a bitmask with corresponding bit set.
*/
static __u16
act2000_find_msn(act2000_card *card, char *msn, int ia5)
{
struct msn_entry *p = card->msn_list;
__u8 eaz = '0';
while (p) {
if (!strcmp(p->msn, msn)) {
eaz = p->eaz;
break;
}
p = p->next;
}
if (!ia5)
return (1 << (eaz - '0'));
else
return eaz;
}
/*
* Find an EAZ entry in the list.
* return a string with corresponding msn.
*/
char *
act2000_find_eaz(act2000_card *card, char eaz)
{
struct msn_entry *p = card->msn_list;
while (p) {
if (p->eaz == eaz)
return(p->msn);
p = p->next;
}
return("\0");
}
/*
* Add or delete an MSN to the MSN list
*
* First character of msneaz is EAZ, rest is MSN.
* If length of eazmsn is 1, delete that entry.
*/
static int
act2000_set_msn(act2000_card *card, char *eazmsn)
{
struct msn_entry *p = card->msn_list;
struct msn_entry *q = NULL;
unsigned long flags;
int i;
if (!strlen(eazmsn))
return 0;
if (strlen(eazmsn) > 16)
return -EINVAL;
for (i = 0; i < strlen(eazmsn); i++)
if (!isdigit(eazmsn[i]))
return -EINVAL;
if (strlen(eazmsn) == 1) {
/* Delete a single MSN */
while (p) {
if (p->eaz == eazmsn[0]) {
save_flags(flags);
cli();
if (q)
q->next = p->next;
else
card->msn_list = p->next;
restore_flags(flags);
kfree(p);
printk(KERN_DEBUG
"Mapping for EAZ %c deleted\n",
eazmsn[0]);
return 0;
}
q = p;
p = p->next;
}
return 0;
}
/* Add a single MSN */
while (p) {
/* Found in list, replace MSN */
if (p->eaz == eazmsn[0]) {
save_flags(flags);
cli();
strcpy(p->msn, &eazmsn[1]);
restore_flags(flags);
printk(KERN_DEBUG
"Mapping for EAZ %c changed to %s\n",
eazmsn[0],
&eazmsn[1]);
return 0;
}
p = p->next;
}
/* Not found in list, add new entry */
p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
if (!p)
return -ENOMEM;
p->eaz = eazmsn[0];
strcpy(p->msn, &eazmsn[1]);
p->next = card->msn_list;
save_flags(flags);
cli();
card->msn_list = p;
restore_flags(flags);
printk(KERN_DEBUG
"Mapping %c -> %s added\n",
eazmsn[0],
&eazmsn[1]);
return 0;
}
static void
act2000_transmit(struct act2000_card *card)
{
switch (card->bus) {
case ACT2000_BUS_ISA:
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 act2000_card *card)
{
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);
save_flags(flags);
cli();
del_timer(&card->ptimer);
card->ptimer.expires = jiffies + 3;
add_timer(&card->ptimer);
restore_flags(flags);
}
static int
act2000_command(act2000_card * card, isdn_ctrl * c)
{
ulong a;
act2000_chan *chan;
act2000_cdef cdef;
isdn_ctrl cmd;
char tmp[17];
int ret;
unsigned long flags;
switch (c->command) {
case ISDN_CMD_IOCTL:
memcpy(&a, c->parm.num, sizeof(ulong));
switch (c->arg) {
case ACT2000_IOCTL_LOADBOOT:
switch (card->bus) {
case ACT2000_BUS_ISA:
ret = act2000_isa_download(card,
(act2000_ddef *)a);
if (!ret) {
card->flags |= ACT2000_FLAGS_LOADED;
if (!(card->flags & ACT2000_FLAGS_IVALID)) {
card->ptimer.expires = jiffies + 3;
card->ptimer.function = act2000_poll;
card->ptimer.data = (unsigned long)card;
add_timer(&card->ptimer);
}
actcapi_manufacturer_req_errh(card);
}
break;
default:
printk(KERN_WARNING
"act2000: Illegal BUS type %d\n",
card->bus);
ret = -EIO;
}
return ret;
case ACT2000_IOCTL_SETPROTO:
card->ptype = a?ISDN_PTYPE_EURO:ISDN_PTYPE_1TR6;
if (!(card->flags & ACT2000_FLAGS_RUNNING))
return 0;
actcapi_manufacturer_req_net(card);
return 0;
case ACT2000_IOCTL_SETMSN:
if ((ret = copy_from_user(tmp, (char *)a, sizeof(tmp))))
return ret;
if ((ret = act2000_set_msn(card, tmp)))
return ret;
if (card->flags & ACT2000_FLAGS_RUNNING)
return(actcapi_manufacturer_req_msn(card));
return 0;
case ACT2000_IOCTL_ADDCARD:
if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef))))
return ret;
if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))
return -EIO;
return 0;
case ACT2000_IOCTL_TEST:
if (!(card->flags & ACT2000_FLAGS_RUNNING))
return -ENODEV;
return 0;
default:
return -EINVAL;
}
break;
case ISDN_CMD_DIAL:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
save_flags(flags);
cli();
if (chan->fsm_state != ACT2000_STATE_NULL) {
restore_flags(flags);
printk(KERN_WARNING "Dial on channel with state %d\n",
chan->fsm_state);
return -EBUSY;
}
if (card->ptype == ISDN_PTYPE_EURO)
tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);
else
tmp[0] = c->parm.setup.eazmsn[0];
chan->fsm_state = ACT2000_STATE_OCALL;
chan->callref = 0xffff;
restore_flags(flags);
ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
tmp[0], c->parm.setup.si1,
c->parm.setup.si2);
if (ret) {
cmd.driver = card->myid;
cmd.command = ISDN_STAT_DHUP;
cmd.arg &= 0x0f;
card->interface.statcallb(&cmd);
}
return ret;
case ISDN_CMD_ACCEPTD:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
if (chan->fsm_state == ACT2000_STATE_ICALL)
actcapi_select_b2_protocol_req(card, chan);
return 0;
case ISDN_CMD_ACCEPTB:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
return 0;
case ISDN_CMD_HANGUP:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
switch (chan->fsm_state) {
case ACT2000_STATE_ICALL:
case ACT2000_STATE_BSETUP:
actcapi_connect_resp(card, chan, 0x15);
break;
case ACT2000_STATE_ACTIVE:
actcapi_disconnect_b3_req(card, chan);
break;
}
return 0;
case ISDN_CMD_SETEAZ:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
if (strlen(c->parm.num)) {
if (card->ptype == ISDN_PTYPE_EURO) {
chan->eazmask = act2000_find_msn(card, c->parm.num, 0);
}
if (card->ptype == ISDN_PTYPE_1TR6) {
int i;
chan->eazmask = 0;
for (i = 0; i < strlen(c->parm.num); i++)
if (isdigit(c->parm.num[i]))
chan->eazmask |= (1 << (c->parm.num[i] - '0'));
}
} else
chan->eazmask = 0x3ff;
actcapi_listen_req(card);
return 0;
case ISDN_CMD_CLREAZ:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
chan->eazmask = 0;
actcapi_listen_req(card);
return 0;
case ISDN_CMD_SETL2:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
chan->l2prot = (c->arg >> 8);
return 0;
case ISDN_CMD_GETL2:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
return chan->l2prot;
case ISDN_CMD_SETL3:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
printk(KERN_WARNING "L3 protocol unknown\n");
return -1;
}
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
chan->l3prot = (c->arg >> 8);
return 0;
case ISDN_CMD_GETL3:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
if (!(chan = find_channel(card, c->arg & 0x0f)))
break;
return chan->l3prot;
case ISDN_CMD_GETEAZ:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
printk(KERN_DEBUG "act2000 CMD_GETEAZ not implemented\n");
return 0;
case ISDN_CMD_SETSIL:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
printk(KERN_DEBUG "act2000 CMD_SETSIL not implemented\n");
return 0;
case ISDN_CMD_GETSIL:
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
printk(KERN_DEBUG "act2000 CMD_GETSIL not implemented\n");
return 0;
case ISDN_CMD_LOCK:
MOD_INC_USE_COUNT;
return 0;
case ISDN_CMD_UNLOCK:
MOD_DEC_USE_COUNT;
return 0;
}
return -EINVAL;
}
static int
act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb)
{
struct sk_buff *xmit_skb;
int len;
act2000_chan *chan;
actcapi_msg *msg;
if (!(chan = find_channel(card, channel)))
return -1;
if (chan->fsm_state != ACT2000_STATE_ACTIVE)
return -1;
len = skb->len;
if ((chan->queued + len) >= ACT2000_MAX_QUEUED)
return 0;
if (!len)
return 0;
if (skb_headroom(skb) < 19) {
printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n",
skb_headroom(skb));
xmit_skb = alloc_skb(len + 19, GFP_ATOMIC);
if (!xmit_skb) {
printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
return 0;
}
skb_reserve(xmit_skb, 19);
memcpy(skb_put(xmit_skb, len), skb->data, len);
} else {
xmit_skb = skb_clone(skb, GFP_ATOMIC);
if (!xmit_skb) {
printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
return 0;
}
}
dev_kfree_skb(skb);
msg = (actcapi_msg *)skb_push(xmit_skb, 19);
msg->hdr.len = 19 + len;
msg->hdr.applicationID = 1;
msg->hdr.cmd.cmd = 0x86;
msg->hdr.cmd.subcmd = 0x00;
msg->hdr.msgnum = actcapi_nextsmsg(card);
msg->msg.data_b3_req.datalen = len;
msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff);
msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci);
msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */
actcapi_debug_msg(xmit_skb, 1);
chan->queued += len;
skb_queue_tail(&card->sndq, xmit_skb);
act2000_schedule_tx(card);
return len;
}
/* Read the Status-replies from the Interface */
static int
act2000_readstatus(u_char * buf, int len, int user, act2000_card * card)
{
int count;
u_char *p;
for (p = buf, count = 0; count < len; p++, count++) {
if (card->status_buf_read == card->status_buf_write)
return count;
if (user)
put_user(*card->status_buf_read++, p);
else
*p = *card->status_buf_read++;
if (card->status_buf_read > card->status_buf_end)
card->status_buf_read = card->status_buf;
}
return count;
}
static void
act2000_putmsg(act2000_card *card, char c)
{
ulong flags;
save_flags(flags);
cli();
*card->status_buf_write++ = c;
if (card->status_buf_write == card->status_buf_read) {
if (++card->status_buf_read > card->status_buf_end)
card->status_buf_read = card->status_buf;
}
if (card->status_buf_write > card->status_buf_end)
card->status_buf_write = card->status_buf;
restore_flags(flags);
}
static void
act2000_logstat(struct act2000_card *card, char *str)
{
char *p = str;
isdn_ctrl c;
while (*p)
act2000_putmsg(card, *p++);
c.command = ISDN_STAT_STAVAIL;
c.driver = card->myid;
c.arg = strlen(str);
card->interface.statcallb(&c);
}
/*
* Find card with given driverId
*/
static inline act2000_card *
act2000_findcard(int driverid)
{
act2000_card *p = cards;
while (p) {
if (p->myid == driverid)
return p;
p = p->next;
}
return (act2000_card *) 0;
}
/*
* Wrapper functions for interface to linklevel
*/
static int
if_command(isdn_ctrl * c)
{
act2000_card *card = act2000_findcard(c->driver);
if (card)
return (act2000_command(card, c));
printk(KERN_ERR
"act2000: if_command %d called with invalid driverId %d!\n",
c->command, c->driver);
return -ENODEV;
}
static int
if_writecmd(const u_char * buf, int len, int user, int id, int channel)
{
act2000_card *card = act2000_findcard(id);
if (card) {
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
return (len);
}
printk(KERN_ERR
"act2000: if_writecmd called with invalid driverId!\n");
return -ENODEV;
}
static int
if_readstatus(u_char * buf, int len, int user, int id, int channel)
{
act2000_card *card = act2000_findcard(id);
if (card) {
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
return (act2000_readstatus(buf, len, user, card));
}
printk(KERN_ERR
"act2000: if_readstatus called with invalid driverId!\n");
return -ENODEV;
}
static int
if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
{
act2000_card *card = act2000_findcard(id);
if (card) {
if (!card->flags & ACT2000_FLAGS_RUNNING)
return -ENODEV;
return (act2000_sendbuf(card, channel, ack, skb));
}
printk(KERN_ERR
"act2000: if_sendbuf called with invalid driverId!\n");
return -ENODEV;
}
/*
* Allocate a new card-struct, initialize it
* link it into cards-list.
*/
static void
act2000_alloccard(int bus, int port, int irq, char *id)
{
int i;
act2000_card *card;
if (!(card = (act2000_card *) kmalloc(sizeof(act2000_card), GFP_KERNEL))) {
printk(KERN_WARNING
"act2000: (%s) Could not allocate card-struct.\n", id);
return;
}
memset((char *) card, 0, sizeof(act2000_card));
skb_queue_head_init(&card->sndq);
skb_queue_head_init(&card->rcvq);
skb_queue_head_init(&card->ackq);
card->snd_tq.routine = (void *) (void *) act2000_transmit;
card->snd_tq.data = card;
card->rcv_tq.routine = (void *) (void *) actcapi_dispatch;
card->rcv_tq.data = card;
card->poll_tq.routine = (void *) (void *) act2000_receive;
card->poll_tq.data = card;
init_timer(&card->ptimer);
card->interface.channels = ACT2000_BCH;
card->interface.maxbufsize = 4000;
card->interface.command = if_command;
card->interface.writebuf_skb = if_sendbuf;
card->interface.writecmd = if_writecmd;
card->interface.readstat = if_readstatus;
card->interface.features =
ISDN_FEATURE_L2_X75I |
ISDN_FEATURE_L2_HDLC |
#if 0
/* Not yet! New Firmware is on the way ... */
ISDN_FEATURE_L2_TRANS |
#endif
ISDN_FEATURE_L3_TRANS |
ISDN_FEATURE_P_UNKNOWN;
card->interface.hl_hdrlen = 20;
card->ptype = ISDN_PTYPE_EURO;
strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
for (i=0; i<ACT2000_BCH; i++) {
card->bch[i].plci = 0x8000;
card->bch[i].ncci = 0x8000;
card->bch[i].l2prot = ISDN_PROTO_L2_X75I;
card->bch[i].l3prot = ISDN_PROTO_L3_TRANS;
}
card->myid = -1;
card->bus = bus;
card->port = port;
card->irq = irq;
card->next = cards;
cards = card;
}
/*
* register card at linklevel
*/
static int
act2000_registercard(act2000_card * card)
{
switch (card->bus) {
case ACT2000_BUS_ISA:
break;
case ACT2000_BUS_MCA:
case ACT2000_BUS_PCMCIA:
default:
printk(KERN_WARNING
"act2000: Illegal BUS type %d\n",
card->bus);
return -1;
}
if (!register_isdn(&card->interface)) {
printk(KERN_WARNING
"act2000: Unable to register %s\n",
card->interface.id);
return -1;
}
card->myid = card->interface.channels;
sprintf(card->regname, "act2000-isdn (%s)", card->interface.id);
return 0;
}
static void
unregister_card(act2000_card * card)
{
isdn_ctrl cmd;
cmd.command = ISDN_STAT_UNLOAD;
cmd.driver = card->myid;
card->interface.statcallb(&cmd);
switch (card->bus) {
case ACT2000_BUS_ISA:
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 < ISA_NRPORTS; 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"
#ifdef MODULE
#define act2000_init init_module
#endif
int
act2000_init(void)
{
printk(KERN_INFO "%s\n", DRIVERNAME);
if (!cards)
act2000_addcard(act_bus, act_port, act_irq, act_id);
if (!cards)
printk(KERN_INFO "act2000: No cards defined yet\n");
/* No symbols to export, hide all symbols */
EXPORT_NO_SYMBOLS;
return 0;
}
#ifdef MODULE
void
cleanup_module(void)
{
act2000_card *card = cards;
act2000_card *last;
while (card) {
unregister_card(card);
del_timer(&card->ptimer);
card = card->next;
}
card = cards;
while (card) {
last = card;
card = card->next;
act2000_clear_msn(last);
kfree(last);
}
printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
}
#else
void
act2000_setup(char *str, int *ints)
{
int i, j, argc, port, irq, bus;
argc = ints[0];
i = 1;
if (argc)
while (argc) {
port = irq = -1;
bus = 0;
if (argc) {
bus = ints[i];
i++;
argc--;
}
if (argc) {
port = ints[i];
i++;
argc--;
}
if (argc) {
irq = ints[i];
i++;
argc--;
}
act2000_addcard(bus, port, irq, act_id);
}
}
#endif

View File

@ -1,160 +0,0 @@
#
# $Id$
#
# Makefile for the CAPI and AVM-B1 device drivers.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now inherited from the
# parent makes..
#
# $Log$
# Revision 1.10 2000/03/03 16:48:38 calle
# - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
# It is now possible to create a connection with a CAPI2.0 applikation
# and than to handle the data connection from /dev/capi/ (capifs) and also
# using async or sync PPP on this connection.
# The two major device number 190 and 191 are not confirmed yet,
# but I want to save the code in cvs, before I go on.
#
# Revision 1.9 2000/03/03 15:50:42 calle
# - kernel CAPI:
# - Changed parameter "param" in capi_signal from __u32 to void *.
# - rewrote notifier handling in kcapi.c
# - new notifier NCCI_UP and NCCI_DOWN
# - User CAPI:
# - /dev/capi20 is now a cloning device.
# - middleware extentions prepared.
# - capidrv.c
# - locking of list operations and module count updates.
#
# Revision 1.8 2000/01/25 14:33:38 calle
# - Added Support AVM B1 PCI V4.0 (tested with prototype)
# - splitted up t1pci.c into b1dma.c for common function with b1pciv4
# - support for revision register
#
# Revision 1.7 1999/09/15 08:16:03 calle
# Implementation of 64Bit extention complete.
#
# Revision 1.6 1999/07/20 06:41:44 calle
# Bugfix: After the redesign of the AVM B1 driver, the driver didn't even
# compile, if not selected as modules.
#
# Revision 1.5 1999/07/01 15:26:20 calle
# complete new version (I love it):
# + new hardware independed "capi_driver" interface that will make it easy to:
# - support other controllers with CAPI-2.0 (i.e. USB Controller)
# - write a CAPI-2.0 for the passive cards
# - support serial link CAPI-2.0 boxes.
# + wrote "capi_driver" for all supported cards.
# + "capi_driver" (supported cards) now have to be configured with
# make menuconfig, in the past all supported cards where included
# at once.
# + new and better informations in /proc/capi/
# + new ioctl to switch trace of capi messages per controller
# using "avmcapictrl trace [contr] on|off|...."
# + complete testcircle with all supported cards and also the
# PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
#
# Revision 1.4 1997/03/30 17:10:40 calle
# added support for AVM-B1-PCI card.
#
# Revision 1.3 1997/03/22 02:00:57 fritz
# -Reworked toplevel Makefile. From now on, no different Makefiles
# for standalone- and in-kernel-compilation are needed any more.
# -Added local Rules.make for above reason.
# -Experimental changes in teles3.c for enhanced IRQ-checking with
# 2.1.X and SMP kernels.
# -Removed diffstd-script, same functionality is in stddiff -r.
# -Enhanced scripts std2kern and stddiff.
#
# Revision 1.1 1997/03/05 21:26:14 fritz
# Renamed, according naming conventions in CVS tree.
#
# Revision 1.1 1997/03/04 21:50:26 calle
# Frirst version in isdn4linux
#
# Revision 2.2 1997/02/12 09:31:39 calle
#
# Revision 1.1 1997/01/31 10:32:20 calle
# Initial revision
#
#
#
# Objects that don't export a symtab
#
L_OBJS := # used as component of an L_TARGET
O_OBJS := # used as component of an O_TARGET
M_OBJS := # used as module
#
# Objects that do export a symtab
#
LX_OBJS := # used as component of an L_TARGET
OX_OBJS := # used as component of an O_TARGET
MX_OBJS := # used as module
#
# Targets, created by linking others
#
O_TARGET := # used for .o targets (from O and OX objects)
L_TARGET := # used for .a targets (from L and LX objects)
ifeq ($(CONFIG_ISDN_CAPI),y)
O_TARGET += avmb1.o
OX_OBJS += kcapi.o
O_OBJS += capi.o
ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
O_OBJS += capifs.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
O_OBJS += b1isa.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
O_OBJS += b1pci.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
O_OBJS += t1isa.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
OX_OBJS += b1pcmcia.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
O_OBJS += t1pci.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_C4
O_OBJS += c4.o
endif
OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
else
ifeq ($(CONFIG_ISDN_CAPI),m)
O_TARGET += kernelcapi.o
OX_OBJS += kcapi.o
M_OBJS += capi.o kernelcapi.o
ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
M_OBJS += capifs.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
M_OBJS += b1isa.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
M_OBJS += b1pci.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
M_OBJS += t1isa.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
MX_OBJS += b1pcmcia.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
M_OBJS += t1pci.o
endif
ifdef CONFIG_ISDN_DRV_AVMB1_C4
M_OBJS += c4.o
endif
MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
endif
endif
include $(TOPDIR)/Rules.make

View File

@ -1,603 +0,0 @@
/*
* $Id$
*
* Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.6 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
* constant string.
* - Moved some data from struct avmcard into new struct avmctrl_info.
* Changed all lowlevel capi driver to match the new structur.
*
* Revision 1.5 1999/09/07 09:02:53 calle
* SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
* DATA_B3_IND is always directly after the CAPI message. The "Data" member
* ist never used inside the kernel.
*
* Revision 1.4 1999/08/04 10:10:08 calle
* Bugfix: corrected /proc functions, added structure for new AVM cards.
*
* Revision 1.3 1999/07/23 08:41:47 calle
* prepared for new AVM cards.
*
* Revision 1.2 1999/07/05 15:09:45 calle
* - renamed "appl_release" to "appl_released".
* - version und profile data now cleared on controller reset
* - extended /proc interface, to allow driver and controller specific
* informations to include by driver hackers.
*
* Revision 1.1 1999/07/01 15:26:22 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
* - write a CAPI-2.0 for the passive cards
* - support serial link CAPI-2.0 boxes.
* + wrote "capi_driver" for all supported cards.
* + "capi_driver" (supported cards) now have to be configured with
* make menuconfig, in the past all supported cards where included
* at once.
* + new and better informations in /proc/capi/
* + new ioctl to switch trace of capi messages per controller
* using "avmcapictrl trace [contr] on|off|...."
* + complete testcircle with all supported cards and also the
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
*
*/
#ifndef _AVMCARD_H_
#define _AVMCARD_H_
#define AVMB1_PORTLEN 0x1f
#define AVM_MAXVERSION 8
#define AVM_NAPPS 30
#define AVM_NCCI_PER_CHANNEL 4
/*
* Versions
*/
#define VER_DRIVER 0
#define VER_CARDTYPE 1
#define VER_HWID 2
#define VER_SERIAL 3
#define VER_OPTION 4
#define VER_PROTO 5
#define VER_PROFILE 6
#define VER_CAPI 7
enum avmcardtype {
avm_b1isa,
avm_b1pci,
avm_b1pcmcia,
avm_m1,
avm_m2,
avm_t1isa,
avm_t1pci,
avm_c4
};
typedef struct avmcard_dmainfo {
__u32 recvlen;
__u8 recvbuf[128+2048];
struct sk_buff_head send_queue;
__u8 sendbuf[128+2048];
} avmcard_dmainfo;
typedef struct avmcard {
char name[32];
unsigned int port;
unsigned irq;
unsigned long membase;
enum avmcardtype cardtype;
unsigned char revision;
unsigned char class;
int cardnr; /* for t1isa */
char msgbuf[128]; /* capimsg msg part */
char databuf[2048]; /* capimsg data part */
int interrupt;
void *mbase;
volatile __u32 csr;
avmcard_dmainfo *dma;
struct avmctrl_info {
char cardname[32];
int versionlen;
char versionbuf[1024];
char *version[AVM_MAXVERSION];
char infobuf[128]; /* for function procinfo */
struct avmcard *card;
struct capi_ctr *capi_ctrl;
} *ctrlinfo;
int nlogcontr;
} avmcard;
typedef struct avmctrl_info avmctrl_info;
extern int b1_irq_table[16];
/*
* LLI Messages to the ISDN-ControllerISDN Controller
*/
#define SEND_POLL 0x72 /*
* after load <- RECEIVE_POLL
*/
#define SEND_INIT 0x11 /*
* first message <- RECEIVE_INIT
* int32 NumApplications int32
* NumNCCIs int32 BoardNumber
*/
#define SEND_REGISTER 0x12 /*
* register an application int32
* ApplIDId int32 NumMessages
* int32 NumB3Connections int32
* NumB3Blocks int32 B3Size
*
* AnzB3Connection != 0 &&
* AnzB3Blocks >= 1 && B3Size >= 1
*/
#define SEND_RELEASE 0x14 /*
* deregister an application int32
* ApplID
*/
#define SEND_MESSAGE 0x15 /*
* send capi-message int32 length
* capi-data ...
*/
#define SEND_DATA_B3_REQ 0x13 /*
* send capi-data-message int32
* MsgLength capi-data ... int32
* B3Length data ....
*/
#define SEND_CONFIG 0x21 /*
*/
#define SEND_POLLACK 0x73 /* T1 Watchdog */
/*
* LLI Messages from the ISDN-ControllerISDN Controller
*/
#define RECEIVE_POLL 0x32 /*
* <- after SEND_POLL
*/
#define RECEIVE_INIT 0x27 /*
* <- after SEND_INIT int32 length
* byte total length b1struct board
* driver revision b1struct card
* type b1struct reserved b1struct
* serial number b1struct driver
* capability b1struct d-channel
* protocol b1struct CAPI-2.0
* profile b1struct capi version
*/
#define RECEIVE_MESSAGE 0x21 /*
* <- after SEND_MESSAGE int32
* AppllID int32 Length capi-data
* ....
*/
#define RECEIVE_DATA_B3_IND 0x22 /*
* received data int32 AppllID
* int32 Length capi-data ...
* int32 B3Length data ...
*/
#define RECEIVE_START 0x23 /*
* Handshake
*/
#define RECEIVE_STOP 0x24 /*
* Handshake
*/
#define RECEIVE_NEW_NCCI 0x25 /*
* int32 AppllID int32 NCCI int32
* WindowSize
*/
#define RECEIVE_FREE_NCCI 0x26 /*
* int32 AppllID int32 NCCI
*/
#define RECEIVE_RELEASE 0x26 /*
* int32 AppllID int32 0xffffffff
*/
#define RECEIVE_TASK_READY 0x31 /*
* int32 tasknr
* int32 Length Taskname ...
*/
#define RECEIVE_DEBUGMSG 0x71 /*
* int32 Length message
*
*/
#define RECEIVE_POLLDWORD 0x75 /* t1pci in dword mode */
#define WRITE_REGISTER 0x00
#define READ_REGISTER 0x01
/*
* port offsets
*/
#define B1_READ 0x00
#define B1_WRITE 0x01
#define B1_INSTAT 0x02
#define B1_OUTSTAT 0x03
#define B1_ANALYSE 0x04
#define B1_REVISION 0x05
#define B1_RESET 0x10
#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l)
#define B1_STAT1(cardtype) (0x80E00000l)
/* ---------------------------------------------------------------- */
static inline unsigned char b1outp(unsigned int base,
unsigned short offset,
unsigned char value)
{
outb(value, base + offset);
return inb(base + B1_ANALYSE);
}
static inline int b1_rx_full(unsigned int base)
{
return inb(base + B1_INSTAT) & 0x1;
}
static inline unsigned char b1_get_byte(unsigned int base)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
while (!b1_rx_full(base) && time_before(jiffies, stop));
if (b1_rx_full(base))
return inb(base + B1_READ);
printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base);
return 0;
}
static inline unsigned int b1_get_word(unsigned int base)
{
unsigned int val = 0;
val |= b1_get_byte(base);
val |= (b1_get_byte(base) << 8);
val |= (b1_get_byte(base) << 16);
val |= (b1_get_byte(base) << 24);
return val;
}
static inline int b1_tx_empty(unsigned int base)
{
return inb(base + B1_OUTSTAT) & 0x1;
}
static inline void b1_put_byte(unsigned int base, unsigned char val)
{
while (!b1_tx_empty(base));
b1outp(base, B1_WRITE, val);
}
static inline int b1_save_put_byte(unsigned int base, unsigned char val)
{
unsigned long stop = jiffies + 2 * HZ;
while (!b1_tx_empty(base) && time_before(jiffies,stop));
if (!b1_tx_empty(base)) return -1;
b1outp(base, B1_WRITE, val);
return 0;
}
static inline void b1_put_word(unsigned int base, unsigned int val)
{
b1_put_byte(base, val & 0xff);
b1_put_byte(base, (val >> 8) & 0xff);
b1_put_byte(base, (val >> 16) & 0xff);
b1_put_byte(base, (val >> 24) & 0xff);
}
static inline unsigned int b1_get_slice(unsigned int base,
unsigned char *dp)
{
unsigned int len, i;
len = i = b1_get_word(base);
while (i-- > 0) *dp++ = b1_get_byte(base);
return len;
}
static inline void b1_put_slice(unsigned int base,
unsigned char *dp, unsigned int len)
{
unsigned i = len;
b1_put_word(base, i);
while (i-- > 0)
b1_put_byte(base, *dp++);
}
static void b1_wr_reg(unsigned int base,
unsigned int reg,
unsigned int value)
{
b1_put_byte(base, WRITE_REGISTER);
b1_put_word(base, reg);
b1_put_word(base, value);
}
static inline unsigned int b1_rd_reg(unsigned int base,
unsigned int reg)
{
b1_put_byte(base, READ_REGISTER);
b1_put_word(base, reg);
return b1_get_word(base);
}
static inline void b1_reset(unsigned int base)
{
b1outp(base, B1_RESET, 0);
udelay(55 * 2 * 1000); /* 2 TIC's */
b1outp(base, B1_RESET, 1);
udelay(55 * 2 * 1000); /* 2 TIC's */
b1outp(base, B1_RESET, 0);
udelay(55 * 2 * 1000); /* 2 TIC's */
}
static inline unsigned char b1_disable_irq(unsigned int base)
{
return b1outp(base, B1_INSTAT, 0x00);
}
/* ---------------------------------------------------------------- */
static inline void b1_set_test_bit(unsigned int base,
enum avmcardtype cardtype,
int onoff)
{
b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20);
}
static inline int b1_get_test_bit(unsigned int base,
enum avmcardtype cardtype)
{
return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0;
}
/* ---------------------------------------------------------------- */
#define T1_FASTLINK 0x00
#define T1_SLOWLINK 0x08
#define T1_READ B1_READ
#define T1_WRITE B1_WRITE
#define T1_INSTAT B1_INSTAT
#define T1_OUTSTAT B1_OUTSTAT
#define T1_IRQENABLE 0x05
#define T1_FIFOSTAT 0x06
#define T1_RESETLINK 0x10
#define T1_ANALYSE 0x11
#define T1_IRQMASTER 0x12
#define T1_IDENT 0x17
#define T1_RESETBOARD 0x1f
#define T1F_IREADY 0x01
#define T1F_IHALF 0x02
#define T1F_IFULL 0x04
#define T1F_IEMPTY 0x08
#define T1F_IFLAGS 0xF0
#define T1F_OREADY 0x10
#define T1F_OHALF 0x20
#define T1F_OEMPTY 0x40
#define T1F_OFULL 0x80
#define T1F_OFLAGS 0xF0
/* there are HEMA cards with 1k and 4k FIFO out */
#define FIFO_OUTBSIZE 256
#define FIFO_INPBSIZE 512
#define HEMA_VERSION_ID 0
#define HEMA_PAL_ID 0
static inline void t1outp(unsigned int base,
unsigned short offset,
unsigned char value)
{
outb(value, base + offset);
}
static inline unsigned char t1inp(unsigned int base,
unsigned short offset)
{
return inb(base + offset);
}
static inline int t1_isfastlink(unsigned int base)
{
return (inb(base + T1_IDENT) & ~0x82) == 1;
}
static inline unsigned char t1_fifostatus(unsigned int base)
{
return inb(base + T1_FIFOSTAT);
}
static inline unsigned int t1_get_slice(unsigned int base,
unsigned char *dp)
{
unsigned int len, i;
#ifdef FASTLINK_DEBUG
unsigned wcnt = 0, bcnt = 0;
#endif
len = i = b1_get_word(base);
if (t1_isfastlink(base)) {
int status;
while (i > 0) {
status = t1_fifostatus(base) & (T1F_IREADY|T1F_IHALF);
if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
switch (status) {
case T1F_IREADY|T1F_IHALF|T1F_IFULL:
insb(base+B1_READ, dp, FIFO_INPBSIZE);
dp += FIFO_INPBSIZE;
i -= FIFO_INPBSIZE;
#ifdef FASTLINK_DEBUG
wcnt += FIFO_INPBSIZE;
#endif
break;
case T1F_IREADY|T1F_IHALF:
insb(base+B1_READ,dp, i);
#ifdef FASTLINK_DEBUG
wcnt += i;
#endif
dp += i;
i = 0;
if (i == 0)
break;
/* fall through */
default:
*dp++ = b1_get_byte(base);
i--;
#ifdef FASTLINK_DEBUG
bcnt++;
#endif
break;
}
}
#ifdef FASTLINK_DEBUG
if (wcnt)
printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n",
base, len, wcnt, bcnt);
#endif
} else {
while (i-- > 0)
*dp++ = b1_get_byte(base);
}
return len;
}
static inline void t1_put_slice(unsigned int base,
unsigned char *dp, unsigned int len)
{
unsigned i = len;
b1_put_word(base, i);
if (t1_isfastlink(base)) {
int status;
while (i > 0) {
status = t1_fifostatus(base) & (T1F_OREADY|T1F_OHALF);
if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY;
switch (status) {
case T1F_OREADY|T1F_OHALF|T1F_OEMPTY:
outsb(base+B1_WRITE, dp, FIFO_OUTBSIZE);
dp += FIFO_OUTBSIZE;
i -= FIFO_OUTBSIZE;
break;
case T1F_OREADY|T1F_OHALF:
outsb(base+B1_WRITE, dp, i);
dp += i;
i = 0;
break;
default:
b1_put_byte(base, *dp++);
i--;
break;
}
}
} else {
while (i-- > 0)
b1_put_byte(base, *dp++);
}
}
static inline void t1_disable_irq(unsigned int base)
{
t1outp(base, T1_IRQMASTER, 0x00);
}
static inline void t1_reset(unsigned int base)
{
/* reset T1 Controller */
b1_reset(base);
/* disable irq on HEMA */
t1outp(base, B1_INSTAT, 0x00);
t1outp(base, B1_OUTSTAT, 0x00);
t1outp(base, T1_IRQMASTER, 0x00);
/* reset HEMA board configuration */
t1outp(base, T1_RESETBOARD, 0xf);
}
static inline void b1_setinterrupt(unsigned int base, unsigned irq,
enum avmcardtype cardtype)
{
switch (cardtype) {
case avm_t1isa:
t1outp(base, B1_INSTAT, 0x00);
t1outp(base, B1_INSTAT, 0x02);
t1outp(base, T1_IRQMASTER, 0x08);
break;
case avm_b1isa:
b1outp(base, B1_INSTAT, 0x00);
b1outp(base, B1_RESET, b1_irq_table[irq]);
b1outp(base, B1_INSTAT, 0x02);
break;
default:
case avm_m1:
case avm_m2:
case avm_b1pci:
b1outp(base, B1_INSTAT, 0x00);
b1outp(base, B1_RESET, 0xf0);
b1outp(base, B1_INSTAT, 0x02);
break;
case avm_c4:
case avm_t1pci:
b1outp(base, B1_RESET, 0xf0);
break;
}
}
/* b1.c */
int b1_detect(unsigned int base, enum avmcardtype cardtype);
void b1_getrevision(avmcard *card);
int b1_load_t4file(avmcard *card, capiloaddatapart * t4file);
int b1_load_config(avmcard *card, capiloaddatapart * config);
int b1_loaded(avmcard *card);
int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
void b1_reset_ctr(struct capi_ctr *ctrl);
void b1_register_appl(struct capi_ctr *ctrl, __u16 appl,
capi_register_params *rp);
void b1_release_appl(struct capi_ctr *ctrl, __u16 appl);
void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
void b1_parse_version(avmctrl_info *card);
void b1_handle_interrupt(avmcard * card);
int b1ctl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl);
/* b1dma.c */
int b1pciv4_detect(avmcard *card);
int t1pci_detect(avmcard *card);
void b1dma_reset(avmcard *card);
void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
void b1dma_reset_ctr(struct capi_ctr *ctrl);
void b1dma_remove_ctr(struct capi_ctr *ctrl);
void b1dma_register_appl(struct capi_ctr *ctrl,
__u16 appl,
capi_register_params *rp);
void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl);
void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
int b1dmactl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl);
#endif /* _AVMCARD_H_ */

View File

@ -1,741 +0,0 @@
/*
* $Id$
*
* Common module for AVM B1 cards.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.12 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
* constant string.
* - Moved some data from struct avmcard into new struct avmctrl_info.
* Changed all lowlevel capi driver to match the new structur.
*
* Revision 1.11 1999/10/11 22:04:12 keil
* COMPAT_NEED_UACCESS (no include in isdn_compat.h)
*
* Revision 1.10 1999/09/15 08:16:03 calle
* Implementation of 64Bit extention complete.
*
* Revision 1.9 1999/09/07 09:02:53 calle
* SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
* DATA_B3_IND is always directly after the CAPI message. The "Data" member
* ist never used inside the kernel.
*
* Revision 1.8 1999/08/22 20:26:22 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.7 1999/08/04 10:10:09 calle
* Bugfix: corrected /proc functions, added structure for new AVM cards.
*
* Revision 1.6 1999/07/23 08:51:04 calle
* small fix and typo in checkin before.
*
* Revision 1.5 1999/07/23 08:41:48 calle
* prepared for new AVM cards.
*
* Revision 1.4 1999/07/09 15:05:38 keil
* compat.h is now isdn_compat.h
*
* Revision 1.3 1999/07/06 07:41:59 calle
* - changes in /proc interface
* - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
*
* Revision 1.2 1999/07/05 15:09:47 calle
* - renamed "appl_release" to "appl_released".
* - version und profile data now cleared on controller reset
* - extended /proc interface, to allow driver and controller specific
* informations to include by driver hackers.
*
* Revision 1.1 1999/07/01 15:26:23 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
* - write a CAPI-2.0 for the passive cards
* - support serial link CAPI-2.0 boxes.
* + wrote "capi_driver" for all supported cards.
* + "capi_driver" (supported cards) now have to be configured with
* make menuconfig, in the past all supported cards where included
* at once.
* + new and better informations in /proc/capi/
* + new ioctl to switch trace of capi messages per controller
* using "avmcapictrl trace [contr] on|off|...."
* + complete testcircle with all supported cards and also the
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
*
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <asm/io.h>
#include <linux/isdn_compat.h>
#ifdef COMPAT_NEED_UACCESS
#include <asm/uaccess.h>
#endif
#include "capilli.h"
#include "avmcard.h"
#include "capicmd.h"
#include "capiutil.h"
static char *revision = "$Revision$";
/* ------------------------------------------------------------- */
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
/* ------------------------------------------------------------- */
int b1_irq_table[16] =
{0,
0,
0,
192, /* irq 3 */
32, /* irq 4 */
160, /* irq 5 */
96, /* irq 6 */
224, /* irq 7 */
0,
64, /* irq 9 */
80, /* irq 10 */
208, /* irq 11 */
48, /* irq 12 */
0,
0,
112, /* irq 15 */
};
/* ------------------------------------------------------------- */
int b1_detect(unsigned int base, enum avmcardtype cardtype)
{
int onoff, i;
/*
* Statusregister 0000 00xx
*/
if ((inb(base + B1_INSTAT) & 0xfc)
|| (inb(base + B1_OUTSTAT) & 0xfc))
return 1;
/*
* Statusregister 0000 001x
*/
b1outp(base, B1_INSTAT, 0x2); /* enable irq */
/* b1outp(base, B1_OUTSTAT, 0x2); */
if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
/* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */)
return 2;
/*
* Statusregister 0000 000x
*/
b1outp(base, B1_INSTAT, 0x0); /* disable irq */
b1outp(base, B1_OUTSTAT, 0x0);
if ((inb(base + B1_INSTAT) & 0xfe)
|| (inb(base + B1_OUTSTAT) & 0xfe))
return 3;
for (onoff = !0, i= 0; i < 10 ; i++) {
b1_set_test_bit(base, cardtype, onoff);
if (b1_get_test_bit(base, cardtype) != onoff)
return 4;
onoff = !onoff;
}
if (cardtype == avm_m1)
return 0;
if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01)
return 5;
return 0;
}
void b1_getrevision(avmcard *card)
{
card->class = inb(card->port + B1_ANALYSE);
card->revision = inb(card->port + B1_REVISION);
}
int b1_load_t4file(avmcard *card, capiloaddatapart * t4file)
{
unsigned char buf[256];
unsigned char *dp;
int i, left, retval;
unsigned int base = card->port;
dp = t4file->data;
left = t4file->len;
while (left > sizeof(buf)) {
if (t4file->user) {
retval = copy_from_user(buf, dp, sizeof(buf));
if (retval)
return -EFAULT;
} else {
memcpy(buf, dp, sizeof(buf));
}
for (i = 0; i < sizeof(buf); i++)
if (b1_save_put_byte(base, buf[i]) < 0) {
printk(KERN_ERR "%s: corrupted firmware file ?\n",
card->name);
return -EIO;
}
left -= sizeof(buf);
dp += sizeof(buf);
}
if (left) {
if (t4file->user) {
retval = copy_from_user(buf, dp, left);
if (retval)
return -EFAULT;
} else {
memcpy(buf, dp, left);
}
for (i = 0; i < left; i++)
if (b1_save_put_byte(base, buf[i]) < 0) {
printk(KERN_ERR "%s: corrupted firmware file ?\n",
card->name);
return -EIO;
}
}
return 0;
}
int b1_load_config(avmcard *card, capiloaddatapart * config)
{
unsigned char buf[256];
unsigned char *dp;
unsigned int base = card->port;
int i, j, left, retval;
dp = config->data;
left = config->len;
if (left) {
b1_put_byte(base, SEND_CONFIG);
b1_put_word(base, 1);
b1_put_byte(base, SEND_CONFIG);
b1_put_word(base, left);
}
while (left > sizeof(buf)) {
if (config->user) {
retval = copy_from_user(buf, dp, sizeof(buf));
if (retval)
return -EFAULT;
} else {
memcpy(buf, dp, sizeof(buf));
}
for (i = 0; i < sizeof(buf); ) {
b1_put_byte(base, SEND_CONFIG);
for (j=0; j < 4; j++) {
b1_put_byte(base, buf[i++]);
}
}
left -= sizeof(buf);
dp += sizeof(buf);
}
if (left) {
if (config->user) {
retval = copy_from_user(buf, dp, left);
if (retval)
return -EFAULT;
} else {
memcpy(buf, dp, left);
}
for (i = 0; i < left; ) {
b1_put_byte(base, SEND_CONFIG);
for (j=0; j < 4; j++) {
if (i < left)
b1_put_byte(base, buf[i++]);
else
b1_put_byte(base, 0);
}
}
}
return 0;
}
int b1_loaded(avmcard *card)
{
unsigned int base = card->port;
unsigned long stop;
unsigned char ans;
unsigned long tout = 2;
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_tx_empty(base))
break;
}
if (!b1_tx_empty(base)) {
printk(KERN_ERR "%s: b1_loaded: tx err, corrupted t4 file ?\n",
card->name);
return 0;
}
b1_put_byte(base, SEND_POLL);
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_rx_full(base)) {
if ((ans = b1_get_byte(base)) == RECEIVE_POLL) {
return 1;
}
printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n",
card->name, ans);
return 0;
}
}
printk(KERN_ERR "%s: b1_loaded: firmware not running\n", card->name);
return 0;
}
/* ------------------------------------------------------------- */
int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int retval;
b1_reset(port);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
b1_disable_irq(port);
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1_loaded(card)) {
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
save_flags(flags);
cli();
b1_setinterrupt(port, card->irq, card->cardtype);
b1_put_byte(port, SEND_INIT);
b1_put_word(port, AVM_NAPPS);
b1_put_word(port, AVM_NCCI_PER_CHANNEL*2);
b1_put_word(port, ctrl->cnr - 1);
restore_flags(flags);
return 0;
}
void b1_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
ctrl->reseted(ctrl);
}
void b1_register_appl(struct capi_ctr *ctrl,
__u16 appl,
capi_register_params *rp)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int nconn, want = rp->level3cnt;
if (want > 0) nconn = want;
else nconn = ctrl->profile.nbchannel * -want;
if (nconn == 0) nconn = ctrl->profile.nbchannel;
save_flags(flags);
cli();
b1_put_byte(port, SEND_REGISTER);
b1_put_word(port, appl);
b1_put_word(port, 1024 * (nconn+1));
b1_put_word(port, nconn);
b1_put_word(port, rp->datablkcnt);
b1_put_word(port, rp->datablklen);
restore_flags(flags);
ctrl->appl_registered(ctrl, appl);
}
void b1_release_appl(struct capi_ctr *ctrl, __u16 appl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
save_flags(flags);
cli();
b1_put_byte(port, SEND_RELEASE);
b1_put_word(port, appl);
restore_flags(flags);
}
void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
__u16 len = CAPIMSG_LEN(skb->data);
__u8 cmd = CAPIMSG_COMMAND(skb->data);
__u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
save_flags(flags);
cli();
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
__u16 dlen = CAPIMSG_DATALEN(skb->data);
b1_put_byte(port, SEND_DATA_B3_REQ);
b1_put_slice(port, skb->data, len);
b1_put_slice(port, skb->data + len, dlen);
} else {
b1_put_byte(port, SEND_MESSAGE);
b1_put_slice(port, skb->data, len);
}
restore_flags(flags);
dev_kfree_skb(skb);
}
/* ------------------------------------------------------------- */
void b1_parse_version(avmctrl_info *cinfo)
{
struct capi_ctr *ctrl = cinfo->capi_ctrl;
avmcard *card = cinfo->card;
capi_profile *profp;
__u8 *dversion;
__u8 flag;
int i, j;
for (j = 0; j < AVM_MAXVERSION; j++)
cinfo->version[j] = "\0\0" + 1;
for (i = 0, j = 0;
j < AVM_MAXVERSION && i < cinfo->versionlen;
j++, i += cinfo->versionbuf[i] + 1)
cinfo->version[j] = &cinfo->versionbuf[i + 1];
strncpy(ctrl->serial, cinfo->version[VER_SERIAL], CAPI_SERIAL_LEN);
memcpy(&ctrl->profile, cinfo->version[VER_PROFILE],sizeof(capi_profile));
strncpy(ctrl->manu, "AVM GmbH", CAPI_MANUFACTURER_LEN);
dversion = cinfo->version[VER_DRIVER];
ctrl->version.majorversion = 2;
ctrl->version.minorversion = 0;
ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
ctrl->version.majormanuversion |= ((dversion[2] - '0') & 0xf);
ctrl->version.minormanuversion = (dversion[3] - '0') << 4;
ctrl->version.minormanuversion |=
(dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf);
profp = &ctrl->profile;
flag = ((__u8 *)(profp->manu))[1];
switch (flag) {
case 0: if (cinfo->version[VER_CARDTYPE])
strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]);
else strcpy(cinfo->cardname, "B1");
break;
case 3: strcpy(cinfo->cardname,"PCMCIA B"); break;
case 4: strcpy(cinfo->cardname,"PCMCIA M1"); break;
case 5: strcpy(cinfo->cardname,"PCMCIA M2"); break;
case 6: strcpy(cinfo->cardname,"B1 V3.0"); break;
case 7: strcpy(cinfo->cardname,"B1 PCI"); break;
default: sprintf(cinfo->cardname, "AVM?%u", (unsigned int)flag); break;
}
printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n",
card->name, ctrl->cnr, cinfo->cardname);
flag = ((__u8 *)(profp->manu))[3];
if (flag)
printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n",
card->name,
ctrl->cnr,
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
flag = ((__u8 *)(profp->manu))[5];
if (flag)
printk(KERN_NOTICE "%s: card %d Linetype:%s%s%s%s\n",
card->name,
ctrl->cnr,
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
/* ------------------------------------------------------------- */
void b1_handle_interrupt(avmcard * card)
{
avmctrl_info *cinfo = &card->ctrlinfo[0];
struct capi_ctr *ctrl = cinfo->capi_ctrl;
unsigned char b1cmd;
struct sk_buff *skb;
unsigned ApplId;
unsigned MsgLen;
unsigned DataB3Len;
unsigned NCCI;
unsigned WindowSize;
if (!b1_rx_full(card->port))
return;
b1cmd = b1_get_byte(card->port);
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
DataB3Len = b1_get_slice(card->port, card->databuf);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
if (NCCI != 0xffffffff)
ctrl->free_ncci(ctrl, ApplId, NCCI);
else ctrl->appl_released(ctrl, ApplId);
break;
case RECEIVE_START:
/* b1_put_byte(card->port, SEND_POLLACK); */
ctrl->resume_output(ctrl);
break;
case RECEIVE_STOP:
ctrl->suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
ctrl->ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
card->msgbuf[MsgLen--] = 0;
while ( MsgLen >= 0
&& ( card->msgbuf[MsgLen] == '\n'
|| card->msgbuf[MsgLen] == '\r'))
card->msgbuf[MsgLen--] = 0;
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = b1_get_slice(card->port, card->msgbuf);
card->msgbuf[MsgLen--] = 0;
while ( MsgLen >= 0
&& ( card->msgbuf[MsgLen] == '\n'
|| card->msgbuf[MsgLen] == '\r'))
card->msgbuf[MsgLen--] = 0;
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
case 0xff:
printk(KERN_ERR "%s: card removed ?\n", card->name);
return;
default:
printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
card->name, b1cmd);
return;
}
}
/* ------------------------------------------------------------- */
int b1ctl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
__u8 flag;
int len = 0;
char *s;
len += sprintf(page+len, "%-16s %s\n", "name", card->name);
len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
case avm_b1pcmcia: s = "B1 PCMCIA"; break;
case avm_m1: s = "M1"; break;
case avm_m2: s = "M2"; break;
case avm_t1isa: s = "T1 ISA (HEMA)"; break;
case avm_t1pci: s = "T1 PCI"; break;
case avm_c4: s = "C4"; break;
default: s = "???"; break;
}
len += sprintf(page+len, "%-16s %s\n", "type", s);
if (card->cardtype == avm_t1isa)
len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
if ((s = cinfo->version[VER_DRIVER]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((__u8 *)(ctrl->profile.manu))[3];
if (flag)
len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
}
if (card->cardtype != avm_m1) {
flag = ((__u8 *)(ctrl->profile.manu))[5];
if (flag)
len += sprintf(page+len, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
if (off+count >= len)
*eof = 1;
if (len < off)
return 0;
*start = page + off;
return ((count < len-off) ? count : len-off);
}
/* ------------------------------------------------------------- */
EXPORT_SYMBOL(b1_irq_table);
EXPORT_SYMBOL(b1_detect);
EXPORT_SYMBOL(b1_getrevision);
EXPORT_SYMBOL(b1_load_t4file);
EXPORT_SYMBOL(b1_load_config);
EXPORT_SYMBOL(b1_loaded);
EXPORT_SYMBOL(b1_load_firmware);
EXPORT_SYMBOL(b1_reset_ctr);
EXPORT_SYMBOL(b1_register_appl);
EXPORT_SYMBOL(b1_release_appl);
EXPORT_SYMBOL(b1_send_message);
EXPORT_SYMBOL(b1_parse_version);
EXPORT_SYMBOL(b1_handle_interrupt);
EXPORT_SYMBOL(b1ctl_read_proc);
#ifdef MODULE
#define b1_init init_module
void cleanup_module(void);
#endif
int b1_init(void)
{
char *p;
char rev[10];
if ((p = strchr(revision, ':'))) {
strncpy(rev, p + 1, sizeof(rev));
p = strchr(rev, '$');
*p = 0;
} else
strcpy(rev, "1.0");
printk(KERN_INFO "b1: revision %s\n", rev);
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
}
#endif

View File

@ -1,989 +0,0 @@
/*
* $Id$
*
* Common module for AVM B1 cards that support dma with AMCC
*
* (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.2 2000/01/25 14:44:47 calle
* typo in b1pciv4_detect().
*
* Revision 1.1 2000/01/25 14:36:43 calle
* common function for T1 PCI and B1 PCI V4.
*
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <asm/io.h>
#include <linux/isdn_compat.h>
#ifdef COMPAT_NEED_UACCESS
#include <asm/uaccess.h>
#endif
#include "capilli.h"
#include "avmcard.h"
#include "capicmd.h"
#include "capiutil.h"
static char *revision = "$Revision$";
/* ------------------------------------------------------------- */
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
int suppress_pollack = 0;
MODULE_PARM(suppress_pollack, "0-1i");
/* ------------------------------------------------------------- */
static void b1dma_dispatch_tx(avmcard *card);
/* ------------------------------------------------------------- */
/* S5933 */
#define AMCC_RXPTR 0x24
#define AMCC_RXLEN 0x28
#define AMCC_TXPTR 0x2c
#define AMCC_TXLEN 0x30
#define AMCC_INTCSR 0x38
# define EN_READ_TC_INT 0x00008000L
# define EN_WRITE_TC_INT 0x00004000L
# define EN_TX_TC_INT EN_READ_TC_INT
# define EN_RX_TC_INT EN_WRITE_TC_INT
# define AVM_FLAG 0x30000000L
# define ANY_S5933_INT 0x00800000L
# define READ_TC_INT 0x00080000L
# define WRITE_TC_INT 0x00040000L
# define TX_TC_INT READ_TC_INT
# define RX_TC_INT WRITE_TC_INT
# define MASTER_ABORT_INT 0x00100000L
# define TARGET_ABORT_INT 0x00200000L
# define BUS_MASTER_INT 0x00200000L
# define ALL_INT 0x000C0000L
#define AMCC_MCSR 0x3c
# define A2P_HI_PRIORITY 0x00000100L
# define EN_A2P_TRANSFERS 0x00000400L
# define P2A_HI_PRIORITY 0x00001000L
# define EN_P2A_TRANSFERS 0x00004000L
# define RESET_A2P_FLAGS 0x04000000L
# define RESET_P2A_FLAGS 0x02000000L
/* ------------------------------------------------------------- */
#define b1dmaoutmeml(addr, value) writel(value, addr)
#define b1dmainmeml(addr) readl(addr)
#define b1dmaoutmemw(addr, value) writew(value, addr)
#define b1dmainmemw(addr) readw(addr)
#define b1dmaoutmemb(addr, value) writeb(value, addr)
#define b1dmainmemb(addr) readb(addr)
/* ------------------------------------------------------------- */
static inline int b1dma_tx_empty(unsigned int port)
{
return inb(port + 0x03) & 0x1;
}
static inline int b1dma_rx_full(unsigned int port)
{
return inb(port + 0x02) & 0x1;
}
static int b1dma_tolink(avmcard *card, void *buf, unsigned int len)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
unsigned char *s = (unsigned char *)buf;
while (len--) {
while ( !b1dma_tx_empty(card->port)
&& time_before(jiffies, stop));
if (!b1dma_tx_empty(card->port))
return -1;
t1outp(card->port, 0x01, *s++);
}
return 0;
}
static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
unsigned char *s = (unsigned char *)buf;
while (len--) {
while ( !b1dma_rx_full(card->port)
&& time_before(jiffies, stop));
if (!b1dma_rx_full(card->port))
return -1;
*s++ = t1inp(card->port, 0x00);
}
return 0;
}
static int WriteReg(avmcard *card, __u32 reg, __u8 val)
{
__u8 cmd = 0x00;
if ( b1dma_tolink(card, &cmd, 1) == 0
&& b1dma_tolink(card, &reg, 4) == 0) {
__u32 tmp = val;
return b1dma_tolink(card, &tmp, 4);
}
return -1;
}
static __u8 ReadReg(avmcard *card, __u32 reg)
{
__u8 cmd = 0x01;
if ( b1dma_tolink(card, &cmd, 1) == 0
&& b1dma_tolink(card, &reg, 4) == 0) {
__u32 tmp;
if (b1dma_fromlink(card, &tmp, 4) == 0)
return (__u8)tmp;
}
return 0xff;
}
/* ------------------------------------------------------------- */
static inline void _put_byte(void **pp, __u8 val)
{
__u8 *s = *pp;
*s++ = val;
*pp = s;
}
static inline void _put_word(void **pp, __u32 val)
{
__u8 *s = *pp;
*s++ = val & 0xff;
*s++ = (val >> 8) & 0xff;
*s++ = (val >> 16) & 0xff;
*s++ = (val >> 24) & 0xff;
*pp = s;
}
static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
{
unsigned i = len;
_put_word(pp, i);
while (i-- > 0)
_put_byte(pp, *dp++);
}
static inline __u8 _get_byte(void **pp)
{
__u8 *s = *pp;
__u8 val;
val = *s++;
*pp = s;
return val;
}
static inline __u32 _get_word(void **pp)
{
__u8 *s = *pp;
__u32 val;
val = *s++;
val |= (*s++ << 8);
val |= (*s++ << 16);
val |= (*s++ << 24);
*pp = s;
return val;
}
static inline __u32 _get_slice(void **pp, unsigned char *dp)
{
unsigned int len, i;
len = i = _get_word(pp);
while (i-- > 0) *dp++ = _get_byte(pp);
return len;
}
/* ------------------------------------------------------------- */
void b1dma_reset(avmcard *card)
{
unsigned long flags;
save_flags(flags);
cli();
card->csr = 0x0;
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
t1outp(card->port, 0x10, 0x00);
t1outp(card->port, 0x07, 0x00);
restore_flags(flags);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
udelay(10 * 1000);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
udelay(10 * 1000);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
if (card->cardtype == avm_t1pci)
udelay(42 * 1000);
else
udelay(10 * 1000);
}
/* ------------------------------------------------------------- */
int b1dma_detect(avmcard *card)
{
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
udelay(10 * 1000);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
udelay(10 * 1000);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
udelay(42 * 1000);
b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
card->csr = 0x0;
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
if (b1dmainmeml(card->mbase+AMCC_MCSR) != 0x000000E6)
return 1;
b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0xffffffff);
b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0xffffffff);
if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0xfffffffc
|| b1dmainmeml(card->mbase+AMCC_TXPTR) != 0xfffffffc)
return 2;
b1dmaoutmeml(card->mbase+AMCC_RXPTR, 0x0);
b1dmaoutmeml(card->mbase+AMCC_TXPTR, 0x0);
if ( b1dmainmeml(card->mbase+AMCC_RXPTR) != 0x0
|| b1dmainmeml(card->mbase+AMCC_TXPTR) != 0x0)
return 3;
t1outp(card->port, 0x10, 0x00);
t1outp(card->port, 0x07, 0x00);
t1outp(card->port, 0x02, 0x02);
t1outp(card->port, 0x03, 0x02);
if ( (t1inp(card->port, 0x02) & 0xFE) != 0x02
|| t1inp(card->port, 0x3) != 0x03)
return 4;
t1outp(card->port, 0x02, 0x00);
t1outp(card->port, 0x03, 0x00);
if ( (t1inp(card->port, 0x02) & 0xFE) != 0x00
|| t1inp(card->port, 0x3) != 0x01)
return 5;
return 0;
}
int t1pci_detect(avmcard *card)
{
int ret;
if ((ret = b1dma_detect(card)) != 0)
return ret;
/* Transputer test */
if ( WriteReg(card, 0x80001000, 0x11) != 0
|| WriteReg(card, 0x80101000, 0x22) != 0
|| WriteReg(card, 0x80201000, 0x33) != 0
|| WriteReg(card, 0x80301000, 0x44) != 0)
return 6;
if ( ReadReg(card, 0x80001000) != 0x11
|| ReadReg(card, 0x80101000) != 0x22
|| ReadReg(card, 0x80201000) != 0x33
|| ReadReg(card, 0x80301000) != 0x44)
return 7;
if ( WriteReg(card, 0x80001000, 0x55) != 0
|| WriteReg(card, 0x80101000, 0x66) != 0
|| WriteReg(card, 0x80201000, 0x77) != 0
|| WriteReg(card, 0x80301000, 0x88) != 0)
return 8;
if ( ReadReg(card, 0x80001000) != 0x55
|| ReadReg(card, 0x80101000) != 0x66
|| ReadReg(card, 0x80201000) != 0x77
|| ReadReg(card, 0x80301000) != 0x88)
return 9;
return 0;
}
int b1pciv4_detect(avmcard *card)
{
int ret, i;
if ((ret = b1dma_detect(card)) != 0)
return ret;
for (i=0; i < 5 ; i++) {
if (WriteReg(card, 0x80A00000, 0x21) != 0)
return 6;
if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01)
return 7;
}
for (i=0; i < 5 ; i++) {
if (WriteReg(card, 0x80A00000, 0x20) != 0)
return 8;
if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00)
return 9;
}
return 0;
}
/* ------------------------------------------------------------- */
static void b1dma_dispatch_tx(avmcard *card)
{
avmcard_dmainfo *dma = card->dma;
unsigned long flags;
struct sk_buff *skb;
__u8 cmd, subcmd;
__u16 len;
__u32 txlen;
int inint;
void *p;
save_flags(flags);
cli();
inint = card->interrupt;
if (card->csr & EN_TX_TC_INT) { /* tx busy */
restore_flags(flags);
return;
}
skb = skb_dequeue(&dma->send_queue);
if (!skb) {
#ifdef CONFIG_B1DMA_DEBUG
printk(KERN_DEBUG "tx(%d): underrun\n", inint);
#endif
restore_flags(flags);
return;
}
len = CAPIMSG_LEN(skb->data);
if (len) {
cmd = CAPIMSG_COMMAND(skb->data);
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
p = dma->sendbuf;
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
__u16 dlen = CAPIMSG_DATALEN(skb->data);
_put_byte(&p, SEND_DATA_B3_REQ);
_put_slice(&p, skb->data, len);
_put_slice(&p, skb->data + len, dlen);
} else {
_put_byte(&p, SEND_MESSAGE);
_put_slice(&p, skb->data, len);
}
txlen = (__u8 *)p - (__u8 *)dma->sendbuf;
#ifdef CONFIG_B1DMA_DEBUG
printk(KERN_DEBUG "tx(%d): put msg len=%d\n",
inint, txlen);
#endif
} else {
txlen = skb->len-2;
#ifdef CONFIG_B1DMA_POLLDEBUG
if (skb->data[2] == SEND_POLLACK)
printk(KERN_INFO "%s: send ack\n", card->name);
#endif
#ifdef CONFIG_B1DMA_DEBUG
printk(KERN_DEBUG "tx(%d): put 0x%x len=%d\n",
inint, skb->data[2], txlen);
#endif
memcpy(dma->sendbuf, skb->data+2, skb->len-2);
}
txlen = (txlen + 3) & ~3;
b1dmaoutmeml(card->mbase+AMCC_TXPTR, virt_to_phys(dma->sendbuf));
b1dmaoutmeml(card->mbase+AMCC_TXLEN, txlen);
card->csr |= EN_TX_TC_INT;
if (!inint)
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
restore_flags(flags);
dev_kfree_skb(skb);
}
/* ------------------------------------------------------------- */
static void queue_pollack(avmcard *card)
{
struct sk_buff *skb;
void *p;
skb = alloc_skb(3, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost poll ack\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_POLLACK);
skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
skb_queue_tail(&card->dma->send_queue, skb);
b1dma_dispatch_tx(card);
}
/* ------------------------------------------------------------- */
static void b1dma_handle_rx(avmcard *card)
{
avmctrl_info *cinfo = &card->ctrlinfo[0];
avmcard_dmainfo *dma = card->dma;
struct capi_ctr *ctrl = cinfo->capi_ctrl;
struct sk_buff *skb;
void *p = dma->recvbuf+4;
__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
__u8 b1cmd = _get_byte(&p);
#ifdef CONFIG_B1DMA_DEBUG
printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
#endif
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
DataB3Len = _get_slice(&p, card->databuf);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = _get_word(&p);
NCCI = _get_word(&p);
WindowSize = _get_word(&p);
ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
break;
case RECEIVE_FREE_NCCI:
ApplId = _get_word(&p);
NCCI = _get_word(&p);
if (NCCI != 0xffffffff)
ctrl->free_ncci(ctrl, ApplId, NCCI);
else ctrl->appl_released(ctrl, ApplId);
break;
case RECEIVE_START:
#ifdef CONFIG_B1DMA_POLLDEBUG
printk(KERN_INFO "%s: receive poll\n", card->name);
#endif
if (!suppress_pollack)
queue_pollack(card);
ctrl->resume_output(ctrl);
break;
case RECEIVE_STOP:
ctrl->suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
ctrl->ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
card->msgbuf[MsgLen--] = 0;
while ( MsgLen >= 0
&& ( card->msgbuf[MsgLen] == '\n'
|| card->msgbuf[MsgLen] == '\r'))
card->msgbuf[MsgLen--] = 0;
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = _get_slice(&p, card->msgbuf);
card->msgbuf[MsgLen--] = 0;
while ( MsgLen >= 0
&& ( card->msgbuf[MsgLen] == '\n'
|| card->msgbuf[MsgLen] == '\r'))
card->msgbuf[MsgLen--] = 0;
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
default:
printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n",
card->name, b1cmd);
return;
}
}
/* ------------------------------------------------------------- */
static void b1dma_handle_interrupt(avmcard *card)
{
__u32 status = b1dmainmeml(card->mbase+AMCC_INTCSR);
__u32 newcsr;
if ((status & ANY_S5933_INT) == 0)
return;
newcsr = card->csr | (status & ALL_INT);
if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
b1dmaoutmeml(card->mbase+AMCC_INTCSR, newcsr);
if ((status & RX_TC_INT) != 0) {
__u8 *recvbuf = card->dma->recvbuf;
__u32 rxlen;
if (card->dma->recvlen == 0) {
card->dma->recvlen = *((__u32 *)recvbuf);
rxlen = (card->dma->recvlen + 3) & ~3;
b1dmaoutmeml(card->mbase+AMCC_RXPTR,
virt_to_phys(recvbuf+4));
b1dmaoutmeml(card->mbase+AMCC_RXLEN, rxlen);
} else {
b1dma_handle_rx(card);
card->dma->recvlen = 0;
b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(recvbuf));
b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
}
}
if ((status & TX_TC_INT) != 0) {
card->csr &= ~EN_TX_TC_INT;
b1dma_dispatch_tx(card);
#if 1
} else if (card->csr & EN_TX_TC_INT) {
if (b1dmainmeml(card->mbase+AMCC_TXLEN) == 0) {
card->csr &= ~EN_TX_TC_INT;
b1dma_dispatch_tx(card);
}
#endif
}
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
}
void b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
{
avmcard *card;
card = (avmcard *) devptr;
if (!card) {
printk(KERN_WARNING "b1dma: interrupt: wrong device\n");
return;
}
if (card->interrupt) {
printk(KERN_ERR "%s: reentering interrupt hander\n", card->name);
return;
}
card->interrupt = 1;
b1dma_handle_interrupt(card);
card->interrupt = 0;
}
/* ------------------------------------------------------------- */
static int b1dma_loaded(avmcard *card)
{
unsigned long stop;
unsigned char ans;
unsigned long tout = 2;
unsigned int base = card->port;
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_tx_empty(base))
break;
}
if (!b1_tx_empty(base)) {
printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n",
card->name);
return 0;
}
b1_put_byte(base, SEND_POLLACK);
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_rx_full(base)) {
if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
return 1;
}
printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
return 0;
}
}
printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name);
return 0;
}
/* ------------------------------------------------------------- */
static void b1dma_send_init(avmcard *card)
{
struct sk_buff *skb;
void *p;
skb = alloc_skb(15, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost register appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_INIT);
_put_word(&p, AVM_NAPPS);
_put_word(&p, AVM_NCCI_PER_CHANNEL*30);
_put_word(&p, card->cardnr - 1);
skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
skb_queue_tail(&card->dma->send_queue, skb);
b1dma_dispatch_tx(card);
}
int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned long flags;
int retval;
b1dma_reset(card);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1dma_loaded(card)) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
save_flags(flags);
cli();
card->csr = AVM_FLAG;
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
b1dmaoutmeml(card->mbase+AMCC_MCSR,
EN_A2P_TRANSFERS|EN_P2A_TRANSFERS
|A2P_HI_PRIORITY|P2A_HI_PRIORITY
|RESET_A2P_FLAGS|RESET_P2A_FLAGS);
t1outp(card->port, 0x07, 0x30);
t1outp(card->port, 0x10, 0xF0);
card->dma->recvlen = 0;
b1dmaoutmeml(card->mbase+AMCC_RXPTR, virt_to_phys(card->dma->recvbuf));
b1dmaoutmeml(card->mbase+AMCC_RXLEN, 4);
card->csr |= EN_RX_TC_INT;
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
restore_flags(flags);
b1dma_send_init(card);
return 0;
}
void b1dma_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
b1dma_reset(card);
memset(cinfo->version, 0, sizeof(cinfo->version));
ctrl->reseted(ctrl);
}
/* ------------------------------------------------------------- */
void b1dma_register_appl(struct capi_ctr *ctrl,
__u16 appl,
capi_register_params *rp)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
struct sk_buff *skb;
int want = rp->level3cnt;
int nconn;
void *p;
if (want > 0) nconn = want;
else nconn = ctrl->profile.nbchannel * -want;
if (nconn == 0) nconn = ctrl->profile.nbchannel;
skb = alloc_skb(23, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost register appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_REGISTER);
_put_word(&p, appl);
_put_word(&p, 1024 * (nconn+1));
_put_word(&p, nconn);
_put_word(&p, rp->datablkcnt);
_put_word(&p, rp->datablklen);
skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
skb_queue_tail(&card->dma->send_queue, skb);
b1dma_dispatch_tx(card);
ctrl->appl_registered(ctrl, appl);
}
/* ------------------------------------------------------------- */
void b1dma_release_appl(struct capi_ctr *ctrl, __u16 appl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
struct sk_buff *skb;
void *p;
skb = alloc_skb(7, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost release appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_RELEASE);
_put_word(&p, appl);
skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
skb_queue_tail(&card->dma->send_queue, skb);
b1dma_dispatch_tx(card);
}
/* ------------------------------------------------------------- */
void b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
skb_queue_tail(&card->dma->send_queue, skb);
b1dma_dispatch_tx(card);
}
/* ------------------------------------------------------------- */
int b1dmactl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned long flags;
__u8 flag;
int len = 0;
char *s;
__u32 txaddr, txlen, rxaddr, rxlen, csr;
len += sprintf(page+len, "%-16s %s\n", "name", card->name);
len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
case avm_b1pcmcia: s = "B1 PCMCIA"; break;
case avm_m1: s = "M1"; break;
case avm_m2: s = "M2"; break;
case avm_t1isa: s = "T1 ISA (HEMA)"; break;
case avm_t1pci: s = "T1 PCI"; break;
case avm_c4: s = "C4"; break;
default: s = "???"; break;
}
len += sprintf(page+len, "%-16s %s\n", "type", s);
if ((s = cinfo->version[VER_DRIVER]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((__u8 *)(ctrl->profile.manu))[3];
if (flag)
len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
}
if (card->cardtype != avm_m1) {
flag = ((__u8 *)(ctrl->profile.manu))[5];
if (flag)
len += sprintf(page+len, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
save_flags(flags);
cli();
txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
txaddr -= (__u32)card->dma->sendbuf;
txlen = b1dmainmeml(card->mbase+0x30);
rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24));
rxaddr -= (__u32)card->dma->recvbuf;
rxlen = b1dmainmeml(card->mbase+0x28);
csr = b1dmainmeml(card->mbase+AMCC_INTCSR);
restore_flags(flags);
len += sprintf(page+len, "%-16s 0x%lx\n",
"csr (cached)", (unsigned long)card->csr);
len += sprintf(page+len, "%-16s 0x%lx\n",
"csr", (unsigned long)csr);
len += sprintf(page+len, "%-16s %lu\n",
"txoff", (unsigned long)txaddr);
len += sprintf(page+len, "%-16s %lu\n",
"txlen", (unsigned long)txlen);
len += sprintf(page+len, "%-16s %lu\n",
"rxoff", (unsigned long)rxaddr);
len += sprintf(page+len, "%-16s %lu\n",
"rxlen", (unsigned long)rxlen);
if (off+count >= len)
*eof = 1;
if (len < off)
return 0;
*start = page + off;
return ((count < len-off) ? count : len-off);
}
/* ------------------------------------------------------------- */
EXPORT_SYMBOL(b1dma_reset);
EXPORT_SYMBOL(t1pci_detect);
EXPORT_SYMBOL(b1pciv4_detect);
EXPORT_SYMBOL(b1dma_interrupt);
EXPORT_SYMBOL(b1dma_load_firmware);
EXPORT_SYMBOL(b1dma_reset_ctr);
EXPORT_SYMBOL(b1dma_register_appl);
EXPORT_SYMBOL(b1dma_release_appl);
EXPORT_SYMBOL(b1dma_send_message);
EXPORT_SYMBOL(b1dmactl_read_proc);
#ifdef MODULE
#define b1dma_init init_module
void cleanup_module(void);
#endif
int b1dma_init(void)
{
char *p;
char rev[10];
if ((p = strchr(revision, ':'))) {
strncpy(rev, p + 1, sizeof(rev));
p = strchr(rev, '$');
*p = 0;
} else
strcpy(rev, "1.0");
printk(KERN_INFO "b1dma: revision %s\n", rev);
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
}
#endif

View File

@ -1,289 +0,0 @@
/*
* $Id$
*
* Module for AVM B1 ISA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.6 2000/01/25 14:37:39 calle
* new message after successfull detection including card revision and
* used resources.
*
* Revision 1.5 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
* constant string.
* - Moved some data from struct avmcard into new struct avmctrl_info.
* Changed all lowlevel capi driver to match the new structur.
*
* Revision 1.4 1999/08/22 20:26:24 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.3 1999/07/09 15:05:40 keil
* compat.h is now isdn_compat.h
*
* Revision 1.2 1999/07/05 15:09:49 calle
* - renamed "appl_release" to "appl_released".
* - version und profile data now cleared on controller reset
* - extended /proc interface, to allow driver and controller specific
* informations to include by driver hackers.
*
* Revision 1.1 1999/07/01 15:26:27 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
* - write a CAPI-2.0 for the passive cards
* - support serial link CAPI-2.0 boxes.
* + wrote "capi_driver" for all supported cards.
* + "capi_driver" (supported cards) now have to be configured with
* make menuconfig, in the past all supported cards where included
* at once.
* + new and better informations in /proc/capi/
* + new ioctl to switch trace of capi messages per controller
* using "avmcapictrl trace [contr] on|off|...."
* + complete testcircle with all supported cards and also the
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
*
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <asm/io.h>
#include <linux/isdn_compat.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
static char *revision = "$Revision$";
/* ------------------------------------------------------------- */
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
/* ------------------------------------------------------------- */
static void b1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
{
avmcard *card;
card = (avmcard *) devptr;
if (!card) {
printk(KERN_WARNING "b1_interrupt: wrong device\n");
return;
}
if (card->interrupt) {
printk(KERN_ERR "b1_interrupt: reentering interrupt hander (%s)\n", card->name);
return;
}
card->interrupt = 1;
b1_handle_interrupt(card);
card->interrupt = 0;
}
/* ------------------------------------------------------------- */
static struct capi_driver_interface *di;
/* ------------------------------------------------------------- */
static void b1isa_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
b1_reset(port);
b1_reset(port);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
static int b1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
{
avmctrl_info *cinfo;
avmcard *card;
int retval;
MOD_INC_USE_COUNT;
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "b1isa: no memory.\n");
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "b1isa: no memory.\n");
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
cinfo->card = card;
sprintf(card->name, "b1isa-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->cardtype = avm_b1isa;
if (check_region(card->port, AVMB1_PORTLEN)) {
printk(KERN_WARNING
"b1isa: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
if (b1_irq_table[card->irq & 0xf] == 0) {
printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EINVAL;
}
if ( card->port != 0x150 && card->port != 0x250
&& card->port != 0x300 && card->port != 0x340) {
printk(KERN_WARNING "b1isa: illegal port 0x%x.\n", card->port);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EINVAL;
}
b1_reset(card->port);
if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n",
card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
b1_getrevision(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
retval = request_irq(card->irq, b1isa_interrupt, 0, card->name, card);
if (retval) {
printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "b1isa: attach controller failed.\n");
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
printk(KERN_INFO
"%s: AVM B1 ISA at i/o %#x, irq %d, revision %d\n",
driver->name, card->port, card->irq, card->revision);
return 0;
}
static char *b1isa_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static struct capi_driver b1isa_driver = {
"b1isa",
"0.0",
b1_load_firmware,
b1_reset_ctr,
b1isa_remove_ctr,
b1_register_appl,
b1_release_appl,
b1_send_message,
b1isa_procinfo,
b1ctl_read_proc,
0, /* use standard driver_read_proc */
b1isa_add_card,
};
#ifdef MODULE
#define b1isa_init init_module
void cleanup_module(void);
#endif
int b1isa_init(void)
{
struct capi_driver *driver = &b1isa_driver;
char *p;
if ((p = strchr(revision, ':'))) {
strncpy(driver->revision, p + 1, sizeof(driver->revision));
p = strchr(driver->revision, '$');
*p = 0;
}
printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
di = attach_capi_driver(driver);
if (!di) {
printk(KERN_ERR "%s: failed to attach capi_driver\n",
driver->name);
return -EIO;
}
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
detach_capi_driver(&b1isa_driver);
}
#endif

View File

@ -1,579 +0,0 @@
/*
* $Id$
*
* Module for AVM B1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.19 2000/01/25 14:33:38 calle
* - Added Support AVM B1 PCI V4.0 (tested with prototype)
* - splitted up t1pci.c into b1dma.c for common function with b1pciv4
* - support for revision register
*
* Revision 1.18 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
* constant string.
* - Moved some data from struct avmcard into new struct avmctrl_info.
* Changed all lowlevel capi driver to match the new structur.
*
* Revision 1.17 1999/10/05 06:50:07 calle
* Forgot SA_SHIRQ as argument to request_irq.
*
* Revision 1.16 1999/08/11 21:01:07 keil
* new PCI codefix
*
* Revision 1.15 1999/08/10 16:02:27 calle
* struct pci_dev changed in 2.3.13. Made the necessary changes.
*
* Revision 1.14 1999/07/09 15:05:41 keil
* compat.h is now isdn_compat.h
*
* Revision 1.13 1999/07/05 15:09:50 calle
* - renamed "appl_release" to "appl_released".
* - version und profile data now cleared on controller reset
* - extended /proc interface, to allow driver and controller specific
* informations to include by driver hackers.
*
* Revision 1.12 1999/07/01 15:26:29 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
* - write a CAPI-2.0 for the passive cards
* - support serial link CAPI-2.0 boxes.
* + wrote "capi_driver" for all supported cards.
* + "capi_driver" (supported cards) now have to be configured with
* make menuconfig, in the past all supported cards where included
* at once.
* + new and better informations in /proc/capi/
* + new ioctl to switch trace of capi messages per controller
* using "avmcapictrl trace [contr] on|off|...."
* + complete testcircle with all supported cards and also the
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
*
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/capi.h>
#include <asm/io.h>
#include <linux/isdn_compat.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
static char *revision = "$Revision$";
/* ------------------------------------------------------------- */
#ifndef PCI_VENDOR_ID_AVM
#define PCI_VENDOR_ID_AVM 0x1244
#endif
#ifndef PCI_DEVICE_ID_AVM_B1
#define PCI_DEVICE_ID_AVM_B1 0x700
#endif
/* ------------------------------------------------------------- */
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
/* ------------------------------------------------------------- */
static struct capi_driver_interface *di;
/* ------------------------------------------------------------- */
static void b1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
{
avmcard *card;
card = (avmcard *) devptr;
if (!card) {
printk(KERN_WARNING "b1pci: interrupt: wrong device\n");
return;
}
if (card->interrupt) {
printk(KERN_ERR "%s: reentering interrupt hander.\n", card->name);
return;
}
card->interrupt = 1;
b1_handle_interrupt(card);
card->interrupt = 0;
}
/* ------------------------------------------------------------- */
static void b1pci_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
b1_reset(port);
b1_reset(port);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
ctrl->driverdata = 0;
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
static char *b1pci_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
{
avmcard *card;
avmctrl_info *cinfo;
int retval;
MOD_INC_USE_COUNT;
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
cinfo->card = card;
sprintf(card->name, "b1pci-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->cardtype = avm_b1pci;
if (check_region(card->port, AVMB1_PORTLEN)) {
printk(KERN_WARNING
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
b1_reset(card->port);
if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
b1_getrevision(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "%s: attach controller failed.\n",
driver->name);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
if (card->revision >= 4) {
printk(KERN_INFO
"%s: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
driver->name, card->port, card->irq, card->revision);
} else {
printk(KERN_INFO
"%s: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
driver->name, card->port, card->irq, card->revision);
}
return 0;
}
/* ------------------------------------------------------------- */
static struct capi_driver b1pci_driver = {
"b1pci",
"0.0",
b1_load_firmware,
b1_reset_ctr,
b1pci_remove_ctr,
b1_register_appl,
b1_release_appl,
b1_send_message,
b1pci_procinfo,
b1ctl_read_proc,
0, /* use standard driver_read_proc */
0, /* no add_card function */
};
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
/* ------------------------------------------------------------- */
static struct capi_driver_interface *div4;
/* ------------------------------------------------------------- */
static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
b1dma_reset(card);
div4->detach_ctr(ctrl);
free_irq(card->irq, card);
iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
release_region(card->port, AVMB1_PORTLEN);
ctrl->driverdata = 0;
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
}
static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->membase : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p)
{
unsigned long base, page_offset;
avmcard *card;
avmctrl_info *cinfo;
int retval;
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
if (!card->dma) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
return -ENOMEM;
}
memset(card->dma, 0, sizeof(avmcard_dmainfo));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card->dma);
kfree(card);
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
cinfo->card = card;
sprintf(card->name, "b1pciv4-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->membase = p->membase;
card->cardtype = avm_b1pci;
if (check_region(card->port, AVMB1_PORTLEN)) {
printk(KERN_WARNING
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
return -EBUSY;
}
base = card->membase & PAGE_MASK;
page_offset = card->membase - base;
card->mbase = ioremap_nocache(base, page_offset + 64);
if (card->mbase) {
card->mbase += page_offset;
} else {
printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
driver->name, card->membase);
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
return -EIO;
}
b1dma_reset(card);
if ((retval = b1pciv4_detect(card)) != 0) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
driver->name, card->port, retval);
iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
return -EIO;
}
b1dma_reset(card);
b1_getrevision(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
return -EBUSY;
}
cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
return -EBUSY;
}
card->cardnr = cinfo->capi_ctrl->cnr;
skb_queue_head_init(&card->dma->send_queue);
printk(KERN_INFO
"%s: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
driver->name, card->port, card->irq,
card->membase, card->revision);
MOD_INC_USE_COUNT;
return 0;
}
/* ------------------------------------------------------------- */
static struct capi_driver b1pciv4_driver = {
"b1pciv4",
"0.0",
b1dma_load_firmware,
b1dma_reset_ctr,
b1pciv4_remove_ctr,
b1dma_register_appl,
b1dma_release_appl,
b1dma_send_message,
b1pciv4_procinfo,
b1dmactl_read_proc,
0, /* use standard driver_read_proc */
0, /* no add_card function */
};
#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
#ifdef MODULE
#define b1pci_init init_module
void cleanup_module(void);
#endif
static int ncards = 0;
static int add_card(struct pci_dev *dev)
{
struct capi_driver *driver = &b1pci_driver;
struct capicardparams param;
int retval;
if (get_pcibase(dev, 2) & PCI_BASE_ADDRESS_IO_MASK) { /* B1 PCI V4 */
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
driver = &b1pciv4_driver;
#endif
param.membase = get_pcibase(dev, 0) & PCI_BASE_ADDRESS_MEM_MASK;
param.port = get_pcibase(dev, 2) & PCI_BASE_ADDRESS_IO_MASK;
param.irq = dev->irq;
printk(KERN_INFO
"%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
driver->name, param.port, param.irq, param.membase);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
retval = b1pciv4_add_card(driver, &param);
#else
retval = b1pci_add_card(driver, &param);
#endif
if (retval != 0) {
printk(KERN_ERR
"%s: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
driver->name, param.port, param.irq, param.membase);
}
} else {
param.membase = 0;
param.port = get_pcibase(dev, 1) & PCI_BASE_ADDRESS_IO_MASK;
param.irq = dev->irq;
printk(KERN_INFO
"%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
driver->name, param.port, param.irq);
retval = b1pci_add_card(driver, &param);
if (retval != 0) {
printk(KERN_ERR
"%s: no AVM-B1 at i/o %#x, irq %d detected\n",
driver->name, param.port, param.irq);
}
}
return retval;
}
int b1pci_init(void)
{
struct capi_driver *driver = &b1pci_driver;
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
struct capi_driver *driverv4 = &b1pciv4_driver;
#endif
struct pci_dev *dev = NULL;
char *p;
int retval;
if ((p = strchr(revision, ':'))) {
strncpy(driver->revision, p + 1, sizeof(driver->revision));
p = strchr(driver->revision, '$');
*p = 0;
}
printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
di = attach_capi_driver(driver);
if (!di) {
printk(KERN_ERR "%s: failed to attach capi_driver\n",
driver->name);
return -EIO;
}
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
printk(KERN_INFO "%s: revision %s\n", driverv4->name, driverv4->revision);
div4 = attach_capi_driver(driverv4);
if (!div4) {
detach_capi_driver(driver);
printk(KERN_ERR "%s: failed to attach capi_driver\n",
driverv4->name);
return -EIO;
}
#endif
#ifdef CONFIG_PCI
if (!pci_present()) {
printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
detach_capi_driver(driver);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
detach_capi_driver(driverv4);
#endif
return -EIO;
}
while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) {
retval = add_card(dev);
if (retval != 0) {
#ifdef MODULE
cleanup_module();
#endif
return retval;
}
ncards++;
}
if (ncards) {
printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n",
driver->name, ncards);
return 0;
}
printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name);
return -ESRCH;
#else
printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
return -EIO;
#endif
}
#ifdef MODULE
void cleanup_module(void)
{
detach_capi_driver(&b1pci_driver);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
detach_capi_driver(&b1pciv4_driver);
#endif
}
#endif

View File

@ -1,320 +0,0 @@
/*
* $Id$
*
* Module for AVM B1/M1/M2 PCMCIA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.6 2000/01/25 14:37:39 calle
* new message after successfull detection including card revision and
* used resources.
*
* Revision 1.5 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
* constant string.
* - Moved some data from struct avmcard into new struct avmctrl_info.
* Changed all lowlevel capi driver to match the new structur.
*
* Revision 1.4 1999/08/22 20:26:26 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.3 1999/07/09 15:05:41 keil
* compat.h is now isdn_compat.h
*
* Revision 1.2 1999/07/05 15:09:51 calle
* - renamed "appl_release" to "appl_released".
* - version und profile data now cleared on controller reset
* - extended /proc interface, to allow driver and controller specific
* informations to include by driver hackers.
*
* Revision 1.1 1999/07/01 15:26:30 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
* - write a CAPI-2.0 for the passive cards
* - support serial link CAPI-2.0 boxes.
* + wrote "capi_driver" for all supported cards.
* + "capi_driver" (supported cards) now have to be configured with
* make menuconfig, in the past all supported cards where included
* at once.
* + new and better informations in /proc/capi/
* + new ioctl to switch trace of capi messages per controller
* using "avmcapictrl trace [contr] on|off|...."
* + complete testcircle with all supported cards and also the
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
*
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/capi.h>
#include <linux/b1pcmcia.h>
#include <linux/isdn_compat.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
static char *revision = "$Revision$";
/* ------------------------------------------------------------- */
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
/* ------------------------------------------------------------- */
static struct capi_driver_interface *di;
/* ------------------------------------------------------------- */
static void b1pcmcia_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
{
avmcard *card;
card = (avmcard *) devptr;
if (!card) {
printk(KERN_WARNING "b1pcmcia: interrupt: wrong device\n");
return;
}
if (card->interrupt) {
printk(KERN_ERR "%s: reentering interrupt hander.\n",
card->name);
return;
}
card->interrupt = 1;
b1_handle_interrupt(card);
card->interrupt = 0;
}
/* ------------------------------------------------------------- */
static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
b1_reset(port);
b1_reset(port);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
/* io addrsses managent by CardServices
* release_region(card->port, AVMB1_PORTLEN);
*/
kfree(card);
MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
static int b1pcmcia_add_card(struct capi_driver *driver,
unsigned int port,
unsigned irq,
enum avmcardtype cardtype)
{
avmctrl_info *cinfo;
avmcard *card;
char *cardname;
int retval;
MOD_INC_USE_COUNT;
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
cinfo->card = card;
switch (cardtype) {
case avm_m1: sprintf(card->name, "m1-%x", port); break;
case avm_m2: sprintf(card->name, "m2-%x", port); break;
default: sprintf(card->name, "b1pcmcia-%x", port); break;
}
card->port = port;
card->irq = irq;
card->cardtype = cardtype;
b1_reset(card->port);
if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
}
b1_reset(card->port);
b1_getrevision(card);
retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "%s: attach controller failed.\n",
driver->name);
free_irq(card->irq, card);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
switch (cardtype) {
case avm_m1: cardname = "M1"; break;
case avm_m2: cardname = "M2"; break;
default : cardname = "B1 PCMCIA"; break;
}
printk(KERN_INFO
"%s: AVM %s at i/o %#x, irq %d, revision %d\n",
driver->name, cardname, card->port, card->irq, card->revision);
return cinfo->capi_ctrl->cnr;
}
/* ------------------------------------------------------------- */
static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static struct capi_driver b1pcmcia_driver = {
"b1pcmcia",
"0.0",
b1_load_firmware,
b1_reset_ctr,
b1pcmcia_remove_ctr,
b1_register_appl,
b1_release_appl,
b1_send_message,
b1pcmcia_procinfo,
b1ctl_read_proc,
0, /* use standard driver_read_proc */
0,
};
/* ------------------------------------------------------------- */
int b1pcmcia_addcard_b1(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_b1pcmcia);
}
int b1pcmcia_addcard_m1(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m1);
}
int b1pcmcia_addcard_m2(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m2);
}
int b1pcmcia_delcard(unsigned int port, unsigned irq)
{
struct capi_ctr *ctrl;
avmcard *card;
for (ctrl = b1pcmcia_driver.controller; ctrl; ctrl = ctrl->next) {
card = ((avmctrl_info *)(ctrl->driverdata))->card;
if (card->port == port && card->irq == irq) {
b1pcmcia_remove_ctr(ctrl);
return 0;
}
}
return -ESRCH;
}
EXPORT_SYMBOL(b1pcmcia_addcard_b1);
EXPORT_SYMBOL(b1pcmcia_addcard_m1);
EXPORT_SYMBOL(b1pcmcia_addcard_m2);
EXPORT_SYMBOL(b1pcmcia_delcard);
/* ------------------------------------------------------------- */
#ifdef MODULE
#define b1pcmcia_init init_module
void cleanup_module(void);
#endif
int b1pcmcia_init(void)
{
struct capi_driver *driver = &b1pcmcia_driver;
char *p;
if ((p = strchr(revision, ':'))) {
strncpy(driver->revision, p + 1, sizeof(driver->revision));
p = strchr(driver->revision, '$');
*p = 0;
}
printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
di = attach_capi_driver(driver);
if (!di) {
printk(KERN_ERR "%s: failed to attach capi_driver\n",
driver->name);
return -EIO;
}
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
detach_capi_driver(&b1pcmcia_driver);
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,134 +0,0 @@
/*
* $Id$
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.2 2000/03/03 15:50:42 calle
* - kernel CAPI:
* - Changed parameter "param" in capi_signal from __u32 to void *.
* - rewrote notifier handling in kcapi.c
* - new notifier NCCI_UP and NCCI_DOWN
* - User CAPI:
* - /dev/capi20 is now a cloning device.
* - middleware extentions prepared.
* - capidrv.c
* - locking of list operations and module count updates.
*
* Revision 1.1 1997/03/04 21:50:30 calle
* Frirst version in isdn4linux
*
* Revision 2.2 1997/02/12 09:31:39 calle
* new version
*
* Revision 1.1 1997/01/31 10:32:20 calle
* Initial revision
*
*
*/
#ifndef __CAPICMD_H__
#define __CAPICMD_H__
#define CAPI_MSG_BASELEN 8
#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2)
#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2)
/*----- CAPI commands -----*/
#define CAPI_ALERT 0x01
#define CAPI_CONNECT 0x02
#define CAPI_CONNECT_ACTIVE 0x03
#define CAPI_CONNECT_B3_ACTIVE 0x83
#define CAPI_CONNECT_B3 0x82
#define CAPI_CONNECT_B3_T90_ACTIVE 0x88
#define CAPI_DATA_B3 0x86
#define CAPI_DISCONNECT_B3 0x84
#define CAPI_DISCONNECT 0x04
#define CAPI_FACILITY 0x80
#define CAPI_INFO 0x08
#define CAPI_LISTEN 0x05
#define CAPI_MANUFACTURER 0xff
#define CAPI_RESET_B3 0x87
#define CAPI_SELECT_B_PROTOCOL 0x41
/*----- CAPI subcommands -----*/
#define CAPI_REQ 0x80
#define CAPI_CONF 0x81
#define CAPI_IND 0x82
#define CAPI_RESP 0x83
/*----- CAPI combined commands -----*/
#define CAPICMD(cmd,subcmd) (((cmd)<<8)|(subcmd))
#define CAPI_DISCONNECT_REQ CAPICMD(CAPI_DISCONNECT,CAPI_REQ)
#define CAPI_DISCONNECT_CONF CAPICMD(CAPI_DISCONNECT,CAPI_CONF)
#define CAPI_DISCONNECT_IND CAPICMD(CAPI_DISCONNECT,CAPI_IND)
#define CAPI_DISCONNECT_RESP CAPICMD(CAPI_DISCONNECT,CAPI_RESP)
#define CAPI_ALERT_REQ CAPICMD(CAPI_ALERT,CAPI_REQ)
#define CAPI_ALERT_CONF CAPICMD(CAPI_ALERT,CAPI_CONF)
#define CAPI_CONNECT_REQ CAPICMD(CAPI_CONNECT,CAPI_REQ)
#define CAPI_CONNECT_CONF CAPICMD(CAPI_CONNECT,CAPI_CONF)
#define CAPI_CONNECT_IND CAPICMD(CAPI_CONNECT,CAPI_IND)
#define CAPI_CONNECT_RESP CAPICMD(CAPI_CONNECT,CAPI_RESP)
#define CAPI_CONNECT_ACTIVE_REQ CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ)
#define CAPI_CONNECT_ACTIVE_CONF CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF)
#define CAPI_CONNECT_ACTIVE_IND CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND)
#define CAPI_CONNECT_ACTIVE_RESP CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP)
#define CAPI_SELECT_B_PROTOCOL_REQ CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ)
#define CAPI_SELECT_B_PROTOCOL_CONF CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF)
#define CAPI_CONNECT_B3_ACTIVE_REQ CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ)
#define CAPI_CONNECT_B3_ACTIVE_CONF CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF)
#define CAPI_CONNECT_B3_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND)
#define CAPI_CONNECT_B3_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP)
#define CAPI_CONNECT_B3_REQ CAPICMD(CAPI_CONNECT_B3,CAPI_REQ)
#define CAPI_CONNECT_B3_CONF CAPICMD(CAPI_CONNECT_B3,CAPI_CONF)
#define CAPI_CONNECT_B3_IND CAPICMD(CAPI_CONNECT_B3,CAPI_IND)
#define CAPI_CONNECT_B3_RESP CAPICMD(CAPI_CONNECT_B3,CAPI_RESP)
#define CAPI_CONNECT_B3_T90_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND)
#define CAPI_CONNECT_B3_T90_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP)
#define CAPI_DATA_B3_REQ CAPICMD(CAPI_DATA_B3,CAPI_REQ)
#define CAPI_DATA_B3_CONF CAPICMD(CAPI_DATA_B3,CAPI_CONF)
#define CAPI_DATA_B3_IND CAPICMD(CAPI_DATA_B3,CAPI_IND)
#define CAPI_DATA_B3_RESP CAPICMD(CAPI_DATA_B3,CAPI_RESP)
#define CAPI_DISCONNECT_B3_REQ CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ)
#define CAPI_DISCONNECT_B3_CONF CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF)
#define CAPI_DISCONNECT_B3_IND CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND)
#define CAPI_DISCONNECT_B3_RESP CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP)
#define CAPI_RESET_B3_REQ CAPICMD(CAPI_RESET_B3,CAPI_REQ)
#define CAPI_RESET_B3_CONF CAPICMD(CAPI_RESET_B3,CAPI_CONF)
#define CAPI_RESET_B3_IND CAPICMD(CAPI_RESET_B3,CAPI_IND)
#define CAPI_RESET_B3_RESP CAPICMD(CAPI_RESET_B3,CAPI_RESP)
#define CAPI_LISTEN_REQ CAPICMD(CAPI_LISTEN,CAPI_REQ)
#define CAPI_LISTEN_CONF CAPICMD(CAPI_LISTEN,CAPI_CONF)
#define CAPI_MANUFACTURER_REQ CAPICMD(CAPI_MANUFACTURER,CAPI_REQ)
#define CAPI_MANUFACTURER_CONF CAPICMD(CAPI_MANUFACTURER,CAPI_CONF)
#define CAPI_MANUFACTURER_IND CAPICMD(CAPI_MANUFACTURER,CAPI_IND)
#define CAPI_MANUFACTURER_RESP CAPICMD(CAPI_MANUFACTURER,CAPI_RESP)
#define CAPI_FACILITY_REQ CAPICMD(CAPI_FACILITY,CAPI_REQ)
#define CAPI_FACILITY_CONF CAPICMD(CAPI_FACILITY,CAPI_CONF)
#define CAPI_FACILITY_IND CAPICMD(CAPI_FACILITY,CAPI_IND)
#define CAPI_FACILITY_RESP CAPICMD(CAPI_FACILITY,CAPI_RESP)
#define CAPI_INFO_REQ CAPICMD(CAPI_INFO,CAPI_REQ)
#define CAPI_INFO_CONF CAPICMD(CAPI_INFO,CAPI_CONF)
#define CAPI_INFO_IND CAPICMD(CAPI_INFO,CAPI_IND)
#define CAPI_INFO_RESP CAPICMD(CAPI_INFO,CAPI_RESP)
#endif /* __CAPICMD_H__ */

View File

@ -1,72 +0,0 @@
/*
* $Id$
*
* CAPI 2.0 Interface for Linux
*
* (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.5 2000/03/03 15:50:42 calle
* - kernel CAPI:
* - Changed parameter "param" in capi_signal from __u32 to void *.
* - rewrote notifier handling in kcapi.c
* - new notifier NCCI_UP and NCCI_DOWN
* - User CAPI:
* - /dev/capi20 is now a cloning device.
* - middleware extentions prepared.
* - capidrv.c
* - locking of list operations and module count updates.
*
* Revision 1.4 1999/07/01 15:26:32 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
* - write a CAPI-2.0 for the passive cards
* - support serial link CAPI-2.0 boxes.
* + wrote "capi_driver" for all supported cards.
* + "capi_driver" (supported cards) now have to be configured with
* make menuconfig, in the past all supported cards where included
* at once.
* + new and better informations in /proc/capi/
* + new ioctl to switch trace of capi messages per controller
* using "avmcapictrl trace [contr] on|off|...."
* + complete testcircle with all supported cards and also the
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
*
* Revision 1.3 1999/07/01 08:22:58 keil
* compatibility macros now in <linux/isdn_compat.h>
*
* Revision 1.2 1999/06/21 15:24:13 calle
* extend information in /proc.
*
* Revision 1.1 1997/03/04 21:50:30 calle
* Frirst version in isdn4linux
*
* Revision 2.2 1997/02/12 09:31:39 calle
* new version
*
* Revision 1.1 1997/01/31 10:32:20 calle
* Initial revision
*
*/
struct capidev {
struct capidev *next;
struct file *file;
__u16 applid;
__u16 errcode;
unsigned int minor;
struct sk_buff_head recv_queue;
#ifdef COMPAT_HAS_NEW_WAITQ
wait_queue_head_t recv_wait;
#else
struct wait_queue *recv_wait;
#endif
/* Statistic */
unsigned long nrecvctlpkt;
unsigned long nrecvdatapkt;
unsigned long nsentctlpkt;
unsigned long nsentdatapkt;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,155 +0,0 @@
/*
* $Id$
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.1.2.1 1998/03/20 14:38:28 calle
* capidrv: prepared state machines for suspend/resume/hold
* capidrv: fix bug in state machine if B1/T1 is out of nccis
* b1capi: changed some errno returns.
* b1capi: detect if you try to add same T1 to different io address.
* b1capi: change number of nccis depending on number of channels.
* b1lli: cosmetics
*
* Revision 1.1 1997/03/04 21:50:33 calle
* Frirst version in isdn4linux
*
* Revision 2.2 1997/02/12 09:31:39 calle
* new version
*
* Revision 1.1 1997/01/31 10:32:20 calle
* Initial revision
*
*/
#ifndef __CAPIDRV_H__
#define __CAPIDRV_H__
/*
* LISTEN state machine
*/
#define ST_LISTEN_NONE 0 /* L-0 */
#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */
#define ST_LISTEN_ACTIVE 2 /* L-1 */
#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */
#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1
L-1 -> L-1.1 */
#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0
L-1.1 -> L-1 */
#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0
L-1.1 -> L-0 */
#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1
L-1.1 -> L.1 */
/*
* per plci state machine
*/
#define ST_PLCI_NONE 0 /* P-0 */
#define ST_PLCI_OUTGOING 1 /* P-0.1 */
#define ST_PLCI_ALLOCATED 2 /* P-1 */
#define ST_PLCI_ACTIVE 3 /* P-ACT */
#define ST_PLCI_INCOMING 4 /* P-2 */
#define ST_PLCI_FACILITY_IND 5 /* P-3 */
#define ST_PLCI_ACCEPTING 6 /* P-4 */
#define ST_PLCI_DISCONNECTING 7 /* P-5 */
#define ST_PLCI_DISCONNECTED 8 /* P-6 */
#define ST_PLCI_RESUMEING 9 /* P-0.Res */
#define ST_PLCI_RESUME 10 /* P-Res */
#define ST_PLCI_HELD 11 /* P-HELD */
#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1
*/
#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0
*/
#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1
*/
#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1
*/
#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2
*/
#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT
*/
#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5
P-3 -> P-5
*/
#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5
P-2 -> P-5
P-3 -> P-5
P-4 -> P-5
P-ACT -> P-5
P-Res -> P-5 (*)
P-HELD -> P-5 (*)
*/
#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6
P-2 -> P-6
P-3 -> P-6
P-4 -> P-6
P-5 -> P-6
P-ACT -> P-6
P-Res -> P-6 (*)
P-HELD -> P-6 (*)
*/
#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5
P-1 -> P-5
P-ACT -> P-5
P-2 -> P-5
P-3 -> P-5
P-4 -> P-5
*/
#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0
*/
#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0
*/
#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res
*/
#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res
*/
#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0
*/
#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT
*/
#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD
*/
#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT
*/
#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5
*/
#define EV_PLCI_CD_IND 20 /* P-2 -> P-5
*/
/*
* per ncci state machine
*/
#define ST_NCCI_PREVIOUS -1
#define ST_NCCI_NONE 0 /* N-0 */
#define ST_NCCI_OUTGOING 1 /* N-0.1 */
#define ST_NCCI_INCOMING 2 /* N-1 */
#define ST_NCCI_ALLOCATED 3 /* N-2 */
#define ST_NCCI_ACTIVE 4 /* N-ACT */
#define ST_NCCI_RESETING 5 /* N-3 */
#define ST_NCCI_DISCONNECTING 6 /* N-4 */
#define ST_NCCI_DISCONNECTED 7 /* N-5 */
#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */
#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */
#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */
#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */
#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */
#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */
#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */
#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */
#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */
#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */
#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */
#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4
N-2 -> N-4
N-3 -> N-4
N-ACT -> N-4 */
#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */
#endif /* __CAPIDRV_H__ */

View File

@ -1,609 +0,0 @@
/*
* $Id$
*
* (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
*
* Heavily based on devpts filesystem from H. Peter Anvin
*
* $Log$
* Revision 1.1 2000/03/03 16:48:38 calle
* - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
* It is now possible to create a connection with a CAPI2.0 applikation
* and than to handle the data connection from /dev/capi/ (capifs) and also
* using async or sync PPP on this connection.
* The two major device number 190 and 191 are not confirmed yet,
* but I want to save the code in cvs, before I go on.
*
*
*/
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/param.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/kernel.h>
#include <linux/locks.h>
#include <linux/major.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/tty.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
static char *revision = "$Revision$";
struct capifs_ncci {
struct inode *inode;
u16 applid;
u32 ncci;
char type[4];
};
struct capifs_sb_info {
u32 magic;
struct super_block *next;
struct super_block **back;
int setuid;
int setgid;
uid_t uid;
gid_t gid;
umode_t mode;
unsigned int max_ncci;
struct capifs_ncci *nccis;
};
#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
#define CAPIFS_SBI_MAGIC (('C'<<24)|('A'<<16)|('P'<<8)|'I')
static inline struct capifs_sb_info *SBI(struct super_block *sb)
{
return (struct capifs_sb_info *)(sb->u.generic_sbp);
}
/* ------------------------------------------------------------------ */
static int capifs_root_readdir(struct file *,void *,filldir_t);
static struct dentry *capifs_root_lookup(struct inode *,struct dentry *);
static int capifs_revalidate(struct dentry *, int);
static struct file_operations capifs_root_operations = {
NULL, /* llseek */
NULL, /* read */
NULL, /* write */
capifs_root_readdir, /* readdir */
};
struct inode_operations capifs_root_inode_operations = {
&capifs_root_operations, /* file operations */
NULL, /* create */
capifs_root_lookup, /* lookup */
};
static struct dentry_operations capifs_dentry_operations = {
capifs_revalidate, /* d_revalidate */
NULL, /* d_hash */
NULL, /* d_compare */
};
/*
* The normal naming convention is simply
* /dev/capi/tty<appl>-<ncci>
* /dev/capi/raw<appl>-<ncci>
*/
static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct inode * inode = filp->f_dentry->d_inode;
struct capifs_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb);
off_t nr;
char numbuf[32];
nr = filp->f_pos;
switch(nr)
{
case 0:
if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
case 1:
if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
return 0;
filp->f_pos = ++nr;
/* fall through */
default:
while ( nr < sbi->max_ncci ) {
int n = nr - 2;
if ( sbi->nccis[n].inode ) {
memcpy(numbuf, sbi->nccis[n].type, 3);
sprintf(numbuf+3, "%u-%x",
sbi->nccis[n].applid,
sbi->nccis[n].ncci);
if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
return 0;
}
filp->f_pos = ++nr;
}
break;
}
return 0;
}
/*
* Revalidate is called on every cache lookup. We use it to check that
* the ncci really does still exist. Never revalidate negative dentries;
* for simplicity (fix later?)
*/
static int capifs_revalidate(struct dentry * dentry, int flags)
{
struct capifs_sb_info *sbi;
if ( !dentry->d_inode )
return 0;
sbi = SBI(dentry->d_inode->i_sb);
return ( sbi->nccis[dentry->d_inode->i_ino - 2].inode == dentry->d_inode );
}
static struct dentry *capifs_root_lookup(struct inode * dir, struct dentry * dentry)
{
struct capifs_sb_info *sbi = SBI(dir->i_sb);
struct capifs_ncci *np;
unsigned int i;
char numbuf[32];
const char *p;
char *tmp;
u16 applid;
u32 ncci;
dentry->d_inode = NULL; /* Assume failure */
dentry->d_op = &capifs_dentry_operations;
if ( dentry->d_name.len < 6 || dentry->d_name.len >= sizeof(numbuf) )
return NULL;
strncpy(numbuf, dentry->d_name.name, dentry->d_name.len);
numbuf[dentry->d_name.len] = 0;
p = tmp = numbuf+3;
applid = (u16)simple_strtoul(p, &tmp, 10);
if (applid == 0 || tmp == p || *tmp != '-')
return NULL;
p = ++tmp;
ncci = (u32)simple_strtoul(p, &tmp, 16);
if (ncci == 0 || tmp == p || *tmp)
return NULL;
for (i = 0, np = sbi->nccis ; i < sbi->max_ncci; i++, np++) {
if (np->applid == applid && np->ncci == ncci
&& memcmp(numbuf, np->type, 3) == 0)
break;
}
if ( i >= sbi->max_ncci )
return NULL;
dentry->d_inode = np->inode;
if ( dentry->d_inode )
dentry->d_inode->i_count++;
d_add(dentry, dentry->d_inode);
return NULL;
}
/* ------------------------------------------------------------------ */
static struct super_block *mounts = NULL;
static void capifs_put_super(struct super_block *sb)
{
struct capifs_sb_info *sbi = SBI(sb);
struct inode *inode;
int i;
for ( i = 0 ; i < sbi->max_ncci ; i++ ) {
if ( (inode = sbi->nccis[i].inode) ) {
if ( inode->i_count != 1 )
printk("capifs_put_super: badness: entry %d count %d\n",
i, inode->i_count);
inode->i_nlink--;
iput(inode);
}
}
*sbi->back = sbi->next;
if ( sbi->next )
SBI(sbi->next)->back = sbi->back;
kfree(sbi->nccis);
kfree(sbi);
MOD_DEC_USE_COUNT;
}
static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
static void capifs_read_inode(struct inode *inode);
static void capifs_write_inode(struct inode *inode);
static struct super_operations capifs_sops = {
capifs_read_inode,
capifs_write_inode,
NULL, /* put_inode */
NULL, /* delete_inode */
NULL, /* notify_change */
capifs_put_super,
NULL, /* write_super */
capifs_statfs,
NULL, /* remount_fs */
NULL, /* clear_inode */
};
static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
{
int setuid = 0;
int setgid = 0;
uid_t uid = 0;
gid_t gid = 0;
umode_t mode = 0600;
unsigned int maxncci = 512;
char *this_char, *value;
this_char = NULL;
if ( options )
this_char = strtok(options,",");
for ( ; this_char; this_char = strtok(NULL,",")) {
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"uid")) {
if (!value || !*value)
return 1;
uid = simple_strtoul(value,&value,0);
if (*value)
return 1;
setuid = 1;
}
else if (!strcmp(this_char,"gid")) {
if (!value || !*value)
return 1;
gid = simple_strtoul(value,&value,0);
if (*value)
return 1;
setgid = 1;
}
else if (!strcmp(this_char,"mode")) {
if (!value || !*value)
return 1;
mode = simple_strtoul(value,&value,8);
if (*value)
return 1;
}
else if (!strcmp(this_char,"maxncci")) {
if (!value || !*value)
return 1;
maxncci = simple_strtoul(value,&value,8);
if (*value)
return 1;
}
else
return 1;
}
sbi->setuid = setuid;
sbi->setgid = setgid;
sbi->uid = uid;
sbi->gid = gid;
sbi->mode = mode & ~S_IFMT;
sbi->max_ncci = maxncci;
return 0;
}
struct super_block *capifs_read_super(struct super_block *s, void *data,
int silent)
{
struct inode * root_inode;
struct dentry * root;
struct capifs_sb_info *sbi;
MOD_INC_USE_COUNT;
lock_super(s);
/* Super block already completed? */
if (s->s_root) {
unlock_super(s);
goto out;
}
sbi = (struct capifs_sb_info *) kmalloc(sizeof(struct capifs_sb_info), GFP_KERNEL);
if ( !sbi ) {
unlock_super(s);
goto fail;
}
memset(sbi, 0, sizeof(struct capifs_sb_info));
sbi->magic = CAPIFS_SBI_MAGIC;
/* Can this call block? (It shouldn't) */
if ( capifs_parse_options(data,sbi) ) {
kfree(sbi);
unlock_super(s);
printk("capifs: called with bogus options\n");
goto fail;
}
sbi->nccis = kmalloc(sizeof(struct capifs_ncci) * sbi->max_ncci, GFP_KERNEL);
if ( !sbi->nccis ) {
kfree(sbi);
unlock_super(s);
goto fail;
}
memset(sbi->nccis, 0, sizeof(struct capifs_ncci) * sbi->max_ncci);
s->u.generic_sbp = (void *) sbi;
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = CAPIFS_SUPER_MAGIC;
s->s_op = &capifs_sops;
s->s_root = NULL;
unlock_super(s); /* shouldn't we keep it locked a while longer? */
/*
* Get the root inode and dentry, but defer checking for errors.
*/
root_inode = iget(s, 1); /* inode 1 == root directory */
#ifdef COMPAT_d_alloc_root_one_parameter
root = d_alloc_root(root_inode);
#else
root = d_alloc_root(root_inode, NULL);
#endif
/*
* Check whether somebody else completed the super block.
*/
if (s->s_root) {
if (root) dput(root);
else iput(root_inode);
goto out;
}
if (!root) {
printk("capifs: get root dentry failed\n");
/*
* iput() can block, so we clear the super block first.
*/
s->s_dev = 0;
iput(root_inode);
kfree(sbi->nccis);
kfree(sbi);
goto fail;
}
/*
* Check whether somebody else completed the super block.
*/
if (s->s_root)
goto out;
/*
* Success! Install the root dentry now to indicate completion.
*/
lock_super(s);
s->s_root = root;
sbi->next = mounts;
if ( sbi->next )
SBI(sbi->next)->back = &(sbi->next);
sbi->back = &mounts;
mounts = s;
unlock_super(s);
return s;
/*
* Success ... somebody else completed the super block for us.
*/
out:
MOD_DEC_USE_COUNT;
return s;
fail:
s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
tmp.f_type = CAPIFS_SUPER_MAGIC;
tmp.f_bsize = 1024;
tmp.f_blocks = 0;
tmp.f_bfree = 0;
tmp.f_bavail = 0;
tmp.f_files = 0;
tmp.f_ffree = 0;
tmp.f_namelen = NAME_MAX;
return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
static void capifs_read_inode(struct inode *inode)
{
ino_t ino = inode->i_ino;
struct capifs_sb_info *sbi = SBI(inode->i_sb);
inode->i_op = NULL;
inode->i_mode = 0;
inode->i_nlink = 0;
inode->i_size = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
inode->i_blksize = 1024;
inode->i_uid = inode->i_gid = 0;
if ( ino == 1 ) {
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &capifs_root_inode_operations;
inode->i_nlink = 2;
return;
}
ino -= 2;
if ( ino >= sbi->max_ncci )
return; /* Bogus */
#ifdef COMPAT_HAS_init_special_inode
/* Gets filled in by capifs_new_ncci() */
init_special_inode(inode,S_IFCHR,0);
#else
inode->i_mode = S_IFCHR;
inode->i_rdev = MKDEV(0,0); /* Gets filled in by devpts_pty_new() */
inode->i_op = &chrdev_inode_operations;
#endif
return;
}
static void capifs_write_inode(struct inode *inode)
{
}
static struct file_system_type capifs_fs_type = {
"capifs",
0,
capifs_read_super,
NULL
};
void capifs_new_ncci(__u16 applid, __u32 ncci, char *type, kdev_t device)
{
struct super_block *sb;
struct capifs_sb_info *sbi;
struct capifs_ncci *np;
char stype[4];
char *s = type;
ino_t ino;
int i;
for (i=0; i < 3; i++) {
if (*s)
stype[i] = *s++;
else
stype[i] = '-';
}
stype[3] = 0;
for ( sb = mounts ; sb ; sb = sbi->next ) {
sbi = SBI(sb);
for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
if (np->applid == 0 && np->ncci == 0) {
np->applid = applid;
np->ncci = ncci;
memcpy(np->type, stype, 4);
break;
}
}
if ((np->inode = iget(sb, ino+2)) != 0) {
struct inode *inode = np->inode;
inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
inode->i_mode = sbi->mode | S_IFCHR;
inode->i_rdev = device;
inode->i_nlink++;
}
}
}
void capifs_free_ncci(__u16 applid, __u32 ncci, char *type)
{
struct super_block *sb;
struct capifs_sb_info *sbi;
struct inode *inode;
struct capifs_ncci *np;
char stype[4];
char *s = type;
ino_t ino;
int i;
for (i=0; i < 3; i++) {
if (*s)
stype[i] = *s++;
else
stype[i] = '-';
}
stype[3] = 0;
for ( sb = mounts ; sb ; sb = sbi->next ) {
sbi = SBI(sb);
for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
if (np->applid != applid || np->ncci != ncci)
continue;
if (np->inode && memcmp(stype, np->type, 4) == 0) {
inode = np->inode;
memset(np, 0, sizeof(struct capifs_ncci));
inode->i_nlink--;
iput(inode);
break;
}
}
}
}
int __init capifs_init(void)
{
char rev[10];
char *p;
int err;
if ((p = strchr(revision, ':'))) {
strcpy(rev, p + 1);
p = strchr(rev, '$');
*p = 0;
} else
strcpy(rev, "1.0");
err = register_filesystem(&capifs_fs_type);
if (err)
return err;
#ifdef MODULE
printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev);
#else
printk(KERN_NOTICE "capifs: Rev%s: started\n", rev);
#endif
return 0;
}
void capifs_exit(void)
{
unregister_filesystem(&capifs_fs_type);
}
EXPORT_SYMBOL(capifs_new_ncci);
EXPORT_SYMBOL(capifs_free_ncci);
#ifdef MODULE
int init_module(void)
{
return capifs_init();
}
void cleanup_module(void)
{
capifs_exit();
}
#endif

View File

@ -1,19 +0,0 @@
/*
* $Id$
*
* (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
*
* $Log$
* Revision 1.1 2000/03/03 16:48:38 calle
* - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
* It is now possible to create a connection with a CAPI2.0 applikation
* and than to handle the data connection from /dev/capi/ (capifs) and also
* using async or sync PPP on this connection.
* The two major device number 190 and 191 are not confirmed yet,
* but I want to save the code in cvs, before I go on.
*
*
*/
void capifs_new_ncci(__u16 applid, __u32 ncci, char *type, kdev_t device);
void capifs_free_ncci(__u16 applid, __u32 ncci, char *type);

View File

@ -1,110 +0,0 @@
/*
* $Id$
*
* Kernel CAPI 2.0 Driver Interface for Linux
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
*/
#ifndef __CAPILLI_H__
#define __CAPILLI_H__
typedef struct capiloaddatapart {
int user; /* data in userspace ? */
int len;
unsigned char *data;
} capiloaddatapart;
typedef struct capiloaddata {
capiloaddatapart firmware;
capiloaddatapart configuration;
} capiloaddata;
typedef struct capicardparams {
unsigned int port;
unsigned irq;
int cardtype;
int cardnr;
unsigned int membase;
} capicardparams;
struct capi_driver;
struct capi_ctr {
struct capi_ctr *next; /* next ctr of same driver */
struct capi_driver *driver;
int cnr; /* controller number */
char name[32]; /* name of controller */
volatile unsigned short cardstate; /* controller state */
volatile int blocked; /* output blocked */
int traceflag; /* capi trace */
void *driverdata; /* driver specific */
/* filled before calling ready callback */
__u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */
capi_version version; /* CAPI_GET_VERSION */
capi_profile profile; /* CAPI_GET_PROFILE */
__u8 serial[CAPI_SERIAL_LEN]; /* CAPI_GET_SERIAL */
/* functions */
void (*ready)(struct capi_ctr * card);
void (*reseted)(struct capi_ctr * card);
void (*suspend_output)(struct capi_ctr * card);
void (*resume_output)(struct capi_ctr * card);
void (*handle_capimsg)(struct capi_ctr * card,
__u16 appl, struct sk_buff *skb);
void (*appl_registered)(struct capi_ctr * card, __u16 appl);
void (*appl_released)(struct capi_ctr * card, __u16 appl);
void (*new_ncci)(struct capi_ctr * card,
__u16 appl, __u32 ncci, __u32 winsize);
void (*free_ncci)(struct capi_ctr * card, __u16 appl, __u32 ncci);
/* management information for kcapi */
unsigned long nrecvctlpkt;
unsigned long nrecvdatapkt;
unsigned long nsentctlpkt;
unsigned long nsentdatapkt;
struct proc_dir_entry *procent;
char procfn[128];
};
struct capi_driver_interface {
struct capi_ctr *(*attach_ctr)(struct capi_driver *driver, char *name, void *data);
int (*detach_ctr)(struct capi_ctr *);
};
struct capi_driver {
char name[32]; /* driver name */
char revision[32];
int (*load_firmware)(struct capi_ctr *, capiloaddata *);
void (*reset_ctr)(struct capi_ctr *);
void (*remove_ctr)(struct capi_ctr *);
void (*register_appl)(struct capi_ctr *, __u16 appl,
capi_register_params *);
void (*release_appl)(struct capi_ctr *, __u16 appl);
void (*send_message)(struct capi_ctr *, struct sk_buff *skb);
char *(*procinfo)(struct capi_ctr *);
int (*ctr_read_proc)(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *card);
int (*driver_read_proc)(char *page, char **start, off_t off,
int count, int *eof, struct capi_driver *driver);
int (*add_card)(struct capi_driver *driver, capicardparams *data);
/* intitialized by kcapi */
struct capi_ctr *controller; /* list of controllers */
struct capi_driver *next;
int ncontroller;
struct proc_dir_entry *procent;
char procfn[128];
};
struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver);
void detach_capi_driver(struct capi_driver *driver);
#endif /* __CAPILLI_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,537 +0,0 @@
/*
* $Id$
*
* CAPI 2.0 defines & types
*
* From CAPI 2.0 Development Kit AVM 1995 (capi20.h)
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.5 2000/03/03 15:50:42 calle
* - kernel CAPI:
* - Changed parameter "param" in capi_signal from __u32 to void *.
* - rewrote notifier handling in kcapi.c
* - new notifier NCCI_UP and NCCI_DOWN
* - User CAPI:
* - /dev/capi20 is now a cloning device.
* - middleware extentions prepared.
* - capidrv.c
* - locking of list operations and module count updates.
*
* Revision 1.4 1999/09/15 08:16:03 calle
* Implementation of 64Bit extention complete.
*
* Revision 1.3 1999/09/07 09:02:53 calle
* SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
* DATA_B3_IND is always directly after the CAPI message. The "Data" member
* ist never used inside the kernel.
*
* Revision 1.2 1997/05/18 09:24:19 calle
* added verbose disconnect reason reporting to avmb1.
* some fixes in capi20 interface.
* changed info messages for B1-PCI
*
* Revision 1.1 1997/03/04 21:50:35 calle
* Frirst version in isdn4linux
*
* Revision 2.2 1997/02/12 09:31:39 calle
* new version
*
* Revision 1.1 1997/01/31 10:32:20 calle
* Initial revision
*
*
*/
#ifndef __CAPIUTIL_H__
#define __CAPIUTIL_H__
#include <asm/types.h>
#define CAPIMSG_BASELEN 8
#define CAPIMSG_U8(m, off) (m[off])
#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8))
#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24))
#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0)
#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2)
#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4)
#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5)
#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5]))
#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6)
#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f)
#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8)
#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m)
#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */
static inline void capimsg_setu8(void *m, int off, __u8 val)
{
((__u8 *)m)[off] = val;
}
static inline void capimsg_setu16(void *m, int off, __u16 val)
{
((__u8 *)m)[off] = val & 0xff;
((__u8 *)m)[off+1] = (val >> 8) & 0xff;
}
static inline void capimsg_setu32(void *m, int off, __u32 val)
{
((__u8 *)m)[off] = val & 0xff;
((__u8 *)m)[off+1] = (val >> 8) & 0xff;
((__u8 *)m)[off+2] = (val >> 16) & 0xff;
((__u8 *)m)[off+3] = (val >> 24) & 0xff;
}
#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len)
#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid)
#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd)
#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd)
#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid)
#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr)
#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len)
/*----- basic-type definitions -----*/
typedef __u8 *_cstruct;
typedef enum {
CAPI_COMPOSE,
CAPI_DEFAULT
} _cmstruct;
/*
The _cmsg structure contains all possible CAPI 2.0 parameter.
All parameters are stored here first. The function CAPI_CMSG_2_MESSAGE
assembles the parameter and builds CAPI2.0 conform messages.
CAPI_MESSAGE_2_CMSG disassembles CAPI 2.0 messages and stores the
parameter in the _cmsg structure
*/
typedef struct {
/* Header */
__u16 ApplId;
__u8 Command;
__u8 Subcommand;
__u16 Messagenumber;
/* Parameter */
union {
__u32 adrController;
__u32 adrPLCI;
__u32 adrNCCI;
} adr;
_cmstruct AdditionalInfo;
_cstruct B1configuration;
__u16 B1protocol;
_cstruct B2configuration;
__u16 B2protocol;
_cstruct B3configuration;
__u16 B3protocol;
_cstruct BC;
_cstruct BChannelinformation;
_cmstruct BProtocol;
_cstruct CalledPartyNumber;
_cstruct CalledPartySubaddress;
_cstruct CallingPartyNumber;
_cstruct CallingPartySubaddress;
__u32 CIPmask;
__u32 CIPmask2;
__u16 CIPValue;
__u32 Class;
_cstruct ConnectedNumber;
_cstruct ConnectedSubaddress;
__u32 Data;
__u16 DataHandle;
__u16 DataLength;
_cstruct FacilityConfirmationParameter;
_cstruct Facilitydataarray;
_cstruct FacilityIndicationParameter;
_cstruct FacilityRequestParameter;
__u16 FacilitySelector;
__u16 Flags;
__u32 Function;
_cstruct HLC;
__u16 Info;
_cstruct InfoElement;
__u32 InfoMask;
__u16 InfoNumber;
_cstruct Keypadfacility;
_cstruct LLC;
_cstruct ManuData;
__u32 ManuID;
_cstruct NCPI;
__u16 Reason;
__u16 Reason_B3;
__u16 Reject;
_cstruct Useruserdata;
/* intern */
unsigned l, p;
unsigned char *par;
__u8 *m;
/* buffer to construct message */
__u8 buf[180];
} _cmsg;
/*
* capi_cmsg2message() assembles the parameter from _cmsg to a CAPI 2.0
* conform message
*/
unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg);
/*
* capi_message2cmsg disassembles a CAPI message an writes the parameter
* into _cmsg for easy access
*/
unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg);
/*
* capi_cmsg_header() fills the _cmsg structure with default values, so only
* parameter with non default values must be changed before sending the
* message.
*/
unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId,
__u8 _Command, __u8 _Subcommand,
__u16 _Messagenumber, __u32 _Controller);
/*
* capi_info2str generated a readable string for Capi2.0 reasons.
*/
char *capi_info2str(__u16 reason);
/*-----------------------------------------------------------------------*/
/*
* Debugging / Tracing functions
*/
char *capi_cmd2str(__u8 cmd, __u8 subcmd);
char *capi_cmsg2str(_cmsg * cmsg);
char *capi_message2str(__u8 * msg);
/*-----------------------------------------------------------------------*/
static inline void capi_cmsg_answer(_cmsg * cmsg)
{
cmsg->Subcommand |= 0x01;
}
/*-----------------------------------------------------------------------*/
static inline void capi_fill_CONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
_cstruct NCPI)
{
capi_cmsg_header(cmsg, ApplId, 0x82, 0x80, Messagenumber, adr);
cmsg->NCPI = NCPI;
}
static inline void capi_fill_FACILITY_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u16 FacilitySelector,
_cstruct FacilityRequestParameter)
{
capi_cmsg_header(cmsg, ApplId, 0x80, 0x80, Messagenumber, adr);
cmsg->FacilitySelector = FacilitySelector;
cmsg->FacilityRequestParameter = FacilityRequestParameter;
}
static inline void capi_fill_INFO_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
_cstruct CalledPartyNumber,
_cstruct BChannelinformation,
_cstruct Keypadfacility,
_cstruct Useruserdata,
_cstruct Facilitydataarray)
{
capi_cmsg_header(cmsg, ApplId, 0x08, 0x80, Messagenumber, adr);
cmsg->CalledPartyNumber = CalledPartyNumber;
cmsg->BChannelinformation = BChannelinformation;
cmsg->Keypadfacility = Keypadfacility;
cmsg->Useruserdata = Useruserdata;
cmsg->Facilitydataarray = Facilitydataarray;
}
static inline void capi_fill_LISTEN_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u32 InfoMask,
__u32 CIPmask,
__u32 CIPmask2,
_cstruct CallingPartyNumber,
_cstruct CallingPartySubaddress)
{
capi_cmsg_header(cmsg, ApplId, 0x05, 0x80, Messagenumber, adr);
cmsg->InfoMask = InfoMask;
cmsg->CIPmask = CIPmask;
cmsg->CIPmask2 = CIPmask2;
cmsg->CallingPartyNumber = CallingPartyNumber;
cmsg->CallingPartySubaddress = CallingPartySubaddress;
}
static inline void capi_fill_ALERT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
_cstruct BChannelinformation,
_cstruct Keypadfacility,
_cstruct Useruserdata,
_cstruct Facilitydataarray)
{
capi_cmsg_header(cmsg, ApplId, 0x01, 0x80, Messagenumber, adr);
cmsg->BChannelinformation = BChannelinformation;
cmsg->Keypadfacility = Keypadfacility;
cmsg->Useruserdata = Useruserdata;
cmsg->Facilitydataarray = Facilitydataarray;
}
static inline void capi_fill_CONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u16 CIPValue,
_cstruct CalledPartyNumber,
_cstruct CallingPartyNumber,
_cstruct CalledPartySubaddress,
_cstruct CallingPartySubaddress,
__u16 B1protocol,
__u16 B2protocol,
__u16 B3protocol,
_cstruct B1configuration,
_cstruct B2configuration,
_cstruct B3configuration,
_cstruct BC,
_cstruct LLC,
_cstruct HLC,
_cstruct BChannelinformation,
_cstruct Keypadfacility,
_cstruct Useruserdata,
_cstruct Facilitydataarray)
{
capi_cmsg_header(cmsg, ApplId, 0x02, 0x80, Messagenumber, adr);
cmsg->CIPValue = CIPValue;
cmsg->CalledPartyNumber = CalledPartyNumber;
cmsg->CallingPartyNumber = CallingPartyNumber;
cmsg->CalledPartySubaddress = CalledPartySubaddress;
cmsg->CallingPartySubaddress = CallingPartySubaddress;
cmsg->B1protocol = B1protocol;
cmsg->B2protocol = B2protocol;
cmsg->B3protocol = B3protocol;
cmsg->B1configuration = B1configuration;
cmsg->B2configuration = B2configuration;
cmsg->B3configuration = B3configuration;
cmsg->BC = BC;
cmsg->LLC = LLC;
cmsg->HLC = HLC;
cmsg->BChannelinformation = BChannelinformation;
cmsg->Keypadfacility = Keypadfacility;
cmsg->Useruserdata = Useruserdata;
cmsg->Facilitydataarray = Facilitydataarray;
}
static inline void capi_fill_DATA_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u32 Data,
__u16 DataLength,
__u16 DataHandle,
__u16 Flags)
{
capi_cmsg_header(cmsg, ApplId, 0x86, 0x80, Messagenumber, adr);
cmsg->Data = Data;
cmsg->DataLength = DataLength;
cmsg->DataHandle = DataHandle;
cmsg->Flags = Flags;
}
static inline void capi_fill_DISCONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
_cstruct BChannelinformation,
_cstruct Keypadfacility,
_cstruct Useruserdata,
_cstruct Facilitydataarray)
{
capi_cmsg_header(cmsg, ApplId, 0x04, 0x80, Messagenumber, adr);
cmsg->BChannelinformation = BChannelinformation;
cmsg->Keypadfacility = Keypadfacility;
cmsg->Useruserdata = Useruserdata;
cmsg->Facilitydataarray = Facilitydataarray;
}
static inline void capi_fill_DISCONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
_cstruct NCPI)
{
capi_cmsg_header(cmsg, ApplId, 0x84, 0x80, Messagenumber, adr);
cmsg->NCPI = NCPI;
}
static inline void capi_fill_MANUFACTURER_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u32 ManuID,
__u32 Class,
__u32 Function,
_cstruct ManuData)
{
capi_cmsg_header(cmsg, ApplId, 0xff, 0x80, Messagenumber, adr);
cmsg->ManuID = ManuID;
cmsg->Class = Class;
cmsg->Function = Function;
cmsg->ManuData = ManuData;
}
static inline void capi_fill_RESET_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
_cstruct NCPI)
{
capi_cmsg_header(cmsg, ApplId, 0x87, 0x80, Messagenumber, adr);
cmsg->NCPI = NCPI;
}
static inline void capi_fill_SELECT_B_PROTOCOL_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u16 B1protocol,
__u16 B2protocol,
__u16 B3protocol,
_cstruct B1configuration,
_cstruct B2configuration,
_cstruct B3configuration)
{
capi_cmsg_header(cmsg, ApplId, 0x41, 0x80, Messagenumber, adr);
cmsg->B1protocol = B1protocol;
cmsg->B2protocol = B2protocol;
cmsg->B3protocol = B3protocol;
cmsg->B1configuration = B1configuration;
cmsg->B2configuration = B2configuration;
cmsg->B3configuration = B3configuration;
}
static inline void capi_fill_CONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u16 Reject,
__u16 B1protocol,
__u16 B2protocol,
__u16 B3protocol,
_cstruct B1configuration,
_cstruct B2configuration,
_cstruct B3configuration,
_cstruct ConnectedNumber,
_cstruct ConnectedSubaddress,
_cstruct LLC,
_cstruct BChannelinformation,
_cstruct Keypadfacility,
_cstruct Useruserdata,
_cstruct Facilitydataarray)
{
capi_cmsg_header(cmsg, ApplId, 0x02, 0x83, Messagenumber, adr);
cmsg->Reject = Reject;
cmsg->B1protocol = B1protocol;
cmsg->B2protocol = B2protocol;
cmsg->B3protocol = B3protocol;
cmsg->B1configuration = B1configuration;
cmsg->B2configuration = B2configuration;
cmsg->B3configuration = B3configuration;
cmsg->ConnectedNumber = ConnectedNumber;
cmsg->ConnectedSubaddress = ConnectedSubaddress;
cmsg->LLC = LLC;
cmsg->BChannelinformation = BChannelinformation;
cmsg->Keypadfacility = Keypadfacility;
cmsg->Useruserdata = Useruserdata;
cmsg->Facilitydataarray = Facilitydataarray;
}
static inline void capi_fill_CONNECT_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr)
{
capi_cmsg_header(cmsg, ApplId, 0x03, 0x83, Messagenumber, adr);
}
static inline void capi_fill_CONNECT_B3_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr)
{
capi_cmsg_header(cmsg, ApplId, 0x83, 0x83, Messagenumber, adr);
}
static inline void capi_fill_CONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u16 Reject,
_cstruct NCPI)
{
capi_cmsg_header(cmsg, ApplId, 0x82, 0x83, Messagenumber, adr);
cmsg->Reject = Reject;
cmsg->NCPI = NCPI;
}
static inline void capi_fill_CONNECT_B3_T90_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr)
{
capi_cmsg_header(cmsg, ApplId, 0x88, 0x83, Messagenumber, adr);
}
static inline void capi_fill_DATA_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u16 DataHandle)
{
capi_cmsg_header(cmsg, ApplId, 0x86, 0x83, Messagenumber, adr);
cmsg->DataHandle = DataHandle;
}
static inline void capi_fill_DISCONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr)
{
capi_cmsg_header(cmsg, ApplId, 0x84, 0x83, Messagenumber, adr);
}
static inline void capi_fill_DISCONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr)
{
capi_cmsg_header(cmsg, ApplId, 0x04, 0x83, Messagenumber, adr);
}
static inline void capi_fill_FACILITY_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u16 FacilitySelector)
{
capi_cmsg_header(cmsg, ApplId, 0x80, 0x83, Messagenumber, adr);
cmsg->FacilitySelector = FacilitySelector;
}
static inline void capi_fill_INFO_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr)
{
capi_cmsg_header(cmsg, ApplId, 0x08, 0x83, Messagenumber, adr);
}
static inline void capi_fill_MANUFACTURER_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr,
__u32 ManuID,
__u32 Class,
__u32 Function,
_cstruct ManuData)
{
capi_cmsg_header(cmsg, ApplId, 0xff, 0x83, Messagenumber, adr);
cmsg->ManuID = ManuID;
cmsg->Class = Class;
cmsg->Function = Function;
cmsg->ManuData = ManuData;
}
static inline void capi_fill_RESET_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
__u32 adr)
{
capi_cmsg_header(cmsg, ApplId, 0x87, 0x83, Messagenumber, adr);
}
#endif /* __CAPIUTIL_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,622 +0,0 @@
/*
* $Id$
*
* Module for AVM T1 HEMA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.9 2000/01/25 14:37:39 calle
* new message after successfull detection including card revision and
* used resources.
*
* Revision 1.8 1999/11/05 16:38:01 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
* constant string.
* - Moved some data from struct avmcard into new struct avmctrl_info.
* Changed all lowlevel capi driver to match the new structur.
*
* Revision 1.7 1999/09/15 08:16:03 calle
* Implementation of 64Bit extention complete.
*
* Revision 1.6 1999/09/07 09:02:53 calle
* SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
* DATA_B3_IND is always directly after the CAPI message. The "Data" member
* ist never used inside the kernel.
*
* Revision 1.5 1999/08/22 20:26:28 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.4 1999/07/09 15:05:50 keil
* compat.h is now isdn_compat.h
*
* Revision 1.3 1999/07/06 07:42:04 calle
* - changes in /proc interface
* - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
*
* Revision 1.2 1999/07/05 15:09:54 calle
* - renamed "appl_release" to "appl_released".
* - version und profile data now cleared on controller reset
* - extended /proc interface, to allow driver and controller specific
* informations to include by driver hackers.
*
* Revision 1.1 1999/07/01 15:26:44 calle
* complete new version (I love it):
* + new hardware independed "capi_driver" interface that will make it easy to:
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
* - write a CAPI-2.0 for the passive cards
* - support serial link CAPI-2.0 boxes.
* + wrote "capi_driver" for all supported cards.
* + "capi_driver" (supported cards) now have to be configured with
* make menuconfig, in the past all supported cards where included
* at once.
* + new and better informations in /proc/capi/
* + new ioctl to switch trace of capi messages per controller
* using "avmcapictrl trace [contr] on|off|...."
* + complete testcircle with all supported cards and also the
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
*
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <asm/io.h>
#include <linux/isdn_compat.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
static char *revision = "$Revision$";
/* ------------------------------------------------------------- */
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
/* ------------------------------------------------------------- */
static struct capi_driver_interface *di;
/* ------------------------------------------------------------- */
static int hema_irq_table[16] =
{0,
0,
0,
0x80, /* irq 3 */
0,
0x90, /* irq 5 */
0,
0xA0, /* irq 7 */
0,
0xB0, /* irq 9 */
0xC0, /* irq 10 */
0xD0, /* irq 11 */
0xE0, /* irq 12 */
0,
0,
0xF0, /* irq 15 */
};
static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
{
unsigned char cregs[8];
unsigned char reverse_cardnr;
unsigned long flags;
unsigned char dummy;
int i;
reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1)
| ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3);
cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf);
cregs[1] = 0x00; /* fast & slow link connected to CON1 */
cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */
cregs[3] = 0;
cregs[4] = 0x11; /* zero wait state */
cregs[5] = hema_irq_table[irq & 0xf];
cregs[6] = 0;
cregs[7] = 0;
save_flags(flags);
cli();
/* board reset */
t1outp(base, T1_RESETBOARD, 0xf);
udelay(100 * 1000);
dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */
/* write config */
dummy = (base >> 4) & 0xff;
for (i=1;i<=0xf;i++) t1outp(base, i, dummy);
t1outp(base, HEMA_PAL_ID & 0xf, dummy);
t1outp(base, HEMA_PAL_ID >> 4, cregs[0]);
for(i=1;i<7;i++) t1outp(base, 0, cregs[i]);
t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
restore_flags(flags);
udelay(100 * 1000);
t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
udelay(10 * 1000);
t1outp(base, T1_FASTLINK+T1_RESETLINK, 1);
t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1);
udelay(100 * 1000);
t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
udelay(10 * 1000);
t1outp(base, T1_FASTLINK+T1_ANALYSE, 0);
udelay(5 * 1000);
t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0);
if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */
return 1;
if (t1inp(base, T1_FASTLINK+T1_INSTAT) != 0x0) /* rx empty */
return 2;
if (t1inp(base, T1_FASTLINK+T1_IRQENABLE) != 0x0)
return 3;
if ((t1inp(base, T1_FASTLINK+T1_FIFOSTAT) & 0xf0) != 0x70)
return 4;
if ((t1inp(base, T1_FASTLINK+T1_IRQMASTER) & 0x0e) != 0)
return 5;
if ((t1inp(base, T1_FASTLINK+T1_IDENT) & 0x7d) != 1)
return 6;
if (t1inp(base, T1_SLOWLINK+T1_OUTSTAT) != 0x1) /* tx empty */
return 7;
if ((t1inp(base, T1_SLOWLINK+T1_IRQMASTER) & 0x0e) != 0)
return 8;
if ((t1inp(base, T1_SLOWLINK+T1_IDENT) & 0x7d) != 0)
return 9;
return 0;
}
static void t1_handle_interrupt(avmcard * card)
{
avmctrl_info *cinfo = &card->ctrlinfo[0];
struct capi_ctr *ctrl = cinfo->capi_ctrl;
unsigned char b1cmd;
struct sk_buff *skb;
unsigned ApplId;
unsigned MsgLen;
unsigned DataB3Len;
unsigned NCCI;
unsigned WindowSize;
while (b1_rx_full(card->port)) {
b1cmd = b1_get_byte(card->port);
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
DataB3Len = t1_get_slice(card->port, card->databuf);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
ctrl->handle_capimsg(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
ctrl->new_ncci(ctrl, ApplId, NCCI, WindowSize);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
if (NCCI != 0xffffffff)
ctrl->free_ncci(ctrl, ApplId, NCCI);
else ctrl->appl_released(ctrl, ApplId);
break;
case RECEIVE_START:
b1_put_byte(card->port, SEND_POLLACK);
ctrl->resume_output(ctrl);
break;
case RECEIVE_STOP:
ctrl->suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
ctrl->ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
card->msgbuf[MsgLen--] = 0;
while ( MsgLen >= 0
&& ( card->msgbuf[MsgLen] == '\n'
|| card->msgbuf[MsgLen] == '\r'))
card->msgbuf[MsgLen--] = 0;
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = t1_get_slice(card->port, card->msgbuf);
card->msgbuf[MsgLen--] = 0;
while ( MsgLen >= 0
&& ( card->msgbuf[MsgLen] == '\n'
|| card->msgbuf[MsgLen] == '\r'))
card->msgbuf[MsgLen--] = 0;
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
case 0xff:
printk(KERN_ERR "%s: card reseted ?\n", card->name);
return;
default:
printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
card->name, b1cmd);
return;
}
}
}
/* ------------------------------------------------------------- */
static void t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
{
avmcard *card;
card = (avmcard *) devptr;
if (!card) {
printk(KERN_WARNING "t1isa: interrupt: wrong device\n");
return;
}
if (card->interrupt) {
printk(KERN_ERR "%s: reentering interrupt hander.\n",
card->name);
return;
}
card->interrupt = 1;
t1_handle_interrupt(card);
card->interrupt = 0;
}
/* ------------------------------------------------------------- */
static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int retval;
t1_disable_irq(port);
b1_reset(port);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1_loaded(card)) {
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
save_flags(flags);
cli();
b1_setinterrupt(port, card->irq, card->cardtype);
b1_put_byte(port, SEND_INIT);
b1_put_word(port, AVM_NAPPS);
b1_put_word(port, AVM_NCCI_PER_CHANNEL*30);
b1_put_word(port, ctrl->cnr - 1);
restore_flags(flags);
return 0;
}
void t1isa_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
t1_disable_irq(port);
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
ctrl->reseted(ctrl);
}
static void t1isa_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
t1_disable_irq(port);
b1_reset(port);
b1_reset(port);
t1_reset(port);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
static int t1isa_add_card(struct capi_driver *driver, struct capicardparams *p)
{
struct capi_ctr *ctrl;
avmctrl_info *cinfo;
avmcard *card;
int retval;
MOD_INC_USE_COUNT;
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
cinfo->card = card;
sprintf(card->name, "t1isa-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->cardtype = avm_t1isa;
card->cardnr = p->cardnr;
if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
printk(KERN_WARNING "%s: illegal port 0x%x.\n",
driver->name, card->port);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EINVAL;
}
if (check_region(card->port, AVMB1_PORTLEN)) {
printk(KERN_WARNING
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
if (hema_irq_table[card->irq & 0xf] == 0) {
printk(KERN_WARNING "%s: irq %d not valid.\n",
driver->name, card->irq);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EINVAL;
}
for (ctrl = driver->controller; ctrl; ctrl = ctrl->next) {
avmcard *cardp = ((avmctrl_info *)(ctrl->driverdata))->card;
if (cardp->cardnr == card->cardnr) {
printk(KERN_WARNING "%s: card with number %d already installed at 0x%x.\n",
driver->name, card->cardnr, cardp->port);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
}
if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
driver->name, card->port, retval);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
}
t1_disable_irq(card->port);
b1_reset(card->port);
request_region(p->port, AVMB1_PORTLEN, card->name);
retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "%s: attach controller failed.\n",
driver->name);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
printk(KERN_INFO
"%s: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
driver->name, card->port, card->irq, card->cardnr);
return 0;
}
static void t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
__u16 len = CAPIMSG_LEN(skb->data);
__u8 cmd = CAPIMSG_COMMAND(skb->data);
__u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
save_flags(flags);
cli();
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
__u16 dlen = CAPIMSG_DATALEN(skb->data);
b1_put_byte(port, SEND_DATA_B3_REQ);
t1_put_slice(port, skb->data, len);
t1_put_slice(port, skb->data + len, dlen);
} else {
b1_put_byte(port, SEND_MESSAGE);
t1_put_slice(port, skb->data, len);
}
restore_flags(flags);
dev_kfree_skb(skb);
}
/* ------------------------------------------------------------- */
static char *t1isa_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d %d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->cardnr : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static struct capi_driver t1isa_driver = {
"t1isa",
"0.0",
t1isa_load_firmware,
t1isa_reset_ctr,
t1isa_remove_ctr,
b1_register_appl,
b1_release_appl,
t1isa_send_message,
t1isa_procinfo,
b1ctl_read_proc,
0, /* use standard driver_read_proc */
t1isa_add_card,
};
#ifdef MODULE
#define t1isa_init init_module
void cleanup_module(void);
#endif
int t1isa_init(void)
{
struct capi_driver *driver = &t1isa_driver;
char *p;
if ((p = strchr(revision, ':'))) {
strncpy(driver->revision, p + 1, sizeof(driver->revision));
p = strchr(driver->revision, '$');
*p = 0;
}
printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
di = attach_capi_driver(driver);
if (!di) {
printk(KERN_ERR "%s: failed to attach capi_driver\n",
driver->name);
return -EIO;
}
return 0;
}
#ifdef MODULE
void cleanup_module(void)
{
detach_capi_driver(&t1isa_driver);
}
#endif

View File

@ -1,327 +0,0 @@
/*
* $Id$
*
* Module for AVM T1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log$
* Revision 1.4 2000/01/25 14:33:38 calle
* - Added Support AVM B1 PCI V4.0 (tested with prototype)
* - splitted up t1pci.c into b1dma.c for common function with b1pciv4
* - support for revision register
*
* Revision 1.3 1999/11/13 21:27:16 keil
* remove KERNELVERSION
*
* Revision 1.2 1999/11/05 16:38:02 calle
* Cleanups before kernel 2.4:
* - Changed all messages to use card->name or driver->name instead of
* constant string.
* - Moved some data from struct avmcard into new struct avmctrl_info.
* Changed all lowlevel capi driver to match the new structur.
*
* Revision 1.1 1999/10/26 15:31:42 calle
* Added driver for T1-PCI card.
*
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/capi.h>
#include <asm/io.h>
#include <linux/isdn_compat.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
static char *revision = "$Revision$";
#undef CONFIG_T1PCI_DEBUG
#undef CONFIG_T1PCI_POLLDEBUG
/* ------------------------------------------------------------- */
#ifndef PCI_VENDOR_ID_AVM
#define PCI_VENDOR_ID_AVM 0x1244
#endif
#ifndef PCI_DEVICE_ID_AVM_T1
#define PCI_DEVICE_ID_AVM_T1 0x1200
#endif
/* ------------------------------------------------------------- */
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
/* ------------------------------------------------------------- */
static struct capi_driver_interface *di;
/* ------------------------------------------------------------- */
static void t1pci_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
b1dma_reset(card);
di->detach_ctr(ctrl);
free_irq(card->irq, card);
iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
release_region(card->port, AVMB1_PORTLEN);
ctrl->driverdata = 0;
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
}
/* ------------------------------------------------------------- */
static int t1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
{
unsigned long base, page_offset;
avmcard *card;
avmctrl_info *cinfo;
int retval;
MOD_INC_USE_COUNT;
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
if (!card) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card, 0, sizeof(avmcard));
card->dma = (avmcard_dmainfo *) kmalloc(sizeof(avmcard_dmainfo), GFP_ATOMIC);
if (!card->dma) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(card->dma, 0, sizeof(avmcard_dmainfo));
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(cinfo, 0, sizeof(avmctrl_info));
card->ctrlinfo = cinfo;
cinfo->card = card;
sprintf(card->name, "t1pci-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->membase = p->membase;
card->cardtype = avm_t1pci;
if (check_region(card->port, AVMB1_PORTLEN)) {
printk(KERN_WARNING
"%s: ports 0x%03x-0x%03x in use.\n",
driver->name, card->port, card->port + AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
base = card->membase & PAGE_MASK;
page_offset = card->membase - base;
card->mbase = ioremap_nocache(base, page_offset + 64);
if (card->mbase) {
card->mbase += page_offset;
} else {
printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
driver->name, card->membase);
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
}
b1dma_reset(card);
if ((retval = t1pci_detect(card)) != 0) {
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
driver->name, card->port, retval);
iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EIO;
}
b1dma_reset(card);
request_region(p->port, AVMB1_PORTLEN, card->name);
retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
if (retval) {
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
driver->name, card->irq);
iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
if (!cinfo->capi_ctrl) {
printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
return -EBUSY;
}
card->cardnr = cinfo->capi_ctrl->cnr;
skb_queue_head_init(&card->dma->send_queue);
printk(KERN_INFO
"%s: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
driver->name, card->port, card->irq, card->membase);
return 0;
}
/* ------------------------------------------------------------- */
static char *t1pci_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->membase : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static struct capi_driver t1pci_driver = {
"t1pci",
"0.0",
b1dma_load_firmware,
b1dma_reset_ctr,
t1pci_remove_ctr,
b1dma_register_appl,
b1dma_release_appl,
b1dma_send_message,
t1pci_procinfo,
b1dmactl_read_proc,
0, /* use standard driver_read_proc */
0, /* no add_card function */
};
#ifdef MODULE
#define t1pci_init init_module
void cleanup_module(void);
#endif
static int ncards = 0;
int t1pci_init(void)
{
struct capi_driver *driver = &t1pci_driver;
struct pci_dev *dev = NULL;
char *p;
int retval;
if ((p = strchr(revision, ':'))) {
strncpy(driver->revision, p + 1, sizeof(driver->revision));
p = strchr(driver->revision, '$');
*p = 0;
}
printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
di = attach_capi_driver(driver);
if (!di) {
printk(KERN_ERR "%s: failed to attach capi_driver\n",
driver->name);
return -EIO;
}
#ifdef CONFIG_PCI
if (!pci_present()) {
printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
detach_capi_driver(driver);
return -EIO;
}
while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) {
struct capicardparams param;
param.port = get_pcibase(dev, 1) & PCI_BASE_ADDRESS_IO_MASK;
param.irq = dev->irq;
param.membase = get_pcibase(dev, 0) & PCI_BASE_ADDRESS_MEM_MASK;
printk(KERN_INFO
"%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
driver->name, param.port, param.irq, param.membase);
retval = t1pci_add_card(driver, &param);
if (retval != 0) {
printk(KERN_ERR
"%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
driver->name, param.port, param.irq, param.membase);
#ifdef MODULE
cleanup_module();
#endif
return retval;
}
ncards++;
}
if (ncards) {
printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n",
driver->name, ncards);
return 0;
}
printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name);
return -ESRCH;
#else
printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
return -EIO;
#endif
}
#ifdef MODULE
void cleanup_module(void)
{
detach_capi_driver(&t1pci_driver);
}
#endif

View File

@ -1,328 +0,0 @@
/* $Id$
* Variable-debugging for isdn4linux.
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1995 Thinking Objects Software GmbH Wuerzburg
*
* This file is part of Isdn4Linux.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.6 1999/04/12 12:33:07 fritz
* Changes from 2.0 tree.
*
* Revision 1.5 1997/02/03 23:34:51 fritz
* Reformatted
*
* Revision 1.4 1996/04/30 07:55:50 fritz
* Disabled mmap.
*
* Revision 1.3 1996/04/28 15:19:23 fritz
* adapted to new ioctl names.
*
* Revision 1.2 1996/01/04 02:46:16 fritz
* Changed copying policy to GPL.
*
* Revision 1.1 1995/12/18 18:22:52 fritz
* Initial revision
*
*/
#include <sys/types.h>
#include <sys/fcntl.h>
/* #include <sys/mman.h> */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/isdn.h>
#include <linux/isdnif.h>
typedef unsigned char uchar;
int mem_fd;
#if 0 /* Weiss der Teufel, warum das nicht mit mmap geht */
uchar
* mapmem(ulong location, long size)
{
ulong mmseg;
ulong mmsize;
ulong addr;
ulong offset;
mmseg = location & 0xffffe000L;
mmsize = (location - mmseg + size) + 0x1000;
offset = location - mmseg;
addr = (ulong) mmap(0, mmsize, PROT_READ, MAP_SHARED, mem_fd, mmseg);
if ((int) addr == -1) {
perror("mmap");
exit(1);
}
printf("mmap: loc=%08lx siz=%08lx mseg=%08lx msiz=%08lx ofs=%08lx adr=%08lx\n", location, size, mmseg, mmsize, offset, addr);
return ((uchar *) (addr + offset));
}
#else
uchar
* mapmem(ulong location, long size)
{
uchar *buffer;
if ((buffer = malloc(size))) {
lseek(mem_fd, location, SEEK_SET);
read(mem_fd, buffer, size);
} else {
perror("malloc");
exit(1);
}
return buffer;
}
#endif
char *
dumpIntArray(int *arr, int count)
{
static char buf[1024];
char *p = buf;
int i;
for (i = 0; i < count; i++)
p += sprintf(p, "%d%s", arr[i], (i < (count - 1)) ? ", " : "\0");
return (buf);
}
char *
dumpCharArray(char *arr, int count)
{
static char buf[1024];
char *p = buf;
int i;
for (i = 0; i < count; i++)
p += sprintf(p, "%02x%s", (uchar) arr[i], (i < (count - 1)) ? ", " : "\0");
return (buf);
}
char *
dumpStringArray(char *arr, int count, int len)
{
static char buf[1024];
char *p = buf;
char *s = arr;
int i;
for (i = 0; i < count; s += len, i++)
p += sprintf(p, "\"%s\"%s", s, (i < (count - 1)) ? ", " : "\0");
return (buf);
}
void
dumpDriver(ulong drvaddr)
{
driver *drv = (driver *) mapmem(drvaddr, sizeof(driver));
isdn_if *ifc = (isdn_if *) mapmem((ulong) drv->interface, sizeof(isdn_if));
printf(" online = %08lx\n", drv->online);
printf(" channels = %d\n", drv->channels);
printf(" locks = %d\n", drv->locks);
printf(" reject_bus = %d\n", drv->flags & DRV_FLAG_REJBUS);
printf(" running = %d\n", drv->flags & DRV_FLAG_RUNNING);
printf(" loaded = %d\n", drv->flags & DRV_FLAG_LOADED);
printf(" maxbufsize = %d\n", drv->maxbufsize);
printf(" pktcount = %ld\n", drv->pktcount);
printf(" stavail = %d\n", drv->stavail);
printf(" Interface @%08lx:\n", (ulong) drv->interface);
printf(" Id(ch) = %d\n", ifc->channels);
printf(" maxbufsize = %d\n", ifc->maxbufsize);
printf(" features = %08lx\n", ifc->features);
}
void
dumpModem(modem mdm)
{
int i;
atemu *atm;
modem_info *info;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
printf("mdm [%02d]\n", i);
printf(" msr = %08x\n", mdm.msr[i]);
printf(" mlr = %08x\n", mdm.mlr[i]);
printf(" refcount = %d\n", mdm.refcount);
printf(" online = %d\n", mdm.online[i]);
printf(" dialing = %d\n", mdm.dialing[i]);
printf(" rcvsched = %d\n", mdm.rcvsched[i]);
printf(" ncarrier = %d\n", mdm.ncarrier[i]);
printf(" atmodem:\n");
atm = &mdm.atmodem[i];
printf(" profile = \n %s\n", dumpCharArray(atm->mdmreg, ISDN_MODEM_NUMREG));
printf(" mdmreg = \n %s\n", dumpCharArray(atm->mdmreg, ISDN_MODEM_NUMREG));
printf(" msn = \"%s\"\n", atm->msn);
printf(" mdmcmdl = %d\n", atm->mdmcmdl);
printf(" pluscount = %d\n", atm->pluscount);
printf(" lastplus = %08x\n", atm->lastplus);
printf(" mdmcmd = \"%s\"\n", atm->mdmcmd);
printf(" info:\n");
info = &mdm.info[i];
printf(" magic = %08x\n", info->magic);
printf(" flags = %08x\n", info->flags);
printf(" type = %d\n", info->type);
printf(" x_char = %02x\n", info->x_char);
printf(" close_delay = %d\n", info->close_delay);
printf(" MCR = %08x\n", info->MCR);
printf(" line = %d\n", info->line);
printf(" count = %d\n", info->count);
printf(" blocked_open = %d\n", info->blocked_open);
printf(" session = %08lx\n", info->session);
printf(" pgrp = %08lx\n", info->pgrp);
printf(" isdn_driver = %d\n", info->isdn_driver);
printf(" isdn_channel = %d\n", info->isdn_channel);
printf(" drv_index = %d\n", info->drv_index);
printf(" xmit_size = %d\n", info->xmit_size);
printf(" xmit_count = %d\n", info->xmit_count);
}
}
void
dumpNetPhone(ulong paddr)
{
ulong pa = paddr;
isdn_net_phone *phone;
while (pa) {
phone = (isdn_net_phone *) mapmem(pa, sizeof(isdn_net_phone));
printf(" @%08lx: \"%s\"\n", pa, phone->num);
pa = (ulong) (phone->next);
}
}
void
dumpNetDev(ulong devaddr)
{
ulong nda = devaddr;
isdn_net_dev *ndev;
while (nda) {
ndev = (isdn_net_dev *) mapmem(nda, sizeof(isdn_net_dev));
printf("Net-Device @%08lx:\n", nda);
printf("dev. :\n");
printf(" start = %d\n", ndev->dev.start);
printf(" tbusy = %ld\n", ndev->dev.tbusy);
printf(" interrupt = %d\n", ndev->dev.interrupt);
printf("local. :\n");
printf(" name = \"%s\"\n", ndev->local.name);
printf(" isdn_device = %d\n", ndev->local.isdn_device);
printf(" isdn_channel = %d\n", ndev->local.isdn_channel);
printf(" ppp_minor = %d\n", ndev->local.ppp_minor);
printf(" pre_device = %d\n", ndev->local.pre_device);
printf(" pre_channel = %d\n", ndev->local.pre_channel);
printf(" exclusive = %d\n", ndev->local.exclusive);
printf(" flags = %d\n", ndev->local.flags);
printf(" dialstate = %d\n", ndev->local.dialstate);
printf(" dialretry = %d\n", ndev->local.dialretry);
printf(" dialmax = %d\n", ndev->local.dialmax);
printf(" msn = \"%s\"\n", ndev->local.msn);
printf(" dtimer = %d\n", ndev->local.dtimer);
printf(" p_encap = %d\n", ndev->local.p_encap);
printf(" l2_proto = %d\n", ndev->local.l2_proto);
printf(" l3_proto = %d\n", ndev->local.l3_proto);
printf(" huptimer = %d\n", ndev->local.huptimer);
printf(" charge = %d\n", ndev->local.charge);
printf(" chargetime = %08x\n", ndev->local.chargetime);
printf(" hupflags = %d\n", ndev->local.hupflags);
printf(" outgoing = %d\n", ndev->local.outgoing);
printf(" onhtime = %d\n", ndev->local.onhtime);
printf(" chargeint = %d\n", ndev->local.chargeint);
printf(" onum = %d\n", ndev->local.onum);
printf(" sqfull = %08x\n", ndev->local.sqfull);
printf(" sqfull_stamp = %08lx\n", ndev->local.sqfull_stamp);
printf(" master = -> %08x\n", (unsigned int) ndev->local.master);
printf(" slave = -> %08x\n", (unsigned int) ndev->local.slave);
if (ndev->local.phone[0]) {
printf(" phone[in]:\n");
dumpNetPhone((ulong) ndev->local.phone[0]);
} else
printf(" phone[in] = NULL\n");
if (ndev->local.phone[1]) {
printf(" phone[out]:\n");
dumpNetPhone((ulong) ndev->local.phone[1]);
} else
printf(" phone[out] = NULL\n");
printf(" dial = @%08lx\n", (ulong) ndev->local.dial);
nda = (ulong) (ndev->next);
}
}
void
main(int argc, char *argv[], char *envp[])
{
int f;
int i;
static isdn_dev *my_isdndev;
ulong kaddr;
printf("\nDebugger for isdn and icn Modules\n");
f = open("/dev/isdnctrl", O_RDONLY);
if (ioctl(f, IIOCDBGVAR, &kaddr)) {
perror("ioctl IIOCDBGVAR");
exit(-1);
}
close(f);
if ((mem_fd = open("/dev/kmem", O_RDWR)) < 0) {
perror("open /dev/kmem");
exit(1);
}
printf("isdn-main-struct at %08lx (%d):\n", kaddr, sizeof(isdn_dev));
my_isdndev = (isdn_dev *) mapmem(kaddr, sizeof(isdn_dev));
printf("isdndev.flags = %d\n", my_isdndev->flags);
printf("isdndev.drivers = %d\n", my_isdndev->drivers);
printf("isdndev.channels = %d\n", my_isdndev->channels);
printf("isdndev.net_verbose = %d\n", my_isdndev->net_verbose);
printf("isdndev.modempoll = %d\n", my_isdndev->modempoll);
printf("isdndev.tflags = %d\n", my_isdndev->tflags);
printf("isdndev.global_flags = %d\n", my_isdndev->global_flags);
if (my_isdndev->infochain) {
printf("isdndev.infochain = @%08lx:\n", (ulong) my_isdndev->infochain);
} else
printf("isdndev.infochain = NULL\n");
if (my_isdndev->info_waitq) {
printf("isdndev.info_waitq = @%08lx:\n", (ulong) my_isdndev->info_waitq);
} else
printf("isdndev.info_waitq = NULL\n");
printf("isdndev.chanmap = %s\n",
dumpIntArray(my_isdndev->chanmap, ISDN_MAX_CHANNELS));
printf("isdndev.drvmap = %s\n",
dumpIntArray(my_isdndev->drvmap, ISDN_MAX_CHANNELS));
printf("isdndev.usage = %s\n",
dumpIntArray(my_isdndev->usage, ISDN_MAX_CHANNELS));
printf("isdndev.num = %s\n",
dumpStringArray(my_isdndev->num[0], ISDN_MAX_CHANNELS, 20));
printf("isdndev.m_idx = %s\n",
dumpIntArray(my_isdndev->m_idx, ISDN_MAX_CHANNELS));
dumpModem(my_isdndev->mdm);
for (i = 0; i < ISDN_MAX_DRIVERS; i++)
if (my_isdndev->drv[i]) {
printf("isdndev.drv[%02d] = @%08lx:\n", i, (ulong) my_isdndev->drv[i]);
dumpDriver((ulong) (my_isdndev->drv[i]));
}
if (my_isdndev->netdev) {
printf("isdndev.netdev = @%08lx:\n", (ulong) my_isdndev->netdev);
dumpNetDev((ulong) my_isdndev->netdev);
} else
printf("isdndev.netdev = NULL\n");
close(mem_fd);
}

View File

@ -1,21 +0,0 @@
L_OBJS :=
LX_OBJS :=
M_OBJS :=
MX_OBJS :=
O_OBJS :=
OX_OBJS :=
L_TARGET :=
O_TARGET :=
O_OBJS += isdn_divert.o divert_procfs.o
O_TARGET := dss1_divert.o
M_OBJS += dss1_divert.o
OX_OBJS += divert_init.o
include $(TOPDIR)/Rules.make

View File

@ -1,104 +0,0 @@
/*
* $Id$
*
* Module init for DSS1 diversion services for i4l.
*
* Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.3 1999/07/05 20:21:39 werner
* changes to use diversion sources for all kernel versions.
* removed static device, only proc filesystem used
*
* Revision 1.2 1999/07/04 21:37:30 werner
* Ported from kernel version 2.0
*
*
*
*/
#include <linux/module.h>
#include <linux/version.h>
#include "isdn_divert.h"
/********************/
/* needed externals */
/********************/
extern int printk(const char *fmt,...);
/****************************************/
/* structure containing interface to hl */
/****************************************/
isdn_divert_if divert_if =
{ DIVERT_IF_MAGIC, /* magic value */
DIVERT_CMD_REG, /* register cmd */
ll_callback, /* callback routine from ll */
NULL, /* command still not specified */
NULL, /* drv_to_name */
NULL, /* name_to_drv */
};
/*************************/
/* Module interface code */
/* no cmd line parms */
/*************************/
int init_module(void)
{ int i;
if (divert_dev_init())
{ printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
return(-EIO);
}
if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
{ divert_dev_deinit();
printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n",i);
return(-EIO);
}
#if (LINUX_VERSION_CODE < 0x020111)
register_symtab(0);
#endif
printk(KERN_INFO "dss1_divert module successfully installed\n");
return(0);
} /* init_module */
/**********************/
/* Module deinit code */
/**********************/
void cleanup_module(void)
{ int flags;
int i;
save_flags(flags);
cli();
divert_if.cmd = DIVERT_CMD_REL; /* release */
if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
{ printk(KERN_WARNING "dss1_divert: error %d releasing module\n",i);
restore_flags(flags);
return;
}
if (divert_dev_deinit())
{ printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
restore_flags(flags);
return;
}
restore_flags(flags);
deleterule(-1); /* delete all rules and free mem */
deleteprocs();
printk(KERN_INFO "dss1_divert module successfully removed \n");
} /* cleanup_module */

View File

@ -1,381 +0,0 @@
/*
* $Id$
*
* Filesystem handling for the diversion supplementary services.
*
* Copyright 1998 by Werner Cornelius (werner@isdn4linux.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.6 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
*
* Revision 1.5 1999/09/14 20:31:01 werner
*
* Removed obsoleted functions for proc fs and synced with new ones.
*
* Revision 1.4 1999/08/06 07:42:48 calle
* Added COMPAT_HAS_NEW_WAITQ for rd_queue for newer kernels.
*
* Revision 1.3 1999/07/05 20:21:41 werner
* changes to use diversion sources for all kernel versions.
* removed static device, only proc filesystem used
*
* Revision 1.2 1999/07/04 21:37:31 werner
* Ported from kernel version 2.0
*
*
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/poll.h>
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#else
#include <linux/fs.h>
#endif
#include <linux/isdnif.h>
#include <linux/isdn_compat.h>
#include "isdn_divert.h"
/*********************************/
/* Variables for interface queue */
/*********************************/
ulong if_used = 0; /* number of interface users */
static struct divert_info *divert_info_head = NULL; /* head of queue */
static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
#ifdef COMPAT_HAS_NEW_WAITQ
static wait_queue_head_t rd_queue;
#else
static struct wait_queue *rd_queue = 0; /* Queue IO */
#endif
/*********************************/
/* put an info buffer into queue */
/*********************************/
void
put_info_buffer(char *cp)
{
struct divert_info *ib;
int flags;
if (if_used <= 0)
return;
if (!cp)
return;
if (!*cp)
return;
if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
return; /* no memory */
strcpy(ib->info_start, cp); /* set output string */
ib->next = NULL;
save_flags(flags);
cli();
ib->usage_cnt = if_used;
if (!divert_info_head)
divert_info_head = ib; /* new head */
else
divert_info_tail->next = ib; /* follows existing messages */
divert_info_tail = ib; /* new tail */
restore_flags(flags);
/* delete old entrys */
while (divert_info_head->next) {
if ((divert_info_head->usage_cnt <= 0) &&
(divert_info_head->next->usage_cnt <= 0)) {
ib = divert_info_head;
divert_info_head = divert_info_head->next;
kfree(ib);
} else
break;
} /* divert_info_head->next */
wake_up_interruptible(&(rd_queue));
} /* put_info_buffer */
/**********************************/
/* deflection device read routine */
/**********************************/
static ssize_t
isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off)
{
struct divert_info *inf;
int len;
if (!*((struct divert_info **) file->private_data)) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
interruptible_sleep_on(&(rd_queue));
}
if (!(inf = *((struct divert_info **) file->private_data)))
return (0);
inf->usage_cnt--; /* new usage count */
(struct divert_info **) file->private_data = &inf->next; /* next structure */
if ((len = strlen(inf->info_start)) <= count) {
if (copy_to_user(buf, inf->info_start, len))
return -EFAULT;
file->f_pos += len;
return (len);
}
return (0);
} /* isdn_divert_read */
/**********************************/
/* deflection device write routine */
/**********************************/
static ssize_t
isdn_divert_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
return (-ENODEV);
} /* isdn_divert_write */
/***************************************/
/* select routines for various kernels */
/***************************************/
static unsigned int
isdn_divert_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
poll_wait(file, &(rd_queue), wait);
/* mask = POLLOUT | POLLWRNORM; */
if (*((struct divert_info **) file->private_data)) {
mask |= POLLIN | POLLRDNORM;
}
return mask;
} /* isdn_divert_poll */
/****************/
/* Open routine */
/****************/
static int
isdn_divert_open(struct inode *ino, struct file *filep)
{
int flags;
MOD_INC_USE_COUNT;
save_flags(flags);
cli();
if_used++;
if (divert_info_head)
(struct divert_info **) filep->private_data = &(divert_info_tail->next);
else
(struct divert_info **) filep->private_data = &divert_info_head;
restore_flags(flags);
/* start_divert(); */
return (0);
} /* isdn_divert_open */
/*******************/
/* close routine */
/*******************/
static int
isdn_divert_close(struct inode *ino, struct file *filep)
{
struct divert_info *inf;
int flags;
save_flags(flags);
cli();
if_used--;
inf = *((struct divert_info **) filep->private_data);
while (inf) {
inf->usage_cnt--;
inf = inf->next;
}
restore_flags(flags);
if (if_used <= 0)
while (divert_info_head) {
inf = divert_info_head;
divert_info_head = divert_info_head->next;
kfree(inf);
}
MOD_DEC_USE_COUNT;
return (0);
} /* isdn_divert_close */
/*********/
/* IOCTL */
/*********/
static int
isdn_divert_ioctl(struct inode *inode, struct file *file,
uint cmd, ulong arg)
{
divert_ioctl dioctl;
int i, flags;
divert_rule *rulep;
char *cp;
if ((i = copy_from_user(&dioctl, (char *) arg, sizeof(dioctl))))
return (i);
switch (cmd) {
case IIOCGETVER:
dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */
break;
case IIOCGETDRV:
if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
return (-EINVAL);
break;
case IIOCGETNAM:
cp = divert_if.drv_to_name(dioctl.getid.drvid);
if (!cp)
return (-EINVAL);
if (!*cp)
return (-EINVAL);
strcpy(dioctl.getid.drvnam, cp);
break;
case IIOCGETRULE:
if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
return (-EINVAL);
dioctl.getsetrule.rule = *rulep; /* copy data */
break;
case IIOCMODRULE:
if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
return (-EINVAL);
save_flags(flags);
cli();
*rulep = dioctl.getsetrule.rule; /* copy data */
restore_flags(flags);
return (0); /* no copy required */
break;
case IIOCINSRULE:
return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
break;
case IIOCDELRULE:
return (deleterule(dioctl.getsetrule.ruleidx));
break;
case IIOCDODFACT:
return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
dioctl.fwd_ctrl.callid,
dioctl.fwd_ctrl.to_nr));
case IIOCDOCFACT:
case IIOCDOCFDIS:
case IIOCDOCFINT:
if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
return (-EINVAL); /* invalid driver */
if ((i = cf_command(dioctl.cf_ctrl.drvid,
(cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
dioctl.cf_ctrl.cfproc,
dioctl.cf_ctrl.msn,
dioctl.cf_ctrl.service,
dioctl.cf_ctrl.fwd_nr,
&dioctl.cf_ctrl.procid)))
return (i);
break;
default:
return (-EINVAL);
} /* switch cmd */
return (copy_to_user((char *) arg, &dioctl, sizeof(dioctl))); /* success */
} /* isdn_divert_ioctl */
#ifdef CONFIG_PROC_FS
static loff_t
isdn_divert_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
}
static struct file_operations isdn_fops =
{
isdn_divert_lseek,
isdn_divert_read,
isdn_divert_write,
NULL, /* isdn_readdir */
isdn_divert_poll, /* isdn_poll */
isdn_divert_ioctl, /* isdn_ioctl */
NULL, /* isdn_mmap */
isdn_divert_open,
NULL, /* flush */
isdn_divert_close,
NULL /* fsync */
};
#ifdef COMPAT_NO_SOFTNET
struct inode_operations divert_file_inode_operations;
#endif
/****************************/
/* isdn subdir in /proc/net */
/****************************/
static struct proc_dir_entry *isdn_proc_entry = NULL;
static struct proc_dir_entry *isdn_divert_entry = NULL;
#endif /* CONFIG_PROC_FS */
/***************************************************************************/
/* divert_dev_init must be called before the proc filesystem may be used */
/***************************************************************************/
int
divert_dev_init(void)
{
#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&rd_queue);
#endif
#ifdef CONFIG_PROC_FS
isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
if (!isdn_proc_entry)
return (-1);
isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
if (!isdn_divert_entry) {
remove_proc_entry("isdn", proc_net);
return (-1);
}
#ifdef COMPAT_NO_SOFTNET
memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations));
divert_file_inode_operations.default_file_ops = &isdn_fops;
isdn_divert_entry->ops = &divert_file_inode_operations;
#else
isdn_divert_entry->proc_fops = &isdn_fops;
#endif
#endif /* CONFIG_PROC_FS */
return (0);
} /* divert_dev_init */
/***************************************************************************/
/* divert_dev_deinit must be called before leaving isdn when included as */
/* a module. */
/***************************************************************************/
int
divert_dev_deinit(void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("divert", isdn_proc_entry);
remove_proc_entry("isdn", proc_net);
#endif /* CONFIG_PROC_FS */
return (0);
} /* divert_dev_deinit */

View File

@ -1,911 +0,0 @@
/*
* $Id$
*
* DSS1 main diversion supplementary handling for i4l.
*
* Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.4 1999/08/25 20:02:21 werner
* Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts
* with existing software definitions. (PtP incomplete called party number)
*
* Revision 1.3 1999/08/22 20:26:35 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.2 1999/07/04 21:37:32 werner
* Ported from kernel version 2.0
*
*
*
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include "isdn_divert.h"
/**********************************/
/* structure keeping calling info */
/**********************************/
struct call_struc
{ isdn_ctrl ics; /* delivered setup + driver parameters */
ulong divert_id; /* Id delivered to user */
unsigned char akt_state; /* actual state */
char deflect_dest[35]; /* deflection destination */
struct timer_list timer; /* timer control structure */
char info[90]; /* device info output */
struct call_struc *next; /* pointer to next entry */
struct call_struc *prev;
};
/********************************************/
/* structure keeping deflection table entry */
/********************************************/
struct deflect_struc
{ struct deflect_struc *next,*prev;
divert_rule rule; /* used rule */
};
/*****************************************/
/* variables for main diversion services */
/*****************************************/
/* diversion/deflection processes */
static struct call_struc *divert_head = NULL; /* head of remembered entrys */
static ulong next_id = 1; /* next info id */
static struct deflect_struc *table_head = NULL;
static struct deflect_struc *table_tail = NULL;
static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
/***************************/
/* timer callback function */
/***************************/
static void deflect_timer_expire(ulong arg)
{ int flags;
struct call_struc *cs = (struct call_struc *) arg;
save_flags(flags);
cli();
del_timer(&cs->timer); /* delete active timer */
restore_flags(flags);
switch(cs->akt_state)
{ case DEFLECT_PROCEED:
cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
divert_if.ll_cmd(&cs->ics);
save_flags(flags);
cli();
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
restore_flags(flags);
break;
case DEFLECT_ALERT:
cs->ics.command = ISDN_CMD_REDIR; /* protocol */
strcpy(cs->ics.parm.setup.phone,cs->deflect_dest);
strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed");
divert_if.ll_cmd(&cs->ics);
save_flags(flags);
cli();
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
restore_flags(flags);
break;
case DEFLECT_AUTODEL:
default:
save_flags(flags);
cli();
if (cs->prev)
cs->prev->next = cs->next; /* forward link */
else
divert_head = cs->next;
if (cs->next)
cs->next->prev = cs->prev; /* back link */
restore_flags(flags);
kfree(cs);
return;
} /* switch */
} /* deflect_timer_func */
/*****************************************/
/* handle call forwarding de/activations */
/* 0 = deact, 1 = act, 2 = interrogate */
/*****************************************/
int cf_command(int drvid, int mode,
u_char proc, char *msn,
u_char service, char *fwd_nr, ulong *procid)
{ int retval,msnlen,flags;
int fwd_len;
char *p,*ielenp,tmp[60];
struct call_struc *cs;
if (strchr(msn,'.')) return(-EINVAL); /* subaddress not allowed in msn */
if ((proc & 0x7F) > 2) return(-EINVAL);
proc &= 3;
p = tmp;
*p++ = 0x30; /* enumeration */
ielenp = p++; /* remember total length position */
*p++ = 0xa; /* proc tag */
*p++ = 1; /* length */
*p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
*p++ = 0xa; /* service tag */
*p++ = 1; /* length */
*p++ = service; /* service to handle */
if (mode == 1)
{ if (!*fwd_nr) return(-EINVAL); /* destination missing */
if (strchr(fwd_nr,'.')) return(-EINVAL); /* subaddress not allowed */
fwd_len = strlen(fwd_nr);
*p++ = 0x30; /* number enumeration */
*p++ = fwd_len + 2; /* complete forward to len */
*p++ = 0x80; /* fwd to nr */
*p++ = fwd_len; /* length of number */
strcpy(p,fwd_nr); /* copy number */
p += fwd_len; /* pointer beyond fwd */
} /* activate */
msnlen = strlen(msn);
*p++ = 0x80; /* msn number */
if (msnlen > 1)
{ *p++ = msnlen; /* length */
strcpy(p,msn);
p += msnlen;
}
else *p++ = 0;
*ielenp = p - ielenp - 1; /* set total IE length */
/* allocate mem for information struct */
if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
return(-ENOMEM); /* no memory */
init_timer(&cs->timer);
cs->info[0] = '\0';
cs->timer.function = deflect_timer_expire;
cs->timer.data = (ulong) cs; /* pointer to own structure */
cs->ics.driver = drvid;
cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
cs->ics.parm.dss1_io.proc = (mode == 1) ? 7: (mode == 2) ? 11:8; /* operation */
cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
save_flags(flags);
cli();
cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
restore_flags(flags);
*procid = cs->ics.parm.dss1_io.ll_id;
sprintf(cs->info,"%d 0x%lx %s%s 0 %s %0x %d%s%s\n",
(!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
cs->ics.parm.dss1_io.ll_id,
(mode != 2) ? "" : "0 ",
divert_if.drv_to_name(cs->ics.driver),
msn,
service & 0xFF,
proc,
(mode != 1) ? "" : " 0 ",
(mode != 1) ? "" : fwd_nr);
retval = divert_if.ll_cmd(&cs->ics); /* excute command */
if (!retval)
{ cs->prev = NULL;
save_flags(flags);
cli();
cs->next = divert_head;
divert_head = cs;
restore_flags(flags);
}
else
kfree(cs);
return(retval);
} /* cf_command */
/****************************************/
/* handle a external deflection command */
/****************************************/
int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
{ struct call_struc *cs;
isdn_ctrl ic;
int flags;
int i;
if ((cmd & 0x7F) > 2) return(-EINVAL); /* invalid command */
cs = divert_head; /* start of parameter list */
while (cs)
{ if (cs->divert_id == callid) break; /* found */
cs = cs->next;
} /* search entry */
if (!cs) return(-EINVAL); /* invalid callid */
ic.driver = cs->ics.driver;
ic.arg = cs->ics.arg;
i = -EINVAL;
if (cs->akt_state == DEFLECT_AUTODEL) return(i); /* no valid call */
switch (cmd & 0x7F)
{ case 0: /* hangup */
del_timer(&cs->timer);
ic.command = ISDN_CMD_HANGUP;
i = divert_if.ll_cmd(&ic);
save_flags(flags);
cli();
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
restore_flags(flags);
break;
case 1: /* alert */
if (cs->akt_state == DEFLECT_ALERT) return(0);
cmd &= 0x7F; /* never wait */
del_timer(&cs->timer);
ic.command = ISDN_CMD_ALERT;
if ((i = divert_if.ll_cmd(&ic)))
{ save_flags(flags);
cli();
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
restore_flags(flags);
}
else
cs->akt_state = DEFLECT_ALERT;
break;
case 2: /* redir */
del_timer(&cs->timer);
strcpy(cs->ics.parm.setup.phone, to_nr);
strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
ic.command = ISDN_CMD_REDIR;
if ((i = divert_if.ll_cmd(&ic)))
{ save_flags(flags);
cli();
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
add_timer(&cs->timer);
restore_flags(flags);
}
else
cs->akt_state = DEFLECT_ALERT;
break;
} /* switch */
return(i);
} /* deflect_extern_action */
/********************************/
/* insert a new rule before idx */
/********************************/
int insertrule(int idx, divert_rule *newrule)
{ struct deflect_struc *ds,*ds1;
int flags;
if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc),
GFP_KERNEL)))
return(-ENOMEM); /* no memory */
ds->rule = *newrule; /* set rule */
save_flags(flags);
cli();
if (idx >= 0)
{ ds1 = table_head;
while ((ds1) && (idx > 0))
{ idx--;
ds1 = ds1->next;
}
if (!ds1) idx = -1;
}
if (idx < 0)
{ ds->prev = table_tail; /* previous entry */
ds->next = NULL; /* end of chain */
if (ds->prev)
ds->prev->next = ds; /* last forward */
else
table_head = ds; /* is first entry */
table_tail = ds; /* end of queue */
}
else
{ ds->next = ds1; /* next entry */
ds->prev = ds1->prev; /* prev entry */
ds1->prev = ds; /* backward chain old element */
if (!ds->prev)
table_head = ds; /* first element */
}
restore_flags(flags);
return(0);
} /* insertrule */
/***********************************/
/* delete the rule at position idx */
/***********************************/
int deleterule(int idx)
{ struct deflect_struc *ds,*ds1;
int flags;
if (idx < 0)
{ save_flags(flags);
cli();
ds = table_head;
table_head = NULL;
table_tail = NULL;
restore_flags(flags);
while (ds)
{ ds1 = ds;
ds = ds->next;
kfree(ds1);
}
return(0);
}
save_flags(flags);
cli();
ds = table_head;
while ((ds) && (idx > 0))
{ idx--;
ds = ds->next;
}
if (!ds)
{ restore_flags(flags);
return(-EINVAL);
}
if (ds->next)
ds->next->prev = ds->prev; /* backward chain */
else
table_tail = ds->prev; /* end of chain */
if (ds->prev)
ds->prev->next = ds->next; /* forward chain */
else
table_head = ds->next; /* start of chain */
restore_flags(flags);
kfree(ds);
return(0);
} /* deleterule */
/*******************************************/
/* get a pointer to a specific rule number */
/*******************************************/
divert_rule *getruleptr(int idx)
{ struct deflect_struc *ds = table_head;
if (idx < 0) return(NULL);
while ((ds) && (idx >= 0))
{ if (!(idx--))
{ return(&ds->rule);
break;
}
ds = ds->next;
}
return(NULL);
} /* getruleptr */
/*************************************************/
/* called from common module on an incoming call */
/*************************************************/
int isdn_divert_icall(isdn_ctrl *ic)
{ int retval = 0;
int flags;
struct call_struc *cs = NULL;
struct deflect_struc *dv;
char *p,*p1;
u_char accept;
/* first check the internal deflection table */
for (dv = table_head; dv ; dv = dv->next )
{ /* scan table */
if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
continue; /* call option check */
if (!(dv->rule.drvid & (1L << ic->driver)))
continue; /* driver not matching */
if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
continue; /* si1 not matching */
if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
continue; /* si2 not matching */
p = dv->rule.my_msn;
p1 = ic->parm.setup.eazmsn;
accept = 0;
while (*p)
{ /* complete compare */
if (*p == '-')
{ accept = 1; /* call accepted */
break;
}
if (*p++ != *p1++)
break; /* not accepted */
if ((!*p) && (!*p1))
accept = 1;
} /* complete compare */
if (!accept) continue; /* not accepted */
if ((strcmp(dv->rule.caller,"0")) || (ic->parm.setup.phone[0]))
{ p = dv->rule.caller;
p1 = ic->parm.setup.phone;
accept = 0;
while (*p)
{ /* complete compare */
if (*p == '-')
{ accept = 1; /* call accepted */
break;
}
if (*p++ != *p1++)
break; /* not accepted */
if ((!*p) && (!*p1))
accept = 1;
} /* complete compare */
if (!accept) continue; /* not accepted */
}
switch (dv->rule.action)
{ case DEFLECT_IGNORE:
return(0);
break;
case DEFLECT_ALERT:
case DEFLECT_PROCEED:
case DEFLECT_REPORT:
case DEFLECT_REJECT:
if (dv->rule.action == DEFLECT_PROCEED)
if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
return(0); /* no external deflection needed */
if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
return(0); /* no memory */
init_timer(&cs->timer);
cs->info[0] = '\0';
cs->timer.function = deflect_timer_expire;
cs->timer.data = (ulong) cs; /* pointer to own structure */
cs->ics = *ic; /* copy incoming data */
if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone,"0");
if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn,"0");
cs->ics.parm.setup.screen = dv->rule.screen;
if (dv->rule.waittime)
cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
else
if (dv->rule.action == DEFLECT_PROCEED)
cs->timer.expires = jiffies + (HZ * extern_wait_max);
else
cs->timer.expires = 0;
cs->akt_state = dv->rule.action;
save_flags(flags);
cli();
cs->divert_id = next_id++; /* new sequence number */
restore_flags(flags);
cs->prev = NULL;
if (cs->akt_state == DEFLECT_ALERT)
{ strcpy(cs->deflect_dest,dv->rule.to_nr);
if (!cs->timer.expires)
{ strcpy(ic->parm.setup.eazmsn,"Testtext direct");
ic->parm.setup.screen = dv->rule.screen;
strcpy(ic->parm.setup.phone,dv->rule.to_nr);
cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
retval = 5;
}
else
retval = 1; /* alerting */
}
else
{ cs->deflect_dest[0] = '\0';
retval = 4; /* only proceed */
}
sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
cs->akt_state,
cs->divert_id,
divert_if.drv_to_name(cs->ics.driver),
(ic->command == ISDN_STAT_ICALLW) ? "1":"0",
cs->ics.parm.setup.phone,
cs->ics.parm.setup.eazmsn,
cs->ics.parm.setup.si1,
cs->ics.parm.setup.si2,
cs->ics.parm.setup.screen,
dv->rule.waittime,
cs->deflect_dest);
if ((dv->rule.action == DEFLECT_REPORT) ||
(dv->rule.action == DEFLECT_REJECT))
{ put_info_buffer(cs->info);
kfree(cs); /* remove */
return((dv->rule.action == DEFLECT_REPORT) ? 0:2); /* nothing to do */
}
break;
default:
return(0); /* ignore call */
break;
} /* switch action */
break;
} /* scan_table */
if (cs)
{ cs->prev = NULL;
save_flags(flags);
cli();
cs->next = divert_head;
divert_head = cs;
if (cs->timer.expires) add_timer(&cs->timer);
restore_flags(flags);
put_info_buffer(cs->info);
return(retval);
}
else
return(0);
} /* isdn_divert_icall */
void deleteprocs(void)
{ struct call_struc *cs, *cs1;
int flags;
save_flags(flags);
cli();
cs = divert_head;
divert_head = NULL;
while (cs)
{ del_timer(&cs->timer);
cs1 = cs;
cs = cs->next;
kfree(cs1);
}
restore_flags(flags);
} /* deleteprocs */
/****************************************************/
/* put a address including address type into buffer */
/****************************************************/
int put_address(char *st, u_char *p, int len)
{ u_char retval = 0;
u_char adr_typ = 0; /* network standard */
if (len < 2) return(retval);
if (*p == 0xA1)
{ retval = *(++p) + 2; /* total length */
if (retval > len) return(0); /* too short */
len = retval - 2; /* remaining length */
if (len < 3) return(0);
if ((*(++p) != 0x0A) || (*(++p) != 1)) return(0);
adr_typ = *(++p);
len -= 3;
p++;
if (len < 2) return(0);
if (*p++ != 0x12) return(0);
if (*p > len) return(0); /* check number length */
len = *p++;
}
else
if (*p == 0x80)
{ retval = *(++p) + 2; /* total length */
if (retval > len) return(0);
len = retval - 2;
p++;
}
else
return(0); /* invalid address information */
sprintf(st,"%d ",adr_typ);
st += strlen(st);
if (!len)
*st++ = '-';
else
while (len--)
*st++ = *p++;
*st = '\0';
return(retval);
} /* put_address */
/*************************************/
/* report a succesfull interrogation */
/*************************************/
int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
{ char *src = ic->parm.dss1_io.data;
int restlen = ic->parm.dss1_io.datalen;
int cnt = 1;
u_char n,n1;
char st[90], *p, *stp;
if (restlen < 2) return(-100); /* frame too short */
if (*src++ != 0x30) return(-101);
if ((n = *src++) > 0x81) return(-102); /* invalid length field */
restlen -= 2; /* remaining bytes */
if (n == 0x80)
{ if (restlen < 2) return(-103);
if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-104);
restlen -= 2;
}
else
if ( n == 0x81)
{ n = *src++;
restlen--;
if (n > restlen) return(-105);
restlen = n;
}
else
if (n > restlen) return(-106);
else
restlen = n; /* standard format */
if (restlen < 3) return(-107); /* no procedure */
if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return(-108);
restlen -= 3;
if (restlen < 2) return(-109); /* list missing */
if (*src == 0x31)
{ src++;
if ((n = *src++) > 0x81) return(-110); /* invalid length field */
restlen -= 2; /* remaining bytes */
if (n == 0x80)
{ if (restlen < 2) return(-111);
if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-112);
restlen -= 2;
}
else
if ( n == 0x81)
{ n = *src++;
restlen--;
if (n > restlen) return(-113);
restlen = n;
}
else
if (n > restlen) return(-114);
else
restlen = n; /* standard format */
} /* result list header */
while (restlen >= 2)
{ stp = st;
sprintf(stp,"%d 0x%lx %d %s ",DIVERT_REPORT, ic->parm.dss1_io.ll_id,
cnt++,divert_if.drv_to_name(ic->driver));
stp += strlen(stp);
if (*src++ != 0x30) return(-115); /* invalid enum */
n = *src++;
restlen -= 2;
if (n > restlen) return(-116); /* enum length wrong */
restlen -= n;
p = src; /* one entry */
src += n;
if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
stp += strlen(stp);
p += n1;
n -= n1;
if (n < 6) continue; /* no service and proc */
if ((*p++ != 0x0A) || (*p++ != 1)) continue;
sprintf(stp," 0x%02x ",(*p++) & 0xFF);
stp += strlen(stp);
if ((*p++ != 0x0A) || (*p++ != 1)) continue;
sprintf(stp,"%d ",(*p++) & 0xFF);
stp += strlen(stp);
n -= 6;
if (n > 2)
{ if (*p++ != 0x30) continue;
if (*p > (n-2)) continue;
n = *p++;
if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
stp += strlen(stp);
}
sprintf(stp,"\n");
put_info_buffer(st);
} /* while restlen */
if (restlen) return(-117);
return(0);
} /* interrogate_success */
/*********************************************/
/* callback for protocol specific extensions */
/*********************************************/
int prot_stat_callback(isdn_ctrl *ic)
{ struct call_struc *cs, *cs1;
int i,flags;
cs = divert_head; /* start of list */
cs1 = NULL;
while (cs)
{ if (ic->driver == cs->ics.driver)
{ switch (cs->ics.arg)
{ case DSS1_CMD_INVOKE:
if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
(cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id))
{ switch (ic->arg)
{ case DSS1_STAT_INVOKE_ERR:
sprintf(cs->info,"128 0x%lx 0x%x\n",
ic->parm.dss1_io.ll_id,
ic->parm.dss1_io.timeout);
put_info_buffer(cs->info);
break;
case DSS1_STAT_INVOKE_RES:
switch (cs->ics.parm.dss1_io.proc)
{ case 7:
case 8:
put_info_buffer(cs->info);
break;
case 11:
i = interrogate_success(ic,cs);
if (i)
sprintf(cs->info,"%d 0x%lx %d\n",DIVERT_REPORT,
ic->parm.dss1_io.ll_id,i);
put_info_buffer(cs->info);
break;
default:
printk(KERN_WARNING "dss1_divert: unknown proc %d\n",cs->ics.parm.dss1_io.proc);
break;
}
#if 0
sprintf(st, "0x%lx 0x%lx",ic->arg, ic->parm.dss1_io.ll_id);
p = st + strlen(st);
p1 = ic->parm.dss1_io.data;
i = ic->parm.dss1_io.datalen;
while ((i > 0) && (p - st < 530))
{ p += sprintf(p," %02x",(*p1++) & 0xFF);
i--;
}
sprintf(p, "\n");
put_info_buffer(st);
#endif
break;
default:
printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n",ic->arg);
break;
}
cs1 = cs; /* remember structure */
cs = NULL;
continue; /* abort search */
} /* id found */
break;
case DSS1_CMD_INVOKE_ABORT:
printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
break;
default:
printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n",cs->ics.arg);
break;
} /* switch ics.arg */
cs = cs->next;
} /* driver ok */
}
if (!cs1)
{ printk(KERN_WARNING "dss1_divert unhandled process\n");
return(0);
}
if (cs1->ics.driver == -1)
{ save_flags(flags);
cli();
del_timer(&cs1->timer);
if (cs1->prev)
cs1->prev->next = cs1->next; /* forward link */
else
divert_head = cs1->next;
if (cs1->next)
cs1->next->prev = cs1->prev; /* back link */
restore_flags(flags);
kfree(cs1);
}
return(0);
} /* prot_stat_callback */
/***************************/
/* status callback from HL */
/***************************/
int isdn_divert_stat_callback(isdn_ctrl *ic)
{ struct call_struc *cs, *cs1;
int flags, retval;
retval = -1;
cs = divert_head; /* start of list */
while (cs)
{ if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg))
{ switch (ic->command)
{ case ISDN_STAT_DHUP:
sprintf(cs->info,"129 0x%lx\n",cs->divert_id);
del_timer(&cs->timer);
cs->ics.driver = -1;
break;
case ISDN_STAT_CAUSE:
sprintf(cs->info,"130 0x%lx %s\n",cs->divert_id,ic->parm.num);
break;
case ISDN_STAT_REDIR:
sprintf(cs->info,"131 0x%lx\n",cs->divert_id);
del_timer(&cs->timer);
cs->ics.driver = -1;
break;
default:
sprintf(cs->info,"999 0x%lx 0x%x\n",cs->divert_id,(int)(ic->command));
break;
}
put_info_buffer(cs->info);
retval = 0;
}
cs1 = cs;
cs = cs->next;
if (cs1->ics.driver == -1)
{
save_flags(flags);
cli();
if (cs1->prev)
cs1->prev->next = cs1->next; /* forward link */
else
divert_head = cs1->next;
if (cs1->next)
cs1->next->prev = cs1->prev; /* back link */
restore_flags(flags);
kfree(cs1);
}
}
return(retval); /* not found */
} /* isdn_divert_stat_callback */
/********************/
/* callback from ll */
/********************/
int ll_callback(isdn_ctrl *ic)
{
switch (ic->command)
{ case ISDN_STAT_ICALL:
case ISDN_STAT_ICALLW:
return(isdn_divert_icall(ic));
break;
case ISDN_STAT_PROT:
if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
{ if (ic->arg != DSS1_STAT_INVOKE_BRD)
return(prot_stat_callback(ic));
else
return(0); /* DSS1 invoke broadcast */
}
else
return(-1); /* protocol not euro */
default:
return(isdn_divert_stat_callback(ic));
}
} /* ll_callback */

View File

@ -1,153 +0,0 @@
/*
* $Id$
*
* Header for the diversion supplementary ioctl interface.
*
* Copyright 1998 by Werner Cornelius (werner@ikt.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.3 1999/08/22 20:26:37 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.2 1999/07/04 21:37:33 werner
* Ported from kernel version 2.0
*
*/
#include <linux/ioctl.h>
#include <linux/types.h>
/******************************************/
/* IOCTL codes for interface to user prog */
/******************************************/
#define DIVERT_IIOC_VERSION 0x01 /* actual version */
#define IIOCGETVER _IO('I', 1) /* get version of interface */
#define IIOCGETDRV _IO('I', 2) /* get driver number */
#define IIOCGETNAM _IO('I', 3) /* get driver name */
#define IIOCGETRULE _IO('I', 4) /* read one rule */
#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */
#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */
#define IIOCDELRULE _IO('I', 7) /* delete a rule */
#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */
#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */
#define IIOCDOCFDIS _IO('I',10) /* deactivate control forwarding in PBX */
#define IIOCDOCFINT _IO('I',11) /* interrogate control forwarding in PBX */
/*************************************/
/* states reported through interface */
/*************************************/
#define DEFLECT_IGNORE 0 /* ignore incoming call */
#define DEFLECT_REPORT 1 /* only report */
#define DEFLECT_PROCEED 2 /* deflect when externally triggered */
#define DEFLECT_ALERT 3 /* alert and deflect after delay */
#define DEFLECT_REJECT 4 /* reject immediately */
#define DIVERT_ACTIVATE 5 /* diversion activate */
#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
#define DIVERT_REPORT 7 /* interrogation result */
#define DEFLECT_AUTODEL 255 /* only for internal use */
#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
typedef struct
{ ulong drvid; /* driver ids, bit mapped */
char my_msn[35]; /* desired msn, subaddr allowed */
char caller[35]; /* caller id, partial string with * + subaddr allowed */
char to_nr[35]; /* deflected to number incl. subaddress */
u_char si1,si2; /* service indicators, si1=bitmask, si1+2 0 = all */
u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */
u_char callopt; /* option for call handling:
0 = all calls
1 = only non waiting calls
2 = only waiting calls */
u_char action; /* desired action:
0 = don't report call -> ignore
1 = report call, do not allow/proceed for deflection
2 = report call, send proceed, wait max waittime secs
3 = report call, alert and deflect after waittime
4 = report call, reject immediately
actions 1-2 only take place if interface is opened
*/
u_char waittime; /* maximum wait time for proceeding */
} divert_rule;
typedef union
{ int drv_version; /* return of driver version */
struct
{ int drvid; /* id of driver */
char drvnam[30]; /* name of driver */
} getid;
struct
{ int ruleidx; /* index of rule */
divert_rule rule; /* rule parms */
} getsetrule;
struct
{ u_char subcmd; /* 0 = hangup/reject,
1 = alert,
2 = deflect */
ulong callid; /* id of call delivered by ascii output */
char to_nr[35]; /* destination when deflect,
else uus1 string (maxlen 31),
data from rule used if empty */
} fwd_ctrl;
struct
{ int drvid; /* id of driver */
u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
ulong procid; /* process id returned when no error */
u_char service; /* basically coded service, 0 = all */
char msn[25]; /* desired msn, empty = all */
char fwd_nr[35];/* forwarded to number + subaddress */
} cf_ctrl;
} divert_ioctl;
#ifdef __KERNEL__
#include <linux/isdnif.h>
#include <linux/isdn_divertif.h>
#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */
/**************************************************/
/* structure keeping ascii info for device output */
/**************************************************/
struct divert_info
{ struct divert_info *next;
ulong usage_cnt; /* number of files still to work */
char info_start[2]; /* info string start */
};
/**************/
/* Prototypes */
/**************/
extern ulong if_used; /* number of interface users */
extern int divert_dev_deinit(void);
extern int divert_dev_init(void);
extern void put_info_buffer(char *);
extern int ll_callback(isdn_ctrl *);
extern isdn_divert_if divert_if;
extern divert_rule *getruleptr(int);
extern int insertrule(int, divert_rule *);
extern int deleterule(int);
extern void deleteprocs(void);
extern int deflect_extern_action(u_char, ulong, char *);
extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *);
#endif /* __KERNEL__ */

View File

@ -1,13 +0,0 @@
L_OBJS :=
M_OBJS :=
O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o
O_TARGET :=
ifeq ($(CONFIG_ISDN_DRV_EICON),y)
O_TARGET += eicon.o
else
O_TARGET += eicon.o
M_OBJS = eicon.o
endif
include $(TOPDIR)/Rules.make

View File

@ -1,707 +0,0 @@
/* $Id$
*
* ISDN low-level module for Eicon active ISDN-Cards.
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1998-2000 by Armin Schindler (mac@melware.de)
* Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.18 1999/11/25 11:43:27 armin
* Fixed statectrl and connect message.
* X.75 fix and HDLC/transparent with autoconnect.
* Minor cleanup.
*
* Revision 1.17 1999/10/26 21:15:33 armin
* using define for checking phone number len to avoid buffer overflow.
*
* Revision 1.16 1999/10/08 22:09:33 armin
* Some fixes of cards interface handling.
* Bugfix of NULL pointer occurence.
* Changed a few log outputs.
*
* Revision 1.15 1999/09/26 14:17:53 armin
* Improved debug and log via readstat()
*
* Revision 1.14 1999/09/08 20:17:31 armin
* Added microchannel patch from Erik Weber.
*
* Revision 1.13 1999/09/06 07:29:35 fritz
* Changed my mail-address.
*
* Revision 1.12 1999/09/04 06:20:05 keil
* Changes from kernel set_current_state()
*
* Revision 1.11 1999/08/29 17:23:44 armin
* New setup compat.
* Bugfix if compile as not module.
*
* Revision 1.10 1999/08/22 20:26:41 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.9 1999/08/18 20:16:57 armin
* Added XLOG function for all cards.
* Bugfix of alloc_skb NULL pointer.
*
* Revision 1.8 1999/07/25 15:12:01 armin
* fix of some debug logs.
* enabled ISA-cards option.
*
* Revision 1.7 1999/07/11 17:16:23 armin
* Bugfixes in queue handling.
* Added DSP-DTMF decoder functions.
* Reorganized ack_handler.
*
* Revision 1.6 1999/06/09 19:31:24 armin
* Wrong PLX size for request_region() corrected.
* Added first MCA code from Erik Weber.
*
* Revision 1.5 1999/03/29 11:19:41 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
*
* Revision 1.4 1999/03/02 12:37:42 armin
* Added some important checks.
* Analog Modem with DSP.
* Channels will be added to Link-Level after loading firmware.
*
* Revision 1.3 1999/01/24 20:14:07 armin
* Changed and added debug stuff.
* Better data sending. (still problems with tty's flip buffer)
*
* Revision 1.2 1999/01/10 18:46:04 armin
* Bug with wrong values in HLC fixed.
* Bytes to send are counted and limited now.
*
* Revision 1.1 1999/01/01 18:09:41 armin
* First checkin of new eicon driver.
* DIVA-Server BRI/PCI and PRI/PCI are supported.
* Old diehl code is obsolete.
*
*
*/
#ifndef eicon_h
#define eicon_h
#define EICON_IOCTL_SETMMIO 0
#define EICON_IOCTL_GETMMIO 1
#define EICON_IOCTL_SETIRQ 2
#define EICON_IOCTL_GETIRQ 3
#define EICON_IOCTL_LOADBOOT 4
#define EICON_IOCTL_ADDCARD 5
#define EICON_IOCTL_GETTYPE 6
#define EICON_IOCTL_LOADPCI 7
#define EICON_IOCTL_LOADISA 8
#define EICON_IOCTL_GETVER 9
#define EICON_IOCTL_GETXLOG 10
#define EICON_IOCTL_MANIF 90
#define EICON_IOCTL_FREEIT 97
#define EICON_IOCTL_TEST 98
#define EICON_IOCTL_DEBUGVAR 99
/* Bus types */
#define EICON_BUS_ISA 1
#define EICON_BUS_MCA 2
#define EICON_BUS_PCI 3
/* Constants for describing Card-Type */
#define EICON_CTYPE_S 0
#define EICON_CTYPE_SX 1
#define EICON_CTYPE_SCOM 2
#define EICON_CTYPE_QUADRO 3
#define EICON_CTYPE_S2M 4
#define EICON_CTYPE_MAESTRA 5
#define EICON_CTYPE_MAESTRAQ 6
#define EICON_CTYPE_MAESTRAQ_U 7
#define EICON_CTYPE_MAESTRAP 8
#define EICON_CTYPE_ISABRI 0x10
#define EICON_CTYPE_ISAPRI 0x20
#define EICON_CTYPE_MASK 0x0f
#define EICON_CTYPE_QUADRO_NR(n) (n<<4)
#define MAX_HEADER_LEN 10
#define MAX_STATUS_BUFFER 150
/* Struct for adding new cards */
typedef struct eicon_cdef {
int membase;
int irq;
char id[10];
} eicon_cdef;
#define EICON_ISA_BOOT_MEMCHK 1
#define EICON_ISA_BOOT_NORMAL 2
/* Struct for downloading protocol via ioctl for ISA cards */
/* same struct for downloading protocol via ioctl for MCA cards */
typedef struct {
/* start-up parameters */
unsigned char tei;
unsigned char nt2;
unsigned char skip1;
unsigned char WatchDog;
unsigned char Permanent;
unsigned char XInterface;
unsigned char StableL2;
unsigned char NoOrderCheck;
unsigned char HandsetType;
unsigned char skip2;
unsigned char LowChannel;
unsigned char ProtVersion;
unsigned char Crc4;
unsigned char Loopback;
unsigned char oad[32];
unsigned char osa[32];
unsigned char spid[32];
unsigned char boot_opt;
unsigned long bootstrap_len;
unsigned long firmware_len;
unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */
} eicon_isa_codebuf;
/* Struct for downloading protocol via ioctl for PCI cards */
typedef struct {
/* start-up parameters */
unsigned char tei;
unsigned char nt2;
unsigned char WatchDog;
unsigned char Permanent;
unsigned char XInterface;
unsigned char StableL2;
unsigned char NoOrderCheck;
unsigned char HandsetType;
unsigned char LowChannel;
unsigned char ProtVersion;
unsigned char Crc4;
unsigned char NoHscx30Mode; /* switch PRI into No HSCX30 test mode */
unsigned char Loopback; /* switch card into Loopback mode */
struct q931_link_s
{
unsigned char oad[32];
unsigned char osa[32];
unsigned char spid[32];
} l[2];
unsigned long protocol_len;
unsigned int dsp_code_num;
unsigned long dsp_code_len[9];
unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */
} eicon_pci_codebuf;
/* Data for downloading protocol via ioctl */
typedef union {
eicon_isa_codebuf isa;
eicon_isa_codebuf mca;
eicon_pci_codebuf pci;
} eicon_codebuf;
/* Data for Management interface */
typedef struct {
int count;
int pos;
int length[50];
unsigned char data[700];
} eicon_manifbuf;
#ifdef __KERNEL__
/* Kernel includes */
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/tqueue.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/isdn.h>
#include <linux/isdnif.h>
#include <linux/isdn_compat.h>
typedef struct {
__u16 length __attribute__ ((packed)); /* length of data/parameter field */
__u8 P[1]; /* data/parameter field */
} eicon_PBUFFER;
#include "eicon_isa.h"
/* Macro for delay via schedule() */
#define SLEEP(j) { \
set_current_state(TASK_UNINTERRUPTIBLE); \
schedule_timeout(j); \
}
#endif /* KERNEL */
#define DIVAS_SHARED_OFFSET (0x1000)
#define MIPS_BUFFER_SZ 128
#define MIPS_MAINT_OFFS 0xff00
#define XLOG_ERR_CARD_NUM (13)
#define XLOG_ERR_DONE (14)
#define XLOG_ERR_CMD (15)
#define XLOG_ERR_TIMEOUT (16)
#define XLOG_ERR_CARD_STATE (17)
#define XLOG_ERR_UNKNOWN (18)
#define XLOG_OK (0)
#define TRACE_OK (1)
typedef struct {
__u8 Id __attribute__ ((packed));
__u8 uX __attribute__ ((packed));
__u8 listen __attribute__ ((packed));
__u8 active __attribute__ ((packed));
__u8 sin[3] __attribute__ ((packed));
__u8 bc[6] __attribute__ ((packed));
__u8 llc[6] __attribute__ ((packed));
__u8 hlc[6] __attribute__ ((packed));
__u8 oad[20] __attribute__ ((packed));
}DSigStruc;
typedef struct {
__u32 cx_b1 __attribute__ ((packed));
__u32 cx_b2 __attribute__ ((packed));
__u32 cr_b1 __attribute__ ((packed));
__u32 cr_b2 __attribute__ ((packed));
__u32 px_b1 __attribute__ ((packed));
__u32 px_b2 __attribute__ ((packed));
__u32 pr_b1 __attribute__ ((packed));
__u32 pr_b2 __attribute__ ((packed));
__u16 er_b1 __attribute__ ((packed));
__u16 er_b2 __attribute__ ((packed));
}BL1Struc;
typedef struct {
__u32 XTotal __attribute__ ((packed));
__u32 RTotal __attribute__ ((packed));
__u16 XError __attribute__ ((packed));
__u16 RError __attribute__ ((packed));
}L2Struc;
typedef struct {
__u16 free_n;
}OSStruc;
typedef union
{
DSigStruc DSigStats;
BL1Struc BL1Stats;
L2Struc L2Stats;
OSStruc OSStats;
__u8 b[MIPS_BUFFER_SZ];
__u16 w[MIPS_BUFFER_SZ>>1];
__u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
__u32 d[MIPS_BUFFER_SZ>>2];
} MIPS_BUFFER;
typedef struct
{
__u8 req __attribute__ ((packed));
__u8 rc __attribute__ ((packed));
__u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */
__u8 *mem __attribute__ ((packed));
__u16 length __attribute__ ((packed)); /* used to be short */
__u16 port __attribute__ ((packed));
__u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */
MIPS_BUFFER data __attribute__ ((packed));
} mi_pc_maint_t;
typedef struct
{
__u16 command;
mi_pc_maint_t pcm;
}xlogreq_t;
typedef struct{
__u16 code __attribute__ ((packed)); /* used to be short */
__u16 timeh __attribute__ ((packed));
__u16 timel __attribute__ ((packed));
char buffer[MIPS_BUFFER_SZ - 6];
}xlog_entry_t;
#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
#define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100
#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
#define DSP_FILE_FORMAT_VERSION_BCD 0x0100
typedef struct tag_dsp_combifile_header
{
char format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
__u16 format_version_bcd __attribute__ ((packed));
__u16 header_size __attribute__ ((packed));
__u16 combifile_description_size __attribute__ ((packed));
__u16 directory_entries __attribute__ ((packed));
__u16 directory_size __attribute__ ((packed));
__u16 download_count __attribute__ ((packed));
__u16 usage_mask_size __attribute__ ((packed));
} t_dsp_combifile_header;
typedef struct tag_dsp_combifile_directory_entry
{
__u16 card_type_number __attribute__ ((packed));
__u16 file_set_number __attribute__ ((packed));
} t_dsp_combifile_directory_entry;
typedef struct tag_dsp_file_header
{
char format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
__u16 format_version_bcd __attribute__ ((packed));
__u16 download_id __attribute__ ((packed));
__u16 download_flags __attribute__ ((packed));
__u16 required_processing_power __attribute__ ((packed));
__u16 interface_channel_count __attribute__ ((packed));
__u16 header_size __attribute__ ((packed));
__u16 download_description_size __attribute__ ((packed));
__u16 memory_block_table_size __attribute__ ((packed));
__u16 memory_block_count __attribute__ ((packed));
__u16 segment_table_size __attribute__ ((packed));
__u16 segment_count __attribute__ ((packed));
__u16 symbol_table_size __attribute__ ((packed));
__u16 symbol_count __attribute__ ((packed));
__u16 total_data_size_dm __attribute__ ((packed));
__u16 data_block_count_dm __attribute__ ((packed));
__u16 total_data_size_pm __attribute__ ((packed));
__u16 data_block_count_pm __attribute__ ((packed));
} t_dsp_file_header;
typedef struct tag_dsp_memory_block_desc
{
__u16 alias_memory_block;
__u16 memory_type;
__u16 address;
__u16 size; /* DSP words */
} t_dsp_memory_block_desc;
typedef struct tag_dsp_segment_desc
{
__u16 memory_block;
__u16 attributes;
__u16 base;
__u16 size;
__u16 alignment; /* ==0 -> no other legal start address than base */
} t_dsp_segment_desc;
typedef struct tag_dsp_symbol_desc
{
__u16 symbol_id;
__u16 segment;
__u16 offset;
__u16 size; /* DSP words */
} t_dsp_symbol_desc;
typedef struct tag_dsp_data_block_header
{
__u16 attributes;
__u16 segment;
__u16 offset;
__u16 size; /* DSP words */
} t_dsp_data_block_header;
typedef struct tag_dsp_download_desc /* be sure to keep native alignment for MAESTRA's */
{
__u16 download_id;
__u16 download_flags;
__u16 required_processing_power;
__u16 interface_channel_count;
__u16 excess_header_size;
__u16 memory_block_count;
__u16 segment_count;
__u16 symbol_count;
__u16 data_block_count_dm;
__u16 data_block_count_pm;
__u8 * p_excess_header_data __attribute__ ((packed));
char * p_download_description __attribute__ ((packed));
t_dsp_memory_block_desc *p_memory_block_table __attribute__ ((packed));
t_dsp_segment_desc *p_segment_table __attribute__ ((packed));
t_dsp_symbol_desc *p_symbol_table __attribute__ ((packed));
__u16 * p_data_blocks_dm __attribute__ ((packed));
__u16 * p_data_blocks_pm __attribute__ ((packed));
} t_dsp_download_desc;
#ifdef __KERNEL__
typedef struct {
__u8 Req; /* pending request */
__u8 Rc; /* return code received */
__u8 Ind; /* indication received */
__u8 ReqCh; /* channel of current Req */
__u8 RcCh; /* channel of current Rc */
__u8 IndCh; /* channel of current Ind */
__u8 D3Id; /* ID used by this entity */
__u8 B2Id; /* ID used by this entity */
__u8 GlobalId; /* reserved field */
__u8 XNum; /* number of X-buffers */
__u8 RNum; /* number of R-buffers */
struct sk_buff_head X; /* X-buffer queue */
struct sk_buff_head R; /* R-buffer queue */
__u8 RNR; /* receive not ready flag */
__u8 complete; /* receive complete status */
__u8 busy; /* busy flag */
__u16 ref; /* saved reference */
} entity;
#define FAX_MAX_SCANLINE 256
typedef struct {
__u8 PrevObject;
__u8 NextObject;
__u8 abLine[FAX_MAX_SCANLINE];
__u8 abFrame[FAX_MAX_SCANLINE];
unsigned int LineLen;
unsigned int LineDataLen;
__u32 LineData;
unsigned int NullBytesPos;
__u8 NullByteExist;
int PageCount;
__u8 Dle;
__u8 Eop;
} eicon_ch_fax_buf;
typedef struct {
int No; /* Channel Number */
unsigned short fsm_state; /* Current D-Channel state */
unsigned short statectrl; /* State controling bits */
unsigned short eazmask; /* EAZ-Mask for this Channel */
int queued; /* User-Data Bytes in TX queue */
int waitq; /* User-Data Bytes in wait queue */
int waitpq; /* User-Data Bytes in packet queue */
struct sk_buff *tskb1; /* temp skb 1 */
struct sk_buff *tskb2; /* temp skb 2 */
unsigned char l2prot; /* Layer 2 protocol */
unsigned char l3prot; /* Layer 3 protocol */
#ifdef CONFIG_ISDN_TTY_FAX
T30_s *fax; /* pointer to fax data in LL */
eicon_ch_fax_buf fax2; /* fax related struct */
#endif
entity e; /* Entity */
char cpn[32]; /* remember cpn */
char oad[32]; /* remember oad */
char dsa[32]; /* remember dsa */
char osa[32]; /* remember osa */
unsigned char cause[2]; /* Last Cause */
unsigned char si1;
unsigned char si2;
unsigned char plan;
unsigned char screen;
} eicon_chan;
typedef struct {
eicon_chan *ptr;
} eicon_chan_ptr;
#include "eicon_pci.h"
#define EICON_FLAGS_RUNNING 1 /* Cards driver activated */
#define EICON_FLAGS_PVALID 2 /* Cards port is valid */
#define EICON_FLAGS_IVALID 4 /* Cards irq is valid */
#define EICON_FLAGS_MVALID 8 /* Cards membase is valid */
#define EICON_FLAGS_LOADED 8 /* Firmware loaded */
#define EICON_BCH 2 /* # of channels per card */
/* D-Channel states */
#define EICON_STATE_NULL 0
#define EICON_STATE_ICALL 1
#define EICON_STATE_OCALL 2
#define EICON_STATE_IWAIT 3
#define EICON_STATE_OWAIT 4
#define EICON_STATE_IBWAIT 5
#define EICON_STATE_OBWAIT 6
#define EICON_STATE_BWAIT 7
#define EICON_STATE_BHWAIT 8
#define EICON_STATE_BHWAIT2 9
#define EICON_STATE_DHWAIT 10
#define EICON_STATE_DHWAIT2 11
#define EICON_STATE_BSETUP 12
#define EICON_STATE_ACTIVE 13
#define EICON_STATE_ICALLW 14
#define EICON_STATE_LISTEN 15
#define EICON_STATE_WMCONN 16
#define EICON_MAX_QUEUE 2138
#define EICON_LOCK_TX 0
#define EICON_LOCK_RX 1
typedef union {
eicon_isa_card isa;
eicon_pci_card pci;
eicon_isa_card mca;
} eicon_hwif;
typedef struct {
__u8 ret;
__u8 id;
__u8 ch;
} eicon_ack;
typedef struct {
__u8 code;
__u8 id;
__u8 ch;
} eicon_req;
typedef struct {
__u8 ret;
__u8 id;
__u8 ch;
__u8 more;
} eicon_indhdr;
typedef struct msn_entry {
char eaz;
char msn[16];
struct msn_entry * next;
} msn_entry;
/*
* Per card driver data
*/
typedef struct eicon_card {
eicon_hwif hwif; /* Hardware dependant interface */
u_char ptype; /* Protocol type (1TR6 or Euro) */
u_char bus; /* Bustype (ISA, MCA, PCI) */
u_char type; /* Cardtype (EICON_CTYPE_...) */
struct eicon_card *qnext; /* Pointer to next quadro adapter */
int Feature; /* Protocol Feature Value */
struct eicon_card *next; /* Pointer to next device struct */
int myid; /* Driver-Nr. assigned by linklevel */
unsigned long flags; /* Statusflags */
struct sk_buff_head rcvq; /* Receive-Message queue */
struct sk_buff_head sndq; /* Send-Message queue */
struct sk_buff_head rackq; /* Req-Ack-Message queue */
struct sk_buff_head sackq; /* Data-Ack-Message queue */
struct sk_buff_head statq; /* Status-Message queue */
int statq_entries;
struct tq_struct snd_tq; /* Task struct for xmit bh */
struct tq_struct rcv_tq; /* Task struct for rcv bh */
struct tq_struct ack_tq; /* Task struct for ack bh */
msn_entry *msn_list;
eicon_chan* IdTable[256]; /* Table to find entity */
__u16 ref_in;
__u16 ref_out;
int nchannels; /* Number of B-Channels */
int ReadyInt; /* Ready Interrupt */
eicon_chan *bch; /* B-Channel status/control */
char status_buf[256]; /* Buffer for status messages */
char *status_buf_read;
char *status_buf_write;
char *status_buf_end;
isdn_if interface; /* Interface to upper layer */
char regname[35]; /* Name used for request_region */
#ifdef CONFIG_MCA
int mca_slot; /* # of cards MCA slot */
int mca_io; /* MCA cards IO port */
#endif /* CONFIG_MCA */
} eicon_card;
/* -----------------------------------------------------------**
** The PROTOCOL_FEATURE_STRING **
** defines capabilities and **
** features of the actual protocol code. It's used as a bit **
** mask. **
** The following Bits are defined: **
** -----------------------------------------------------------*/
#define PROTCAP_TELINDUS 0x0001 /* Telindus Variant of protocol code */
#define PROTCAP_MANIF 0x0002 /* Management interface implemented */
#define PROTCAP_V_42 0x0004 /* V42 implemented */
#define PROTCAP_V90D 0x0008 /* V.90D (implies up to 384k DSP code) */
#define PROTCAP_EXTD_FAX 0x0010 /* Extended FAX (ECM, 2D, T6, Polling) */
#define PROTCAP_FREE4 0x0020 /* not used */
#define PROTCAP_FREE5 0x0040 /* not used */
#define PROTCAP_FREE6 0x0080 /* not used */
#define PROTCAP_FREE7 0x0100 /* not used */
#define PROTCAP_FREE8 0x0200 /* not used */
#define PROTCAP_FREE9 0x0400 /* not used */
#define PROTCAP_FREE10 0x0800 /* not used */
#define PROTCAP_FREE11 0x1000 /* not used */
#define PROTCAP_FREE12 0x2000 /* not used */
#define PROTCAP_FREE13 0x4000 /* not used */
#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */
#include "eicon_idi.h"
extern eicon_card *cards;
extern char *eicon_ctype_name[];
extern __inline__ void eicon_schedule_tx(eicon_card *card)
{
queue_task(&card->snd_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
extern __inline__ void eicon_schedule_rx(eicon_card *card)
{
queue_task(&card->rcv_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
extern __inline__ void eicon_schedule_ack(eicon_card *card)
{
queue_task(&card->ack_tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
extern char *eicon_find_eaz(eicon_card *, char);
extern int eicon_addcard(int, int, int, char *);
extern void eicon_io_transmit(eicon_card *card);
extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs);
extern void eicon_io_rcv_dispatch(eicon_card *ccard);
extern void eicon_io_ack_dispatch(eicon_card *ccard);
extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq);
#ifdef CONFIG_MCA
extern int eicon_mca_find_card(int, int, int, char *);
extern int eicon_mca_probe(int, int, int, int, char *);
extern int eicon_info(char *, int , void *);
#endif /* CONFIG_MCA */
extern ulong DebugVar;
extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
extern void eicon_putstatus(eicon_card * card, char * buf);
#endif /* __KERNEL__ */
#endif /* eicon_h */

View File

@ -1,419 +0,0 @@
/* $Id$
*
* ISDN lowlevel-module for Eicon active cards.
* DSP definitions
*
* Copyright 1999,2000 by Armin Schindler (mac@melware.de)
* Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.4 1999/07/25 15:12:02 armin
* fix of some debug logs.
* enabled ISA-cards option.
*
* Revision 1.3 1999/07/11 17:16:24 armin
* Bugfixes in queue handling.
* Added DSP-DTMF decoder functions.
* Reorganized ack_handler.
*
* Revision 1.2 1999/03/29 11:19:42 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
*
* Revision 1.1 1999/03/02 12:18:54 armin
* First checkin of DSP defines for audio features.
*
*
*/
#ifndef DSP_H
#define DSP_H
#define DSP_UDATA_REQUEST_RECONFIGURE 0
/*
parameters:
<word> reconfigure delay (in 8kHz samples)
<word> reconfigure code
<byte> reconfigure hdlc preamble flags
*/
#define DSP_RECONFIGURE_TX_FLAG 0x8000
#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG 0x4000
#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000
#define DSP_RECONFIGURE_HDLC_FLAG 0x1000
#define DSP_RECONFIGURE_SYNC_FLAG 0x0800
#define DSP_RECONFIGURE_PROTOCOL_MASK 0x00ff
#define DSP_RECONFIGURE_IDLE 0
#define DSP_RECONFIGURE_V25 1
#define DSP_RECONFIGURE_V21_CH2 2
#define DSP_RECONFIGURE_V27_2400 3
#define DSP_RECONFIGURE_V27_4800 4
#define DSP_RECONFIGURE_V29_7200 5
#define DSP_RECONFIGURE_V29_9600 6
#define DSP_RECONFIGURE_V33_12000 7
#define DSP_RECONFIGURE_V33_14400 8
#define DSP_RECONFIGURE_V17_7200 9
#define DSP_RECONFIGURE_V17_9600 10
#define DSP_RECONFIGURE_V17_12000 11
#define DSP_RECONFIGURE_V17_14400 12
/*
data indications if transparent framer
<byte> data 0
<byte> data 1
...
data indications if HDLC framer
<byte> data 0
<byte> data 1
...
<byte> CRC 0
<byte> CRC 1
<byte> preamble flags
*/
#define DSP_UDATA_REQUEST_SWITCH_FRAMER 1
/*
parameters:
<byte> transmit framer type
<byte> receive framer type
*/
#define DSP_REQUEST_SWITCH_FRAMER_HDLC 0
#define DSP_REQUEST_SWITCH_FRAMER_TRANSPARENT 1
#define DSP_REQUEST_SWITCH_FRAMER_ASYNC 2
#define DSP_UDATA_REQUEST_CLEARDOWN 2
/*
parameters:
- none -
*/
#define DSP_UDATA_REQUEST_TX_CONFIRMATION_ON 3
/*
parameters:
- none -
*/
#define DSP_UDATA_REQUEST_TX_CONFIRMATION_OFF 4
/*
parameters:
- none -
*/
#define DSP_UDATA_INDICATION_SYNC 0
/*
returns:
<word> time of sync (sampled from counter at 8kHz)
*/
#define DSP_UDATA_INDICATION_DCD_OFF 1
/*
returns:
<word> time of DCD off (sampled from counter at 8kHz)
*/
#define DSP_UDATA_INDICATION_DCD_ON 2
/*
returns:
<word> time of DCD on (sampled from counter at 8kHz)
<byte> connected norm
<word> connected options
<dword> connected speed (bit/s, max of tx and rx speed)
<word> roundtrip delay (ms)
<dword> connected speed tx (bit/s)
<dword> connected speed rx (bit/s)
*/
#define DSP_UDATA_INDICATION_CTS_OFF 3
/*
returns:
<word> time of CTS off (sampled from counter at 8kHz)
*/
#define DSP_UDATA_INDICATION_CTS_ON 4
/*
returns:
<word> time of CTS on (sampled from counter at 8kHz)
<byte> connected norm
<word> connected options
<dword> connected speed (bit/s, max of tx and rx speed)
<word> roundtrip delay (ms)
<dword> connected speed tx (bit/s)
<dword> connected speed rx (bit/s)
*/
typedef struct eicon_dsp_ind {
__u16 time __attribute__ ((packed));
__u8 norm __attribute__ ((packed));
__u16 options __attribute__ ((packed));
__u32 speed __attribute__ ((packed));
__u16 delay __attribute__ ((packed));
__u32 txspeed __attribute__ ((packed));
__u32 rxspeed __attribute__ ((packed));
} eicon_dsp_ind;
#define DSP_CONNECTED_NORM_UNSPECIFIED 0
#define DSP_CONNECTED_NORM_V21 1
#define DSP_CONNECTED_NORM_V23 2
#define DSP_CONNECTED_NORM_V22 3
#define DSP_CONNECTED_NORM_V22_BIS 4
#define DSP_CONNECTED_NORM_V32_BIS 5
#define DSP_CONNECTED_NORM_V34 6
#define DSP_CONNECTED_NORM_V8 7
#define DSP_CONNECTED_NORM_BELL_212A 8
#define DSP_CONNECTED_NORM_BELL_103 9
#define DSP_CONNECTED_NORM_V29_LEASED_LINE 10
#define DSP_CONNECTED_NORM_V33_LEASED_LINE 11
#define DSP_CONNECTED_NORM_V90 12
#define DSP_CONNECTED_NORM_V21_CH2 13
#define DSP_CONNECTED_NORM_V27_TER 14
#define DSP_CONNECTED_NORM_V29 15
#define DSP_CONNECTED_NORM_V33 16
#define DSP_CONNECTED_NORM_V17 17
#define DSP_CONNECTED_OPTION_TRELLIS 0x0001
#define DSP_CONNECTED_OPTION_V42_TRANS 0x0002
#define DSP_CONNECTED_OPTION_V42_LAPM 0x0004
#define DSP_CONNECTED_OPTION_SHORT_TRAIN 0x0008
#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
#define DSP_UDATA_INDICATION_DISCONNECT 5
/*
returns:
<byte> cause
*/
#define DSP_DISCONNECT_CAUSE_NONE 0x00
#define DSP_DISCONNECT_CAUSE_BUSY_TONE 0x01
#define DSP_DISCONNECT_CAUSE_CONGESTION_TONE 0x02
#define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY 0x03
#define DSP_DISCONNECT_CAUSE_CLEARDOWN 0x04
#define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT 0x05
#define DSP_UDATA_INDICATION_TX_CONFIRMATION 6
/*
returns:
<word> confirmation number
*/
#define DSP_UDATA_REQUEST_SEND_DTMF_DIGITS 16
/*
parameters:
<word> tone duration (ms)
<word> gap duration (ms)
<byte> digit 0 tone code
...
<byte> digit n tone code
*/
#define DSP_SEND_DTMF_DIGITS_HEADER_LENGTH 5
#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_697_HZ 0x00
#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_770_HZ 0x01
#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_852_HZ 0x02
#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_941_HZ 0x03
#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_MASK 0x03
#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ 0x00
#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ 0x04
#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ 0x08
#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ 0x0c
#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_MASK 0x0c
#define DSP_DTMF_DIGIT_TONE_CODE_0 0x07
#define DSP_DTMF_DIGIT_TONE_CODE_1 0x00
#define DSP_DTMF_DIGIT_TONE_CODE_2 0x04
#define DSP_DTMF_DIGIT_TONE_CODE_3 0x08
#define DSP_DTMF_DIGIT_TONE_CODE_4 0x01
#define DSP_DTMF_DIGIT_TONE_CODE_5 0x05
#define DSP_DTMF_DIGIT_TONE_CODE_6 0x09
#define DSP_DTMF_DIGIT_TONE_CODE_7 0x02
#define DSP_DTMF_DIGIT_TONE_CODE_8 0x06
#define DSP_DTMF_DIGIT_TONE_CODE_9 0x0a
#define DSP_DTMF_DIGIT_TONE_CODE_STAR 0x03
#define DSP_DTMF_DIGIT_TONE_CODE_HASHMARK 0x0b
#define DSP_DTMF_DIGIT_TONE_CODE_A 0x0c
#define DSP_DTMF_DIGIT_TONE_CODE_B 0x0d
#define DSP_DTMF_DIGIT_TONE_CODE_C 0x0e
#define DSP_DTMF_DIGIT_TONE_CODE_D 0x0f
#define DSP_UDATA_INDICATION_DTMF_DIGITS_SENT 16
/*
returns:
- none -
One indication will be sent for every request.
*/
#define DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER 17
/*
parameters:
<word> tone duration (ms)
<word> gap duration (ms)
*/
typedef struct enable_dtmf_s {
__u16 tone;
__u16 gap;
} enable_dtmf_s;
#define DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER 18
/*
parameters:
- none -
*/
#define DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED 17
/*
returns:
<byte> digit 0 tone code
...
<byte> digit n tone code
*/
#define DSP_DTMF_DIGITS_RECEIVED_HEADER_LENGTH 1
#define DSP_UDATA_INDICATION_MODEM_CALLING_TONE 18
/*
returns:
- none -
*/
#define DSP_UDATA_INDICATION_FAX_CALLING_TONE 19
/*
returns:
- none -
*/
#define DSP_UDATA_INDICATION_ANSWER_TONE 20
/*
returns:
- none -
*/
/* ============= FAX ================ */
#define EICON_FAXID_LEN 20
typedef struct eicon_t30_s {
__u8 code;
__u8 rate;
__u8 resolution;
__u8 format;
__u8 pages_low;
__u8 pages_high;
__u8 atf;
__u8 control_bits_low;
__u8 control_bits_high;
__u8 feature_bits_low;
__u8 feature_bits_high;
__u8 universal_5;
__u8 universal_6;
__u8 universal_7;
__u8 station_id_len;
__u8 head_line_len;
__u8 station_id[EICON_FAXID_LEN];
/* __u8 head_line[]; */
} eicon_t30_s;
/* EDATA transmit messages */
#define EDATA_T30_DIS 0x01
#define EDATA_T30_FTT 0x02
#define EDATA_T30_MCF 0x03
/* EDATA receive messages */
#define EDATA_T30_DCS 0x81
#define EDATA_T30_TRAIN_OK 0x82
#define EDATA_T30_EOP 0x83
#define EDATA_T30_MPS 0x84
#define EDATA_T30_EOM 0x85
#define EDATA_T30_DTC 0x86
#define T30_FORMAT_SFF 0
#define T30_FORMAT_ASCII 1
#define T30_FORMAT_COUNT 2
#define T30_CONTROL_BIT_DISABLE_FINE 0x0001
#define T30_CONTROL_BIT_ENABLE_ECM 0x0002
#define T30_CONTROL_BIT_ECM_64_BYTES 0x0004
#define T30_CONTROL_BIT_ENABLE_2D_CODING 0x0008
#define T30_CONTROL_BIT_ENABLE_T6_CODING 0x0010
#define T30_CONTROL_BIT_ENABLE_UNCOMPR 0x0020
#define T30_CONTROL_BIT_ACCEPT_POLLING 0x0040
#define T30_CONTROL_BIT_REQUEST_POLLING 0x0080
#define T30_CONTROL_BIT_MORE_DOCUMENTS 0x0100
#define T30_CONTROL_BIT_ALL_FEATURES\
(T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING |\
T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR)
#define T30_FEATURE_BIT_FINE 0x0001
#define T30_FEATURE_BIT_ECM 0x0002
#define T30_FEATURE_BIT_ECM_64_BYTES 0x0004
#define T30_FEATURE_BIT_2D_CODING 0x0008
#define T30_FEATURE_BIT_T6_CODING 0x0010
#define T30_FEATURE_BIT_UNCOMPR_ENABLED 0x0020
#define T30_FEATURE_BIT_POLLING 0x0040
#define FAX_OBJECT_DOCU 1
#define FAX_OBJECT_PAGE 2
#define FAX_OBJECT_LINE 3
#define T4_EOL 0x800
#define T4_EOL_BITSIZE 12
#define T4_EOL_DWORD (T4_EOL << (32 - T4_EOL_BITSIZE))
#define T4_EOL_MASK_DWORD ((__u32) -1 << (32 - T4_EOL_BITSIZE))
#define SFF_LEN_FLD_SIZE 3
#define _DLE_ 0x10
#define _ETX_ 0x03
typedef struct eicon_sff_dochead {
__u32 id __attribute__ ((packed));
__u8 version __attribute__ ((packed));
__u8 reserved1 __attribute__ ((packed));
__u16 userinfo __attribute__ ((packed));
__u16 pagecount __attribute__ ((packed));
__u16 off1pagehead __attribute__ ((packed));
__u32 offnpagehead __attribute__ ((packed));
__u32 offdocend __attribute__ ((packed));
} eicon_sff_dochead;
typedef struct eicon_sff_pagehead {
__u8 pageheadid __attribute__ ((packed));
__u8 pageheadlen __attribute__ ((packed));
__u8 resvert __attribute__ ((packed));
__u8 reshoriz __attribute__ ((packed));
__u8 coding __attribute__ ((packed));
__u8 reserved2 __attribute__ ((packed));
__u16 linelength __attribute__ ((packed));
__u16 pagelength __attribute__ ((packed));
__u32 offprevpage __attribute__ ((packed));
__u32 offnextpage __attribute__ ((packed));
} eicon_sff_pagehead;
#endif /* DSP_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,284 +0,0 @@
/* $Id$
*
* ISDN lowlevel-module for the Eicon active cards.
* IDI-Interface
*
* Copyright 1998-2000 by Armin Schindler (mac@melware.de)
* Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.8 1999/11/25 11:43:27 armin
* Fixed statectrl and connect message.
* X.75 fix and HDLC/transparent with autoconnect.
* Minor cleanup.
*
* Revision 1.7 1999/08/22 20:26:46 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.6 1999/07/25 15:12:04 armin
* fix of some debug logs.
* enabled ISA-cards option.
*
* Revision 1.5 1999/07/11 17:16:26 armin
* Bugfixes in queue handling.
* Added DSP-DTMF decoder functions.
* Reorganized ack_handler.
*
* Revision 1.4 1999/03/29 11:19:44 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
*
* Revision 1.3 1999/03/02 12:37:45 armin
* Added some important checks.
* Analog Modem with DSP.
* Channels will be added to Link-Level after loading firmware.
*
* Revision 1.2 1999/01/24 20:14:18 armin
* Changed and added debug stuff.
* Better data sending. (still problems with tty's flip buffer)
*
* Revision 1.1 1999/01/01 18:09:42 armin
* First checkin of new eicon driver.
* DIVA-Server BRI/PCI and PRI/PCI are supported.
* Old diehl code is obsolete.
*
*
*/
#ifndef IDI_H
#define IDI_H
#include <linux/config.h>
#define ASSIGN 0x01
#define REMOVE 0xff
#define CALL_REQ 1 /* call request */
#define CALL_CON 1 /* call confirmation */
#define CALL_IND 2 /* incoming call connected */
#define LISTEN_REQ 2 /* listen request */
#define HANGUP 3 /* hangup request/indication */
#define SUSPEND 4 /* call suspend request/confirm */
#define RESUME 5 /* call resume request/confirm */
#define SUSPEND_REJ 6 /* suspend rejected indication */
#define USER_DATA 8 /* user data for user to user signaling */
#define CONGESTION 9 /* network congestion indication */
#define INDICATE_REQ 10 /* request to indicate an incoming call */
#define INDICATE_IND 10 /* indicates that there is an incoming call */
#define CALL_RES 11 /* accept an incoming call */
#define CALL_ALERT 12 /* send ALERT for incoming call */
#define INFO_REQ 13 /* INFO request */
#define INFO_IND 13 /* INFO indication */
#define REJECT 14 /* reject an incoming call */
#define RESOURCES 15 /* reserve B-Channel hardware resources */
#define TEL_CTRL 16 /* Telephone control request/indication */
#define STATUS_REQ 17 /* Request D-State (returned in INFO_IND) */
#define FAC_REG_REQ 18 /* connection idependent fac registration */
#define FAC_REG_ACK 19 /* fac registration acknowledge */
#define FAC_REG_REJ 20 /* fac registration reject */
#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call */
#define AOC_IND 26/* Advice of Charge */
#define IDI_N_MDATA (0x01)
#define IDI_N_CONNECT (0x02)
#define IDI_N_CONNECT_ACK (0x03)
#define IDI_N_DISC (0x04)
#define IDI_N_DISC_ACK (0x05)
#define IDI_N_RESET (0x06)
#define IDI_N_RESET_ACK (0x07)
#define IDI_N_DATA (0x08)
#define IDI_N_EDATA (0x09)
#define IDI_N_UDATA (0x0a)
#define IDI_N_BDATA (0x0b)
#define IDI_N_DATA_ACK (0x0c)
#define IDI_N_EDATA_ACK (0x0d)
#define N_Q_BIT 0x10 /* Q-bit for req/ind */
#define N_M_BIT 0x20 /* M-bit for req/ind */
#define N_D_BIT 0x40 /* D-bit for req/ind */
#define SHIFT 0x90 /* codeset shift */
#define MORE 0xa0 /* more data */
#define CL 0xb0 /* congestion level */
/* codeset 0 */
#define BC 0x04 /* Bearer Capability */
#define CAU 0x08 /* cause */
#define CAD 0x0c /* Connected address */
#define CAI 0x10 /* call identity */
#define CHI 0x18 /* channel identification */
#define LLI 0x19 /* logical link id */
#define CHA 0x1a /* charge advice */
#define FTY 0x1c
#define PI 0x1e /* Progress Indicator */
#define NI 0x27 /* Notification Indicator */
#define DT 0x29 /* ETSI date/time */
#define KEY 0x2c /* keypad information element */
#define DSP 0x28 /* display */
#define OAD 0x6c /* origination address */
#define OSA 0x6d /* origination sub-address */
#define CPN 0x70 /* called party number */
#define DSA 0x71 /* destination sub-address */
#define RDN 0x74 /* redirecting number */
#define LLC 0x7c /* low layer compatibility */
#define HLC 0x7d /* high layer compatibility */
#define UUI 0x7e /* user user information */
#define ESC 0x7f /* escape extension */
#define DLC 0x20 /* data link layer configuration */
#define NLC 0x21 /* network layer configuration */
/* codeset 6 */
#define SIN 0x01 /* service indicator */
#define CIF 0x02 /* charging information */
#define DATE 0x03 /* date */
#define CPS 0x07 /* called party status */
/*------------------------------------------------------------------*/
/* return code coding */
/*------------------------------------------------------------------*/
#define UNKNOWN_COMMAND 0x01 /* unknown command */
#define WRONG_COMMAND 0x02 /* wrong command */
#define WRONG_ID 0x03 /* unknown task/entity id */
#define WRONG_CH 0x04 /* wrong task/entity id */
#define UNKNOWN_IE 0x05 /* unknown information el. */
#define WRONG_IE 0x06 /* wrong information el. */
#define OUT_OF_RESOURCES 0x07 /* card out of res. */
#define N_FLOW_CONTROL 0x10 /* Flow-Control, retry */
#define ASSIGN_RC 0xe0 /* ASSIGN acknowledgement */
#define ASSIGN_OK 0xef /* ASSIGN OK */
#define OK_FC 0xfc /* Flow-Control RC */
#define READY_INT 0xfd /* Ready interrupt */
#define TIMER_INT 0xfe /* timer interrupt */
#define OK 0xff /* command accepted */
/*------------------------------------------------------------------*/
/* defines for statectrl */
#define WAITING_FOR_HANGUP 0x01
#define HAVE_CONN_REQ 0x02
typedef struct {
char cpn[32];
char oad[32];
char dsa[32];
char osa[32];
__u8 plan;
__u8 screen;
__u8 sin[4];
__u8 chi[4];
__u8 e_chi[4];
__u8 bc[12];
__u8 e_bc[12];
__u8 llc[18];
__u8 hlc[5];
__u8 cau[4];
__u8 e_cau[2];
__u8 e_mt;
__u8 dt[6];
char display[83];
char keypad[35];
char rdn[32];
} idi_ind_message;
typedef struct {
__u16 next __attribute__ ((packed));
__u8 Req __attribute__ ((packed));
__u8 ReqId __attribute__ ((packed));
__u8 ReqCh __attribute__ ((packed));
__u8 Reserved1 __attribute__ ((packed));
__u16 Reference __attribute__ ((packed));
__u8 Reserved[8] __attribute__ ((packed));
eicon_PBUFFER XBuffer;
} eicon_REQ;
typedef struct {
__u16 next __attribute__ ((packed));
__u8 Rc __attribute__ ((packed));
__u8 RcId __attribute__ ((packed));
__u8 RcCh __attribute__ ((packed));
__u8 Reserved1 __attribute__ ((packed));
__u16 Reference __attribute__ ((packed));
__u8 Reserved2[8] __attribute__ ((packed));
} eicon_RC;
typedef struct {
__u16 next __attribute__ ((packed));
__u8 Ind __attribute__ ((packed));
__u8 IndId __attribute__ ((packed));
__u8 IndCh __attribute__ ((packed));
__u8 MInd __attribute__ ((packed));
__u16 MLength __attribute__ ((packed));
__u16 Reference __attribute__ ((packed));
__u8 RNR __attribute__ ((packed));
__u8 Reserved __attribute__ ((packed));
__u32 Ack __attribute__ ((packed));
eicon_PBUFFER RBuffer;
} eicon_IND;
typedef struct {
__u16 NextReq __attribute__ ((packed)); /* pointer to next Req Buffer */
__u16 NextRc __attribute__ ((packed)); /* pointer to next Rc Buffer */
__u16 NextInd __attribute__ ((packed)); /* pointer to next Ind Buffer */
__u8 ReqInput __attribute__ ((packed)); /* number of Req Buffers sent */
__u8 ReqOutput __attribute__ ((packed)); /* number of Req Buffers returned */
__u8 ReqReserved __attribute__ ((packed));/*number of Req Buffers reserved */
__u8 Int __attribute__ ((packed)); /* ISDN-P interrupt */
__u8 XLock __attribute__ ((packed)); /* Lock field for arbitration */
__u8 RcOutput __attribute__ ((packed)); /* number of Rc buffers received */
__u8 IndOutput __attribute__ ((packed)); /* number of Ind buffers received */
__u8 IMask __attribute__ ((packed)); /* Interrupt Mask Flag */
__u8 Reserved1[2] __attribute__ ((packed)); /* reserved field, do not use */
__u8 ReadyInt __attribute__ ((packed)); /* request field for ready int */
__u8 Reserved2[12] __attribute__ ((packed)); /* reserved field, do not use */
__u8 InterfaceType __attribute__ ((packed)); /* interface type 1=16K */
__u16 Signature __attribute__ ((packed)); /* ISDN-P initialized ind */
__u8 B[1]; /* buffer space for Req,Ind and Rc */
} eicon_pr_ram;
typedef struct {
__u8 *Data;
unsigned int Size;
unsigned int Len;
__u8 *Next;
} eicon_OBJBUFFER;
extern int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer);
extern int idi_hangup(eicon_card *card, eicon_chan *chan);
extern int idi_connect_res(eicon_card *card, eicon_chan *chan);
extern int eicon_idi_listen_req(eicon_card *card, eicon_chan *chan);
extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
char *eazmsn, int si1, int si2);
extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que);
extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value);
#ifdef CONFIG_ISDN_TTY_FAX
extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan);
extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb);
#endif
#endif

View File

@ -1,916 +0,0 @@
/* $Id$
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Code for communicating with hardware.
*
* Copyright 1999,2000 by Armin Schindler (mac@melware.de)
* Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.9 1999/11/18 20:55:25 armin
* Ready_Int fix of ISA cards.
*
* Revision 1.8 1999/10/08 22:09:34 armin
* Some fixes of cards interface handling.
* Bugfix of NULL pointer occurence.
* Changed a few log outputs.
*
* Revision 1.7 1999/09/26 14:17:53 armin
* Improved debug and log via readstat()
*
* Revision 1.6 1999/09/21 20:35:43 armin
* added more error checking.
*
* Revision 1.5 1999/08/31 11:20:11 paul
* various spelling corrections (new checksums may be needed, Karsten!)
*
* Revision 1.4 1999/08/22 20:26:47 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.3 1999/08/18 20:17:01 armin
* Added XLOG function for all cards.
* Bugfix of alloc_skb NULL pointer.
*
* Revision 1.2 1999/07/25 15:12:05 armin
* fix of some debug logs.
* enabled ISA-cards option.
*
* Revision 1.1 1999/03/29 11:19:45 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
*
*
*/
#include <linux/config.h>
#include "eicon.h"
void
eicon_io_rcv_dispatch(eicon_card *ccard) {
ulong flags;
struct sk_buff *skb, *skb2, *skb_new;
eicon_IND *ind, *ind2, *ind_new;
eicon_chan *chan;
if (!ccard) {
eicon_log(ccard, 1, "eicon_err: NULL card in rcv_dispatch !\n");
return;
}
while((skb = skb_dequeue(&ccard->rcvq))) {
ind = (eicon_IND *)skb->data;
save_flags(flags);
cli();
if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
if (DebugVar & 1) {
switch(ind->Ind) {
case IDI_N_DISC_ACK:
/* doesn't matter if this happens */
break;
default:
eicon_log(ccard, 1, "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
eicon_log(ccard, 1, "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
}
}
restore_flags(flags);
dev_kfree_skb(skb);
continue;
}
restore_flags(flags);
if (chan->e.complete) { /* check for rec-buffer chaining */
if (ind->MLength == ind->RBuffer.length) {
chan->e.complete = 1;
idi_handle_ind(ccard, skb);
continue;
}
else {
chan->e.complete = 0;
ind->Ind = ind->MInd;
skb_queue_tail(&chan->e.R, skb);
continue;
}
}
else {
save_flags(flags);
cli();
if (!(skb2 = skb_dequeue(&chan->e.R))) {
chan->e.complete = 1;
eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n");
restore_flags(flags);
dev_kfree_skb(skb);
continue;
}
ind2 = (eicon_IND *)skb2->data;
skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length),
GFP_ATOMIC);
if (!skb_new) {
eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n");
restore_flags(flags);
dev_kfree_skb(skb);
dev_kfree_skb(skb2);
continue;
}
ind_new = (eicon_IND *)skb_put(skb_new,
((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length));
ind_new->Ind = ind2->Ind;
ind_new->IndId = ind2->IndId;
ind_new->IndCh = ind2->IndCh;
ind_new->MInd = ind2->MInd;
ind_new->MLength = ind2->MLength;
ind_new->RBuffer.length = ind2->RBuffer.length + ind->RBuffer.length;
memcpy(&ind_new->RBuffer.P, &ind2->RBuffer.P, ind2->RBuffer.length);
memcpy((&ind_new->RBuffer.P)+ind2->RBuffer.length, &ind->RBuffer.P, ind->RBuffer.length);
dev_kfree_skb(skb);
dev_kfree_skb(skb2);
if (ind->MLength == ind->RBuffer.length) {
chan->e.complete = 2;
restore_flags(flags);
idi_handle_ind(ccard, skb_new);
continue;
}
else {
chan->e.complete = 0;
skb_queue_tail(&chan->e.R, skb_new);
restore_flags(flags);
continue;
}
}
}
}
void
eicon_io_ack_dispatch(eicon_card *ccard) {
struct sk_buff *skb;
if (!ccard) {
eicon_log(ccard, 1, "eicon_err: NULL card in ack_dispatch!\n");
return;
}
while((skb = skb_dequeue(&ccard->rackq))) {
idi_handle_ack(ccard, skb);
}
}
/*
* IO-Functions for different card-types
*/
u8 ram_inb(eicon_card *card, void *adr) {
eicon_pci_card *pcard;
eicon_isa_card *icard;
u32 addr = (u32) adr;
pcard = &card->hwif.pci;
icard = &card->hwif.isa;
switch(card->type) {
case EICON_CTYPE_MAESTRA:
outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
return(inb((u16)pcard->PCIreg + M_DATA));
case EICON_CTYPE_MAESTRAP:
case EICON_CTYPE_S2M:
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
return(readb(addr));
}
return(0);
}
u16 ram_inw(eicon_card *card, void *adr) {
eicon_pci_card *pcard;
eicon_isa_card *icard;
u32 addr = (u32) adr;
pcard = &card->hwif.pci;
icard = &card->hwif.isa;
switch(card->type) {
case EICON_CTYPE_MAESTRA:
outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
return(inw((u16)pcard->PCIreg + M_DATA));
case EICON_CTYPE_MAESTRAP:
case EICON_CTYPE_S2M:
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
return(readw(addr));
}
return(0);
}
void ram_outb(eicon_card *card, void *adr, u8 data) {
eicon_pci_card *pcard;
eicon_isa_card *icard;
u32 addr = (u32) adr;
pcard = &card->hwif.pci;
icard = &card->hwif.isa;
switch(card->type) {
case EICON_CTYPE_MAESTRA:
outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
outb((u8)data, (u16)pcard->PCIreg + M_DATA);
break;
case EICON_CTYPE_MAESTRAP:
case EICON_CTYPE_S2M:
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
writeb(data, addr);
break;
}
}
void ram_outw(eicon_card *card, void *adr , u16 data) {
eicon_pci_card *pcard;
eicon_isa_card *icard;
u32 addr = (u32) adr;
pcard = &card->hwif.pci;
icard = &card->hwif.isa;
switch(card->type) {
case EICON_CTYPE_MAESTRA:
outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
outw((u16)data, (u16)pcard->PCIreg + M_DATA);
break;
case EICON_CTYPE_MAESTRAP:
case EICON_CTYPE_S2M:
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
writew(data, addr);
break;
}
}
void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) {
int i;
switch(card->type) {
case EICON_CTYPE_MAESTRA:
for(i = 0; i < len; i++) {
writeb(ram_inb(card, adr + i), adrto + i);
}
break;
case EICON_CTYPE_MAESTRAP:
memcpy(adrto, adr, len);
break;
case EICON_CTYPE_S2M:
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
memcpy_fromio(adrto, adr, len);
break;
}
}
void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) {
int i;
switch(card->type) {
case EICON_CTYPE_MAESTRA:
for(i = 0; i < len; i++) {
ram_outb(card, adrto + i, readb(adr + i));
}
break;
case EICON_CTYPE_MAESTRAP:
memcpy(adrto, adr, len);
break;
case EICON_CTYPE_S2M:
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
memcpy_toio(adrto, adr, len);
break;
}
}
/*
* XLOG
*/
int
eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq)
{
int timeout, i;
int divas_shared_offset = 0;
int len = 0;
int stype = 0;
__u32 time = 0;
mi_pc_maint_t *pcm = &xlogreq->pcm;
eicon_pci_card *pci_card = &card->hwif.pci;
eicon_isa_card *isa_card = &card->hwif.isa;
eicon_pr_ram *prram = 0;
char *ram;
switch(card->type) {
case EICON_CTYPE_MAESTRAP:
ram = (char *)pci_card->PCIram;
prram = (eicon_pr_ram *)ram;
divas_shared_offset = DIVAS_SHARED_OFFSET;
len = sizeof(mi_pc_maint_t);
break;
case EICON_CTYPE_MAESTRA:
prram = 0;
divas_shared_offset = 0;
len = sizeof(mi_pc_maint_t);
break;
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
case EICON_CTYPE_S2M:
prram = (eicon_pr_ram *)isa_card->shmem;
divas_shared_offset = 0xfb80;
len = sizeof(mi_pc_maint_t) - 78;
stype = 1;
break;
default:
return -ENODEV;
}
memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t));
xlogreq->pcm.rc = 0;
xlogreq->pcm.req = 1; /* DO_LOG */
ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset;
ram_outb(card, ram+1, pcm->rc);
ram_outb(card, ram+0, pcm->req);
timeout = jiffies + 50;
while (timeout > jiffies) {
pcm->rc = ram_inb(card, ram+1);
pcm->req = ram_inb(card, ram+0);
if (!pcm->req) break;
SLEEP(10);
}
if (pcm->req) {
return XLOG_ERR_TIMEOUT;
}
if (pcm->rc != OK) {
return XLOG_ERR_DONE;
}
ram_copyfromcard(card, pcm, ram, len);
if (stype) {
for (i=0; i<8; i++)
((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i];
time = (__u32)pcm->data.w[2] * 3600 * 1000 +
(__u32)pcm->data.w[1] * 1000 +
(__u32)pcm->data.b[1] * 20 +
(__u32)pcm->data.b[0] ;
pcm->data.w[1] = (__u16) (time >> 16);
pcm->data.w[2] = (__u16) (time & 0x0000ffff);
pcm->data.w[0] = 2;
}
return XLOG_OK;
}
/*
* Transmit-Function
*/
void
eicon_io_transmit(eicon_card *ccard) {
eicon_pci_card *pci_card;
eicon_isa_card *isa_card;
struct sk_buff *skb;
struct sk_buff *skb2;
unsigned long flags;
char *ram, *reg, *cfg;
eicon_pr_ram *prram = 0;
eicon_isa_com *com = 0;
eicon_REQ *ReqOut = 0;
eicon_REQ *reqbuf = 0;
eicon_chan *chan;
eicon_chan_ptr *chan2;
int ReqCount;
int scom = 0;
int tmp = 0;
int quloop = 1;
int dlev = 0;
pci_card = &ccard->hwif.pci;
isa_card = &ccard->hwif.isa;
if (!ccard) {
eicon_log(ccard, 1, "eicon_transmit: NULL card!\n");
return;
}
switch(ccard->type) {
#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
scom = 1;
com = (eicon_isa_com *)isa_card->shmem;
break;
case EICON_CTYPE_S2M:
scom = 0;
prram = (eicon_pr_ram *)isa_card->shmem;
break;
#endif
case EICON_CTYPE_MAESTRAP:
scom = 0;
ram = (char *)pci_card->PCIram;
reg = (char *)pci_card->PCIreg;
cfg = (char *)pci_card->PCIcfg;
prram = (eicon_pr_ram *)ram;
break;
case EICON_CTYPE_MAESTRA:
scom = 0;
ram = (char *)pci_card->PCIram;
reg = (char *)pci_card->PCIreg;
cfg = (char *)pci_card->PCIcfg;
prram = 0;
break;
default:
eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n");
return;
}
ReqCount = 0;
if (!(skb2 = skb_dequeue(&ccard->sndq)))
quloop = 0;
while(quloop) {
save_flags(flags);
cli();
if (scom) {
if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) {
if (!ccard->ReadyInt) {
tmp = ram_inb(ccard, &com->ReadyInt) + 1;
ram_outb(ccard, &com->ReadyInt, tmp);
ccard->ReadyInt++;
}
restore_flags(flags);
skb_queue_head(&ccard->sndq, skb2);
eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
return;
}
} else {
if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) {
restore_flags(flags);
skb_queue_head(&ccard->sndq, skb2);
eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
return;
}
}
restore_flags(flags);
chan2 = (eicon_chan_ptr *)skb2->data;
chan = chan2->ptr;
if (!chan->e.busy) {
if((skb = skb_dequeue(&chan->e.X))) {
save_flags(flags);
cli();
reqbuf = (eicon_REQ *)skb->data;
if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No);
} else {
if (scom) {
ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh);
} else {
/* get address of next available request buffer */
ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)];
ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length);
ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh);
ram_outb(ccard, &ReqOut->Req, reqbuf->Req);
}
dlev = 160;
if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
if (!reqbuf->Reference) { /* Signal Layer */
if (scom)
ram_outb(ccard, &com->ReqId, chan->e.D3Id);
else
ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id);
chan->e.ReqCh = 0;
}
else { /* Net Layer */
if (scom)
ram_outb(ccard, &com->ReqId, chan->e.B2Id);
else
ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id);
chan->e.ReqCh = 1;
if (((reqbuf->Req & 0x0f) == 0x08) ||
((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
chan->waitq = reqbuf->XBuffer.length;
chan->waitpq += reqbuf->XBuffer.length;
dlev = 128;
}
}
} else { /* It is an ASSIGN */
if (scom)
ram_outb(ccard, &com->ReqId, reqbuf->ReqId);
else
ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId);
if (!reqbuf->Reference)
chan->e.ReqCh = 0;
else
chan->e.ReqCh = 1;
}
if (scom)
chan->e.ref = ccard->ref_out++;
else
chan->e.ref = ram_inw(ccard, &ReqOut->Reference);
chan->e.Req = reqbuf->Req;
ReqCount++;
if (scom)
ram_outb(ccard, &com->Req, reqbuf->Req);
else
ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next));
chan->e.busy = 1;
eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n",
reqbuf->Req,
(scom) ? ram_inb(ccard, &com->ReqId) :
ram_inb(ccard, &ReqOut->ReqId),
reqbuf->ReqCh, reqbuf->XBuffer.length,
chan->e.ref);
}
restore_flags(flags);
dev_kfree_skb(skb);
}
dev_kfree_skb(skb2);
}
else {
skb_queue_tail(&ccard->sackq, skb2);
eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No);
}
if (scom)
quloop = 0;
else
if (!(skb2 = skb_dequeue(&ccard->sndq)))
quloop = 0;
}
if (!scom)
ram_outb(ccard, &prram->ReqInput, (__u8)(ram_inb(ccard, &prram->ReqInput) + ReqCount));
while((skb = skb_dequeue(&ccard->sackq))) {
skb_queue_tail(&ccard->sndq, skb);
}
}
/*
* IRQ handler
*/
void
eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
eicon_card *ccard = (eicon_card *)dev_id;
eicon_pci_card *pci_card;
eicon_isa_card *isa_card;
char *ram = 0;
char *reg = 0;
char *cfg = 0;
eicon_pr_ram *prram = 0;
eicon_isa_com *com = 0;
eicon_RC *RcIn;
eicon_IND *IndIn;
struct sk_buff *skb;
int Count = 0;
int Rc = 0;
int Ind = 0;
unsigned char *irqprobe = 0;
int scom = 0;
int tmp = 0;
int dlev = 0;
if (!ccard) {
eicon_log(ccard, 1, "eicon_irq: spurious interrupt %d\n", irq);
return;
}
if (ccard->type == EICON_CTYPE_QUADRO) {
tmp = 4;
while(tmp) {
com = (eicon_isa_com *)ccard->hwif.isa.shmem;
if ((readb(ccard->hwif.isa.intack))) { /* quadro found */
break;
}
ccard = ccard->qnext;
tmp--;
}
}
pci_card = &ccard->hwif.pci;
isa_card = &ccard->hwif.isa;
switch(ccard->type) {
#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
scom = 1;
com = (eicon_isa_com *)isa_card->shmem;
irqprobe = &isa_card->irqprobe;
break;
case EICON_CTYPE_S2M:
scom = 0;
prram = (eicon_pr_ram *)isa_card->shmem;
irqprobe = &isa_card->irqprobe;
break;
#endif
case EICON_CTYPE_MAESTRAP:
scom = 0;
ram = (char *)pci_card->PCIram;
reg = (char *)pci_card->PCIreg;
cfg = (char *)pci_card->PCIcfg;
irqprobe = &pci_card->irqprobe;
prram = (eicon_pr_ram *)ram;
break;
case EICON_CTYPE_MAESTRA:
scom = 0;
ram = (char *)pci_card->PCIram;
reg = (char *)pci_card->PCIreg;
cfg = (char *)pci_card->PCIcfg;
irqprobe = &pci_card->irqprobe;
prram = 0;
break;
default:
eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n");
return;
}
if (*irqprobe) {
switch(ccard->type) {
#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
if (readb(isa_card->intack)) {
writeb(0, &com->Rc);
writeb(0, isa_card->intack);
}
(*irqprobe)++;
break;
case EICON_CTYPE_S2M:
if (readb(isa_card->intack)) {
writeb(0, &prram->RcOutput);
writeb(0, isa_card->intack);
}
(*irqprobe)++;
break;
#endif
case EICON_CTYPE_MAESTRAP:
if (readb(&ram[0x3fe])) {
writeb(0, &prram->RcOutput);
writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
writew(0, &cfg[MP_IRQ_RESET + 2]);
writeb(0, &ram[0x3fe]);
}
*irqprobe = 0;
break;
case EICON_CTYPE_MAESTRA:
outb(0x08, pci_card->PCIreg + M_RESET);
*irqprobe = 0;
break;
}
return;
}
switch(ccard->type) {
#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
case EICON_CTYPE_S2M:
if (!(readb(isa_card->intack))) { /* card did not interrupt */
eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
return;
}
break;
#endif
case EICON_CTYPE_MAESTRAP:
if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
return;
}
break;
case EICON_CTYPE_MAESTRA:
outw(0x3fe, pci_card->PCIreg + M_ADDR);
if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */
eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
return;
}
break;
}
if (scom) {
/* if a return code is available ... */
if ((tmp = ram_inb(ccard, &com->Rc))) {
eicon_RC *ack;
if (tmp == READY_INT) {
eicon_log(ccard, 64, "eicon: IRQ Rc=READY_INT\n");
if (ccard->ReadyInt) {
ccard->ReadyInt--;
ram_outb(ccard, &com->Rc, 0);
eicon_schedule_tx(ccard);
}
} else {
skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
if (!skb) {
eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
} else {
ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
ack->Rc = tmp;
ack->RcId = ram_inb(ccard, &com->RcId);
ack->RcCh = ram_inb(ccard, &com->RcCh);
ack->Reference = ccard->ref_in++;
eicon_log(ccard, 128, "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
tmp,ack->RcId,ack->RcCh,ack->Reference);
skb_queue_tail(&ccard->rackq, skb);
eicon_schedule_ack(ccard);
}
ram_outb(ccard, &com->Req, 0);
ram_outb(ccard, &com->Rc, 0);
}
} else {
/* if an indication is available ... */
if ((tmp = ram_inb(ccard, &com->Ind))) {
eicon_IND *ind;
int len = ram_inw(ccard, &com->RBuffer.length);
skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
if (!skb) {
eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
} else {
ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
ind->Ind = tmp;
ind->IndId = ram_inb(ccard, &com->IndId);
ind->IndCh = ram_inb(ccard, &com->IndCh);
ind->MInd = ram_inb(ccard, &com->MInd);
ind->MLength = ram_inw(ccard, &com->MLength);
ind->RBuffer.length = len;
if ((tmp == 1) || (tmp == 8))
dlev = 128;
else
dlev = 192;
eicon_log(ccard, dlev, "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len);
skb_queue_tail(&ccard->rcvq, skb);
eicon_schedule_rx(ccard);
}
ram_outb(ccard, &com->Ind, 0);
}
}
} else {
/* if return codes are available ... */
if((Count = ram_inb(ccard, &prram->RcOutput))) {
eicon_RC *ack;
/* get the buffer address of the first return code */
RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &prram->NextRc)];
/* for all return codes do ... */
while(Count--) {
if((Rc=ram_inb(ccard, &RcIn->Rc))) {
skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
if (!skb) {
eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
} else {
ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
ack->Rc = Rc;
ack->RcId = ram_inb(ccard, &RcIn->RcId);
ack->RcCh = ram_inb(ccard, &RcIn->RcCh);
ack->Reference = ram_inw(ccard, &RcIn->Reference);
eicon_log(ccard, 128, "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n",
Rc,ack->RcId,ack->RcCh,ack->Reference);
skb_queue_tail(&ccard->rackq, skb);
eicon_schedule_ack(ccard);
}
ram_outb(ccard, &RcIn->Rc, 0);
}
/* get buffer address of next return code */
RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &RcIn->next)];
}
/* clear all return codes (no chaining!) */
ram_outb(ccard, &prram->RcOutput, 0);
}
/* if indications are available ... */
if((Count = ram_inb(ccard, &prram->IndOutput))) {
eicon_IND *ind;
/* get the buffer address of the first indication */
IndIn = (eicon_IND *)&prram->B[ram_inw(ccard, &prram->NextInd)];
/* for all indications do ... */
while(Count--) {
Ind = ram_inb(ccard, &IndIn->Ind);
if(Ind) {
int len = ram_inw(ccard, &IndIn->RBuffer.length);
skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
if (!skb) {
eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _irq()\n");
} else {
ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
ind->Ind = Ind;
ind->IndId = ram_inb(ccard, &IndIn->IndId);
ind->IndCh = ram_inb(ccard, &IndIn->IndCh);
ind->MInd = ram_inb(ccard, &IndIn->MInd);
ind->MLength = ram_inw(ccard, &IndIn->MLength);
ind->RBuffer.length = len;
if ((Ind == 1) || (Ind == 8))
dlev = 128;
else
dlev = 192;
eicon_log(ccard, dlev, "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len);
ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len);
skb_queue_tail(&ccard->rcvq, skb);
eicon_schedule_rx(ccard);
}
ram_outb(ccard, &IndIn->Ind, 0);
}
/* get buffer address of next indication */
IndIn = (eicon_IND *)&prram->B[ram_inw(ccard, &IndIn->next)];
}
ram_outb(ccard, &prram->IndOutput, 0);
}
}
/* clear interrupt */
switch(ccard->type) {
#ifdef CONFIG_ISDN_DRV_EICON_ISA
case EICON_CTYPE_QUADRO:
writeb(0, isa_card->intack);
writeb(0, &com[0x401]);
break;
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_S2M:
writeb(0, isa_card->intack);
break;
#endif
case EICON_CTYPE_MAESTRAP:
writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
writew(0, &cfg[MP_IRQ_RESET + 2]);
writeb(0, &ram[0x3fe]);
break;
case EICON_CTYPE_MAESTRA:
outb(0x08, pci_card->PCIreg + M_RESET);
outw(0x3fe, pci_card->PCIreg + M_ADDR);
outb(0, pci_card->PCIreg + M_DATA);
break;
}
return;
}

View File

@ -1,544 +0,0 @@
/* $Id$
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for old ISA cards.
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1998-2000 by Armin Schindler (mac@melware.de)
* Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.13 2000/01/23 21:21:23 armin
* Added new trace capability and some updates.
* DIVA Server BRI now supports data for ISDNLOG.
*
* Revision 1.12 1999/11/27 12:56:19 armin
* Forgot some iomem changes for last ioremap compat.
*
* Revision 1.11 1999/11/25 11:33:09 armin
* Microchannel fix from Erik Weber (exrz73@ibm.net).
*
* Revision 1.10 1999/11/18 21:14:30 armin
* New ISA memory mapped IO
*
* Revision 1.9 1999/09/08 20:17:31 armin
* Added microchannel patch from Erik Weber (exrz73@ibm.net).
*
* Revision 1.8 1999/09/06 07:29:35 fritz
* Changed my mail-address.
*
* Revision 1.7 1999/08/22 20:26:48 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.6 1999/07/25 15:12:06 armin
* fix of some debug logs.
* enabled ISA-cards option.
*
* Revision 1.5 1999/04/01 12:48:33 armin
* Changed some log outputs.
*
* Revision 1.4 1999/03/29 11:19:46 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
*
* Revision 1.3 1999/03/02 12:37:45 armin
* Added some important checks.
* Analog Modem with DSP.
* Channels will be added to Link-Level after loading firmware.
*
* Revision 1.2 1999/01/24 20:14:19 armin
* Changed and added debug stuff.
* Better data sending. (still problems with tty's flip buffer)
*
* Revision 1.1 1999/01/01 18:09:43 armin
* First checkin of new eicon driver.
* DIVA-Server BRI/PCI and PRI/PCI are supported.
* Old diehl code is obsolete.
*
*
*/
#include <linux/config.h>
#include "eicon.h"
#include "eicon_isa.h"
#define check_shmem check_region
#define release_shmem release_region
#define request_shmem request_region
char *eicon_isa_revision = "$Revision$";
#undef EICON_MCA_DEBUG
#ifdef CONFIG_ISDN_DRV_EICON_ISA
/* Mask for detecting invalid IRQ parameter */
static int eicon_isa_valid_irq[] = {
0x1c1c, /* 2, 3, 4, 10, 11, 12 (S)*/
0x1c1c, /* 2, 3, 4, 10, 11, 12 (SX) */
0x1cbc, /* 2, 3, 4, 5, 7, 10, 11, 12 (SCOM) */
0x1cbc, /* 2, 3, 4, 5, 6, 10, 11, 12 (Quadro) */
0x1cbc /* 2, 3, 4, 5, 7, 10, 11, 12 (S2M) */
};
static void
eicon_isa_release_shmem(eicon_isa_card *card) {
if (card->mvalid) {
#ifdef COMPAT_HAS_ISA_IOREMAP
iounmap(card->shmem);
release_mem_region(card->physmem, card->ramsize);
#else
release_shmem((unsigned long)card->shmem, card->ramsize);
#endif
}
card->mvalid = 0;
}
static void
eicon_isa_release_irq(eicon_isa_card *card) {
if (!card->master)
return;
if (card->ivalid)
free_irq(card->irq, card);
card->ivalid = 0;
}
void
eicon_isa_release(eicon_isa_card *card) {
eicon_isa_release_irq(card);
eicon_isa_release_shmem(card);
}
void
eicon_isa_printpar(eicon_isa_card *card) {
switch (card->type) {
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
case EICON_CTYPE_S2M:
printk(KERN_INFO "Eicon %s at 0x%lx, irq %d.\n",
eicon_ctype_name[card->type],
card->physmem,
card->irq);
}
}
int
eicon_isa_find_card(int Mem, int Irq, char * Id)
{
int primary = 1;
unsigned long amem;
if (!strlen(Id))
return -1;
if (Mem == -1)
return -1;
/* Check for valid membase address */
if ((Mem < 0x0c0000) ||
(Mem > 0x0fc000) ||
(Mem & 0xfff)) {
printk(KERN_WARNING "eicon_isa: illegal membase 0x%x for %s\n",
Mem, Id);
return -1;
}
#ifdef COMPAT_HAS_ISA_IOREMAP
if (check_mem_region(Mem, RAMSIZE)) {
#else
if (check_shmem(Mem, RAMSIZE)) {
#endif
printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem);
return -1;
}
#ifdef COMPAT_HAS_ISA_IOREMAP
amem = (unsigned long) ioremap(Mem, RAMSIZE);
#else
amem = (unsigned long) Mem;
#endif
writew(0x55aa, amem + 0x402);
if (readw(amem + 0x402) != 0x55aa) primary = 0;
writew(0, amem + 0x402);
if (readw(amem + 0x402) != 0) primary = 0;
printk(KERN_INFO "Eicon: Driver-ID: %s\n", Id);
if (primary) {
printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem);
writeb(0, amem + 0x3ffe);
#ifdef COMPAT_HAS_ISA_IOREMAP
iounmap((unsigned char *)amem);
#endif
return EICON_CTYPE_ISAPRI;
} else {
printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem);
writeb(0, amem + 0x400);
#ifdef COMPAT_HAS_ISA_IOREMAP
iounmap((unsigned char *)amem);
#endif
return EICON_CTYPE_ISABRI;
}
return -1;
}
int
eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
int tmp;
int timeout;
eicon_isa_codebuf cbuf;
unsigned char *code;
eicon_isa_boot *boot;
if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))
return -EFAULT;
/* Allocate code-buffer and copy code from userspace */
if (cbuf.bootstrap_len > 1024) {
printk(KERN_WARNING "eicon_isa_boot: Invalid startup-code size %ld\n",
cbuf.bootstrap_len);
return -EINVAL;
}
if (!(code = kmalloc(cbuf.bootstrap_len, GFP_KERNEL))) {
printk(KERN_WARNING "eicon_isa_boot: Couldn't allocate code buffer\n");
return -ENOMEM;
}
if (copy_from_user(code, &cb->code, cbuf.bootstrap_len)) {
kfree(code);
return -EFAULT;
}
if (card->type == EICON_CTYPE_ISAPRI)
card->ramsize = RAMSIZE_P;
else
card->ramsize = RAMSIZE;
#ifdef COMPAT_HAS_ISA_IOREMAP
if (check_mem_region(card->physmem, card->ramsize)) {
printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
card->physmem);
kfree(code);
return -EBUSY;
}
request_mem_region(card->physmem, card->ramsize, "Eicon ISA ISDN");
card->shmem = (eicon_isa_shmem *) ioremap(card->physmem, card->ramsize);
#else
/* Register shmem */
if (check_shmem((unsigned long)card->shmem, card->ramsize)) {
printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
(unsigned long)card->shmem);
kfree(code);
return -EBUSY;
}
request_shmem((unsigned long)card->shmem, card->ramsize, "Eicon ISA ISDN");
#endif
#ifdef EICON_MCA_DEBUG
printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize);
#endif
card->mvalid = 1;
switch(card->type) {
case EICON_CTYPE_S:
case EICON_CTYPE_SX:
case EICON_CTYPE_SCOM:
case EICON_CTYPE_QUADRO:
case EICON_CTYPE_ISABRI:
card->intack = (__u8 *)card->shmem + INTACK;
card->startcpu = (__u8 *)card->shmem + STARTCPU;
card->stopcpu = (__u8 *)card->shmem + STOPCPU;
break;
case EICON_CTYPE_S2M:
case EICON_CTYPE_ISAPRI:
card->intack = (__u8 *)card->shmem + INTACK_P;
card->startcpu = (__u8 *)card->shmem + STARTCPU_P;
card->stopcpu = (__u8 *)card->shmem + STOPCPU_P;
break;
default:
printk(KERN_WARNING "eicon_isa_boot: Invalid card type %d\n", card->type);
eicon_isa_release_shmem(card);
kfree(code);
return -EINVAL;
}
/* clear any pending irq's */
readb(card->intack);
#ifdef CONFIG_MCA
if (MCA_bus) {
if (card->type == EICON_CTYPE_SCOM) {
outb_p(0,card->io+1);
}
else {
printk(KERN_WARNING "eicon_isa_boot: Card type not supported yet.\n");
eicon_isa_release_shmem(card);
return -EINVAL;
};
#ifdef EICON_MCA_DEBUG
printk(KERN_INFO "eicon_isa_boot: card->io = %x.\n", card->io);
printk(KERN_INFO "eicon_isa_boot: card->irq = %d.\n", (int)card->irq);
#endif
}
#else
/* set reset-line active */
writeb(0, card->stopcpu);
#endif /* CONFIG_MCA */
/* clear irq-requests */
writeb(0, card->intack);
readb(card->intack);
/* Copy code into card */
memcpy_toio(&card->shmem->c, code, cbuf.bootstrap_len);
/* Check for properly loaded code */
if (!check_signature((unsigned long)&card->shmem->c, code, 1020)) {
printk(KERN_WARNING "eicon_isa_boot: Could not load startup-code\n");
eicon_isa_release_shmem(card);
kfree(code);
return -EIO;
}
/* if 16k-ramsize, duplicate the reset-jump-code */
if (card->ramsize == RAMSIZE_P)
memcpy_toio((__u8 *)card->shmem + 0x3ff0, &code[0x3f0], 12);
kfree(code);
boot = &card->shmem->boot;
/* Delay 0.2 sec. */
SLEEP(20);
/* Start CPU */
writeb(cbuf.boot_opt, &boot->ctrl);
#ifdef CONFIG_MCA
if (MCA_bus) {
outb_p(0, card->io);
}
#else
writeb(0, card->startcpu);
#endif /* CONFIG_MCA */
/* Delay 0.2 sec. */
SLEEP(20);
timeout = jiffies + (HZ * 22);
while (timeout > jiffies) {
if (readb(&boot->ctrl) == 0)
break;
SLEEP(10);
}
if (readb(&boot->ctrl) != 0) {
printk(KERN_WARNING "eicon_isa_boot: CPU test failed.\n");
#ifdef EICON_MCA_DEBUG
printk(KERN_INFO "eicon_isa_boot: &boot->ctrl = %d.\n",
readb(&boot->ctrl));
#endif
eicon_isa_release_shmem(card);
return -EIO;
}
/* Check for memory-test errors */
if (readw(&boot->ebit)) {
printk(KERN_WARNING "eicon_isa_boot: memory test failed (bit 0x%04x at 0x%08x)\n",
readw(&boot->ebit), readl(&boot->eloc));
eicon_isa_release_shmem(card);
return -EIO;
}
/* Check card type and memory size */
tmp = readb(&boot->card);
if ((tmp < 0) || (tmp > 4)) {
printk(KERN_WARNING "eicon_isa_boot: Type detect failed\n");
eicon_isa_release_shmem(card);
return -EIO;
}
card->type = tmp;
((eicon_card *)card->card)->type = tmp;
tmp = readb(&boot->msize);
if (tmp != 8 && tmp != 16 && tmp != 24 &&
tmp != 32 && tmp != 48 && tmp != 60) {
printk(KERN_WARNING "eicon_isa_boot: invalid memsize\n");
eicon_isa_release_shmem(card);
return -EIO;
}
printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]);
if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
tmp = eicon_addcard(card->type, card->physmem, card->irq,
((eicon_card *)card->card)->regname);
printk(KERN_INFO "Eicon: %d adapters added\n", tmp);
}
return 0;
}
int
eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) {
eicon_isa_boot *boot;
int tmp;
int timeout;
int j;
eicon_isa_codebuf cbuf;
unsigned char *code;
unsigned char *p;
if (copy_from_user(&cbuf, cb, sizeof(eicon_isa_codebuf)))
return -EFAULT;
if (!(code = kmalloc(cbuf.firmware_len, GFP_KERNEL))) {
printk(KERN_WARNING "eicon_isa_load: Couldn't allocate code buffer\n");
return -ENOMEM;
}
if (copy_from_user(code, &cb->code, cbuf.firmware_len)) {
kfree(code);
return -EFAULT;
}
boot = &card->shmem->boot;
if ((!card->ivalid) && card->master) {
card->irqprobe = 1;
/* Check for valid IRQ */
if ((card->irq < 0) || (card->irq > 15) ||
(!((1 << card->irq) & eicon_isa_valid_irq[card->type & 0x0f]))) {
printk(KERN_WARNING "eicon_isa_load: illegal irq: %d\n", card->irq);
eicon_isa_release_shmem(card);
kfree(code);
return -EINVAL;
}
/* Register irq */
if (!request_irq(card->irq, &eicon_irq, 0, "Eicon ISA ISDN", card))
card->ivalid = 1;
else {
printk(KERN_WARNING "eicon_isa_load: irq %d already in use.\n",
card->irq);
eicon_isa_release_shmem(card);
kfree(code);
return -EBUSY;
}
}
tmp = readb(&boot->msize);
if (tmp != 8 && tmp != 16 && tmp != 24 &&
tmp != 32 && tmp != 48 && tmp != 60) {
printk(KERN_WARNING "eicon_isa_load: invalid memsize\n");
eicon_isa_release_shmem(card);
return -EIO;
}
eicon_isa_printpar(card);
/* Download firmware */
printk(KERN_INFO "%s %dkB, loading firmware ...\n",
eicon_ctype_name[card->type],
tmp * 16);
tmp = cbuf.firmware_len >> 8;
p = code;
while (tmp--) {
memcpy_toio(&boot->b, p, 256);
writeb(1, &boot->ctrl);
timeout = jiffies + 10;
while (timeout > jiffies) {
if (readb(&boot->ctrl) == 0)
break;
SLEEP(2);
}
if (readb(&boot->ctrl)) {
printk(KERN_WARNING "eicon_isa_load: download timeout at 0x%x\n", p-code);
eicon_isa_release(card);
kfree(code);
return -EIO;
}
p += 256;
}
kfree(code);
/* Initialize firmware parameters */
memcpy_toio(&card->shmem->c[8], &cbuf.tei, 14);
memcpy_toio(&card->shmem->c[32], &cbuf.oad, 96);
memcpy_toio(&card->shmem->c[128], &cbuf.oad, 96);
/* Start firmware, wait for signature */
writeb(2, &boot->ctrl);
timeout = jiffies + (5*HZ);
while (timeout > jiffies) {
if (readw(&boot->signature) == 0x4447)
break;
SLEEP(2);
}
if (readw(&boot->signature) != 0x4447) {
printk(KERN_WARNING "eicon_isa_load: firmware selftest failed %04x\n",
readw(&boot->signature));
eicon_isa_release(card);
return -EIO;
}
card->channels = readb(&card->shmem->c[0x3f6]);
/* clear irq-requests, reset irq-count */
readb(card->intack);
writeb(0, card->intack);
if (card->master) {
card->irqprobe = 1;
/* Trigger an interrupt and check if it is delivered */
tmp = readb(&card->shmem->com.ReadyInt);
tmp ++;
writeb(tmp, &card->shmem->com.ReadyInt);
timeout = jiffies + 20;
while (timeout > jiffies) {
if (card->irqprobe > 1)
break;
SLEEP(2);
}
if (card->irqprobe == 1) {
printk(KERN_WARNING "eicon_isa_load: IRQ # %d test failed\n", card->irq);
eicon_isa_release(card);
return -EIO;
}
}
#ifdef EICON_MCA_DEBUG
printk(KERN_INFO "eicon_isa_load: IRQ # %d test succeeded.\n", card->irq);
#endif
writeb(card->irq, &card->shmem->com.Int);
/* initializing some variables */
((eicon_card *)card->card)->ReadyInt = 0;
((eicon_card *)card->card)->ref_in = 1;
((eicon_card *)card->card)->ref_out = 1;
for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
for(j=0; j< (card->channels + 1); j++) {
((eicon_card *)card->card)->bch[j].e.busy = 0;
((eicon_card *)card->card)->bch[j].e.D3Id = 0;
((eicon_card *)card->card)->bch[j].e.B2Id = 0;
((eicon_card *)card->card)->bch[j].e.ref = 0;
((eicon_card *)card->card)->bch[j].e.Req = 0;
((eicon_card *)card->card)->bch[j].e.complete = 1;
((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
}
printk(KERN_INFO "Eicon: Supported channels: %d\n", card->channels);
printk(KERN_INFO "%s successfully started\n", eicon_ctype_name[card->type]);
/* Enable normal IRQ processing */
card->irqprobe = 0;
return 0;
}
#endif /* CONFIG_ISDN_DRV_EICON_ISA */

View File

@ -1,161 +0,0 @@
/* $Id$
*
* ISDN low-level module for Eicon active ISDN-Cards.
*
* Copyright 1998 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1998-2000 by Armin Schindler (mac@melware.de)
* Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.7 1999/11/18 21:14:30 armin
* New ISA memory mapped IO
*
* Revision 1.6 1999/11/15 19:37:04 keil
* need config.h
*
* Revision 1.5 1999/09/08 20:17:31 armin
* Added microchannel patch from Erik Weber.
*
* Revision 1.4 1999/09/06 07:29:35 fritz
* Changed my mail-address.
*
* Revision 1.3 1999/03/29 11:19:47 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
*
* Revision 1.2 1999/03/02 12:37:46 armin
* Added some important checks.
* Analog Modem with DSP.
* Channels will be added to Link-Level after loading firmware.
*
* Revision 1.1 1999/01/01 18:09:44 armin
* First checkin of new eicon driver.
* DIVA-Server BRI/PCI and PRI/PCI are supported.
* Old diehl code is obsolete.
*
*
*/
#ifndef eicon_isa_h
#define eicon_isa_h
#ifdef __KERNEL__
#include <linux/config.h>
/* Factory defaults for ISA-Cards */
#define EICON_ISA_MEMBASE 0xd0000
#define EICON_ISA_IRQ 3
/* shmem offset for Quadro parts */
#define EICON_ISA_QOFFSET 0x0800
typedef struct {
__u16 length __attribute__ ((packed)); /* length of data/parameter field */
__u8 P[270]; /* data/parameter field */
} eicon_scom_PBUFFER;
/* General communication buffer */
typedef struct {
__u8 Req; /* request register */
__u8 ReqId; /* request task/entity identification */
__u8 Rc; /* return code register */
__u8 RcId; /* return code task/entity identification */
__u8 Ind; /* Indication register */
__u8 IndId; /* Indication task/entity identification */
__u8 IMask; /* Interrupt Mask Flag */
__u8 RNR; /* Receiver Not Ready (set by PC) */
__u8 XLock; /* XBuffer locked Flag */
__u8 Int; /* ISDN interrupt */
__u8 ReqCh; /* Channel field for layer-3 Requests */
__u8 RcCh; /* Channel field for layer-3 Returncodes */
__u8 IndCh; /* Channel field for layer-3 Indications */
__u8 MInd; /* more data indication field */
__u16 MLength; /* more data total packet length */
__u8 ReadyInt; /* request field for ready interrupt */
__u8 Reserved[12]; /* reserved space */
__u8 IfType; /* 1 = 16k-Interface */
__u16 Signature __attribute__ ((packed)); /* ISDN adapter Signature */
eicon_scom_PBUFFER XBuffer; /* Transmit Buffer */
eicon_scom_PBUFFER RBuffer; /* Receive Buffer */
} eicon_isa_com;
/* struct for downloading firmware */
typedef struct {
__u8 ctrl;
__u8 card;
__u8 msize;
__u8 fill0;
__u16 ebit __attribute__ ((packed));
__u32 eloc __attribute__ ((packed));
__u8 reserved[20];
__u16 signature __attribute__ ((packed));
__u8 fill[224];
__u8 b[256];
} eicon_isa_boot;
/* Shared memory */
typedef union {
unsigned char c[0x400];
eicon_isa_com com;
eicon_isa_boot boot;
} eicon_isa_shmem;
/*
* card's description
*/
typedef struct {
int ramsize;
int irq; /* IRQ */
unsigned long physmem; /* physical memory address */
#ifdef CONFIG_MCA
int io; /* IO-port for MCA brand */
#endif /* CONFIG_MCA */
void* card;
eicon_isa_shmem* shmem; /* Shared-memory area */
unsigned char* intack; /* Int-Acknowledge */
unsigned char* stopcpu; /* Writing here stops CPU */
unsigned char* startcpu; /* Writing here starts CPU */
unsigned char type; /* card type */
int channels; /* No. of channels */
unsigned char irqprobe; /* Flag: IRQ-probing */
unsigned char mvalid; /* Flag: Memory is valid */
unsigned char ivalid; /* Flag: IRQ is valid */
unsigned char master; /* Flag: Card ist Quadro 1/4 */
void* generic; /* Ptr to generic card struct */
} eicon_isa_card;
/* Offsets for special locations on standard cards */
#define INTACK 0x03fe
#define STOPCPU 0x0400
#define STARTCPU 0x0401
#define RAMSIZE 0x0400
/* Offsets for special location on PRI card */
#define INTACK_P 0x3ffc
#define STOPCPU_P 0x3ffe
#define STARTCPU_P 0x3fff
#define RAMSIZE_P 0x4000
extern int eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb);
extern int eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb);
extern void eicon_isa_release(eicon_isa_card *card);
extern void eicon_isa_printpar(eicon_isa_card *card);
extern void eicon_isa_transmit(eicon_isa_card *card);
extern int eicon_isa_find_card(int Mem, int Irq, char * Id);
#endif /* __KERNEL__ */
#endif /* eicon_isa_h */

File diff suppressed because it is too large Load Diff

View File

@ -1,969 +0,0 @@
/* $Id$
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for PCI cards.
*
* Copyright 1998-2000 by Armin Schindler (mac@melware.de)
* Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* Thanks to Eicon Technology GmbH & Co. oHG for
* documents, informations and hardware.
*
* Deutsche Telekom AG for S2M support.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.10 1999/08/22 20:26:49 calle
* backported changes from kernel 2.3.14:
* - several #include "config.h" gone, others come.
* - "struct device" changed to "struct net_device" in 2.3.14, added a
* define in isdn_compat.h for older kernel versions.
*
* Revision 1.9 1999/08/11 21:01:11 keil
* new PCI codefix
*
* Revision 1.8 1999/08/10 16:02:20 calle
* struct pci_dev changed in 2.3.13. Made the necessary changes.
*
* Revision 1.7 1999/06/09 19:31:29 armin
* Wrong PLX size for request_region() corrected.
* Added first MCA code from Erik Weber.
*
* Revision 1.6 1999/04/01 12:48:37 armin
* Changed some log outputs.
*
* Revision 1.5 1999/03/29 11:19:49 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
*
* Revision 1.4 1999/03/02 12:37:48 armin
* Added some important checks.
* Analog Modem with DSP.
* Channels will be added to Link-Level after loading firmware.
*
* Revision 1.3 1999/01/24 20:14:24 armin
* Changed and added debug stuff.
* Better data sending. (still problems with tty's flip buffer)
*
* Revision 1.2 1999/01/10 18:46:06 armin
* Bug with wrong values in HLC fixed.
* Bytes to send are counted and limited now.
*
* Revision 1.1 1999/01/01 18:09:45 armin
* First checkin of new eicon driver.
* DIVA-Server BRI/PCI and PRI/PCI are supported.
* Old diehl code is obsolete.
*
*
*/
#include <linux/config.h>
#include <linux/pci.h>
#include "eicon.h"
#include "eicon_pci.h"
char *eicon_pci_revision = "$Revision$";
#if CONFIG_PCI /* intire stuff is only for PCI */
#undef EICON_PCI_DEBUG
int eicon_pci_find_card(char *ID)
{
if (pci_present()) {
struct pci_dev *pdev = NULL;
int pci_nextindex=0, pci_cards=0, pci_akt=0;
int pci_type = PCI_MAESTRA;
int NoMorePCICards = FALSE;
char *ram, *reg, *cfg;
unsigned int pram=0, preg=0, pcfg=0;
char did[12];
eicon_pci_card *aparms;
if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) {
printk(KERN_WARNING
"eicon_pci: Could not allocate card-struct.\n");
return 0;
}
for (pci_cards = 0; pci_cards < 0x0f; pci_cards++)
{
do {
if ((pdev = pci_find_device(PCI_VENDOR_EICON,
pci_type,
pdev)))
{
pci_nextindex++;
break;
}
else {
pci_nextindex = 0;
switch (pci_type) /* switch to next card type */
{
case PCI_MAESTRA:
pci_type = PCI_MAESTRAQ; break;
case PCI_MAESTRAQ:
pci_type = PCI_MAESTRAQ_U; break;
case PCI_MAESTRAQ_U:
pci_type = PCI_MAESTRAP; break;
default:
case PCI_MAESTRAP:
NoMorePCICards = TRUE;
}
}
}
while (!NoMorePCICards);
if (NoMorePCICards)
{
if (pci_cards < 1) {
printk(KERN_INFO "Eicon: No supported PCI cards found.\n");
kfree(aparms);
return 0;
}
else
{
printk(KERN_INFO "Eicon: %d PCI card%s registered.\n",
pci_cards, (pci_cards > 1) ? "s":"");
kfree(aparms);
return (pci_cards);
}
}
pci_akt = 0;
switch(pci_type)
{
case PCI_MAESTRA:
printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n");
aparms->type = EICON_CTYPE_MAESTRA;
aparms->irq = pdev->irq;
preg = get_pcibase(pdev, 2) & 0xfffffffc;
pcfg = get_pcibase(pdev, 1) & 0xffffff80;
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg);
printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg);
#endif
pci_akt = 1;
break;
case PCI_MAESTRAQ:
case PCI_MAESTRAQ_U:
printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n");
pci_cards--;
pci_akt = 0;
break;
case PCI_MAESTRAP:
printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n");
aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/
aparms->irq = pdev->irq;
pram = get_pcibase(pdev, 0) & 0xfffff000;
preg = get_pcibase(pdev, 2) & 0xfffff000;
pcfg = get_pcibase(pdev, 4) & 0xfffff000;
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
printk(KERN_DEBUG "eicon_pci: ram=0x%x\n",
(pram));
printk(KERN_DEBUG "eicon_pci: reg=0x%x\n",
(preg));
printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n",
(pcfg));
#endif
pci_akt = 1;
break;
default:
printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n");
pci_cards--;
pci_akt = 0;
break;
}
if (pci_akt) {
/* remapping memory */
switch(pci_type)
{
case PCI_MAESTRA:
aparms->PCIreg = (unsigned int) preg;
aparms->PCIcfg = (unsigned int) pcfg;
if (check_region((aparms->PCIreg), 0x20)) {
printk(KERN_WARNING "eicon_pci: reg port already in use !\n");
aparms->PCIreg = 0;
break;
} else {
request_region(aparms->PCIreg, 0x20, "eicon reg");
}
if (check_region((aparms->PCIcfg), 0x80)) {
printk(KERN_WARNING "eicon_pci: cfg port already in use !\n");
aparms->PCIcfg = 0;
release_region(aparms->PCIreg, 0x20);
break;
} else {
request_region(aparms->PCIcfg, 0x80, "eicon cfg");
}
break;
case PCI_MAESTRAQ:
case PCI_MAESTRAQ_U:
case PCI_MAESTRAP:
aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000);
ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET);
reg = ioremap(preg, 0x4000);
cfg = ioremap(pcfg, 0x1000);
aparms->PCIram = (unsigned int) ram;
aparms->PCIreg = (unsigned int) reg;
aparms->PCIcfg = (unsigned int) cfg;
break;
}
if ((!aparms->PCIreg) || (!aparms->PCIcfg)) {
printk(KERN_ERR "eicon_pci: Card could not be added !\n");
pci_cards--;
} else {
aparms->mvalid = 1;
sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards);
printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did);
if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) {
printk(KERN_ERR "eicon_pci: Card could not be added !\n");
pci_cards--;
}
}
}
}
} else
printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n");
return 0;
}
/*
* Checks protocol file id for "F#xxxx" string fragment to
* extract the features, supported by this protocol version.
* binary representation of the feature string value is returned
* in *value. The function returns 0 if feature string was not
* found or has a wrong format, else 1.
*/
static int GetProtFeatureValue(char *sw_id, int *value)
{
__u8 i, offset;
while (*sw_id)
{
if ((sw_id[0] == 'F') && (sw_id[1] == '#'))
{
sw_id = &sw_id[2];
for (i=0, *value=0; i<4; i++, sw_id++)
{
if ((*sw_id >= '0') && (*sw_id <= '9'))
{
offset = '0';
}
else if ((*sw_id >= 'A') && (*sw_id <= 'F'))
{
offset = 'A' + 10;
}
else if ((*sw_id >= 'a') && (*sw_id <= 'f'))
{
offset = 'a' + 10;
}
else
{
return 0;
}
*value |= (*sw_id - offset) << (4*(3-i));
}
return 1;
}
else
{
sw_id++;
}
}
return 0;
}
void
eicon_pci_printpar(eicon_pci_card *card) {
switch (card->type) {
case EICON_CTYPE_MAESTRA:
printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n",
eicon_ctype_name[card->type],
(unsigned int)card->PCIreg,
(unsigned int)card->PCIcfg,
card->irq);
break;
case EICON_CTYPE_MAESTRAQ:
case EICON_CTYPE_MAESTRAQ_U:
case EICON_CTYPE_MAESTRAP:
printk(KERN_INFO "%s at 0x%x, irq %d\n",
eicon_ctype_name[card->type],
(unsigned int)card->shmem,
card->irq);
#ifdef EICON_PCI_DEBUG
printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram);
printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg);
printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg);
#endif
break;
}
}
static void
eicon_pci_release_shmem(eicon_pci_card *card) {
if (!card->master)
return;
if (card->mvalid) {
switch (card->type) {
case EICON_CTYPE_MAESTRA:
/* reset board */
outb(0, card->PCIcfg + 0x4c); /* disable interrupts from PLX */
outb(0, card->PCIreg + M_RESET);
SLEEP(20);
outb(0, card->PCIreg + M_ADDRH);
outw(0, card->PCIreg + M_ADDR);
outw(0, card->PCIreg + M_DATA);
release_region(card->PCIreg, 0x20);
release_region(card->PCIcfg, 0x80);
break;
case EICON_CTYPE_MAESTRAQ:
case EICON_CTYPE_MAESTRAQ_U:
case EICON_CTYPE_MAESTRAP:
/* reset board */
writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
SLEEP(20);
writeb(0, card->PCIreg + MP_RESET);
SLEEP(20);
iounmap((void *)card->shmem);
iounmap((void *)card->PCIreg);
iounmap((void *)card->PCIcfg);
break;
}
}
card->mvalid = 0;
}
static void
eicon_pci_release_irq(eicon_pci_card *card) {
if (!card->master)
return;
if (card->ivalid)
free_irq(card->irq, card);
card->ivalid = 0;
}
void
eicon_pci_release(eicon_pci_card *card) {
eicon_pci_release_irq(card);
eicon_pci_release_shmem(card);
}
/*
* Upload buffer content to adapters shared memory
* on verify error, 1 is returned and a message is printed on screen
* else 0 is returned
* Can serve IO-Type and Memory type adapters
*/
int eicon_upload(t_dsp_download_space *p_para,
__u16 length, /* byte count */
__u8 *buffer,
int verify)
{
__u32 i, dwdata = 0, val = 0, timeout;
__u16 data;
eicon_pci_boot *boot = 0;
switch (p_para->type) /* actions depend on type of union */
{
case DL_PARA_IO_TYPE:
for (i=0; i<length; i+=2)
{
outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR);
/* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */
outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA);
}
if (verify) /* check written block */
{
for (i=0; i<length; i+=2)
{
outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR);
data = inw(p_para->dat.io.ioDATA);
if (data != *(u16 *)&buffer[i])
{
p_para->dat.io.r3addr += i;
p_para->dat.io.BadData = data;
p_para->dat.io.GoodData = *(u16 *)&buffer[i];
return 1;
}
}
}
break;
case DL_PARA_MEM_TYPE:
boot = p_para->dat.mem.boot;
writel(p_para->dat.mem.r3addr, &boot->addr);
for (i=0; i<length; i+=4)
{
writel(((u32 *)buffer)[i >> 2], &boot->data[i]);
}
if (verify) /* check written block */
{
for (i=0; i<length; i+=4)
{
dwdata = readl(&boot->data[i]);
if (((u32 *)buffer)[i >> 2] != dwdata)
{
p_para->dat.mem.r3addr += i;
p_para->dat.mem.BadData = dwdata;
p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2];
return 1;
}
}
}
writel(((length + 3) / 4), &boot->len); /* len in dwords */
writel(2, &boot->cmd);
timeout = jiffies + 20;
while (timeout > jiffies) {
val = readl(&boot->cmd);
if (!val) break;
SLEEP(2);
}
if (val)
{
p_para->dat.mem.timeout = 1;
return 1;
}
break;
}
return 0;
}
/* show header information of code file */
static
int eicon_pci_print_hdr(unsigned char *code, int offset)
{
unsigned char hdr[80];
int i, fvalue = 0;
i = 0;
while ((i < (sizeof(hdr) -1))
&& (code[offset + i] != '\0')
&& (code[offset + i] != '\r')
&& (code[offset + i] != '\n'))
{
hdr[i] = code[offset + i];
i++;
}
hdr[i] = '\0';
printk(KERN_DEBUG "Eicon: loading %s\n", hdr);
if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue);
else return(0);
}
/*
* Configure a card, download code into BRI card,
* check if we get interrupts and return 0 on succes.
* Return -ERRNO on failure.
*/
int
eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
int i,j;
int timeout;
unsigned int offset, offp=0, size, length;
int signature = 0;
int FeatureValue = 0;
eicon_pci_codebuf cbuf;
t_dsp_download_space dl_para;
t_dsp_download_desc dsp_download_table;
unsigned char *code;
unsigned int reg;
unsigned int cfg;
if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
return -EFAULT;
reg = card->PCIreg;
cfg = card->PCIcfg;
/* reset board */
outb(0, reg + M_RESET);
SLEEP(10);
outb(0, reg + M_ADDRH);
outw(0, reg + M_ADDR);
outw(0, reg + M_DATA);
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: reset card\n");
#endif
/* clear shared memory */
outb(0xff, reg + M_ADDRH);
outw(0, reg + M_ADDR);
for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA);
SLEEP(10);
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: clear shared memory\n");
#endif
/* download protocol and dsp file */
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
#endif
/* Allocate code-buffer */
if (!(code = kmalloc(400, GFP_KERNEL))) {
printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
return -ENOMEM;
}
/* prepare protocol upload */
dl_para.type = DL_PARA_IO_TYPE;
dl_para.dat.io.ioADDR = reg + M_ADDR;
dl_para.dat.io.ioADDRH = reg + M_ADDRH;
dl_para.dat.io.ioDATA = reg + M_DATA;
for (j = 0; j <= cbuf.dsp_code_num; j++)
{
if (j == 0) size = cbuf.protocol_len;
else size = cbuf.dsp_code_len[j];
offset = 0;
if (j == 0) dl_para.dat.io.r3addr = 0;
if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE +
((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE;
if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32);
do /* download block of up to 400 bytes */
{
length = ((size - offset) >= 400) ? 400 : (size - offset);
if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
kfree(code);
return -EFAULT;
}
if ((offset == 0) && (j < 2)) {
FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80);
#ifdef EICON_PCI_DEBUG
if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue);
#endif
if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
kfree(code);
return -EFAULT;
}
((eicon_card *)card->card)->Feature = FeatureValue;
}
if (eicon_upload(&dl_para, length, code, 1))
{
printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
kfree(code);
return -EIO;
}
/* move onto next block */
offset += length;
dl_para.dat.io.r3addr += length;
} while (offset < size);
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset);
#endif
offp += size;
}
kfree(code);
/* clear signature */
outb(0xff, reg + M_ADDRH);
outw(0x1e, reg + M_ADDR);
outw(0, reg + M_DATA);
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
#endif
/* copy configuration data into shared memory */
outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA);
outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA);
outw(10,reg + M_ADDR); outb(0, reg + M_DATA);
outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA);
outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA);
outw(13,reg + M_ADDR); outb(0, reg + M_DATA); /* XInterface */
outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA);
outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA);
outw(16,reg + M_ADDR); outb(0, reg + M_DATA); /* HandsetType */
outw(17,reg + M_ADDR); outb(0, reg + M_DATA); /* SigFlags */
outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA);
outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA);
outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA);
outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA);
for (i=0;i<32;i++)
{
outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA);
outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA);
outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA);
outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA);
outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA);
outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA);
}
#ifdef EICON_PCI_DEBUG
printk(KERN_ERR "eicon_pci: starting CPU...\n");
#endif
/* let the CPU run */
outw(0x08, reg + M_RESET);
timeout = jiffies + (5*HZ);
while (timeout > jiffies) {
outw(0x1e, reg + M_ADDR);
signature = inw(reg + M_DATA);
if (signature == DIVAS_SIGNATURE) break;
SLEEP(2);
}
if (signature != DIVAS_SIGNATURE)
{
#ifdef EICON_PCI_DEBUG
printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE);
#endif
printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n");
return -EIO;
}
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
#endif
/* get serial number and number of channels supported by card */
outb(0xff, reg + M_ADDRH);
outw(0x3f6, reg + M_ADDR);
card->channels = inw(reg + M_DATA);
card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26);
printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
/* test interrupt */
card->irqprobe = 1;
if (!card->ivalid) {
if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card))
{
printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
return -EIO;
}
}
card->ivalid = 1;
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
#endif
/* Trigger an interrupt and check if it is delivered */
outb(0x41, cfg + 0x4c); /* enable PLX for interrupts */
outb(0x89, reg + M_RESET); /* place int request */
timeout = jiffies + 20;
while (timeout > jiffies) {
if (card->irqprobe != 1) break;
SLEEP(5);
}
if (card->irqprobe == 1) {
free_irq(card->irq, card);
card->ivalid = 0;
printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
return -EIO;
}
/* initializing some variables */
((eicon_card *)card->card)->ReadyInt = 0;
for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
for(j=0; j< (card->channels + 1); j++) {
((eicon_card *)card->card)->bch[j].e.busy = 0;
((eicon_card *)card->card)->bch[j].e.D3Id = 0;
((eicon_card *)card->card)->bch[j].e.B2Id = 0;
((eicon_card *)card->card)->bch[j].e.ref = 0;
((eicon_card *)card->card)->bch[j].e.Req = 0;
((eicon_card *)card->card)->bch[j].e.complete = 1;
((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
}
printk(KERN_INFO "Eicon: Card successfully started\n");
return 0;
}
/*
* Configure a card, download code into PRI card,
* check if we get interrupts and return 0 on succes.
* Return -ERRNO on failure.
*/
int
eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
eicon_pci_boot *boot;
eicon_pr_ram *prram;
int i,j;
int timeout;
int FeatureValue = 0;
unsigned int offset, offp=0, size, length;
unsigned long int signature = 0;
t_dsp_download_space dl_para;
t_dsp_download_desc dsp_download_table;
eicon_pci_codebuf cbuf;
unsigned char *code;
unsigned char req_int;
char *ram, *reg, *cfg;
if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
return -EFAULT;
boot = &card->shmem->boot;
ram = (char *)card->PCIram;
reg = (char *)card->PCIreg;
cfg = (char *)card->PCIcfg;
prram = (eicon_pr_ram *)ram;
/* reset board */
writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
SLEEP(20);
writeb(0, card->PCIreg + MP_RESET);
SLEEP(20);
/* set command count to 0 */
writel(0, &boot->reserved);
/* check if CPU increments the life word */
i = readw(&boot->live);
SLEEP(20);
if (i == readw(&boot->live)) {
printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n");
return -EIO;
}
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n");
#endif
/* download firmware : DSP and Protocol */
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
#endif
/* Allocate code-buffer */
if (!(code = kmalloc(400, GFP_KERNEL))) {
printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
return -ENOMEM;
}
/* prepare protocol upload */
dl_para.type = DL_PARA_MEM_TYPE;
dl_para.dat.mem.boot = boot;
for (j = 0; j <= cbuf.dsp_code_num; j++)
{
if (j==0) size = cbuf.protocol_len;
else size = cbuf.dsp_code_len[j];
if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */
if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR;
if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE +
((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE;
if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32);
offset = 0;
do /* download block of up to 400 bytes */
{
length = ((size - offset) >= 400) ? 400 : (size - offset);
if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
kfree(code);
return -EFAULT;
}
if ((offset == 0) && (j < 2)) {
FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80);
#ifdef EICON_PCI_DEBUG
if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue);
#endif
if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
kfree(code);
return -EFAULT;
}
((eicon_card *)card->card)->Feature = FeatureValue;
}
if (eicon_upload(&dl_para, length, code, 1))
{
if (dl_para.dat.mem.timeout == 0)
printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
else
printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n");
kfree(code);
return -EIO;
}
/* move onto next block */
offset += length;
dl_para.dat.mem.r3addr += length;
} while (offset < size);
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset);
#endif
offp += size;
}
kfree(code);
/* initialize the adapter data structure */
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
#endif
/* clear out config space */
for (i = 0; i < 256; i++) writeb(0, &ram[i]);
/* copy configuration down to the card */
writeb(cbuf.tei, &ram[8]);
writeb(cbuf.nt2, &ram[9]);
writeb(0, &ram[10]);
writeb(cbuf.WatchDog, &ram[11]);
writeb(cbuf.Permanent, &ram[12]);
writeb(cbuf.XInterface, &ram[13]);
writeb(cbuf.StableL2, &ram[14]);
writeb(cbuf.NoOrderCheck, &ram[15]);
writeb(cbuf.HandsetType, &ram[16]);
writeb(0, &ram[17]);
writeb(cbuf.LowChannel, &ram[18]);
writeb(cbuf.ProtVersion, &ram[19]);
writeb(cbuf.Crc4, &ram[20]);
for (i = 0; i < 32; i++)
{
writeb(cbuf.l[0].oad[i], &ram[32 + i]);
writeb(cbuf.l[0].osa[i], &ram[64 + i]);
writeb(cbuf.l[0].spid[i], &ram[96 + i]);
writeb(cbuf.l[1].oad[i], &ram[128 + i]);
writeb(cbuf.l[1].osa[i], &ram[160 + i]);
writeb(cbuf.l[1].spid[i], &ram[192 + i]);
}
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: configured card OK\n");
#endif
/* start adapter */
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: tell card to start...\n");
#endif
writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */
writel(3, &boot->cmd); /* DIVAS_START_CMD */
/* wait till card ACKs */
timeout = jiffies + (5*HZ);
while (timeout > jiffies) {
signature = readl(&boot->signature);
if ((signature >> 16) == DIVAS_SIGNATURE) break;
SLEEP(2);
}
if ((signature >> 16) != DIVAS_SIGNATURE)
{
#ifdef EICON_PCI_DEBUG
printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE);
#endif
printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n");
return -EIO;
}
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
#endif
/* get serial number and number of channels supported by card */
card->channels = readb(&ram[0x3f6]);
card->serial = readl(&ram[0x3f0]);
printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
/* test interrupt */
readb(&ram[0x3fe]);
writeb(0, &ram[0x3fe]); /* reset any pending interrupt */
readb(&ram[0x3fe]);
writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
writew(0, &cfg[MP_IRQ_RESET + 2]);
card->irqprobe = 1;
if (!card->ivalid) {
if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card))
{
printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
return -EIO;
}
}
card->ivalid = 1;
req_int = readb(&prram->ReadyInt);
#ifdef EICON_PCI_DEBUG
printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
#endif
req_int++;
/* Trigger an interrupt and check if it is delivered */
writeb(req_int, &prram->ReadyInt);
timeout = jiffies + 20;
while (timeout > jiffies) {
if (card->irqprobe != 1) break;
SLEEP(2);
}
if (card->irqprobe == 1) {
free_irq(card->irq, card);
card->ivalid = 0;
printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
return -EIO;
}
/* initializing some variables */
((eicon_card *)card->card)->ReadyInt = 0;
for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
for(j=0; j< (card->channels + 1); j++) {
((eicon_card *)card->card)->bch[j].e.busy = 0;
((eicon_card *)card->card)->bch[j].e.D3Id = 0;
((eicon_card *)card->card)->bch[j].e.B2Id = 0;
((eicon_card *)card->card)->bch[j].e.ref = 0;
((eicon_card *)card->card)->bch[j].e.Req = 0;
((eicon_card *)card->card)->bch[j].e.complete = 1;
((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
}
printk(KERN_INFO "Eicon: Card successfully started\n");
return 0;
}
#endif /* CONFIG_PCI */

View File

@ -1,188 +0,0 @@
/* $Id$
*
* ISDN low-level module for Eicon active ISDN-Cards (PCI part).
*
* Copyright 1998-2000 by Armin Schindler (mac@melware.de)
* Copyright 1999,2000 Cytronics & Melware (info@melware.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.3 1999/03/29 11:19:51 armin
* I/O stuff now in seperate file (eicon_io.c)
* Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
*
* Revision 1.2 1999/03/02 12:37:50 armin
* Added some important checks.
* Analog Modem with DSP.
* Channels will be added to Link-Level after loading firmware.
*
* Revision 1.1 1999/01/01 18:09:46 armin
* First checkin of new eicon driver.
* DIVA-Server BRI/PCI and PRI/PCI are supported.
* Old diehl code is obsolete.
*
*
*/
#ifndef eicon_pci_h
#define eicon_pci_h
#ifdef __KERNEL__
#define PCI_VENDOR_EICON 0x1133
#define PCI_DIVA_PRO20 0xe001 /* Not supported */
#define PCI_DIVA20 0xe002 /* Not supported */
#define PCI_DIVA_PRO20_U 0xe003 /* Not supported */
#define PCI_DIVA20_U 0xe004 /* Not supported */
#define PCI_MAESTRA 0xe010
#define PCI_MAESTRAQ 0xe012
#define PCI_MAESTRAQ_U 0xe013
#define PCI_MAESTRAP 0xe014
#define DIVA_PRO20 1
#define DIVA20 2
#define DIVA_PRO20_U 3
#define DIVA20_U 4
#define MAESTRA 5
#define MAESTRAQ 6
#define MAESTRAQ_U 7
#define MAESTRAP 8
#define TRUE 1
#define FALSE 0
#define DIVAS_SIGNATURE 0x4447
/* MAESTRA BRI PCI */
#define M_RESET 0x10 /* offset of reset register */
#define M_DATA 0x00 /* offset of data register */
#define M_ADDR 0x04 /* offset of address register */
#define M_ADDRH 0x0c /* offset of high address register */
#define M_DSP_CODE_LEN 0xbf7d0000
#define M_DSP_CODE 0xbf7d0004 /* max 128K DSP-Code */
#define M_DSP_CODE_BASE 0xbf7a0000
#define M_MAX_DSP_CODE_SIZE 0x00050000 /* max 320K DSP-Code (Telindus) */
/* MAESTRA PRI PCI */
#define MP_SHARED_RAM_OFFSET 0x1000 /* offset of shared RAM base in the DRAM memory bar */
#define MP_IRQ_RESET 0xc18 /* offset of interrupt status register in the CONFIG memory bar */
#define MP_IRQ_RESET_VAL 0xfe /* value to clear an interrupt */
#define MP_PROTOCOL_ADDR 0xa0011000 /* load address of protocol code */
#define MP_DSP_ADDR 0xa03c0000 /* load address of DSP code */
#define MP_MAX_PROTOCOL_CODE_SIZE 0x000a0000 /* max 640K Protocol-Code */
#define MP_DSP_CODE_BASE 0xa03a0000
#define MP_MAX_DSP_CODE_SIZE 0x00060000 /* max 384K DSP-Code */
#define MP_RESET 0x20 /* offset of RESET register in the DEVICES memory bar */
/* RESET register bits */
#define _MP_S2M_RESET 0x10 /* active lo */
#define _MP_LED2 0x08 /* 1 = on */
#define _MP_LED1 0x04 /* 1 = on */
#define _MP_DSP_RESET 0x02 /* active lo */
#define _MP_RISC_RESET 0x81 /* active hi, bit 7 for compatibility with old boards */
/* boot interface structure */
typedef struct {
__u32 cmd __attribute__ ((packed));
__u32 addr __attribute__ ((packed));
__u32 len __attribute__ ((packed));
__u32 err __attribute__ ((packed));
__u32 live __attribute__ ((packed));
__u32 reserved[(0x1020>>2)-6] __attribute__ ((packed));
__u32 signature __attribute__ ((packed));
__u8 data[1]; /* real interface description */
} eicon_pci_boot;
#define DL_PARA_IO_TYPE 0
#define DL_PARA_MEM_TYPE 1
typedef struct tag_dsp_download_space
{
__u16 type; /* see definitions above to differ union elements */
union
{
struct
{
__u32 r3addr;
__u16 ioADDR;
__u16 ioADDRH;
__u16 ioDATA;
__u16 BadData; /* in case of verify error */
__u16 GoodData;
} io; /* for io based adapters */
struct
{
__u32 r3addr;
eicon_pci_boot *boot;
__u32 BadData; /* in case of verify error */
__u32 GoodData;
__u16 timeout;
} mem; /* for memory based adapters */
} dat;
} t_dsp_download_space;
/* Shared memory */
typedef union {
eicon_pci_boot boot;
} eicon_pci_shmem;
/*
* card's description
*/
typedef struct {
int ramsize;
int irq; /* IRQ */
unsigned int PCIram;
unsigned int PCIreg;
unsigned int PCIcfg;
long int serial; /* Serial No. */
int channels; /* No. of supported channels */
void* card;
eicon_pci_shmem* shmem; /* Shared-memory area */
unsigned char* intack; /* Int-Acknowledge */
unsigned char* stopcpu; /* Writing here stops CPU */
unsigned char* startcpu; /* Writing here starts CPU */
unsigned char type; /* card type */
unsigned char irqprobe; /* Flag: IRQ-probing */
unsigned char mvalid; /* Flag: Memory is valid */
unsigned char ivalid; /* Flag: IRQ is valid */
unsigned char master; /* Flag: Card is Quadro 1/4 */
void* generic; /* Ptr to generic card struct */
} eicon_pci_card;
extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb);
extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb);
extern void eicon_pci_release(eicon_pci_card *card);
extern void eicon_pci_printpar(eicon_pci_card *card);
extern int eicon_pci_find_card(char *ID);
#endif /* __KERNEL__ */
#endif /* eicon_pci_h */

View File

@ -1,24 +0,0 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
ALL_SUB_DIRS :=
L_OBJS :=
LX_OBJS :=
M_OBJS :=
MX_OBJS :=
O_OBJS :=
OX_OBJS :=
L_TARGET :=
O_TARGET :=
ifeq ($(CONFIG_PROC_FS),y)
ifeq ($(CONFIG_HYSDN),y)
M_OBJS += hysdn.o
O_TARGET += hysdn.o
O_OBJS += hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o hysdn_sched.o hysdn_net.o
OX_OBJS += hysdn_init.o
endif
endif
include $(TOPDIR)/Rules.make

View File

@ -1,464 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, specific routines for ergo type boards.
*
* As all Linux supported cards Champ2, Ergo and Metro2/4 use the same
* DPRAM interface and layout with only minor differences all related
* stuff is done here, not in separate modules.
*
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <asm/io.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include "hysdn_defs.h"
#include "boardergo.h"
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
/***************************************************/
/* The cards interrupt handler. Called from system */
/***************************************************/
static void
ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
hysdn_card *card = dev_id; /* parameter from irq */
tErgDpram *dpr;
ulong flags;
uchar volatile b;
if (!card)
return; /* error -> spurious interrupt */
if (!card->irq_enabled)
return; /* other device interrupting or irq switched off */
save_flags(flags);
cli(); /* no further irqs allowed */
if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
restore_flags(flags); /* restore old state */
return; /* no interrupt requested by E1 */
}
/* clear any pending ints on the board */
dpr = card->dpram;
b = dpr->ToPcInt; /* clear for ergo */
b |= dpr->ToPcIntMetro; /* same for metro */
b |= dpr->ToHyInt; /* and for champ */
/* start kernel task immediately after leaving all interrupts */
if (!card->hw_lock) {
queue_task(&card->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
restore_flags(flags);
} /* ergo_interrupt */
/******************************************************************************/
/* ergo_irq_bh is the function called by the immediate kernel task list after */
/* being activated with queue_task and no interrupts active. This task is the */
/* only one handling data transfer from or to the card after booting. The task */
/* may be queued from everywhere (interrupts included). */
/******************************************************************************/
static void
ergo_irq_bh(hysdn_card * card)
{
tErgDpram *dpr;
int again;
ulong flags;
if (card->state != CARD_STATE_RUN)
return; /* invalid call */
dpr = card->dpram; /* point to DPRAM */
save_flags(flags);
cli();
if (card->hw_lock) {
restore_flags(flags); /* hardware currently unavailable */
return;
}
card->hw_lock = 1; /* we now lock the hardware */
do {
sti(); /* reenable other ints */
again = 0; /* assume loop not to be repeated */
if (!dpr->ToHyFlag) {
/* we are able to send a buffer */
if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel,
ERG_TO_HY_BUF_SIZE)) {
dpr->ToHyFlag = 1; /* enable tx */
again = 1; /* restart loop */
}
} /* we are able to send a buffer */
if (dpr->ToPcFlag) {
/* a message has arrived for us, handle it */
if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) {
dpr->ToPcFlag = 0; /* we worked the data */
again = 1; /* restart loop */
}
} /* a message has arrived for us */
cli(); /* no further ints */
if (again) {
dpr->ToHyInt = 1;
dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
} else
card->hw_lock = 0; /* free hardware again */
} while (again); /* until nothing more to do */
restore_flags(flags);
} /* ergo_irq_bh */
/*********************************************************/
/* stop the card (hardware reset) and disable interrupts */
/*********************************************************/
static void
ergo_stopcard(hysdn_card * card)
{
ulong flags;
uchar val;
hysdn_net_release(card); /* first release the net device if existing */
save_flags(flags);
cli();
val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */
byteout(card->iobase + PCI9050_INTR_REG, val);
card->irq_enabled = 0;
byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */
card->state = CARD_STATE_UNUSED;
card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */
restore_flags(flags);
} /* ergo_stopcard */
/**************************************************************************/
/* enable or disable the cards error log. The event is queued if possible */
/**************************************************************************/
static void
ergo_set_errlog_state(hysdn_card * card, int on)
{
ulong flags;
if (card->state != CARD_STATE_RUN) {
card->err_log_state = ERRLOG_STATE_OFF; /* must be off */
return;
}
save_flags(flags);
cli();
if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
((card->err_log_state == ERRLOG_STATE_ON) && on)) {
restore_flags(flags);
return; /* nothing to do */
}
if (on)
card->err_log_state = ERRLOG_STATE_START; /* request start */
else
card->err_log_state = ERRLOG_STATE_STOP; /* request stop */
restore_flags(flags);
queue_task(&card->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
} /* ergo_set_errlog_state */
/******************************************/
/* test the cards RAM and return 0 if ok. */
/******************************************/
static const char TestText[36] = "This Message is filler, why read it";
static int
ergo_testram(hysdn_card * card)
{
tErgDpram *dpr = card->dpram;
memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */
dpr->ToHyInt = 1; /* E1 INTR state forced */
memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
sizeof(TestText));
if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
sizeof(TestText)))
return (-1);
memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
sizeof(TestText));
if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
sizeof(TestText)))
return (-1);
return (0);
} /* ergo_testram */
/*****************************************************************************/
/* this function is intended to write stage 1 boot image to the cards buffer */
/* this is done in two steps. First the 1024 hi-words are written (offs=0), */
/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */
/* PCI-write-buffers flushed and the card is taken out of reset. */
/* The function then waits for a reaction of the E1 processor or a timeout. */
/* Negative return values are interpreted as errors. */
/*****************************************************************************/
static int
ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
{
uchar *dst;
tErgDpram *dpram;
int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs);
dst = card->dpram; /* pointer to start of DPRAM */
dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */
while (cnt--) {
*dst++ = *(buf + 1); /* high byte */
*dst++ = *buf; /* low byte */
dst += 2; /* point to next longword */
buf += 2; /* buffer only filled with words */
}
/* if low words (offs = 2) have been written, clear the rest of the DPRAM, */
/* flush the PCI-write-buffer and take the E1 out of reset */
if (offs) {
memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */
dpram = card->dpram; /* get pointer to dpram structure */
dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */
while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */
byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */
/* the interrupts are still masked */
sti();
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) {
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write bootldr no answer");
return (-ERR_BOOTIMG_FAIL);
}
} /* start_boot_img */
return (0); /* successfull */
} /* ergo_writebootimg */
/********************************************************************************/
/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */
/* using the boot spool mechanism. If everything works fine 0 is returned. In */
/* case of errors a negative error value is returned. */
/********************************************************************************/
static int
ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len)
{
tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram;
uchar *dst;
uchar buflen;
int nr_write;
uchar tmp_rdptr;
uchar wr_mirror;
int i;
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write boot seq len=%d ", len);
dst = sp->Data; /* point to data in spool structure */
buflen = sp->Len; /* maximum len of spooled data */
wr_mirror = sp->WrPtr; /* only once read */
sti();
/* try until all bytes written or error */
i = 0x1000; /* timeout value */
while (len) {
/* first determine the number of bytes that may be buffered */
do {
tmp_rdptr = sp->RdPtr; /* first read the pointer */
i--; /* decrement timeout */
} while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */
if (!i) {
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: write boot seq timeout");
return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */
}
if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0)
nr_write += buflen; /* now we got number of free bytes - 1 in buffer */
if (!nr_write)
continue; /* no free bytes in buffer */
if (nr_write > len)
nr_write = len; /* limit if last few bytes */
i = 0x1000; /* reset timeout value */
/* now we know how much bytes we may put in the puffer */
len -= nr_write; /* we savely could adjust len before output */
while (nr_write--) {
*(dst + wr_mirror) = *buf++; /* output one byte */
if (++wr_mirror >= buflen)
wr_mirror = 0;
sp->WrPtr = wr_mirror; /* announce the next byte to E1 */
} /* while (nr_write) */
} /* while (len) */
return (0);
} /* ergo_writebootseq */
/***********************************************************************************/
/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */
/* boot process. If the process has been successfull 0 is returned otherwise a */
/* negative error code is returned. */
/***********************************************************************************/
static int
ergo_waitpofready(struct HYSDN_CARD *card)
{
tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */
int timecnt = 10000 / 50; /* timeout is 10 secs max. */
ulong flags;
int msg_size;
int i;
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: waiting for pof ready");
while (timecnt--) {
/* wait until timeout */
if (dpr->ToPcFlag) {
/* data has arrived */
if ((dpr->ToPcChannel != CHAN_SYSTEM) ||
(dpr->ToPcSize < MIN_RDY_MSG_SIZE) ||
(dpr->ToPcSize > MAX_RDY_MSG_SIZE) ||
((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC))
break; /* an error occured */
/* Check for additional data delivered during SysReady */
msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE;
if (msg_size > 0)
if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size))
break;
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "ERGO: pof boot success");
save_flags(flags);
cli();
card->state = CARD_STATE_RUN; /* now card is running */
/* enable the cards interrupt */
byteout(card->iobase + PCI9050_INTR_REG,
bytein(card->iobase + PCI9050_INTR_REG) |
(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1));
card->irq_enabled = 1; /* we are ready to receive interrupts */
dpr->ToPcFlag = 0; /* reset data indicator */
dpr->ToHyInt = 1;
dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
restore_flags(flags);
if ((i = hysdn_net_create(card))) {
ergo_stopcard(card);
card->state = CARD_STATE_BOOTERR;
return (i);
}
return (0); /* success */
} /* data has arrived */
sti();
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((50 * HZ) / 1000); /* Timeout 50ms */
} /* wait until timeout */
if (card->debug_flags & LOG_POF_CARD)
hysdn_addlog(card, "ERGO: pof boot ready timeout");
return (-ERR_POF_TIMEOUT);
} /* ergo_waitpofready */
/************************************************************************************/
/* release the cards hardware. Before releasing do a interrupt disable and hardware */
/* reset. Also unmap dpram. */
/* Use only during module release. */
/************************************************************************************/
static void
ergo_releasehardware(hysdn_card * card)
{
ergo_stopcard(card); /* first stop the card if not already done */
free_irq(card->irq, card); /* release interrupt */
release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */
release_region(card->iobase + PCI9050_USER_IO, 1);
vfree(card->dpram);
card->dpram = NULL; /* release shared mem */
} /* ergo_releasehardware */
/*********************************************************************************/
/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */
/* value is returned. */
/* Use only during module init. */
/*********************************************************************************/
int
ergo_inithardware(hysdn_card * card)
{
if (check_region(card->iobase + PCI9050_INTR_REG, 1) ||
check_region(card->iobase + PCI9050_USER_IO, 1))
return (-1); /* ports already in use */
card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1;
if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE)))
return (-1);
request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN");
request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN");
ergo_stopcard(card); /* disable interrupts */
if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) {
ergo_releasehardware(card); /* return the aquired hardware */
return (-1);
}
/* success, now setup the function pointers */
card->stopcard = ergo_stopcard;
card->releasehardware = ergo_releasehardware;
card->testram = ergo_testram;
card->writebootimg = ergo_writebootimg;
card->writebootseq = ergo_writebootseq;
card->waitpofready = ergo_waitpofready;
card->set_errlog_state = ergo_set_errlog_state;
card->irq_queue.next = 0;
card->irq_queue.sync = 0;
card->irq_queue.data = card; /* init task queue for interrupt */
card->irq_queue.routine = (void *) (void *) ergo_irq_bh;
return (0);
} /* ergo_inithardware */

View File

@ -1,114 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
*
*/
#include <linux/isdn_compat.h>
/************************************************/
/* defines for the dual port memory of the card */
/************************************************/
#define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */
#define BOOT_IMG_SIZE 4096
#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE)
#define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */
#define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */
/* following DPRAM layout copied from OS2-driver boarderg.h */
typedef struct ErgDpram_tag {
/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE];
/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE];
/*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART];
/* size 0x1B0 */
/*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64];
/* size 64 bytes */
/*1DB0 ulong ulErrType; */
/*1DB4 ulong ulErrSubtype; */
/*1DB8 ulong ucTextSize; */
/*1DB9 ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */
/*1DF0 */
/*1DF0 */ word volatile ToHyChannel;
/*1DF2 */ word volatile ToHySize;
/*1DF4 */ uchar volatile ToHyFlag;
/* !=0: msg for Hy waiting */
/*1DF5 */ uchar volatile ToPcFlag;
/* !=0: msg for PC waiting */
/*1DF6 */ word volatile ToPcChannel;
/*1DF8 */ word volatile ToPcSize;
/*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA];
/* 6 bytes */
/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00];
/*1F00 */ ulong TrapTable[62];
/*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8];
/* low part of reset vetor */
/*1FFB */ uchar ToPcIntMetro;
/* notes:
* - metro has 32-bit boot ram - accessing
* ToPcInt and ToHyInt would be the same;
* so we moved ToPcInt to 1FFB.
* Because on the PC side both vars are
* readonly (reseting on int from E1 to PC),
* we can read both vars on both cards
* without destroying anything.
* - 1FFB is the high byte of the reset vector,
* so E1 side should NOT change this byte
* when writing!
*/
/*1FFC */ uchar volatile ToHyNoDpramErrLog;
/* note: ToHyNoDpramErrLog is used to inform
* boot loader, not to use DPRAM based
* ErrLog; when DOS driver is rewritten
* this becomes obsolete
*/
/*1FFD */ uchar bRes1FFD;
/*1FFE */ uchar ToPcInt;
/* E1_intclear; on CHAMP2: E1_intset */
/*1FFF */ uchar ToHyInt;
/* E1_intset; on CHAMP2: E1_intclear */
} tErgDpram;
/**********************************************/
/* PCI9050 controller local register offsets: */
/* copied from boarderg.c */
/**********************************************/
#define PCI9050_INTR_REG 0x4C /* Interrupt register */
#define PCI9050_USER_IO 0x51 /* User I/O register */
/* bitmask for PCI9050_INTR_REG: */
#define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */
#define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */
#define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */
#define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */
/* bitmask for PCI9050_USER_IO: */
#define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */
#define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */
#define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */
#define PCI9050_E1_RESET ( PCI9050_USER_IO_DIR3) /* 0x04 */
#define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3) /* 0x0C */

View File

@ -1,417 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, specific routines for booting and pof handling.
*
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/malloc.h>
#include <asm/uaccess.h>
#include "hysdn_defs.h"
#include "hysdn_pof.h"
/********************************/
/* defines for pof read handler */
/********************************/
#define POF_READ_FILE_HEAD 0
#define POF_READ_TAG_HEAD 1
#define POF_READ_TAG_DATA 2
/************************************************************/
/* definition of boot specific data area. This data is only */
/* needed during boot and so allocated dynamically. */
/************************************************************/
struct boot_data {
word Cryptor; /* for use with Decrypt function */
word Nrecs; /* records remaining in file */
uchar pof_state; /* actual state of read handler */
uchar is_crypted; /* card data is crypted */
int BufSize; /* actual number of bytes bufferd */
int last_error; /* last occured error */
word pof_recid; /* actual pof recid */
ulong pof_reclen; /* total length of pof record data */
ulong pof_recoffset; /* actual offset inside pof record */
union {
uchar BootBuf[BOOT_BUF_SIZE]; /* buffer as byte count */
tPofRecHdr PofRecHdr; /* header for actual record/chunk */
tPofFileHdr PofFileHdr; /* header from POF file */
tPofTimeStamp PofTime; /* time information */
} buf;
};
/*****************************************************/
/* start decryption of sucessive POF file chuncks. */
/* */
/* to be called at start of POF file reading, */
/* before starting any decryption on any POF record. */
/*****************************************************/
void
StartDecryption(struct boot_data *boot)
{
boot->Cryptor = CRYPT_STARTTERM;
} /* StartDecryption */
/***************************************************************/
/* decrypt complete BootBuf */
/* NOTE: decryption must be applied to all or none boot tags - */
/* to HI and LO boot loader and (all) seq tags, because */
/* global Cryptor is started for whole POF. */
/***************************************************************/
void
DecryptBuf(struct boot_data *boot, int cnt)
{
uchar *bufp = boot->buf.BootBuf;
while (cnt--) {
boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
*bufp++ ^= (uchar) boot->Cryptor;
}
} /* DecryptBuf */
/********************************************************************************/
/* pof_handle_data executes the required actions dependant on the active record */
/* id. If successfull 0 is returned, a negative value shows an error. */
/********************************************************************************/
static int
pof_handle_data(hysdn_card * card, int datlen)
{
struct boot_data *boot = card->boot; /* pointer to boot specific data */
long l;
uchar *imgp;
int img_len;
/* handle the different record types */
switch (boot->pof_recid) {
case TAG_TIMESTMP:
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText);
break;
case TAG_CBOOTDTA:
DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
case TAG_BOOTDTA:
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
(boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA",
datlen, boot->pof_recoffset);
if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) {
boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */
return (boot->last_error);
}
imgp = boot->buf.BootBuf; /* start of buffer */
img_len = datlen; /* maximum length to transfer */
l = POF_BOOT_LOADER_OFF_IN_PAGE -
(boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1));
if (l > 0) {
/* buffer needs to be truncated */
imgp += l; /* advance pointer */
img_len -= l; /* adjust len */
}
/* at this point no special handling for data wrapping over buffer */
/* is necessary, because the boot image always will be adjusted to */
/* match a page boundary inside the buffer. */
/* The buffer for the boot image on the card is filled in 2 cycles */
/* first the 1024 hi-words are put in the buffer, then the low 1024 */
/* word are handled in the same way with different offset. */
if (img_len > 0) {
/* data available for copy */
if ((boot->last_error =
card->writebootimg(card, imgp,
(boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0)
return (boot->last_error);
}
break; /* end of case boot image hi/lo */
case TAG_CABSDATA:
DecryptBuf(boot, datlen); /* we need to encrypt the buffer */
case TAG_ABSDATA:
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
(boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
datlen, boot->pof_recoffset);
if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
return (boot->last_error); /* error writing data */
if (boot->pof_recoffset + datlen >= boot->pof_reclen)
return (card->waitpofready(card)); /* data completely spooled, wait for ready */
break; /* end of case boot seq data */
default:
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid,
datlen, boot->pof_recoffset);
break; /* simply skip record */
} /* switch boot->pof_recid */
return (0);
} /* pof_handle_data */
/******************************************************************************/
/* pof_write_buffer is called when the buffer has been filled with the needed */
/* number of data bytes. The number delivered is additionally supplied for */
/* verification. The functions handles the data and returns the needed number */
/* of bytes for the next action. If the returned value is 0 or less an error */
/* occured and booting must be aborted. */
/******************************************************************************/
int
pof_write_buffer(hysdn_card * card, int datlen)
{
struct boot_data *boot = card->boot; /* pointer to boot specific data */
if (!boot)
return (-EFAULT); /* invalid call */
if (boot->last_error < 0)
return (boot->last_error); /* repeated error */
if (card->debug_flags & LOG_POF_WRITE)
hysdn_addlog(card, "POF write: got %d bytes ", datlen);
switch (boot->pof_state) {
case POF_READ_FILE_HEAD:
if (card->debug_flags & LOG_POF_WRITE)
hysdn_addlog(card, "POF write: checking file header");
if (datlen != sizeof(tPofFileHdr)) {
boot->last_error = -EPOF_INTERNAL;
break;
}
if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) {
boot->last_error = -EPOF_BAD_MAGIC;
break;
}
/* Setup the new state and vars */
boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */
boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
boot->last_error = sizeof(tPofRecHdr); /* new length */
break;
case POF_READ_TAG_HEAD:
if (card->debug_flags & LOG_POF_WRITE)
hysdn_addlog(card, "POF write: checking tag header");
if (datlen != sizeof(tPofRecHdr)) {
boot->last_error = -EPOF_INTERNAL;
break;
}
boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */
boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */
boot->pof_recoffset = 0; /* no starting offset */
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ",
boot->pof_recid, boot->pof_reclen);
boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */
if (boot->pof_reclen < BOOT_BUF_SIZE)
boot->last_error = boot->pof_reclen; /* limit size */
else
boot->last_error = BOOT_BUF_SIZE; /* maximum */
if (!boot->last_error) { /* no data inside record */
boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
boot->last_error = sizeof(tPofRecHdr); /* new length */
}
break;
case POF_READ_TAG_DATA:
if (card->debug_flags & LOG_POF_WRITE)
hysdn_addlog(card, "POF write: getting tag data");
if (datlen != boot->last_error) {
boot->last_error = -EPOF_INTERNAL;
break;
}
if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
return (boot->last_error); /* an error occured */
boot->pof_recoffset += datlen;
if (boot->pof_recoffset >= boot->pof_reclen) {
boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */
boot->last_error = sizeof(tPofRecHdr); /* new length */
} else {
if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE)
boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */
else
boot->last_error = BOOT_BUF_SIZE; /* maximum */
}
break;
default:
boot->last_error = -EPOF_INTERNAL; /* unknown state */
break;
} /* switch (boot->pof_state) */
return (boot->last_error);
} /* pof_write_buffer */
/*******************************************************************************/
/* pof_write_open is called when an open for boot on the cardlog device occurs. */
/* The function returns the needed number of bytes for the next operation. If */
/* the returned number is less or equal 0 an error specified by this code */
/* occurred. Additionally the pointer to the buffer data area is set on success */
/*******************************************************************************/
int
pof_write_open(hysdn_card * card, uchar ** bufp)
{
struct boot_data *boot; /* pointer to boot specific data */
if (card->boot) {
if (card->debug_flags & LOG_POF_OPEN)
hysdn_addlog(card, "POF open: already opened for boot");
return (-ERR_ALREADY_BOOT); /* boot already active */
}
/* error no mem available */
if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) {
if (card->debug_flags & LOG_MEM_ERR)
hysdn_addlog(card, "POF open: unable to allocate mem");
return (-EFAULT);
}
card->boot = boot;
card->state = CARD_STATE_BOOTING;
memset(boot, 0, sizeof(struct boot_data));
card->stopcard(card); /* first stop the card */
if (card->testram(card)) {
if (card->debug_flags & LOG_POF_OPEN)
hysdn_addlog(card, "POF open: DPRAM test failure");
boot->last_error = -ERR_BOARD_DPRAM;
card->state = CARD_STATE_BOOTERR; /* show boot error */
return (boot->last_error);
}
boot->BufSize = 0; /* Buffer is empty */
boot->pof_state = POF_READ_FILE_HEAD; /* read file header */
StartDecryption(boot); /* if POF File should be encrypted */
if (card->debug_flags & LOG_POF_OPEN)
hysdn_addlog(card, "POF open: success");
*bufp = boot->buf.BootBuf; /* point to buffer */
return (sizeof(tPofFileHdr));
} /* pof_write_open */
/********************************************************************************/
/* pof_write_close is called when an close of boot on the cardlog device occurs. */
/* The return value must be 0 if everything has happened as desired. */
/********************************************************************************/
int
pof_write_close(hysdn_card * card)
{
struct boot_data *boot = card->boot; /* pointer to boot specific data */
if (!boot)
return (-EFAULT); /* invalid call */
card->boot = NULL; /* no boot active */
kfree(boot);
if (card->state == CARD_STATE_RUN)
card->set_errlog_state(card, 1); /* activate error log */
if (card->debug_flags & LOG_POF_OPEN)
hysdn_addlog(card, "POF close: success");
return (0);
} /* pof_write_close */
/*********************************************************************************/
/* EvalSysrTokData checks additional records delivered with the Sysready Message */
/* when POF has been booted. A return value of 0 is used if no error occured. */
/*********************************************************************************/
int
EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
{
u_char *p;
u_char crc;
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "SysReady Token data length %d", len);
if (len < 2) {
hysdn_addlog(card, "SysReady Token Data to short");
return (1);
}
for (p = cp, crc = 0; p < (cp + len - 2); p++)
if ((crc & 0x80))
crc = (((u_char) (crc << 1)) + 1) + *p;
else
crc = ((u_char) (crc << 1)) + *p;
crc = ~crc;
if (crc != *(cp + len - 1)) {
hysdn_addlog(card, "SysReady Token Data invalid CRC");
return (1);
}
len--; /* dont check CRC byte */
while (len > 0) {
if (*cp == SYSR_TOK_END)
return (0); /* End of Token stream */
if (len < (*(cp + 1) + 2)) {
hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1));
return (1);
}
switch (*cp) {
case SYSR_TOK_B_CHAN: /* 1 */
if (*(cp + 1) != 1)
return (1); /* length invalid */
card->bchans = *(cp + 2);
break;
case SYSR_TOK_FAX_CHAN: /* 2 */
if (*(cp + 1) != 1)
return (1); /* length invalid */
card->faxchans = *(cp + 2);
break;
case SYSR_TOK_MAC_ADDR: /* 3 */
if (*(cp + 1) != 6)
return (1); /* length invalid */
memcpy(card->mac_addr, cp + 2, 6);
break;
default:
hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1));
break;
}
len -= (*(cp + 1) + 2); /* adjust len */
cp += (*(cp + 1) + 2); /* and pointer */
}
hysdn_addlog(card, "no end token found");
return (1);
} /* EvalSysrTokData */

View File

@ -1,226 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, global definitions and exported vars and functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
*
*/
#include <linux/hysdn_if.h>
#include <linux/interrupt.h>
#include <linux/tqueue.h>
#include <linux/skbuff.h>
#include <linux/isdn_compat.h>
/****************************/
/* storage type definitions */
/****************************/
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define word unsigned short
#include "ince1pc.h"
/************************************************/
/* constants and bits for debugging/log outputs */
/************************************************/
#define LOG_MAX_LINELEN 120
#define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */
#define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */
#define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */
#define LOG_POF_RECORD 0x00000020 /* log pof record parser */
#define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */
#define LOG_POF_CARD 0x00000080 /* log pof related card functions */
#define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */
#define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */
#define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */
#define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */
#define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */
#define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */
#define LOG_NET_INIT 0x00010000 /* network init and deinit logging */
#define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */
/**********************************/
/* proc filesystem name constants */
/**********************************/
#define PROC_SUBDIR_NAME "hysdn"
#define PROC_CONF_BASENAME "cardconf"
#define PROC_LOG_BASENAME "cardlog"
/************************/
/* PCI constant defines */
/************************/
#define PCI_VENDOR_ID_HYPERCOPE 0x1365
#define PCI_DEVICE_ID_PLX 0x9050 /* all DPRAM cards use the same id */
/*****************************/
/* sub ids determining cards */
/*****************************/
#define PCI_SUB_ID_OLD_ERGO 0x0104
#define PCI_SUB_ID_ERGO 0x0106
#define PCI_SUB_ID_METRO 0x0107
#define PCI_SUB_ID_CHAMP2 0x0108
#define PCI_SUB_ID_PLEXUS 0x0109
/***********************************/
/* PCI 32 bit parms for IO and MEM */
/***********************************/
#define PCI_REG_PLX_MEM_BASE 0
#define PCI_REG_PLX_IO_BASE 1
#define PCI_REG_MEMORY_BASE 3
/**************/
/* card types */
/**************/
#define BD_NONE 0U
#define BD_PERFORMANCE 1U
#define BD_VALUE 2U
#define BD_PCCARD 3U
#define BD_ERGO 4U
#define BD_METRO 5U
#define BD_CHAMP2 6U
#define BD_PLEXUS 7U
/******************************************************/
/* defined states for cards shown by reading cardconf */
/******************************************************/
#define CARD_STATE_UNUSED 0 /* never been used or booted */
#define CARD_STATE_BOOTING 1 /* booting is in progress */
#define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */
#define CARD_STATE_RUN 3 /* card is active */
/*******************************/
/* defines for error_log_state */
/*******************************/
#define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */
#define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */
#define ERRLOG_STATE_START 2 /* start error logging */
#define ERRLOG_STATE_STOP 3 /* stop error logging */
/*******************************/
/* data structure for one card */
/*******************************/
typedef struct HYSDN_CARD {
/* general variables for the cards */
int myid; /* own driver card id */
uchar bus; /* pci bus the card is connected to */
uchar devfn; /* slot+function bit encoded */
word subsysid; /* PCI subsystem id */
uchar brdtype; /* type of card */
uint bchans; /* number of available B-channels */
uint faxchans; /* number of available fax-channels */
uchar mac_addr[6]; /* MAC Address read from card */
uint irq; /* interrupt number */
uint iobase; /* IO-port base address */
ulong plxbase; /* PLX memory base */
ulong membase; /* DPRAM memory base */
ulong memend; /* DPRAM memory end */
void *dpram; /* mapped dpram */
int state; /* actual state of card -> CARD_STATE_** */
struct HYSDN_CARD *next; /* pointer to next card */
/* data areas for the /proc file system */
void *proclog; /* pointer to proclog filesystem specific data */
void *procconf; /* pointer to procconf filesystem specific data */
/* debugging and logging */
uchar err_log_state; /* actual error log state of the card */
ulong debug_flags; /* tells what should be debugged and where */
void (*set_errlog_state) (struct HYSDN_CARD *, int);
/* interrupt handler + interrupt synchronisation */
struct tq_struct irq_queue; /* interrupt task queue */
uchar volatile irq_enabled; /* interrupt enabled if != 0 */
uchar volatile hw_lock; /* hardware is currently locked -> no access */
/* boot process */
void *boot; /* pointer to boot private data */
int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong);
int (*writebootseq) (struct HYSDN_CARD *, uchar *, int);
int (*waitpofready) (struct HYSDN_CARD *);
int (*testram) (struct HYSDN_CARD *);
/* scheduler for data transfer (only async parts) */
uchar async_data[256]; /* async data to be sent (normally for config) */
word volatile async_len; /* length of data to sent */
word volatile async_channel; /* channel number for async transfer */
int volatile async_busy; /* flag != 0 sending in progress */
int volatile net_tx_busy; /* a network packet tx is in progress */
/* network interface */
void *netif; /* pointer to network structure */
/* init and deinit stopcard for booting, too */
void (*stopcard) (struct HYSDN_CARD *);
void (*releasehardware) (struct HYSDN_CARD *);
} hysdn_card;
/*****************/
/* exported vars */
/*****************/
extern int cardmax; /* number of found cards */
extern hysdn_card *card_root; /* pointer to first card */
/*************************/
/* im/exported functions */
/*************************/
extern int printk(const char *fmt,...);
extern char *hysdn_getrev(const char *);
/* hysdn_procconf.c */
extern int hysdn_procconf_init(void); /* init proc config filesys */
extern void hysdn_procconf_release(void); /* deinit proc config filesys */
/* hysdn_proclog.c */
extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */
extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */
extern void put_log_buffer(hysdn_card *, char *); /* output log data */
extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */
extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */
/* boardergo.c */
extern int ergo_inithardware(hysdn_card * card); /* get hardware -> module init */
/* hysdn_boot.c */
extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */
extern int pof_write_open(hysdn_card *, uchar **); /* open proc file for writing pof */
extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */
extern int EvalSysrTokData(hysdn_card *, uchar *, int); /* Check Sysready Token Data */
/* hysdn_sched.c */
extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *,
word);
extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word);
extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word); /* send one cfg line */
/* hysdn_net.c */
extern char *hysdn_net_revision;
extern int hysdn_net_create(hysdn_card *); /* create a new net device */
extern int hysdn_net_release(hysdn_card *); /* delete the device */
extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */
extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */
extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */
extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word); /* rxed packet from network */

View File

@ -1,239 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, init functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/malloc.h>
#include <linux/pci.h>
#include "hysdn_defs.h"
static char *hysdn_init_revision = "$Revision$";
int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
/**********************************************/
/* table assigning PCI-sub ids to board types */
/* the last entry contains all 0 */
/**********************************************/
static struct {
word subid; /* PCI sub id */
uchar cardtyp; /* card type assigned */
} pci_subid_map[] = {
{
PCI_SUB_ID_METRO, BD_METRO
},
{
PCI_SUB_ID_CHAMP2, BD_CHAMP2
},
{
PCI_SUB_ID_ERGO, BD_ERGO
},
{
PCI_SUB_ID_OLD_ERGO, BD_ERGO
},
{
0, 0
} /* terminating entry */
};
/*********************************************************************/
/* search_cards searches for available cards in the pci config data. */
/* If a card is found, the card structure is allocated and the cards */
/* ressources are reserved. cardmax is incremented. */
/*********************************************************************/
static void
search_cards(void)
{
struct pci_dev *akt_pcidev = NULL;
hysdn_card *card, *card_last;
uchar irq;
int i;
card_root = NULL;
card_last = NULL;
while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_PLX,
akt_pcidev)) != NULL) {
if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
return;
}
memset(card, 0, sizeof(hysdn_card));
card->myid = cardmax; /* set own id */
card->bus = akt_pcidev->bus->number;
card->devfn = akt_pcidev->devfn; /* slot + function */
pcibios_read_config_word(card->bus, card->devfn, PCI_SUBSYSTEM_ID, &card->subsysid);
pcibios_read_config_byte(card->bus, card->devfn, PCI_INTERRUPT_LINE, &irq);
card->irq = irq;
card->iobase = get_pcibase(akt_pcidev, PCI_REG_PLX_IO_BASE) & PCI_BASE_ADDRESS_IO_MASK;
card->plxbase = get_pcibase(akt_pcidev, PCI_REG_PLX_MEM_BASE);
card->membase = get_pcibase(akt_pcidev, PCI_REG_MEMORY_BASE);
card->brdtype = BD_NONE; /* unknown */
card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
card->faxchans = 0; /* default no fax channels */
card->bchans = 2; /* and 2 b-channels */
for (i = 0; pci_subid_map[i].subid; i++)
if (pci_subid_map[i].subid == card->subsysid) {
card->brdtype = pci_subid_map[i].cardtyp;
break;
}
if (card->brdtype != BD_NONE) {
if (ergo_inithardware(card)) {
printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
kfree(card);
continue;
}
} else {
printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
kfree(card); /* release mem */
continue;
}
cardmax++;
card->next = NULL; /*end of chain */
if (card_last)
card_last->next = card; /* pointer to next card */
else
card_root = card;
card_last = card; /* new chain end */
} /* device found */
} /* search_cards */
/************************************************************************************/
/* free_resources frees the acquired PCI resources and returns the allocated memory */
/************************************************************************************/
static void
free_resources(void)
{
hysdn_card *card;
while (card_root) {
card = card_root;
if (card->releasehardware)
card->releasehardware(card); /* free all hardware resources */
card_root = card_root->next; /* remove card from chain */
kfree(card); /* return mem */
} /* while card_root */
} /* free_resources */
/**************************************************************************/
/* stop_cards disables (hardware resets) all cards and disables interrupt */
/**************************************************************************/
static void
stop_cards(void)
{
hysdn_card *card;
card = card_root; /* first in chain */
while (card) {
if (card->stopcard)
card->stopcard(card);
card = card->next; /* remove card from chain */
} /* while card */
} /* stop_cards */
/****************************************************************************/
/* The module startup and shutdown code. Only compiled when used as module. */
/* Using the driver as module is always advisable, because the booting */
/* image becomes smaller and the driver code is only loaded when needed. */
/* Additionally newer versions may be activated without rebooting. */
/****************************************************************************/
#ifdef CONFIG_MODULES
/******************************************************/
/* extract revision number from string for log output */
/******************************************************/
char *
hysdn_getrev(const char *revision)
{
char *rev;
char *p;
if ((p = strchr(revision, ':'))) {
rev = p + 2;
p = strchr(rev, '$');
*--p = 0;
} else
rev = "???";
return rev;
}
/****************************************************************************/
/* init_module is called once when the module is loaded to do all necessary */
/* things like autodetect... */
/* If the return value of this function is 0 the init has been successfull */
/* and the module is added to the list in /proc/modules, otherwise an error */
/* is assumed and the module will not be kept in memory. */
/****************************************************************************/
int
init_module(void)
{
char tmp[50];
strcpy(tmp, hysdn_init_revision);
printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
strcpy(tmp, hysdn_net_revision);
printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
if (!pci_present()) {
printk(KERN_ERR "HYSDN: no PCI bus present, module not loaded\n");
return (-1);
}
search_cards();
printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
if (hysdn_procconf_init()) {
free_resources(); /* proc file_sys not created */
return (-1);
}
return (0); /* no error */
} /* init_module */
/***********************************************************************/
/* cleanup_module is called when the module is released by the kernel. */
/* The routine is only called if init_module has been successfull and */
/* the module counter has a value of 0. Otherwise this function will */
/* not be called. This function must release all resources still allo- */
/* cated as after the return from this function the module code will */
/* be removed from memory. */
/***********************************************************************/
void
cleanup_module(void)
{
stop_cards();
hysdn_procconf_release();
free_resources();
printk(KERN_NOTICE "HYSDN: module unloaded\n");
} /* cleanup_module */
#endif /* CONFIG_MODULES */

View File

@ -1,462 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, net (ethernet type) handling routines.
*
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This net module has been inspired by the skeleton driver from
* Donald Becker (becker@CESDIS.gsfc.nasa.gov)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.2 2000/02/13 17:32:19 werner
*
* Added support for new network layer of 2.3.43 and 44 kernels and tested driver.
*
* Revision 1.1 2000/02/10 19:45:18 werner
*
* Initial release
*
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/inetdevice.h>
#include "hysdn_defs.h"
/* store the actual version for log reporting */
char *hysdn_net_revision = "$Revision$";
#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
/****************************************************************************/
/* structure containing the complete network data. The structure is aligned */
/* in a way that both, the device and statistics are kept inside it. */
/* for proper access, the device structure MUST be the first var/struct */
/* inside the definition. */
/****************************************************************************/
struct net_local {
struct net_device netdev; /* the network device */
struct net_device_stats stats;
/* additional vars may be added here */
char dev_name[9]; /* our own device name */
#ifdef COMPAT_NO_SOFTNET
struct sk_buff *tx_skb; /* buffer for tx operation */
#else
/* Tx control lock. This protects the transmit buffer ring
* state along with the "tx full" state of the driver. This
* means all netif_queue flow control actions are protected
* by this lock as well.
*/
spinlock_t lock;
struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */
int in_idx, out_idx; /* indexes to buffer ring */
int sk_count; /* number of buffers currently in ring */
int is_open; /* flag controlling module locking */
#endif
}; /* net_local */
/*****************************************************/
/* Get the current statistics for this card. */
/* This may be called with the card open or closed ! */
/*****************************************************/
static struct net_device_stats *
net_get_stats(struct net_device *dev)
{
return (&((struct net_local *) dev)->stats);
} /* net_device_stats */
/*********************************************************************/
/* Open/initialize the board. This is called (in the current kernel) */
/* sometime after booting when the 'ifconfig' program is run. */
/* This routine should set everything up anew at each open, even */
/* registers that "should" only need to be set once at boot, so that */
/* there is non-reboot way to recover if something goes wrong. */
/*********************************************************************/
static int
net_open(struct net_device *dev)
{
struct in_device *in_dev;
hysdn_card *card = dev->priv;
int i;
#ifdef COMPAT_NO_SOFTNET
dev->tbusy = 0; /* non busy state */
dev->interrupt = 0;
if (!dev->start)
MOD_INC_USE_COUNT; /* increment only if device is down */
dev->start = 1; /* and started */
#else
if (!((struct net_local *) dev)->is_open)
MOD_INC_USE_COUNT; /* increment only if interface is actually down */
((struct net_local *) dev)->is_open = 1; /* device actually open */
netif_start_queue(dev); /* start tx-queueing */
#endif
/* Fill in the MAC-level header (if not already set) */
if (!card->mac_addr[0]) {
for (i = 0; i < ETH_ALEN - sizeof(ulong); i++)
dev->dev_addr[i] = 0xfc;
if ((in_dev = dev->ip_ptr) != NULL) {
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL)
memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong));
}
} else
memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
return (0);
} /* net_open */
#ifndef COMPAT_NO_SOFTNET
/*******************************************/
/* flush the currently occupied tx-buffers */
/* must only be called when device closed */
/*******************************************/
static void
flush_tx_buffers(struct net_local *nl)
{
while (nl->sk_count) {
dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */
if (nl->out_idx >= MAX_SKB_BUFFERS)
nl->out_idx = 0; /* wrap around */
nl->sk_count--;
}
} /* flush_tx_buffers */
#endif
/*********************************************************************/
/* close/decativate the device. The device is not removed, but only */
/* deactivated. */
/*********************************************************************/
static int
net_close(struct net_device *dev)
{
#ifdef COMPAT_NO_SOFTNET
dev->tbusy = 1; /* we are busy */
if (dev->start)
MOD_DEC_USE_COUNT; /* dec only if device has been active */
dev->start = 0; /* and not started */
#else
netif_stop_queue(dev); /* disable queueing */
if (((struct net_local *) dev)->is_open)
MOD_DEC_USE_COUNT; /* adjust module counter */
((struct net_local *) dev)->is_open = 0;
flush_tx_buffers((struct net_local *) dev);
#endif
return (0); /* success */
} /* net_close */
#ifdef COMPAT_NO_SOFTNET
/************************************/
/* send a packet on this interface. */
/* only for kernel versions < 2.3.33 */
/************************************/
static int
net_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev;
if (dev->tbusy) {
/*
* If we get here, some higher level has decided we are broken.
* There should really be a "kick me" function call instead.
* As ISDN may have higher timeouts than real ethernet 10s timeout
*/
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < (10000 * HZ) / 1000)
return 1;
printk(KERN_WARNING "%s: transmit timed out. \n", dev->name);
dev->tbusy = 0;
dev->trans_start = jiffies;
}
/*
* Block a timer-based transmit from overlapping. This could better be
* done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
else {
lp->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
lp->tx_skb = skb; /* remember skb pointer */
queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
return (0); /* success */
} /* net_send_packet */
#else
/************************************/
/* send a packet on this interface. */
/* new style for kernel >= 2.3.33 */
/************************************/
static int
net_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct net_local *lp = (struct net_local *) dev;
spin_lock_irq(&lp->lock);
lp->skbs[lp->in_idx++] = skb; /* add to buffer list */
if (lp->in_idx >= MAX_SKB_BUFFERS)
lp->in_idx = 0; /* wrap around */
lp->sk_count++; /* adjust counter */
dev->trans_start = jiffies;
/* If we just used up the very last entry in the
* TX ring on this device, tell the queueing
* layer to send no more.
*/
if (lp->sk_count >= MAX_SKB_BUFFERS)
netif_stop_queue(dev);
/* When the TX completion hw interrupt arrives, this
* is when the transmit statistics are updated.
*/
spin_unlock_irq(&lp->lock);
if (lp->sk_count <= 3) {
queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
return (0); /* success */
} /* net_send_packet */
#endif
/***********************************************************************/
/* acknowlegde a packet send. The network layer will be informed about */
/* completion */
/***********************************************************************/
void
hysdn_tx_netack(hysdn_card * card)
{
struct net_local *lp = card->netif;
if (!lp)
return; /* non existing device */
#ifdef COMPAT_NO_SOFTNET
if (lp->tx_skb)
dev_kfree_skb(lp->tx_skb); /* free tx pointer */
lp->tx_skb = NULL; /* reset pointer */
lp->stats.tx_packets++;
lp->netdev.tbusy = 0;
mark_bh(NET_BH); /* Inform upper layers. */
#else
if (!lp->sk_count)
return; /* error condition */
lp->stats.tx_packets++;
lp->stats.tx_bytes += lp->skbs[lp->out_idx]->len;
dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */
if (lp->out_idx >= MAX_SKB_BUFFERS)
lp->out_idx = 0; /* wrap around */
if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */
netif_start_queue((struct net_device *) lp);
#endif
} /* hysdn_tx_netack */
/*****************************************************/
/* we got a packet from the network, go and queue it */
/*****************************************************/
void
hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len)
{
struct net_local *lp = card->netif;
struct sk_buff *skb;
if (!lp)
return; /* non existing device */
lp->stats.rx_bytes += len;
skb = dev_alloc_skb(len);
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
lp->netdev.name);
lp->stats.rx_dropped++;
return;
}
skb->dev = &lp->netdev;
/* copy the data */
memcpy(skb_put(skb, len), buf, len);
/* determine the used protocol */
skb->protocol = eth_type_trans(skb, &lp->netdev);
netif_rx(skb);
lp->stats.rx_packets++; /* adjust packet count */
} /* hysdn_rx_netpkt */
/*****************************************************/
/* return the pointer to a network packet to be send */
/*****************************************************/
struct sk_buff *
hysdn_tx_netget(hysdn_card * card)
{
struct net_local *lp = card->netif;
if (!lp)
return (NULL); /* non existing device */
#ifdef COMPAT_NO_SOFTNET
return (lp->tx_skb); /* return packet pointer */
#else
if (!lp->sk_count)
return (NULL); /* nothing available */
return (lp->skbs[lp->out_idx]); /* next packet to send */
#endif
} /* hysdn_tx_netget */
/*******************************************/
/* init function called by register device */
/*******************************************/
static int
net_init(struct net_device *dev)
{
/* setup the function table */
dev->open = net_open;
dev->stop = net_close;
dev->hard_start_xmit = net_send_packet;
dev->get_stats = net_get_stats;
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
return (0); /* success */
} /* net_init */
/*****************************************************************************/
/* hysdn_net_create creates a new net device for the given card. If a device */
/* already exists, it will be deleted and created a new one. The return value */
/* 0 announces success, else a negative error code will be returned. */
/*****************************************************************************/
int
hysdn_net_create(hysdn_card * card)
{
struct net_device *dev;
int i;
hysdn_net_release(card); /* release an existing net device */
if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
if (card->debug_flags & LOG_NET_INIT)
return (-ENOMEM);
}
memset(dev, 0, sizeof(struct net_local)); /* clean the structure */
#ifndef COMPAT_NO_SOFTNET
spin_lock_init(&((struct net_local *) dev)->lock);
#endif
/* initialise necessary or informing fields */
dev->base_addr = card->iobase; /* IO address */
dev->irq = card->irq; /* irq */
dev->init = net_init; /* the init function of the device */
dev->name = ((struct net_local *) dev)->dev_name; /* device name */
if ((i = register_netdev(dev))) {
printk(KERN_WARNING "HYSDN: unable to create network device\n");
kfree(dev);
return (i);
}
dev->priv = card; /* remember pointer to own data structure */
card->netif = dev; /* setup the local pointer */
if (card->debug_flags & LOG_NET_INIT)
hysdn_addlog(card, "network device created");
return (0); /* and return success */
} /* hysdn_net_create */
/***************************************************************************/
/* hysdn_net_release deletes the net device for the given card. The return */
/* value 0 announces success, else a negative error code will be returned. */
/***************************************************************************/
int
hysdn_net_release(hysdn_card * card)
{
struct net_device *dev = card->netif;
if (!dev)
return (0); /* non existing */
card->netif = NULL; /* clear out pointer */
dev->stop(dev); /* close the device */
#ifndef COMPAT_NO_SOFTNET
flush_tx_buffers((struct net_local *) dev); /* empty buffers */
#endif
unregister_netdev(dev); /* release the device */
kfree(dev); /* release the memory allocated */
if (card->debug_flags & LOG_NET_INIT)
hysdn_addlog(card, "network device deleted");
return (0); /* always successfull */
} /* hysdn_net_release */
/*****************************************************************************/
/* hysdn_net_getname returns a pointer to the name of the network interface. */
/* if the interface is not existing, a "-" is returned. */
/*****************************************************************************/
char *
hysdn_net_getname(hysdn_card * card)
{
struct net_device *dev = card->netif;
if (!dev)
return ("-"); /* non existing */
return (dev->name);
} /* hysdn_net_getname */

View File

@ -1,91 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, definitions used for handling pof-files.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
*
*/
/************************/
/* POF specific defines */
/************************/
#define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */
#define CRYPT_FEEDTERM 0x8142
#define CRYPT_STARTTERM 0x81a5
/* max. timeout time in seconds
* from end of booting to POF is ready
*/
#define POF_READY_TIME_OUT_SEC 10
/**********************************/
/* defines for 1.stage boot image */
/**********************************/
/* the POF file record containing the boot loader image
* has 2 pages a 16KB:
* 1. page contains the high 16-bit part of the 32-bit E1 words
* 2. page contains the low 16-bit part of the 32-bit E1 words
*
* In each 16KB page we assume the start of the boot loader code
* in the highest 2KB part (at offset 0x3800);
* the rest (0x0000..0x37FF) is assumed to contain 0 bytes.
*/
#define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */
#define POF_BOOT_LOADER_TOTAL_SIZE (2U*POF_BOOT_LOADER_PAGE_SIZE)
#define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */
/* offset in boot page, where loader code may start */
/* =0x3800= 14336U */
#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE)
/*--------------------------------------POF file record structs------------*/
typedef struct PofFileHdr_tag { /* Pof file header */
/*00 */ ulong Magic __attribute__((packed));
/*04 */ ulong N_PofRecs __attribute__((packed));
/*08 */
} tPofFileHdr;
typedef struct PofRecHdr_tag { /* Pof record header */
/*00 */ word PofRecId __attribute__((packed));
/*02 */ ulong PofRecDataLen __attribute__((packed));
/*06 */
} tPofRecHdr;
typedef struct PofTimeStamp_tag {
/*00 */ ulong UnixTime __attribute__((packed));
/*04 */ uchar DateTimeText[0x28] __attribute__((packed));
/* =40 */
/*2C */
} tPofTimeStamp;
/* tPofFileHdr.Magic value: */
#define TAGFILEMAGIC 0x464F501AUL
/* tPofRecHdr.PofRecId values: */
#define TAG_ABSDATA 0x1000 /* abs. data */
#define TAG_BOOTDTA 0x1001 /* boot data */
#define TAG_COMMENT 0x0020
#define TAG_SYSCALL 0x0021
#define TAG_FLOWCTRL 0x0022
#define TAG_TIMESTMP 0x0010 /* date/time stamp of version */
#define TAG_CABSDATA 0x1100 /* crypted abs. data */
#define TAG_CBOOTDTA 0x1101 /* crypted boot data */

View File

@ -1,492 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.2 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
*
* Revision 1.1 2000/02/10 19:45:18 werner
*
* Initial release
*
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include "hysdn_defs.h"
static char *hysdn_procconf_revision = "$Revision$";
#define INFO_OUT_LEN 80 /* length of info line including lf */
/********************************************************/
/* defines and data structure for conf write operations */
/********************************************************/
#define CONF_STATE_DETECT 0 /* waiting for detect */
#define CONF_STATE_CONF 1 /* writing config data */
#define CONF_STATE_POF 2 /* writing pof data */
#define CONF_LINE_LEN 80 /* 80 chars max */
struct conf_writedata {
hysdn_card *card; /* card the device is connected to */
int buf_size; /* actual number of bytes in the buffer */
int needed_size; /* needed size when reading pof */
int state; /* actual interface states from above constants */
uchar conf_line[CONF_LINE_LEN]; /* buffered conf line */
word channel; /* active channel number */
uchar *pof_buffer; /* buffer when writing pof */
};
/***********************************************************************/
/* process_line parses one config line and transfers it to the card if */
/* necessary. */
/* if the return value is negative an error occured. */
/***********************************************************************/
static int
process_line(struct conf_writedata *cnf)
{
uchar *cp = cnf->conf_line;
int i;
if (cnf->card->debug_flags & LOG_CNF_LINE)
hysdn_addlog(cnf->card, "conf line: %s", cp);
if (*cp == '-') { /* option */
cp++; /* point to option char */
if (*cp++ != 'c')
return (0); /* option unknown or used */
i = 0; /* start value for channel */
while ((*cp <= '9') && (*cp >= '0'))
i = i * 10 + *cp++ - '0'; /* get decimal number */
if (i > 65535) {
if (cnf->card->debug_flags & LOG_CNF_MISC)
hysdn_addlog(cnf->card, "conf channel invalid %d", i);
return (-ERR_INV_CHAN); /* invalid channel */
}
cnf->channel = i & 0xFFFF; /* set new channel number */
return (0); /* success */
} /* option */
if (*cp == '*') { /* line to send */
if (cnf->card->debug_flags & LOG_CNF_DATA)
hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp);
return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1,
cnf->channel)); /* send the line without * */
} /* line to send */
return (0);
} /* process_line */
/*************************/
/* dummy file operations */
/*************************/
static loff_t
hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
} /* hysdn_dummy_lseek */
/***********************************/
/* conf file operations and tables */
/***********************************/
/****************************************************/
/* write conf file -> boot or send cfg line to card */
/****************************************************/
static ssize_t
hysdn_conf_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
struct conf_writedata *cnf;
int i;
uchar ch, *cp;
if (&file->f_pos != off) /* fs error check */
return (-ESPIPE);
if (!count)
return (0); /* nothing to handle */
if (!(cnf = file->private_data))
return (-EFAULT); /* should never happen */
if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */
if (copy_from_user(&ch, buf, 1)) /* get first char for detect */
return (-EFAULT);
if (ch == 0x1A) {
/* we detected a pof file */
if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0)
return (cnf->needed_size); /* an error occured -> exit */
cnf->buf_size = 0; /* buffer is empty */
cnf->state = CONF_STATE_POF; /* new state */
} else {
/* conf data has been detected */
cnf->buf_size = 0; /* buffer is empty */
cnf->state = CONF_STATE_CONF; /* requested conf data write */
if (cnf->card->state != CARD_STATE_RUN)
return (-ERR_NOT_BOOTED);
cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */
cnf->channel = 4098; /* default channel for output */
}
} /* state was auto detect */
if (cnf->state == CONF_STATE_POF) { /* pof write active */
i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */
if (i <= 0)
return (-EINVAL); /* size error handling pof */
if (i < count)
count = i; /* limit requested number of bytes */
if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count))
return (-EFAULT); /* error while copying */
cnf->buf_size += count;
if (cnf->needed_size == cnf->buf_size) {
cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */
if (cnf->needed_size <= 0) {
cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */
return (cnf->needed_size); /* an error occured */
}
cnf->buf_size = 0; /* buffer is empty again */
}
}
/* pof write active */
else { /* conf write active */
if (cnf->card->state != CARD_STATE_RUN) {
if (cnf->card->debug_flags & LOG_CNF_MISC)
hysdn_addlog(cnf->card, "cnf write denied -> not booted");
return (-ERR_NOT_BOOTED);
}
i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */
if (i > 0) {
/* copy remaining bytes into buffer */
if (count > i)
count = i; /* limit transfer */
if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count))
return (-EFAULT); /* error while copying */
i = count; /* number of chars in buffer */
cp = cnf->conf_line + cnf->buf_size;
while (i) {
/* search for end of line */
if ((*cp < ' ') && (*cp != 9))
break; /* end of line found */
cp++;
i--;
} /* search for end of line */
if (i) {
/* delimiter found */
*cp++ = 0; /* string termination */
count -= (i - 1); /* subtract remaining bytes from count */
while ((i) && (*cp < ' ') && (*cp != 9)) {
i--; /* discard next char */
count++; /* mark as read */
cp++; /* next char */
}
cnf->buf_size = 0; /* buffer is empty after transfer */
if ((i = process_line(cnf)) < 0) /* handle the line */
count = i; /* return the error */
}
/* delimiter found */
else {
cnf->buf_size += count; /* add chars to string */
if (cnf->buf_size >= CONF_LINE_LEN - 1) {
if (cnf->card->debug_flags & LOG_CNF_MISC)
hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count);
return (-ERR_CONF_LONG);
}
} /* not delimited */
}
/* copy remaining bytes into buffer */
else {
if (cnf->card->debug_flags & LOG_CNF_MISC)
hysdn_addlog(cnf->card, "cnf line too long");
return (-ERR_CONF_LONG);
}
} /* conf write active */
return (count);
} /* hysdn_conf_write */
/*******************************************/
/* read conf file -> output card info data */
/*******************************************/
static ssize_t
hysdn_conf_read(struct file *file, char *buf, size_t count, loff_t * off)
{
char *cp;
int i;
if (off != &file->f_pos) /* fs error check */
return -ESPIPE;
if (file->f_mode & FMODE_READ) {
if (!(cp = file->private_data))
return (-EFAULT); /* should never happen */
i = strlen(cp); /* get total string length */
if (*off < i) {
/* still bytes to transfer */
cp += *off; /* point to desired data offset */
i -= *off; /* remaining length */
if (i > count)
i = count; /* limit length to transfer */
if (copy_to_user(buf, cp, i))
return (-EFAULT); /* copy error */
*off += i; /* adjust offset */
} else
return (0);
} else
return (-EPERM); /* no permission to read */
return (i);
} /* hysdn_conf_read */
/******************/
/* open conf file */
/******************/
static int
hysdn_conf_open(struct inode *ino, struct file *filep)
{
hysdn_card *card;
struct proc_dir_entry *pd;
struct conf_writedata *cnf;
char *cp, *tmp;
MOD_INC_USE_COUNT; /* lock module */
/* now search the addressed card */
card = card_root;
while (card) {
pd = card->procconf;
if (pd->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (!card) {
MOD_DEC_USE_COUNT; /* unlock module */
return (-ENODEV); /* device is unknown/invalid */
}
if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x",
filep->f_uid, filep->f_gid, filep->f_mode);
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write boot file or conf line */
if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
MOD_DEC_USE_COUNT;
return (-EFAULT);
}
cnf->card = card;
cnf->buf_size = 0; /* nothing buffered */
cnf->state = CONF_STATE_DETECT; /* start auto detect */
filep->private_data = cnf;
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> output card info data */
if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
MOD_DEC_USE_COUNT;
return (-EFAULT); /* out of memory */
}
filep->private_data = tmp; /* start of string */
/* first output a headline */
sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device");
cp = tmp; /* start of string */
while (*cp)
cp++;
while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
*cp++ = ' ';
*cp++ = '\n';
/* and now the data */
sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08x %7d %9d %3d %s",
card->myid,
card->bus,
PCI_SLOT(card->devfn),
card->brdtype,
card->irq,
card->iobase,
card->membase,
card->bchans,
card->faxchans,
card->state,
hysdn_net_getname(card));
while (*cp)
cp++;
while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
*cp++ = ' ';
*cp++ = '\n';
*cp = 0; /* end of string */
} else { /* simultaneous read/write access forbidden ! */
MOD_DEC_USE_COUNT; /* unlock module */
return (-EPERM); /* no permission this time */
}
return (0);
} /* hysdn_conf_open */
/***************************/
/* close a config file. */
/***************************/
static int
hysdn_conf_close(struct inode *ino, struct file *filep)
{
hysdn_card *card;
struct conf_writedata *cnf;
int retval = 0;
struct proc_dir_entry *pd;
/* search the addressed card */
card = card_root;
while (card) {
pd = card->procconf;
if (pd->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (!card) {
return (-ENODEV); /* device is unknown/invalid */
}
if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x",
filep->f_uid, filep->f_gid, filep->f_mode);
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write boot file or conf line */
if (filep->private_data) {
cnf = filep->private_data;
if (cnf->state == CONF_STATE_POF)
retval = pof_write_close(cnf->card); /* close the pof write */
kfree(filep->private_data); /* free allocated memory for buffer */
} /* handle write private data */
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> output card info data */
if (filep->private_data)
kfree(filep->private_data); /* release memory */
}
MOD_DEC_USE_COUNT; /* reduce usage count */
return (retval);
} /* hysdn_conf_close */
/******************************************************/
/* table for conf filesystem functions defined above. */
/******************************************************/
static struct file_operations conf_fops =
{
hysdn_dummy_lseek,
hysdn_conf_read,
hysdn_conf_write,
NULL, /* readdir */
NULL, /* poll */
NULL, /* ioctl */
NULL, /* mmap */
hysdn_conf_open,
NULL, /* flush */
hysdn_conf_close,
NULL /* fsync */
};
#ifdef COMPAT_NO_SOFTNET
static struct inode_operations conf_inode_operations;
#endif
/*****************************/
/* hysdn subdir in /proc/net */
/*****************************/
struct proc_dir_entry *hysdn_proc_entry = NULL;
/*******************************************************************************/
/* hysdn_procconf_init is called when the module is loaded and after the cards */
/* have been detected. The needed proc dir and card config files are created. */
/* The log init is called at last. */
/*******************************************************************************/
int
hysdn_procconf_init(void)
{
hysdn_card *card;
uchar conf_name[20];
hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
if (!hysdn_proc_entry) {
printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
return (-1);
}
card = card_root; /* point to first card */
while (card) {
sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
if ((card->procconf = (void *) create_proc_entry(conf_name,
S_IFREG | S_IRUGO | S_IWUSR,
hysdn_proc_entry)) != NULL) {
#ifdef COMPAT_NO_SOFTNET
memset(&conf_inode_operations, 0, sizeof(struct inode_operations));
conf_inode_operations.default_file_ops = &conf_fops;
((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations;
#else
((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops;
#endif
hysdn_proclog_init(card); /* init the log file entry */
}
card = card->next; /* next entry */
}
printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision));
return (0);
} /* hysdn_procconf_init */
/*************************************************************************************/
/* hysdn_procconf_release is called when the module is unloaded and before the cards */
/* resources are released. The module counter is assumed to be 0 ! */
/*************************************************************************************/
void
hysdn_procconf_release(void)
{
hysdn_card *card;
uchar conf_name[20];
card = card_root; /* start with first card */
while (card) {
sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
if (card->procconf)
remove_proc_entry(conf_name, hysdn_proc_entry);
hysdn_proclog_release(card); /* init the log file entry */
card = card->next; /* point to next card */
}
remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
} /* hysdn_procfs_release */

View File

@ -1,495 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, /proc/net filesystem log functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.2 2000/02/14 19:23:03 werner
*
* Changed handling of proc filesystem tables to a more portable version
*
* Revision 1.1 2000/02/10 19:45:18 werner
*
* Initial release
*
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include "hysdn_defs.h"
static char *hysdn_proclog_revision = "$Revision$";
/* the proc subdir for the interface is defined in the procconf module */
extern struct proc_dir_entry *hysdn_proc_entry;
/*************************************************/
/* structure keeping ascii log for device output */
/*************************************************/
struct log_data {
struct log_data *next;
ulong usage_cnt; /* number of files still to work */
void *proc_ctrl; /* pointer to own control procdata structure */
char log_start[2]; /* log string start (final len aligned by size) */
};
/**********************************************/
/* structure holding proc entrys for one card */
/**********************************************/
struct procdata {
struct proc_dir_entry *log; /* log entry */
char log_name[15]; /* log filename */
struct log_data *log_head, *log_tail; /* head and tail for queue */
int if_used; /* open count for interface */
int volatile del_lock; /* lock for delete operations */
uchar logtmp[LOG_MAX_LINELEN];
#ifdef COMPAT_HAS_NEW_WAITQ
wait_queue_head_t rd_queue;
#else
struct wait_queue *rd_queue; /* wait queue structure */
#endif
};
/**********************************************/
/* log function for cards error log interface */
/**********************************************/
void
hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize)
{
char buf[ERRLOG_TEXT_SIZE + 40];
sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText);
put_log_buffer(card, buf); /* output the string */
} /* hysdn_card_errlog */
/***************************************************/
/* Log function using format specifiers for output */
/***************************************************/
void
hysdn_addlog(hysdn_card * card, char *fmt,...)
{
struct procdata *pd = card->proclog;
char *cp;
va_list args;
if (!pd)
return; /* log structure non existent */
cp = pd->logtmp;
cp += sprintf(cp, "HYSDN: card %d ", card->myid);
va_start(args, fmt);
cp += vsprintf(cp, fmt, args);
va_end(args);
*cp++ = '\n';
*cp = 0;
if (card->debug_flags & DEB_OUT_SYSLOG)
printk(KERN_INFO "%s", pd->logtmp);
else
put_log_buffer(card, pd->logtmp);
} /* hysdn_addlog */
/********************************************/
/* put an log buffer into the log queue. */
/* This buffer will be kept until all files */
/* opened for read got the contents. */
/* Flushes buffers not longer in use. */
/********************************************/
void
put_log_buffer(hysdn_card * card, char *cp)
{
struct log_data *ib;
struct procdata *pd = card->proclog;
int i, flags;
if (!pd)
return;
if (!cp)
return;
if (!*cp)
return;
if (pd->if_used <= 0)
return; /* no open file for read */
if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
return; /* no memory */
strcpy(ib->log_start, cp); /* set output string */
ib->next = NULL;
ib->proc_ctrl = pd; /* point to own control structure */
save_flags(flags);
cli();
ib->usage_cnt = pd->if_used;
if (!pd->log_head)
pd->log_head = ib; /* new head */
else
pd->log_tail->next = ib; /* follows existing messages */
pd->log_tail = ib; /* new tail */
i = pd->del_lock++; /* get lock state */
restore_flags(flags);
/* delete old entrys */
if (!i)
while (pd->log_head->next) {
if ((pd->log_head->usage_cnt <= 0) &&
(pd->log_head->next->usage_cnt <= 0)) {
ib = pd->log_head;
pd->log_head = pd->log_head->next;
kfree(ib);
} else
break;
} /* pd->log_head->next */
pd->del_lock--; /* release lock level */
wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */
} /* put_log_buffer */
/*************************/
/* dummy file operations */
/*************************/
static loff_t
hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
} /* hysdn_dummy_lseek */
/******************************/
/* file operations and tables */
/******************************/
/****************************************/
/* write log file -> set log level bits */
/****************************************/
static ssize_t
hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
{
ulong u = 0;
int found = 0;
uchar *cp, valbuf[128];
long base = 10;
hysdn_card *card = (hysdn_card *) file->private_data;
if (&file->f_pos != off) /* fs error check */
return (-ESPIPE);
if (count > (sizeof(valbuf) - 1))
count = sizeof(valbuf) - 1; /* limit length */
if (copy_from_user(valbuf, buf, count))
return (-EFAULT); /* copy failed */
valbuf[count] = 0; /* terminating 0 */
cp = valbuf;
if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
cp += 2; /* pointer after hex modifier */
base = 16;
}
/* scan the input for debug flags */
while (*cp) {
if ((*cp >= '0') && (*cp <= '9')) {
found = 1;
u *= base; /* adjust to next digit */
u += *cp++ - '0';
continue;
}
if (base != 16)
break; /* end of number */
if ((*cp >= 'a') && (*cp <= 'f')) {
found = 1;
u *= base; /* adjust to next digit */
u += *cp++ - 'a' + 10;
continue;
}
break; /* terminated */
}
if (found) {
card->debug_flags = u; /* remember debug flags */
hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
}
return (count);
} /* hysdn_log_write */
/******************/
/* read log file */
/******************/
static ssize_t
hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
{
struct log_data *inf;
int len;
word ino;
struct procdata *pd;
hysdn_card *card;
if (!*((struct log_data **) file->private_data)) {
if (file->f_flags & O_NONBLOCK)
return (-EAGAIN);
/* sorry, but we need to search the card */
ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
card = card_root;
while (card) {
pd = card->proclog;
if (pd->log->low_ino == ino)
break;
card = card->next; /* search next entry */
}
if (card)
interruptible_sleep_on(&(pd->rd_queue));
else
return (-EAGAIN);
}
if (!(inf = *((struct log_data **) file->private_data)))
return (0);
inf->usage_cnt--; /* new usage count */
(struct log_data **) file->private_data = &inf->next; /* next structure */
if ((len = strlen(inf->log_start)) <= count) {
if (copy_to_user(buf, inf->log_start, len))
return -EFAULT;
file->f_pos += len;
return (len);
}
return (0);
} /* hysdn_log_read */
/******************/
/* open log file */
/******************/
static int
hysdn_log_open(struct inode *ino, struct file *filep)
{
hysdn_card *card;
struct procdata *pd;
ulong flags;
MOD_INC_USE_COUNT; /* lock module */
card = card_root;
while (card) {
pd = card->proclog;
if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (!card) {
MOD_DEC_USE_COUNT; /* unlock module */
return (-ENODEV); /* device is unknown/invalid */
}
filep->private_data = card; /* remember our own card */
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write log level only */
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> log/debug read */
save_flags(flags);
cli();
pd->if_used++;
if (pd->log_head)
(struct log_data **) filep->private_data = &(pd->log_tail->next);
else
(struct log_data **) filep->private_data = &(pd->log_head);
restore_flags(flags);
} else { /* simultaneous read/write access forbidden ! */
MOD_DEC_USE_COUNT; /* unlock module */
return (-EPERM); /* no permission this time */
}
return (0);
} /* hysdn_log_open */
/*******************************************************************************/
/* close a cardlog file. If the file has been opened for exclusive write it is */
/* assumed as pof data input and the pof loader is noticed about. */
/* Otherwise file is handled as log output. In this case the interface usage */
/* count is decremented and all buffers are noticed of closing. If this file */
/* was the last one to be closed, all buffers are freed. */
/*******************************************************************************/
static int
hysdn_log_close(struct inode *ino, struct file *filep)
{
struct log_data *inf;
struct procdata *pd;
hysdn_card *card;
int flags, retval = 0;
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
/* write only access -> write debug level written */
retval = 0; /* success */
} else {
/* read access -> log/debug read, mark one further file as closed */
pd = NULL;
save_flags(flags);
cli();
inf = *((struct log_data **) filep->private_data); /* get first log entry */
if (inf)
pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
else {
/* no info available -> search card */
card = card_root;
while (card) {
pd = card->proclog;
if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
break;
card = card->next; /* search next entry */
}
if (card)
pd = card->proclog; /* pointer to procfs log */
}
if (pd)
pd->if_used--; /* decrement interface usage count by one */
while (inf) {
inf->usage_cnt--; /* decrement usage count for buffers */
inf = inf->next;
}
restore_flags(flags);
if (pd)
if (pd->if_used <= 0) /* delete buffers if last file closed */
while (pd->log_head) {
inf = pd->log_head;
pd->log_head = pd->log_head->next;
kfree(inf);
}
} /* read access */
MOD_DEC_USE_COUNT;
return (retval);
} /* hysdn_log_close */
/*************************************************/
/* select/poll routine to be able using select() */
/*************************************************/
static unsigned int
hysdn_log_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
word ino;
hysdn_card *card;
struct procdata *pd;
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
return (mask); /* no polling for write supported */
/* we need to search the card */
ino = file->f_dentry->d_inode->i_ino & 0xFFFF; /* low-ino */
card = card_root;
while (card) {
pd = card->proclog;
if (pd->log->low_ino == ino)
break;
card = card->next; /* search next entry */
}
if (!card)
return (mask); /* card not found */
poll_wait(file, &(pd->rd_queue), wait);
if (*((struct log_data **) file->private_data))
mask |= POLLIN | POLLRDNORM;
return mask;
} /* hysdn_log_poll */
/**************************************************/
/* table for log filesystem functions defined above. */
/**************************************************/
static struct file_operations log_fops =
{
hysdn_dummy_lseek,
hysdn_log_read,
hysdn_log_write,
NULL, /* readdir */
hysdn_log_poll, /* poll */
NULL,
NULL, /* mmap */
hysdn_log_open,
NULL, /* flush */
hysdn_log_close,
NULL /* fsync */
};
#ifdef COMPAT_NO_SOFTNET
struct inode_operations log_inode_operations;
#endif
/***********************************************************************************/
/* hysdn_proclog_init is called when the module is loaded after creating the cards */
/* conf files. */
/***********************************************************************************/
int
hysdn_proclog_init(hysdn_card * card)
{
struct procdata *pd;
/* create a cardlog proc entry */
if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
memset(pd, 0, sizeof(struct procdata));
#ifdef COMPAT_NO_SOFTNET
memset(&log_inode_operations, 0, sizeof(struct inode_operations));
log_inode_operations.default_file_ops = &log_fops;
#endif
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
#ifdef COMPAT_NO_SOFTNET
pd->log->ops = &log_inode_operations; /* set new operations table */
#else
pd->log->proc_fops = &log_fops;
#endif
#ifdef COMPAT_HAS_NEW_WAITQ
init_waitqueue_head(&(pd->rd_queue));
#endif
card->proclog = (void *) pd; /* remember procfs structure */
}
return (0);
} /* hysdn_proclog_init */
/************************************************************************************/
/* hysdn_proclog_release is called when the module is unloaded and before the cards */
/* conf file is released */
/* The module counter is assumed to be 0 ! */
/************************************************************************************/
void
hysdn_proclog_release(hysdn_card * card)
{
struct procdata *pd;
if ((pd = (struct procdata *) card->proclog) != NULL) {
if (pd->log)
remove_proc_entry(pd->log_name, hysdn_proc_entry);
kfree(pd); /* release memory */
card->proclog = NULL;
}
} /* hysdn_proclog_release */

View File

@ -1,199 +0,0 @@
/* $Id$
* Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc.
*
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
*
* Copyright 1999 by Werner Cornelius (werner@titro.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <asm/io.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include "hysdn_defs.h"
/*****************************************************************************/
/* hysdn_sched_rx is called from the cards handler to announce new data is */
/* available from the card. The routine has to handle the data and return */
/* with a nonzero code if the data could be worked (or even thrown away), if */
/* no room to buffer the data is available a zero return tells the card */
/* to keep the data until later. */
/*****************************************************************************/
int
hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
{
switch (chan) {
case CHAN_NDIS_DATA:
hysdn_rx_netpkt(card, buf, len); /* give packet to network handler */
break;
case CHAN_ERRLOG:
hysdn_card_errlog(card, (tErrLogEntry *) buf, len);
if (card->err_log_state == ERRLOG_STATE_ON)
card->err_log_state = ERRLOG_STATE_START; /* start new fetch */
break;
default:
printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
break;
} /* switch rx channel */
return (1); /* always handled */
} /* hysdn_sched_rx */
/*****************************************************************************/
/* hysdn_sched_tx is called from the cards handler to announce that there is */
/* room in the tx-buffer to the card and data may be sent if needed. */
/* If the routine wants to send data it must fill buf, len and chan with the */
/* appropriate data and return a nonzero value. With a zero return no new */
/* data to send is assumed. maxlen specifies the buffer size available for */
/* sending. */
/*****************************************************************************/
int
hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen)
{
struct sk_buff *skb;
if (card->net_tx_busy) {
card->net_tx_busy = 0; /* reset flag */
hysdn_tx_netack(card); /* acknowledge packet send */
} /* a network packet has completely been transferred */
/* first of all async requests are handled */
if (card->async_busy) {
if (card->async_len <= maxlen) {
memcpy(buf, card->async_data, card->async_len);
*len = card->async_len;
*chan = card->async_channel;
card->async_busy = 0; /* reset request */
return (1);
}
card->async_busy = 0; /* in case of length error */
} /* async request */
if ((card->err_log_state == ERRLOG_STATE_START) &&
(maxlen >= ERRLOG_CMD_REQ_SIZE)) {
strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */
*len = ERRLOG_CMD_REQ_SIZE; /* buffer length */
*chan = CHAN_ERRLOG; /* and channel */
card->err_log_state = ERRLOG_STATE_ON; /* new state is on */
return (1); /* tell that data should be send */
} /* error log start and able to send */
if ((card->err_log_state == ERRLOG_STATE_STOP) &&
(maxlen >= ERRLOG_CMD_STOP_SIZE)) {
strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */
*len = ERRLOG_CMD_STOP_SIZE; /* buffer length */
*chan = CHAN_ERRLOG; /* and channel */
card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */
return (1); /* tell that data should be send */
} /* error log start and able to send */
/* now handle network interface packets */
if ((skb = hysdn_tx_netget(card)) != NULL) {
if (skb->len <= maxlen) {
memcpy(buf, skb->data, skb->len); /* copy the packet to the buffer */
*len = skb->len;
*chan = CHAN_NDIS_DATA;
card->net_tx_busy = 1; /* we are busy sending network data */
return (1); /* go and send the data */
} else
hysdn_tx_netack(card); /* aknowledge packet -> throw away */
} /* send a network packet if available */
return (0); /* nothing to send */
} /* hysdn_sched_tx */
/*****************************************************************************/
/* send one config line to the card and return 0 if successfull, otherwise a */
/* negative error code. */
/* The function works with timeouts perhaps not giving the greatest speed */
/* sending the line, but this should be meaningless beacuse only some lines */
/* are to be sent and this happens very seldom. */
/*****************************************************************************/
int
hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
{
int cnt = 50; /* timeout intervalls */
ulong flags;
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
save_flags(flags);
cli();
while (card->async_busy) {
sti();
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg delayed");
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
if (!--cnt) {
restore_flags(flags);
return (-ERR_ASYNC_TIME); /* timed out */
}
cli();
} /* wait for buffer to become free */
strcpy(card->async_data, line);
card->async_len = strlen(line) + 1;
card->async_channel = chan;
card->async_busy = 1; /* request transfer */
/* now queue the task */
queue_task(&card->irq_queue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
sti();
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg data queued");
cnt++; /* short delay */
cli();
while (card->async_busy) {
sti();
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
if (!--cnt) {
restore_flags(flags);
return (-ERR_ASYNC_TIME); /* timed out */
}
cli();
} /* wait for buffer to become free again */
restore_flags(flags);
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg data send");
return (0); /* line send correctly */
} /* hysdn_tx_cfgline */

View File

@ -1,132 +0,0 @@
#ifndef __INCE1PC_H__
#define __INCE1PC_H__
/****************************************************************************
FILE: ince1pc.h
AUTHOR: M.Steinkopf
PURPOSE: common definitions for both sides of the bus:
- conventions both spoolers must know
- channel numbers agreed upon
*****************************************************************************/
/* basic scalar definitions have same meanning,
* but their declaration location depends on environment
*/
/*--------------------------------------channel numbers---------------------*/
#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */
#define CHAN_ERRLOG 0x0005 /* error logger */
#define CHAN_CAPI 0x0064 /* CAPI interface */
#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */
/*--------------------------------------POF ready msg-----------------------*/
/* NOTE: after booting POF sends system ready message to PC: */
#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */
#define RDY_MAGIC_SIZE 4 /* size in bytes */
#define MAX_N_TOK_BYTES 255
#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE
#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
#define SYSR_TOK_END 0
#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */
#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */
#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */
#define SYSR_TOK_ESC 255 /* undefined data size yet */
/* default values, if not corrected by token: */
#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */
#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */
/* syntax of new SYSR token stream:
* channel: CHAN_SYSTEM
* msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
* RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
* msg : 0 1 2 3 {4 5 6 ..}
* S Y S R MAX_N_TOK_BYTES bytes of TokenStream
*
* TokenStream := empty
* | {NonEndTokenChunk} EndToken RotlCRC
* NonEndTokenChunk:= NonEndTokenId DataLen [Data]
* NonEndTokenId := 0x01 .. 0xFE 1 BYTE
* DataLen := 0x00 .. 0xFF 1 BYTE
* Data := DataLen bytes
* EndToken := 0x00
* RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes
* s. RotlCRC algorithm
*
* RotlCRC algorithm:
* ucSum= 0 1 uchar
* for all NonEndTokenChunk bytes:
* ROTL(ucSum,1) rotate left by 1
* ucSum += Char; add current byte with swap around
* RotlCRC= ~ucSum; invert all bits for result
*
* note:
* - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
*/
/*--------------------------------------error logger------------------------*/
/* note: pof needs final 0 ! */
#define ERRLOG_CMD_REQ "ERRLOG ON"
#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */
#define ERRLOG_CMD_STOP "ERRLOG OFF"
#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */
#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */
/* remaining text size = 55 */
#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE-2*4-1)
typedef struct ErrLogEntry_tag {
/*00 */ ulong ulErrType;
/*04 */ ulong ulErrSubtype;
/*08 */ uchar ucTextSize;
/*09 */ uchar ucText[ERRLOG_TEXT_SIZE];
/* ASCIIZ of len ucTextSize-1 */
/*40 */
} tErrLogEntry;
#if defined(__TURBOC__)
#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
#endif /* */
#endif /* */
/*--------------------------------------DPRAM boot spooler------------------*/
/* this is the struture used between pc and
* hyperstone to exchange boot data
*/
#define DPRAM_SPOOLER_DATA_SIZE 0x20
typedef struct DpramBootSpooler_tag {
/*00 */ uchar Len;
/*01 */ volatile uchar RdPtr;
/*02 */ uchar WrPtr;
/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE];
/*23 */
} tDpramBootSpooler;
#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */
#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */
/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/
/* at DPRAM offset 0x1C00: */
#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */
#endif /* __INCE1PC_H__ */

View File

@ -1,8 +0,0 @@
ifeq ($(CONFIG_ISDN_DRV_ICN),y)
O_TARGET := icn_obj.o
O_OBJS := icn.o
else
M_OBJS := icn.o
endif
include $(TOPDIR)/Rules.make

File diff suppressed because it is too large Load Diff

View File

@ -1,400 +0,0 @@
/* $Id$
* ISDN lowlevel-module for the ICN active ISDN-Card.
*
* Copyright 1994 by Fritz Elfert (fritz@isdn4linux.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.28 1997/10/10 15:56:18 fritz
* New HL<->LL interface:
* New BSENT callback with nr. of bytes included.
* Sending without ACK.
*
* Revision 1.27 1997/10/01 09:21:56 fritz
* Removed old compatibility stuff for 2.0.X kernels.
* From now on, this code is for 2.1.X ONLY!
* Old stuff is still in the separate branch.
*
* Revision 1.26 1997/02/14 12:23:16 fritz
* Added support for new insmod parameter handling.
*
* Revision 1.25 1997/02/10 10:10:31 fritz
* Changes for Kernel 2.1.X compatibility.
* Enhanced initialization, can recover from
* misconfiguration by other autoprobing drivers.
*
* Revision 1.24 1997/01/29 22:34:46 fritz
* Cleanup, Corrected D64S setup of 2nd channel.
*
* Revision 1.23 1996/12/17 18:47:55 tsbogend
* changed timeouts from absolute numbers to HZ based values
*
* Revision 1.22 1996/11/13 02:37:33 fritz
* Added delay include.
*
* Revision 1.21 1996/08/29 20:35:57 fritz
* Speed up B-Channel polling interval.
*
* Revision 1.20 1996/06/24 17:20:37 fritz
* Bugfixes in pollbchan_send():
* - Using lock field of skbuff breaks networking.
* - Added channel locking
* - changed dequeuing scheme.
* Eliminated misc. compiler warnings.
*
* Revision 1.19 1996/06/06 13:58:35 fritz
* Changed code to be architecture independent
*
* Revision 1.18 1996/06/03 19:59:30 fritz
* Removed include of config.h
*
* Revision 1.17 1996/05/18 00:47:04 fritz
* Removed callback debug code.
*
* Revision 1.16 1996/05/17 15:46:43 fritz
* Removed own queue management.
* Changed queue management to use sk_buffs.
*
* Revision 1.15 1996/05/02 04:01:57 fritz
* Removed ICN_MAXCARDS
*
* Revision 1.14 1996/05/02 00:40:29 fritz
* Major rewrite to support more than one card
* with a single module.
* Support for new firmware.
*
* Revision 1.13 1996/04/20 16:51:41 fritz
* Increased status buffer.
* Misc. typos
*
* Revision 1.12 1996/01/22 05:01:22 fritz
* Revert to GPL.
*
* Revision 1.11 1995/12/18 18:25:00 fritz
* Support for ICN-2B Cards.
* Change for supporting user-settable service-octet.
*
* Revision 1.10 1995/10/29 21:43:10 fritz
* Added support for leased lines.
*
* Revision 1.9 1995/04/23 13:42:10 fritz
* Added some constants for distinguishing 1TR6 and DSS1
*
* Revision 1.8 1995/03/25 23:18:55 fritz
* Changed ICN_PORTLEN to reflect correct number of ports.
*
* Revision 1.7 1995/03/15 12:52:06 fritz
* Some cleanup
*
* Revision 1.6 1995/02/20 03:49:22 fritz
* Fixed ICN_MAX_SQUEUE to correctly reflect outstanding bytes, not number
* of buffers.
*
* Revision 1.5 1995/01/29 23:36:50 fritz
* Minor cleanup.
*
* Revision 1.4 1995/01/09 07:41:20 fritz
* Added GPL-Notice
*
* Revision 1.3 1995/01/04 05:14:20 fritz
* removed include of linux/asm/string.h for compiling with Linux 1.1.76
*
* Revision 1.2 1995/01/02 02:15:57 fritz
* Misc. Bugfixes
*
* Revision 1.1 1994/12/14 18:02:38 fritz
* Initial revision
*
*/
#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/module.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/isdnif.h>
#endif /* __KERNEL__ */
/* some useful macros for debugging */
#ifdef ICN_DEBUG_PORT
#define OUTB_P(v,p) {printk(KERN_DEBUG "icn: outb_p(0x%02x,0x%03x)\n",v,p); outb_p(v,p);}
#else
#define OUTB_P outb
#endif
/* Defaults for Port-Address and shared-memory */
#define ICN_BASEADDR 0x320
#define ICN_PORTLEN (0x04)
#define ICN_MEMADDR 0x0d0000
#define ICN_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */
#define ICN_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */
#define ICN_FLAGS_RUNNING 4 /* Cards driver activated */
#define ICN_FLAGS_RBTIMER 8 /* cyclic scheduling of B-Channel-poll */
#define ICN_BOOT_TIMEOUT1 (HZ) /* Delay for Boot-download (jiffies) */
#define ICN_CHANLOCK_DELAY (HZ/10) /* Delay for Channel-mapping (jiffies) */
#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() */
} icn_card;
/*
* Main driver data
*/
typedef struct icn_dev {
icn_shmem *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;
/* With modutils >= 1.1.67 Integers can be changed while loading a
* module. For this reason define the Port-Base an Shmem-Base as
* integers.
*/
static int portbase = ICN_BASEADDR;
static int membase = ICN_MEMADDR;
static char *icn_id = "\0";
static char *icn_id2 = "\0";
#ifdef MODULE
MODULE_AUTHOR("Fritz Elfert");
MODULE_PARM(portbase, "i");
MODULE_PARM_DESC(portbase, "Port adress of first card");
MODULE_PARM(membase, "i");
MODULE_PARM_DESC(membase, "Shared memory adress of all cards");
MODULE_PARM(icn_id, "s");
MODULE_PARM_DESC(icn_id, "ID-String of first card");
MODULE_PARM(icn_id2, "s");
MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
#endif
#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)
#define MIN(a,b) ((a<b)?a:b)
#define MAX(a,b) ((a>b)?a:b)
/* Hopefully, a separate resource-registration-scheme for shared-memory
* will be introduced into the kernel. Until then, we use the normal
* routines, designed for port-registration.
*/
#define check_shmem check_region
#define release_shmem release_region
#define request_shmem request_region
#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
#endif /* icn_h */

View File

@ -1,806 +0,0 @@
/* $Id$
* Linux ISDN subsystem, audio conversion and compression (linklevel).
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
* DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
* Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.16 1999/08/06 12:47:35 calle
* Using __GNUC__ == 2 && __GNUC_MINOR__ < 95 how to define
* ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
*
* Revision 1.15 1999/08/06 12:02:52 calle
* egcs 2.95 complain about invalid asm statement:
* "fixed or forbidden register 2 (cx) was spilled for class CREG."
* Using ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT and not
* define it at the moment.
*
* Revision 1.14 1999/07/11 17:14:06 armin
* Added new layer 2 and 3 protocols for Fax and DSP functions.
* Moved "Add CPN to RING message" to new register S23,
* "Display message" is now correct on register S13 bit 7.
* New audio command AT+VDD implemented (deactivate DTMF decoder and
* activate possible existing hardware/DSP decoder).
* Moved some tty defines to .h file.
* Made whitespace possible in AT command line.
* Some AT-emulator output bugfixes.
* First Fax G3 implementations.
*
* Revision 1.13 1999/04/12 12:33:09 fritz
* Changes from 2.0 tree.
*
* Revision 1.12 1998/07/26 18:48:43 armin
* Added silence detection in voice receive mode.
*
* Revision 1.11 1998/04/10 10:35:10 paul
* fixed (silly?) warnings from egcs on Alpha.
*
* Revision 1.10 1998/02/20 17:09:40 fritz
* Changes for recent kernels.
*
* Revision 1.9 1997/10/01 09:20:25 fritz
* Removed old compatibility stuff for 2.0.X kernels.
* From now on, this code is for 2.1.X ONLY!
* Old stuff is still in the separate branch.
*
* Revision 1.8 1997/03/02 14:29:16 fritz
* More ttyI related cleanup.
*
* Revision 1.7 1997/02/03 22:44:11 fritz
* Reformatted according CodingStyle
*
* Revision 1.6 1996/06/06 14:43:31 fritz
* Changed to support DTMF decoding on audio playback also.
*
* Revision 1.5 1996/06/05 02:24:08 fritz
* Added DTMF decoder for audio mode.
*
* Revision 1.4 1996/05/17 03:48:01 fritz
* Removed some test statements.
* Added revision string.
*
* Revision 1.3 1996/05/10 08:48:11 fritz
* Corrected adpcm bugs.
*
* Revision 1.2 1996/04/30 09:31:17 fritz
* General rewrite.
*
* Revision 1.1.1.1 1996/04/28 12:25:40 fritz
* Taken under CVS control
*
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/isdn.h>
#include "isdn_audio.h"
#include "isdn_common.h"
char *isdn_audio_revision = "$Revision$";
/*
* Misc. lookup-tables.
*/
/* ulaw -> signed 16-bit */
static short isdn_audio_ulaw_to_s16[] =
{
0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
};
/* alaw -> signed 16-bit */
static short isdn_audio_alaw_to_s16[] =
{
0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
};
/* alaw -> ulaw */
static char isdn_audio_alaw_to_ulaw[] =
{
0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49,
0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57,
0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41,
0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f,
0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d,
0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b,
0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45,
0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53,
0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47,
0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55,
0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f,
0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e,
0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b,
0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59,
0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43,
0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51,
0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a,
0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58,
0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42,
0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50,
0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e,
0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c,
0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46,
0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54,
0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48,
0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56,
0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40,
0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f,
0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c,
0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a,
0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44,
0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52
};
/* ulaw -> alaw */
static char isdn_audio_ulaw_to_alaw[] =
{
0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35,
0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25,
0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d,
0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d,
0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31,
0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21,
0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9,
0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9,
0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47,
0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf,
0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f,
0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33,
0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23,
0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b,
0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b,
0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b,
0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34,
0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24,
0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c,
0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c,
0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30,
0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20,
0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8,
0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8,
0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46,
0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde,
0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e,
0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32,
0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22,
0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a,
0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a,
0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
};
#define NCOEFF 16 /* number of frequencies to be analyzed */
#define DTMF_TRESH 50000 /* above this is dtmf */
#define SILENCE_TRESH 100 /* below this is silence */
#define H2_TRESH 10000 /* 2nd harmonic */
#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
#define LOGRP 0
#define HIGRP 1
typedef struct {
int grp; /* low/high group */
int k; /* k */
int k2; /* k fuer 2. harmonic */
} dtmf_t;
/* For DTMF recognition:
* 2 * cos(2 * PI * k / N) precalculated for all k
*/
static int cos2pik[NCOEFF] =
{
55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517,
38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279
};
static dtmf_t dtmf_tones[8] =
{
{LOGRP, 0, 1}, /* 697 Hz */
{LOGRP, 2, 3}, /* 770 Hz */
{LOGRP, 4, 5}, /* 852 Hz */
{LOGRP, 6, 7}, /* 941 Hz */
{HIGRP, 8, 9}, /* 1209 Hz */
{HIGRP, 10, 11}, /* 1336 Hz */
{HIGRP, 12, 13}, /* 1477 Hz */
{HIGRP, 14, 15} /* 1633 Hz */
};
static char dtmf_matrix[4][4] =
{
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
/*
* egcs 2.95 complain about invalid asm statement:
* "fixed or forbidden register 2 (cx) was spilled for class CREG."
*/
#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) && defined(__GNUC__)
#if __GNUC__ == 2 && __GNUC_MINOR__ < 95
#define ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
#endif
#endif
#ifdef ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT
static inline void
isdn_audio_tlookup(const void *table, void *buff, unsigned long n)
{
__asm__("cld\n"
"1:\tlodsb\n\t"
"xlatb\n\t"
"stosb\n\t"
"loop 1b\n\t"
: : "b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
: "bx", "cx", "di", "si", "ax");
}
#else
static inline void
isdn_audio_tlookup(const char *table, char *buff, unsigned long n)
{
while (n--)
*buff++ = table[*(unsigned char *)buff];
}
#endif
void
isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
{
isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len);
}
void
isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len)
{
isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
}
/*
* linear <-> adpcm conversion stuff
* Most parts from the mgetty-package.
* (C) by Gert Doering and Klaus Weidner
* Used by permission of Gert Doering
*/
#define ZEROTRAP /* turn on the trap as per the MIL-STD */
#undef ZEROTRAP
#define BIAS 0x84 /* define the add-in bias for 16 bit samples */
#define CLIP 32635
static unsigned char
isdn_audio_linear2ulaw(int sample)
{
static int exp_lut[256] =
{
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
int sign,
exponent,
mantissa;
unsigned char ulawbyte;
/* Get the sample into sign-magnitude. */
sign = (sample >> 8) & 0x80; /* set aside the sign */
if (sign != 0)
sample = -sample; /* get magnitude */
if (sample > CLIP)
sample = CLIP; /* clip the magnitude */
/* Convert from 16 bit linear to ulaw. */
sample = sample + BIAS;
exponent = exp_lut[(sample >> 7) & 0xFF];
mantissa = (sample >> (exponent + 3)) & 0x0F;
ulawbyte = ~(sign | (exponent << 4) | mantissa);
#ifdef ZEROTRAP
/* optional CCITT trap */
if (ulawbyte == 0)
ulawbyte = 0x02;
#endif
return (ulawbyte);
}
static int Mx[3][8] =
{
{0x3800, 0x5600, 0, 0, 0, 0, 0, 0},
{0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0},
{0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607},
};
static int bitmask[9] =
{
0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
};
static int
isdn_audio_get_bits(adpcm_state * s, unsigned char **in, int *len)
{
while (s->nleft < s->nbits) {
int d = *((*in)++);
(*len)--;
s->word = (s->word << 8) | d;
s->nleft += 8;
}
s->nleft -= s->nbits;
return (s->word >> s->nleft) & bitmask[s->nbits];
}
static void
isdn_audio_put_bits(int data, int nbits, adpcm_state * s,
unsigned char **out, int *len)
{
s->word = (s->word << nbits) | (data & bitmask[nbits]);
s->nleft += nbits;
while (s->nleft >= 8) {
int d = (s->word >> (s->nleft - 8));
*(out[0]++) = d & 255;
(*len)++;
s->nleft -= 8;
}
}
adpcm_state *
isdn_audio_adpcm_init(adpcm_state * s, int nbits)
{
if (!s)
s = (adpcm_state *) kmalloc(sizeof(adpcm_state), GFP_ATOMIC);
if (s) {
s->a = 0;
s->d = 5;
s->word = 0;
s->nleft = 0;
s->nbits = nbits;
}
return s;
}
dtmf_state *
isdn_audio_dtmf_init(dtmf_state * s)
{
if (!s)
s = (dtmf_state *) kmalloc(sizeof(dtmf_state), GFP_ATOMIC);
if (s) {
s->idx = 0;
s->last = ' ';
}
return s;
}
/*
* Decompression of adpcm data to a/u-law
*
*/
int
isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in,
unsigned char *out, int len)
{
int a = s->a;
int d = s->d;
int nbits = s->nbits;
int olen = 0;
while (len) {
int e = isdn_audio_get_bits(s, &in, &len);
int sign;
if (nbits == 4 && e == 0)
d = 4;
sign = (e >> (nbits - 1)) ? -1 : 1;
e &= bitmask[nbits - 1];
a += sign * ((e << 1) + 1) * d >> 1;
if (d & 1)
a++;
if (fmt)
*out++ = isdn_audio_ulaw_to_alaw[
isdn_audio_linear2ulaw(a << 2)];
else
*out++ = isdn_audio_linear2ulaw(a << 2);
olen++;
d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
if (d < 5)
d = 5;
}
s->a = a;
s->d = d;
return olen;
}
int
isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out)
{
int olen = 0;
if (s->nleft)
isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen);
return olen;
}
int
isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,
unsigned char *out, int len)
{
int a = s->a;
int d = s->d;
int nbits = s->nbits;
int olen = 0;
while (len--) {
int e = 0,
nmax = 1 << (nbits - 1);
int sign,
delta;
if (fmt)
delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a;
else
delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a;
if (delta < 0) {
e = nmax;
delta = -delta;
}
while (--nmax && delta > d) {
delta -= d;
e++;
}
if (nbits == 4 && ((e & 0x0f) == 0))
e = 8;
isdn_audio_put_bits(e, nbits, s, &out, &olen);
sign = (e >> (nbits - 1)) ? -1 : 1;
e &= bitmask[nbits - 1];
a += sign * ((e << 1) + 1) * d >> 1;
if (d & 1)
a++;
d = (d * Mx[nbits - 2][e] + 0x2000) >> 14;
if (d < 5)
d = 5;
}
s->a = a;
s->d = d;
return olen;
}
/*
* Goertzel algorithm.
* See http://ptolemy.eecs.berkeley.edu/~pino/Ptolemy/papers/96/dtmf_ict/
* for more info.
* Result is stored into an sk_buff and queued up for later
* evaluation.
*/
static void
isdn_audio_goertzel(int *sample, modem_info * info)
{
int sk,
sk1,
sk2;
int k,
n;
struct sk_buff *skb;
int *result;
skb = dev_alloc_skb(sizeof(int) * NCOEFF);
if (!skb) {
printk(KERN_WARNING
"isdn_audio: Could not alloc DTMF result for ttyI%d\n",
info->line);
return;
}
result = (int *) skb_put(skb, sizeof(int) * NCOEFF);
for (k = 0; k < NCOEFF; k++) {
sk = sk1 = sk2 = 0;
for (n = 0; n < DTMF_NPOINTS; n++) {
sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2;
sk2 = sk1;
sk1 = sk;
}
result[k] =
((sk * sk) >> AMP_BITS) -
((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
((sk2 * sk2) >> AMP_BITS);
}
skb_queue_tail(&info->dtmf_queue, skb);
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
}
void
isdn_audio_eval_dtmf(modem_info * info)
{
struct sk_buff *skb;
int *result;
dtmf_state *s;
int silence;
int i;
int di;
int ch;
unsigned long flags;
int grp[2];
char what;
char *p;
while ((skb = skb_dequeue(&info->dtmf_queue))) {
result = (int *) skb->data;
s = info->dtmf_state;
grp[LOGRP] = grp[HIGRP] = -2;
silence = 0;
for (i = 0; i < 8; i++) {
if ((result[dtmf_tones[i].k] > DTMF_TRESH) &&
(result[dtmf_tones[i].k2] < H2_TRESH))
grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1;
else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) &&
(result[dtmf_tones[i].k2] < SILENCE_TRESH))
silence++;
}
if (silence == 8)
what = ' ';
else {
if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4];
if (s->last != ' ' && s->last != '.')
s->last = what; /* min. 1 non-DTMF between DTMF */
} else
what = '.';
}
if ((what != s->last) && (what != ' ') && (what != '.')) {
printk(KERN_DEBUG "dtmf: tt='%c'\n", what);
p = skb->data;
*p++ = 0x10;
*p = what;
skb_trim(skb, 2);
if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
printk(KERN_WARNING
"isdn_audio: insufficient skb_headroom, dropping\n");
kfree_skb(skb);
return;
}
ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
ISDN_AUDIO_SKB_LOCK(skb) = 0;
save_flags(flags);
cli();
di = info->isdn_driver;
ch = info->isdn_channel;
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
dev->drv[di]->rcvcount[ch] += 2;
restore_flags(flags);
/* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched))
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
} else
kfree_skb(skb);
s->last = what;
}
}
/*
* Decode DTMF tones, queue result in separate sk_buf for
* later examination.
* Parameters:
* s = pointer to state-struct.
* buf = input audio data
* len = size of audio data.
* fmt = audio data format (0 = ulaw, 1 = alaw)
*/
void
isdn_audio_calc_dtmf(modem_info * info, unsigned char *buf, int len, int fmt)
{
dtmf_state *s = info->dtmf_state;
int i;
int c;
while (len) {
c = MIN(len, (DTMF_NPOINTS - s->idx));
if (c <= 0)
break;
for (i = 0; i < c; i++) {
if (fmt)
s->buf[s->idx++] =
isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS);
else
s->buf[s->idx++] =
isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS);
}
if (s->idx == DTMF_NPOINTS) {
isdn_audio_goertzel(s->buf, info);
s->idx = 0;
}
len -= c;
}
}
silence_state *
isdn_audio_silence_init(silence_state * s)
{
if (!s)
s = (silence_state *) kmalloc(sizeof(silence_state), GFP_ATOMIC);
if (s) {
s->idx = 0;
s->state = 0;
}
return s;
}
void
isdn_audio_calc_silence(modem_info * info, unsigned char *buf, int len, int fmt)
{
silence_state *s = info->silence_state;
int i;
signed char c;
if (!info->emu.vpar[1]) return;
for (i = 0; i < len; i++) {
if (fmt)
c = isdn_audio_alaw_to_ulaw[*buf++];
else
c = *buf++;
if (c > 0) c -= 128;
c = abs(c);
if (c > (info->emu.vpar[1] * 4)) {
s->idx = 0;
s->state = 1;
} else {
if (s->idx < 210000) s->idx++;
}
}
}
void
isdn_audio_put_dle_code(modem_info * info, u_char code)
{
struct sk_buff *skb;
unsigned long flags;
int di;
int ch;
char *p;
skb = dev_alloc_skb(2);
if (!skb) {
printk(KERN_WARNING
"isdn_audio: Could not alloc skb for ttyI%d\n",
info->line);
return;
}
p = (char *) skb_put(skb, 2);
p[0] = 0x10;
p[1] = code;
if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
printk(KERN_WARNING
"isdn_audio: insufficient skb_headroom, dropping\n");
kfree_skb(skb);
return;
}
ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
ISDN_AUDIO_SKB_LOCK(skb) = 0;
save_flags(flags);
cli();
di = info->isdn_driver;
ch = info->isdn_channel;
__skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
dev->drv[di]->rcvcount[ch] += 2;
restore_flags(flags);
/* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched))
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
}
void
isdn_audio_eval_silence(modem_info * info)
{
silence_state *s = info->silence_state;
char what;
what = ' ';
if (s->idx > (info->emu.vpar[2] * 800)) {
s->idx = 0;
if (!s->state) { /* silence from beginning of rec */
what = 's';
} else {
what = 'q';
}
}
if ((what == 's') || (what == 'q')) {
printk(KERN_DEBUG "ttyI%d: %s\n", info->line,
(what=='s') ? "silence":"quiet");
isdn_audio_put_dle_code(info, what);
}
}

View File

@ -1,77 +0,0 @@
/* $Id$
* Linux ISDN subsystem, audio conversion and compression (linklevel).
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.7 1999/04/12 12:33:11 fritz
* Changes from 2.0 tree.
*
* Revision 1.6 1998/07/26 18:48:44 armin
* Added silence detection in voice receive mode.
*
* Revision 1.5 1997/02/03 22:45:21 fritz
* Reformatted according CodingStyle
*
* Revision 1.4 1996/06/06 14:43:32 fritz
* Changed to support DTMF decoding on audio playback also.
*
* Revision 1.3 1996/06/05 02:24:09 fritz
* Added DTMF decoder for audio mode.
*
* Revision 1.2 1996/05/10 08:48:32 fritz
* Corrected adpcm bugs.
*
* Revision 1.1 1996/04/30 09:29:06 fritz
* Taken under CVS control.
*
*/
#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
typedef struct adpcm_state {
int a;
int d;
int word;
int nleft;
int nbits;
} adpcm_state;
typedef struct dtmf_state {
char last;
int idx;
int buf[DTMF_NPOINTS];
} dtmf_state;
typedef struct silence_state {
int state;
unsigned int idx;
} silence_state;
extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long);
extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out);
extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
extern void isdn_audio_eval_dtmf(modem_info *);
dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int);
extern void isdn_audio_eval_silence(modem_info *);
silence_state *isdn_audio_silence_init(silence_state *);
extern void isdn_audio_put_dle_code(modem_info *, u_char);

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
/* $Id$
* Linux ISDN subsystem, initialization for non-modularized drivers.
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.9 1999/04/12 12:33:11 fritz
* Changes from 2.0 tree.
*
* Revision 1.8 1999/03/29 11:13:23 armin
* Added eicon driver init.
*
* Revision 1.7 1998/02/20 17:24:28 fritz
* Added ACT2000 init.
*
* Revision 1.6 1997/04/23 18:56:03 fritz
* Old Teles driver removed, Changed doc and scripts accordingly.
*
* Revision 1.5 1997/03/30 17:10:36 calle
* added support for AVM-B1-PCI card.
*
* Revision 1.4 1997/03/04 21:59:44 calle
* Added AVM-B1-CAPI2.0 driver
*
* Revision 1.3 1997/02/03 23:31:14 fritz
* Reformatted according CodingStyle
*
* Revision 1.2 1996/10/13 19:52:17 keil
* HiSax support
*
* Revision 1.1 1996/04/20 16:04:36 fritz
* Initial revision
*
*/
#include <linux/config.h>
#ifdef CONFIG_ISDN_DRV_ICN
extern void icn_init(void);
#endif
#ifdef CONFIG_ISDN_DRV_HISAX
extern void HiSax_init(void);
#endif
#ifdef CONFIG_ISDN_DRV_PCBIT
extern void pcbit_init(void);
#endif
#ifdef CONFIG_ISDN_DRV_EICON
extern void eicon_init(void);
#endif
#ifdef CONFIG_ISDN_DRV_AVMB1
extern void kcapi_init(void);
extern void capi_init(void);
extern void capidrv_init(void);
#endif
void
isdn_cards_init(void)
{
#if CONFIG_ISDN_DRV_ICN
icn_init();
#endif
#ifdef CONFIG_ISDN_DRV_HISAX
HiSax_init();
#endif
#if CONFIG_ISDN_DRV_PCBIT
pcbit_init();
#endif
#ifdef CONFIG_ISDN_DRV_AVMB1
kcapi_init();
capi_init();
capidrv_init();
#endif
#if CONFIG_ISDN_DRV_ACT2000
act2000_init();
#endif
#if CONFIG_ISDN_DRV_EICON
eicon_init();
#endif
}

View File

@ -1,30 +0,0 @@
/* $Id$
* Linux ISDN subsystem, initialization for non-modularized drivers.
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.2 1997/02/03 23:31:55 fritz
* Reformatted according CodingStyle
*
* Revision 1.1 1996/04/20 16:04:03 fritz
* Initial revision
*
*/
extern void isdn_cards_init(void);

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More