This commit was manufactured by cvs2git to create tag 'T3'.
This commit is contained in:
parent
f9ad4cbc72
commit
a2dccf8d1b
8
.config
8
.config
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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 ;-)
|
||||
|
|
@ -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-----
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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>.
|
||||
|
|
@ -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)
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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 .
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
------------------------------------------------------------------------------
|
||||
README file for the PCBIT-D Device Driver.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
The PCBIT is a Euro ISDN adapter manufactured in Portugal by Octal and
|
||||
developed in cooperation with Portugal Telecom and Inesc.
|
||||
The driver interfaces with the standard kernel isdn facilities
|
||||
originally developed by Fritz Elfert in the isdn4linux project.
|
||||
|
||||
The common versions of the pcbit board require a firmware that is
|
||||
distributed (and copyrighted) by the manufacturer. To load this
|
||||
firmware you need "pcbitctl" available on the standard isdn4k-utils
|
||||
package or in the pcbit package available in:
|
||||
|
||||
ftp://ftp.di.fc.ul.pt/pub/systems/Linux/isdn
|
||||
|
||||
Known Limitations:
|
||||
|
||||
- The board reset procedure is at the moment incorrect and will only
|
||||
allow you to load the firmware after a hard reset.
|
||||
|
||||
- Only HDLC in B-channels is supported at the moment. There is no
|
||||
current support for X.25 in B or D channels nor LAPD in B
|
||||
channels. The main reason is that these two other protocol modes have,
|
||||
to my knowledge, very little use. If you want to see them implemented
|
||||
*do* send me a mail.
|
||||
|
||||
- The driver often triggers errors in the board that I and the
|
||||
manufacturer believe to be caused by bugs in the firmware. The current
|
||||
version includes several procedures for error recovery that should
|
||||
allow normal operation. Plans for the future include cooperation with
|
||||
the manufacturer in order to solve this problem.
|
||||
|
||||
Information/hints/help can be obtained in the linux isdn
|
||||
mailing list (isdn4linux@listserv.isdn4linux.de) or directly from me.
|
||||
|
||||
regards,
|
||||
Pedro.
|
||||
|
||||
<roque@di.fc.ul.pt>
|
|
@ -1,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
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
126
Makefile
|
@ -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
|
|
@ -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.
|
189
Rules.make
189
Rules.make
|
@ -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
|
66
do_indent
66
do_indent
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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 */
|
|
@ -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));
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -1,130 +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.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_DRV_AVMB1),y)
|
||||
O_TARGET += avmb1.o
|
||||
OX_OBJS += kcapi.o
|
||||
O_OBJS += capi.o
|
||||
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_DRV_AVMB1),m)
|
||||
O_TARGET += kernelcapi.o
|
||||
OX_OBJS += kcapi.o
|
||||
M_OBJS += capi.o kernelcapi.o
|
||||
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
|
|
@ -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_ */
|
|
@ -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
|
|
@ -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, ®, 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, ®, 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
|
|
@ -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
|
|
@ -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, ¶m);
|
||||
#else
|
||||
retval = b1pci_add_card(driver, ¶m);
|
||||
#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, ¶m);
|
||||
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
|
|
@ -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
|
@ -1,696 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* CAPI 2.0 Interface for Linux
|
||||
*
|
||||
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.22 1999/11/13 21:27:16 keil
|
||||
* remove KERNELVERSION
|
||||
*
|
||||
* Revision 1.21 1999/09/10 17:24:18 calle
|
||||
* Changes for proposed standard for CAPI2.0:
|
||||
* - AK148 "Linux Exention"
|
||||
*
|
||||
* Revision 1.20 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.19 1999/07/09 15:05:42 keil
|
||||
* compat.h is now isdn_compat.h
|
||||
*
|
||||
* Revision 1.18 1999/07/06 07:42:01 calle
|
||||
* - changes in /proc interface
|
||||
* - check and changed calls to [dev_]kfree_skb and [dev_]alloc_skb.
|
||||
*
|
||||
* Revision 1.17 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.
|
||||
*
|
||||
* Revision 1.16 1999/07/01 08:22:57 keil
|
||||
* compatibility macros now in <linux/isdn_compat.h>
|
||||
*
|
||||
* Revision 1.15 1999/06/21 15:24:11 calle
|
||||
* extend information in /proc.
|
||||
*
|
||||
* Revision 1.14 1999/06/10 16:51:03 calle
|
||||
* Bugfix: open/release of control device was not handled correct.
|
||||
*
|
||||
* Revision 1.13 1998/08/28 04:32:25 calle
|
||||
* Added patch send by Michael.Mueller4@post.rwth-aachen.de, to get AVM B1
|
||||
* driver running with 2.1.118.
|
||||
*
|
||||
* Revision 1.12 1998/05/26 22:39:34 he
|
||||
* sync'ed with 2.1.102 where appropriate (CAPABILITY changes)
|
||||
* concap typo
|
||||
* cleared dev.tbusy in isdn_net BCONN status callback
|
||||
*
|
||||
* Revision 1.11 1998/03/09 17:46:37 he
|
||||
* merged in 2.1.89 changes
|
||||
*
|
||||
* Revision 1.10 1998/02/13 07:09:13 calle
|
||||
* change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
|
||||
*
|
||||
* Revision 1.9 1998/01/31 11:14:44 calle
|
||||
* merged changes to 2.0 tree, prepare 2.1.82 to work.
|
||||
*
|
||||
* Revision 1.8 1997/11/04 06:12:08 calle
|
||||
* capi.c: new read/write in file_ops since 2.1.60
|
||||
* capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
|
||||
* capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
|
||||
* compat.h: added #define LinuxVersionCode
|
||||
*
|
||||
* Revision 1.7 1997/10/11 10:29:34 calle
|
||||
* llseek() parameters changed in 2.1.56.
|
||||
*
|
||||
* Revision 1.6 1997/10/01 09:21:15 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.5 1997/08/21 23:11:55 fritz
|
||||
* Added changes for kernels >= 2.1.45
|
||||
*
|
||||
* Revision 1.4 1997/05/27 15:17:50 fritz
|
||||
* Added changes for recent 2.1.x kernels:
|
||||
* changed return type of isdn_close
|
||||
* queue_task_* -> queue_task
|
||||
* clear/set_bit -> test_and_... where apropriate.
|
||||
* changed type of hard_header_cache parameter.
|
||||
*
|
||||
* Revision 1.3 1997/05/18 09:24:14 calle
|
||||
* added verbose disconnect reason reporting to avmb1.
|
||||
* some fixes in capi20 interface.
|
||||
* changed info messages for B1-PCI
|
||||
*
|
||||
* Revision 1.2 1997/03/05 21:17:59 fritz
|
||||
* Added capi_poll for compiling under 2.1.27
|
||||
*
|
||||
* Revision 1.1 1997/03/04 21:50:29 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/malloc.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/capi.h>
|
||||
#include <linux/kernelcapi.h>
|
||||
#ifdef HAVE_DEVFS_FS
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#endif /* HAVE_DEVFS_FS */
|
||||
|
||||
#include <linux/isdn_compat.h>
|
||||
#include "capiutil.h"
|
||||
#include "capicmd.h"
|
||||
#include "capidev.h"
|
||||
|
||||
MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
|
||||
|
||||
/* -------- driver information -------------------------------------- */
|
||||
|
||||
int capi_major = 68; /* allocated */
|
||||
|
||||
MODULE_PARM(capi_major, "i");
|
||||
|
||||
/* -------- global variables ---------------------------------------- */
|
||||
|
||||
static struct capidev capidevs[CAPI_MAXMINOR + 1];
|
||||
struct capi_interface *capifuncs;
|
||||
|
||||
/* -------- function called by lower level -------------------------- */
|
||||
|
||||
static void capi_signal(__u16 applid, __u32 minor)
|
||||
{
|
||||
struct capidev *cdev;
|
||||
struct sk_buff *skb = 0;
|
||||
|
||||
if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) {
|
||||
printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor);
|
||||
return;
|
||||
}
|
||||
cdev = &capidevs[minor];
|
||||
(void) (*capifuncs->capi_get_message) (applid, &skb);
|
||||
if (skb) {
|
||||
skb_queue_tail(&cdev->recv_queue, skb);
|
||||
wake_up_interruptible(&cdev->recv_wait);
|
||||
} else {
|
||||
printk(KERN_ERR "BUG: capi_signal: no skb\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- file_operations ----------------------------------------- */
|
||||
|
||||
static long long capi_llseek(struct file *file,
|
||||
long long offset, int origin)
|
||||
{
|
||||
return -ESPIPE;
|
||||
}
|
||||
|
||||
static ssize_t capi_read(struct file *file, char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
struct capidev *cdev;
|
||||
struct sk_buff *skb;
|
||||
int retval;
|
||||
size_t copied;
|
||||
|
||||
if (ppos != &file->f_pos)
|
||||
return -ESPIPE;
|
||||
|
||||
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
|
||||
return -ENODEV;
|
||||
|
||||
cdev = &capidevs[minor];
|
||||
|
||||
if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) {
|
||||
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
for (;;) {
|
||||
interruptible_sleep_on(&cdev->recv_wait);
|
||||
if ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
|
||||
break;
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
}
|
||||
if (skb == 0)
|
||||
return -ERESTARTNOHAND;
|
||||
}
|
||||
if (skb->len > count) {
|
||||
skb_queue_head(&cdev->recv_queue, skb);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
retval = copy_to_user(buf, skb->data, skb->len);
|
||||
if (retval) {
|
||||
skb_queue_head(&cdev->recv_queue, skb);
|
||||
return retval;
|
||||
}
|
||||
copied = skb->len;
|
||||
|
||||
if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
|
||||
&& CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)
|
||||
cdev->nrecvdatapkt++;
|
||||
else cdev->nrecvctlpkt++;
|
||||
kfree_skb(skb);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static ssize_t capi_write(struct file *file, const char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct inode *inode = file->f_dentry->d_inode;
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
struct capidev *cdev;
|
||||
struct sk_buff *skb;
|
||||
int retval;
|
||||
__u8 cmd;
|
||||
__u8 subcmd;
|
||||
__u16 mlen;
|
||||
|
||||
if (ppos != &file->f_pos)
|
||||
return -ESPIPE;
|
||||
|
||||
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
|
||||
return -ENODEV;
|
||||
|
||||
cdev = &capidevs[minor];
|
||||
|
||||
skb = alloc_skb(count, GFP_USER);
|
||||
|
||||
if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
|
||||
kfree_skb(skb);
|
||||
return retval;
|
||||
}
|
||||
cmd = CAPIMSG_COMMAND(skb->data);
|
||||
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
|
||||
mlen = CAPIMSG_LEN(skb->data);
|
||||
if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
|
||||
__u16 dlen = CAPIMSG_DATALEN(skb->data);
|
||||
if (mlen + dlen != count) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (mlen != count) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
CAPIMSG_SETAPPID(skb->data, cdev->applid);
|
||||
|
||||
cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb);
|
||||
|
||||
if (cdev->errcode) {
|
||||
kfree_skb(skb);
|
||||
return -EIO;
|
||||
}
|
||||
if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ)
|
||||
cdev->nsentdatapkt++;
|
||||
else cdev->nsentctlpkt++;
|
||||
return count;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
capi_poll(struct file *file, poll_table * wait)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
unsigned int minor = MINOR_PART(file);
|
||||
struct capidev *cdev;
|
||||
|
||||
if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
|
||||
return POLLERR;
|
||||
|
||||
cdev = &capidevs[minor];
|
||||
poll_wait(file, &(cdev->recv_wait), wait);
|
||||
mask = POLLOUT | POLLWRNORM;
|
||||
if (!skb_queue_empty(&cdev->recv_queue))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int capi_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
struct capidev *cdev;
|
||||
capi_ioctl_struct data;
|
||||
int retval;
|
||||
|
||||
|
||||
if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open)
|
||||
return -ENODEV;
|
||||
|
||||
cdev = &capidevs[minor];
|
||||
|
||||
switch (cmd) {
|
||||
case CAPI_REGISTER:
|
||||
{
|
||||
if (!minor)
|
||||
return -EINVAL;
|
||||
retval = copy_from_user((void *) &data.rparams,
|
||||
(void *) arg, sizeof(struct capi_register_params));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
if (cdev->is_registered)
|
||||
return -EEXIST;
|
||||
cdev->errcode = (*capifuncs->capi_register) (&data.rparams,
|
||||
&cdev->applid);
|
||||
if (cdev->errcode)
|
||||
return -EIO;
|
||||
(void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor);
|
||||
cdev->is_registered = 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case CAPI_GET_VERSION:
|
||||
{
|
||||
retval = copy_from_user((void *) &data.contr,
|
||||
(void *) arg,
|
||||
sizeof(data.contr));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
cdev->errcode = (*capifuncs->capi_get_version) (data.contr, &data.version);
|
||||
if (cdev->errcode)
|
||||
return -EIO;
|
||||
retval = copy_to_user((void *) arg,
|
||||
(void *) &data.version,
|
||||
sizeof(data.version));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case CAPI_GET_SERIAL:
|
||||
{
|
||||
retval = copy_from_user((void *) &data.contr,
|
||||
(void *) arg,
|
||||
sizeof(data.contr));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
cdev->errcode = (*capifuncs->capi_get_serial) (data.contr, data.serial);
|
||||
if (cdev->errcode)
|
||||
return -EIO;
|
||||
retval = copy_to_user((void *) arg,
|
||||
(void *) data.serial,
|
||||
sizeof(data.serial));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
case CAPI_GET_PROFILE:
|
||||
{
|
||||
retval = copy_from_user((void *) &data.contr,
|
||||
(void *) arg,
|
||||
sizeof(data.contr));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
|
||||
if (data.contr == 0) {
|
||||
cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile);
|
||||
if (cdev->errcode)
|
||||
return -EIO;
|
||||
|
||||
retval = copy_to_user((void *) arg,
|
||||
(void *) &data.profile.ncontroller,
|
||||
sizeof(data.profile.ncontroller));
|
||||
|
||||
} else {
|
||||
cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile);
|
||||
if (cdev->errcode)
|
||||
return -EIO;
|
||||
|
||||
retval = copy_to_user((void *) arg,
|
||||
(void *) &data.profile,
|
||||
sizeof(data.profile));
|
||||
}
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case CAPI_GET_MANUFACTURER:
|
||||
{
|
||||
retval = copy_from_user((void *) &data.contr,
|
||||
(void *) arg,
|
||||
sizeof(data.contr));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
cdev->errcode = (*capifuncs->capi_get_manufacturer) (data.contr, data.manufacturer);
|
||||
if (cdev->errcode)
|
||||
return -EIO;
|
||||
|
||||
retval = copy_to_user((void *) arg, (void *) data.manufacturer,
|
||||
sizeof(data.manufacturer));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
|
||||
}
|
||||
return 0;
|
||||
case CAPI_GET_ERRCODE:
|
||||
data.errcode = cdev->errcode;
|
||||
cdev->errcode = CAPI_NOERROR;
|
||||
if (arg) {
|
||||
retval = copy_to_user((void *) arg,
|
||||
(void *) &data.errcode,
|
||||
sizeof(data.errcode));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
}
|
||||
return data.errcode;
|
||||
|
||||
case CAPI_INSTALLED:
|
||||
if ((*capifuncs->capi_isinstalled)() == CAPI_NOERROR)
|
||||
return 0;
|
||||
return -ENXIO;
|
||||
|
||||
case CAPI_MANUFACTURER_CMD:
|
||||
{
|
||||
struct capi_manufacturer_cmd mcmd;
|
||||
if (minor)
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
retval = copy_from_user((void *) &mcmd, (void *) arg,
|
||||
sizeof(mcmd));
|
||||
if (retval)
|
||||
return -EFAULT;
|
||||
return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int capi_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
|
||||
if (minor >= CAPI_MAXMINOR)
|
||||
return -ENXIO;
|
||||
|
||||
if (minor) {
|
||||
if (capidevs[minor].is_open)
|
||||
return -EEXIST;
|
||||
|
||||
capidevs[minor].is_open = 1;
|
||||
skb_queue_head_init(&capidevs[minor].recv_queue);
|
||||
MOD_INC_USE_COUNT;
|
||||
capidevs[minor].nopen++;
|
||||
|
||||
} else {
|
||||
capidevs[minor].is_open++;
|
||||
MOD_INC_USE_COUNT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
capi_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
unsigned int minor = MINOR(inode->i_rdev);
|
||||
struct capidev *cdev;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
|
||||
printk(KERN_ERR "capi20: release minor %d ???\n", minor);
|
||||
return 0;
|
||||
}
|
||||
cdev = &capidevs[minor];
|
||||
|
||||
if (minor) {
|
||||
|
||||
if (cdev->is_registered)
|
||||
(*capifuncs->capi_release) (cdev->applid);
|
||||
|
||||
cdev->is_registered = 0;
|
||||
cdev->applid = 0;
|
||||
|
||||
while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) {
|
||||
kfree_skb(skb);
|
||||
}
|
||||
cdev->is_open = 0;
|
||||
} else {
|
||||
cdev->is_open--;
|
||||
}
|
||||
|
||||
MOD_DEC_USE_COUNT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations capi_fops =
|
||||
{
|
||||
capi_llseek,
|
||||
capi_read,
|
||||
capi_write,
|
||||
NULL, /* capi_readdir */
|
||||
capi_poll,
|
||||
capi_ioctl,
|
||||
NULL, /* capi_mmap */
|
||||
capi_open,
|
||||
#ifdef FILEOP_HAS_FLUSH
|
||||
NULL, /* capi_flush */
|
||||
#endif
|
||||
capi_release,
|
||||
NULL, /* capi_fsync */
|
||||
NULL, /* capi_fasync */
|
||||
};
|
||||
|
||||
/* -------- /proc functions ----------------------------------- */
|
||||
|
||||
/*
|
||||
* /proc/capi/capi20:
|
||||
* minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
|
||||
*/
|
||||
static int proc_capidev_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
struct capidev *cp;
|
||||
int i;
|
||||
int len = 0;
|
||||
off_t begin = 0;
|
||||
|
||||
for (i=0; i < CAPI_MAXMINOR; i++) {
|
||||
cp = &capidevs[i+1];
|
||||
if (cp->nopen == 0) continue;
|
||||
len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n",
|
||||
i+1,
|
||||
cp->nopen,
|
||||
cp->nrecvctlpkt,
|
||||
cp->nrecvdatapkt,
|
||||
cp->nsentctlpkt,
|
||||
cp->nsentdatapkt);
|
||||
if (len+begin > off+count)
|
||||
goto endloop;
|
||||
if (len+begin < off) {
|
||||
begin += len;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
endloop:
|
||||
if (i >= CAPI_MAXMINOR)
|
||||
*eof = 1;
|
||||
if (off >= len+begin)
|
||||
return 0;
|
||||
*start = page + (begin-off);
|
||||
return ((count < begin+len-off) ? count : begin+len-off);
|
||||
}
|
||||
|
||||
static struct procfsentries {
|
||||
char *name;
|
||||
mode_t mode;
|
||||
int (*read_proc)(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data);
|
||||
struct proc_dir_entry *procent;
|
||||
} procfsentries[] = {
|
||||
/* { "capi", S_IFDIR, 0 }, */
|
||||
{ "capi/capi20", 0 , proc_capidev_read_proc },
|
||||
};
|
||||
|
||||
static void proc_init(void)
|
||||
{
|
||||
int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
|
||||
int i;
|
||||
|
||||
for (i=0; i < nelem; i++) {
|
||||
struct procfsentries *p = procfsentries + i;
|
||||
p->procent = create_proc_entry(p->name, p->mode, 0);
|
||||
if (p->procent) p->procent->read_proc = p->read_proc;
|
||||
}
|
||||
}
|
||||
|
||||
static void proc_exit(void)
|
||||
{
|
||||
int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
|
||||
int i;
|
||||
|
||||
for (i=nelem-1; i >= 0; i--) {
|
||||
struct procfsentries *p = procfsentries + i;
|
||||
if (p->procent) {
|
||||
remove_proc_entry(p->name, 0);
|
||||
p->procent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* -------- init function and module interface ---------------------- */
|
||||
|
||||
#ifdef MODULE
|
||||
#define capi_init init_module
|
||||
#endif
|
||||
|
||||
static struct capi_interface_user cuser = {
|
||||
"capi20",
|
||||
0,
|
||||
};
|
||||
|
||||
int capi_init(void)
|
||||
{
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
int j;
|
||||
#endif
|
||||
|
||||
memset(capidevs, 0, sizeof(capidevs));
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
for ( j = 0; j < CAPI_MAXMINOR+1; j++ ) {
|
||||
init_waitqueue_head(&capidevs[j].recv_wait);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) {
|
||||
printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
|
||||
return -EIO;
|
||||
}
|
||||
#ifdef HAVE_DEVFS_FS
|
||||
devfs_register (NULL, "isdn/capi20", 0, DEVFS_FL_DEFAULT,
|
||||
capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
|
||||
&capi_fops, NULL);
|
||||
devfs_register_series (NULL, "isdn/capi20.0%u", 10, DEVFS_FL_DEFAULT,
|
||||
capi_major, 1,
|
||||
S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
|
||||
&capi_fops, NULL);
|
||||
devfs_register_series (NULL, "isdn/capi20.1%u", 10, DEVFS_FL_DEFAULT,
|
||||
capi_major, 11,
|
||||
S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
|
||||
&capi_fops, NULL);
|
||||
#endif
|
||||
printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
|
||||
|
||||
if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
|
||||
devfs_unregister_chrdev(capi_major, "capi20");
|
||||
#ifdef HAVE_DEVFS_FS
|
||||
devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
|
||||
capi_major, 0,
|
||||
DEVFS_SPECIAL_CHR, 0));
|
||||
for (j = 0; j < 10; j++) {
|
||||
char devname[32];
|
||||
|
||||
sprintf(devname, "isdn/capi20.0%i", j);
|
||||
devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 1, DEVFS_SPECIAL_CHR, 0));
|
||||
sprintf (devname, "isdn/capi20.1%i", j);
|
||||
devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, j + 11, DEVFS_SPECIAL_CHR, 0));
|
||||
}
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
(void)proc_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
void cleanup_module(void)
|
||||
{
|
||||
#ifdef HAVE_DEVFS_FS
|
||||
int i;
|
||||
char devname[32];
|
||||
|
||||
#endif
|
||||
(void)proc_exit();
|
||||
devfs_unregister_chrdev(capi_major, "capi20");
|
||||
#ifdef HAVE_DEVFS_FS
|
||||
devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0));
|
||||
for (i = 0; i < 10; i++) {
|
||||
sprintf (devname, "isdn/capi20.0%i", i);
|
||||
devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 1, DEVFS_SPECIAL_CHR, 0));
|
||||
sprintf (devname, "isdn/capi20.1%i", i);
|
||||
devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_major, i + 11, DEVFS_SPECIAL_CHR, 0));
|
||||
}
|
||||
#endif
|
||||
(void) detach_capi_interface(&cuser);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* CAPI 2.0 Interface for Linux
|
||||
*
|
||||
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* 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__
|
||||
|
||||
/*----- 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__ */
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* CAPI 2.0 Interface for Linux
|
||||
*
|
||||
* (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* 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 {
|
||||
int is_open;
|
||||
int is_registered;
|
||||
__u16 applid;
|
||||
struct sk_buff_head recv_queue;
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
wait_queue_head_t recv_wait;
|
||||
#else
|
||||
struct wait_queue *recv_wait;
|
||||
#endif
|
||||
__u16 errcode;
|
||||
/* Statistic */
|
||||
unsigned long nopen;
|
||||
unsigned long nrecvctlpkt;
|
||||
unsigned long nrecvdatapkt;
|
||||
unsigned long nsentctlpkt;
|
||||
unsigned long nsentdatapkt;
|
||||
};
|
||||
|
||||
#define CAPI_MAXMINOR CAPI_MAXAPPL
|
File diff suppressed because it is too large
Load Diff
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -1,994 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* CAPI 2.0 convert capi message to capi message struct
|
||||
*
|
||||
* From CAPI 2.0 Development Kit AVM 1995 (msg.c)
|
||||
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.9 1999/07/09 15:05:46 keil
|
||||
* compat.h is now isdn_compat.h
|
||||
*
|
||||
* Revision 1.8 1999/07/01 15:26:37 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.7 1999/07/01 08:23:01 keil
|
||||
* compatibility macros now in <linux/isdn_compat.h>
|
||||
*
|
||||
* Revision 1.6 1997/11/04 06:12:12 calle
|
||||
* capi.c: new read/write in file_ops since 2.1.60
|
||||
* capidrv.c: prepared isdnlog interface for d2-trace in newer firmware.
|
||||
* capiutil.c: needs config.h (CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON)
|
||||
* compat.h: added #define LinuxVersionCode
|
||||
*
|
||||
* Revision 1.5 1997/10/01 09:21:19 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.4 1997/08/10 07:43:55 calle
|
||||
* forgot to export symbol capi_info2str for 2.1.x
|
||||
*
|
||||
* Revision 1.3 1997/05/18 09:24:18 calle
|
||||
* added verbose disconnect reason reporting to avmb1.
|
||||
* some fixes in capi20 interface.
|
||||
* changed info messages for B1-PCI
|
||||
*
|
||||
* Revision 1.2 1997/03/05 21:22:13 fritz
|
||||
* Fix: Symbols have to be exported unconditionally.
|
||||
*
|
||||
* Revision 1.1 1997/03/04 21:50:34 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
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/segment.h>
|
||||
#include <linux/config.h>
|
||||
|
||||
#include <linux/isdn_compat.h>
|
||||
#include "capiutil.h"
|
||||
|
||||
/* from CAPI2.0 DDK AVM Berlin GmbH */
|
||||
|
||||
#ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
|
||||
char *capi_info2str(__u16 reason)
|
||||
{
|
||||
return "..";
|
||||
}
|
||||
#else
|
||||
char *capi_info2str(__u16 reason)
|
||||
{
|
||||
switch (reason) {
|
||||
|
||||
/*-- informative values (corresponding message was processed) -----*/
|
||||
case 0x0001:
|
||||
return "NCPI not supported by current protocol, NCPI ignored";
|
||||
case 0x0002:
|
||||
return "Flags not supported by current protocol, flags ignored";
|
||||
case 0x0003:
|
||||
return "Alert already sent by another application";
|
||||
|
||||
/*-- error information concerning CAPI_REGISTER -----*/
|
||||
case 0x1001:
|
||||
return "Too many applications";
|
||||
case 0x1002:
|
||||
return "Logical block size too small, must be at least 128 Bytes";
|
||||
case 0x1003:
|
||||
return "Buffer exceeds 64 kByte";
|
||||
case 0x1004:
|
||||
return "Message buffer size too small, must be at least 1024 Bytes";
|
||||
case 0x1005:
|
||||
return "Max. number of logical connections not supported";
|
||||
case 0x1006:
|
||||
return "Reserved";
|
||||
case 0x1007:
|
||||
return "The message could not be accepted because of an internal busy condition";
|
||||
case 0x1008:
|
||||
return "OS resource error (no memory ?)";
|
||||
case 0x1009:
|
||||
return "CAPI not installed";
|
||||
case 0x100A:
|
||||
return "Controller does not support external equipment";
|
||||
case 0x100B:
|
||||
return "Controller does only support external equipment";
|
||||
|
||||
/*-- error information concerning message exchange functions -----*/
|
||||
case 0x1101:
|
||||
return "Illegal application number";
|
||||
case 0x1102:
|
||||
return "Illegal command or subcommand or message length less than 12 bytes";
|
||||
case 0x1103:
|
||||
return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
|
||||
case 0x1104:
|
||||
return "Queue is empty";
|
||||
case 0x1105:
|
||||
return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
|
||||
case 0x1106:
|
||||
return "Unknown notification parameter";
|
||||
case 0x1107:
|
||||
return "The Message could not be accepted because of an internal busy condition";
|
||||
case 0x1108:
|
||||
return "OS Resource error (no memory ?)";
|
||||
case 0x1109:
|
||||
return "CAPI not installed";
|
||||
case 0x110A:
|
||||
return "Controller does not support external equipment";
|
||||
case 0x110B:
|
||||
return "Controller does only support external equipment";
|
||||
|
||||
/*-- error information concerning resource / coding problems -----*/
|
||||
case 0x2001:
|
||||
return "Message not supported in current state";
|
||||
case 0x2002:
|
||||
return "Illegal Controller / PLCI / NCCI";
|
||||
case 0x2003:
|
||||
return "Out of PLCI";
|
||||
case 0x2004:
|
||||
return "Out of NCCI";
|
||||
case 0x2005:
|
||||
return "Out of LISTEN";
|
||||
case 0x2006:
|
||||
return "Out of FAX resources (protocol T.30)";
|
||||
case 0x2007:
|
||||
return "Illegal message parameter coding";
|
||||
|
||||
/*-- error information concerning requested services -----*/
|
||||
case 0x3001:
|
||||
return "B1 protocol not supported";
|
||||
case 0x3002:
|
||||
return "B2 protocol not supported";
|
||||
case 0x3003:
|
||||
return "B3 protocol not supported";
|
||||
case 0x3004:
|
||||
return "B1 protocol parameter not supported";
|
||||
case 0x3005:
|
||||
return "B2 protocol parameter not supported";
|
||||
case 0x3006:
|
||||
return "B3 protocol parameter not supported";
|
||||
case 0x3007:
|
||||
return "B protocol combination not supported";
|
||||
case 0x3008:
|
||||
return "NCPI not supported";
|
||||
case 0x3009:
|
||||
return "CIP Value unknown";
|
||||
case 0x300A:
|
||||
return "Flags not supported (reserved bits)";
|
||||
case 0x300B:
|
||||
return "Facility not supported";
|
||||
case 0x300C:
|
||||
return "Data length not supported by current protocol";
|
||||
case 0x300D:
|
||||
return "Reset procedure not supported by current protocol";
|
||||
|
||||
/*-- informations about the clearing of a physical connection -----*/
|
||||
case 0x3301:
|
||||
return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
|
||||
case 0x3302:
|
||||
return "Protocol error layer 2";
|
||||
case 0x3303:
|
||||
return "Protocol error layer 3";
|
||||
case 0x3304:
|
||||
return "Another application got that call";
|
||||
/*-- T.30 specific reasons -----*/
|
||||
case 0x3311:
|
||||
return "Connecting not successful (remote station is no FAX G3 machine)";
|
||||
case 0x3312:
|
||||
return "Connecting not successful (training error)";
|
||||
case 0x3313:
|
||||
return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
|
||||
case 0x3314:
|
||||
return "Disconnected during transfer (remote abort)";
|
||||
case 0x3315:
|
||||
return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
|
||||
case 0x3316:
|
||||
return "Disconnected during transfer (local tx data underrun)";
|
||||
case 0x3317:
|
||||
return "Disconnected during transfer (local rx data overflow)";
|
||||
case 0x3318:
|
||||
return "Disconnected during transfer (local abort)";
|
||||
case 0x3319:
|
||||
return "Illegal parameter coding (e.g. SFF coding error)";
|
||||
|
||||
/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
|
||||
case 0x3481: return "Unallocated (unassigned) number";
|
||||
case 0x3482: return "No route to specified transit network";
|
||||
case 0x3483: return "No route to destination";
|
||||
case 0x3486: return "Channel unacceptable";
|
||||
case 0x3487:
|
||||
return "Call awarded and being delivered in an established channel";
|
||||
case 0x3490: return "Normal call clearing";
|
||||
case 0x3491: return "User busy";
|
||||
case 0x3492: return "No user responding";
|
||||
case 0x3493: return "No answer from user (user alerted)";
|
||||
case 0x3495: return "Call rejected";
|
||||
case 0x3496: return "Number changed";
|
||||
case 0x349A: return "Non-selected user clearing";
|
||||
case 0x349B: return "Destination out of order";
|
||||
case 0x349C: return "Invalid number format";
|
||||
case 0x349D: return "Facility rejected";
|
||||
case 0x349E: return "Response to STATUS ENQUIRY";
|
||||
case 0x349F: return "Normal, unspecified";
|
||||
case 0x34A2: return "No circuit / channel available";
|
||||
case 0x34A6: return "Network out of order";
|
||||
case 0x34A9: return "Temporary failure";
|
||||
case 0x34AA: return "Switching equipment congestion";
|
||||
case 0x34AB: return "Access information discarded";
|
||||
case 0x34AC: return "Requested circuit / channel not available";
|
||||
case 0x34AF: return "Resources unavailable, unspecified";
|
||||
case 0x34B1: return "Quality of service unavailable";
|
||||
case 0x34B2: return "Requested facility not subscribed";
|
||||
case 0x34B9: return "Bearer capability not authorized";
|
||||
case 0x34BA: return "Bearer capability not presently available";
|
||||
case 0x34BF: return "Service or option not available, unspecified";
|
||||
case 0x34C1: return "Bearer capability not implemented";
|
||||
case 0x34C2: return "Channel type not implemented";
|
||||
case 0x34C5: return "Requested facility not implemented";
|
||||
case 0x34C6: return "Only restricted digital information bearer capability is available";
|
||||
case 0x34CF: return "Service or option not implemented, unspecified";
|
||||
case 0x34D1: return "Invalid call reference value";
|
||||
case 0x34D2: return "Identified channel does not exist";
|
||||
case 0x34D3: return "A suspended call exists, but this call identity does not";
|
||||
case 0x34D4: return "Call identity in use";
|
||||
case 0x34D5: return "No call suspended";
|
||||
case 0x34D6: return "Call having the requested call identity has been cleared";
|
||||
case 0x34D8: return "Incompatible destination";
|
||||
case 0x34DB: return "Invalid transit network selection";
|
||||
case 0x34DF: return "Invalid message, unspecified";
|
||||
case 0x34E0: return "Mandatory information element is missing";
|
||||
case 0x34E1: return "Message type non-existent or not implemented";
|
||||
case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
|
||||
case 0x34E3: return "Information element non-existent or not implemented";
|
||||
case 0x34E4: return "Invalid information element contents";
|
||||
case 0x34E5: return "Message not compatible with call state";
|
||||
case 0x34E6: return "Recovery on timer expiry";
|
||||
case 0x34EF: return "Protocol error, unspecified";
|
||||
case 0x34FF: return "Interworking, unspecified";
|
||||
|
||||
default: return "No additional information";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int typ;
|
||||
size_t off;
|
||||
} _cdef;
|
||||
|
||||
#define _CBYTE 1
|
||||
#define _CWORD 2
|
||||
#define _CDWORD 3
|
||||
#define _CSTRUCT 4
|
||||
#define _CMSTRUCT 5
|
||||
#define _CEND 6
|
||||
|
||||
static _cdef cdef[] =
|
||||
{
|
||||
/*00 */
|
||||
{_CEND},
|
||||
/*01 */
|
||||
{_CEND},
|
||||
/*02 */
|
||||
{_CEND},
|
||||
/*03 */
|
||||
{_CDWORD, offsetof(_cmsg, adr.adrController)},
|
||||
/*04 */
|
||||
{_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)},
|
||||
/*05 */
|
||||
{_CSTRUCT, offsetof(_cmsg, B1configuration)},
|
||||
/*06 */
|
||||
{_CWORD, offsetof(_cmsg, B1protocol)},
|
||||
/*07 */
|
||||
{_CSTRUCT, offsetof(_cmsg, B2configuration)},
|
||||
/*08 */
|
||||
{_CWORD, offsetof(_cmsg, B2protocol)},
|
||||
/*09 */
|
||||
{_CSTRUCT, offsetof(_cmsg, B3configuration)},
|
||||
/*0a */
|
||||
{_CWORD, offsetof(_cmsg, B3protocol)},
|
||||
/*0b */
|
||||
{_CSTRUCT, offsetof(_cmsg, BC)},
|
||||
/*0c */
|
||||
{_CSTRUCT, offsetof(_cmsg, BChannelinformation)},
|
||||
/*0d */
|
||||
{_CMSTRUCT, offsetof(_cmsg, BProtocol)},
|
||||
/*0e */
|
||||
{_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)},
|
||||
/*0f */
|
||||
{_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)},
|
||||
/*10 */
|
||||
{_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)},
|
||||
/*11 */
|
||||
{_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)},
|
||||
/*12 */
|
||||
{_CDWORD, offsetof(_cmsg, CIPmask)},
|
||||
/*13 */
|
||||
{_CDWORD, offsetof(_cmsg, CIPmask2)},
|
||||
/*14 */
|
||||
{_CWORD, offsetof(_cmsg, CIPValue)},
|
||||
/*15 */
|
||||
{_CDWORD, offsetof(_cmsg, Class)},
|
||||
/*16 */
|
||||
{_CSTRUCT, offsetof(_cmsg, ConnectedNumber)},
|
||||
/*17 */
|
||||
{_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)},
|
||||
/*18 */
|
||||
{_CDWORD, offsetof(_cmsg, Data)},
|
||||
/*19 */
|
||||
{_CWORD, offsetof(_cmsg, DataHandle)},
|
||||
/*1a */
|
||||
{_CWORD, offsetof(_cmsg, DataLength)},
|
||||
/*1b */
|
||||
{_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)},
|
||||
/*1c */
|
||||
{_CSTRUCT, offsetof(_cmsg, Facilitydataarray)},
|
||||
/*1d */
|
||||
{_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)},
|
||||
/*1e */
|
||||
{_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)},
|
||||
/*1f */
|
||||
{_CWORD, offsetof(_cmsg, FacilitySelector)},
|
||||
/*20 */
|
||||
{_CWORD, offsetof(_cmsg, Flags)},
|
||||
/*21 */
|
||||
{_CDWORD, offsetof(_cmsg, Function)},
|
||||
/*22 */
|
||||
{_CSTRUCT, offsetof(_cmsg, HLC)},
|
||||
/*23 */
|
||||
{_CWORD, offsetof(_cmsg, Info)},
|
||||
/*24 */
|
||||
{_CSTRUCT, offsetof(_cmsg, InfoElement)},
|
||||
/*25 */
|
||||
{_CDWORD, offsetof(_cmsg, InfoMask)},
|
||||
/*26 */
|
||||
{_CWORD, offsetof(_cmsg, InfoNumber)},
|
||||
/*27 */
|
||||
{_CSTRUCT, offsetof(_cmsg, Keypadfacility)},
|
||||
/*28 */
|
||||
{_CSTRUCT, offsetof(_cmsg, LLC)},
|
||||
/*29 */
|
||||
{_CSTRUCT, offsetof(_cmsg, ManuData)},
|
||||
/*2a */
|
||||
{_CDWORD, offsetof(_cmsg, ManuID)},
|
||||
/*2b */
|
||||
{_CSTRUCT, offsetof(_cmsg, NCPI)},
|
||||
/*2c */
|
||||
{_CWORD, offsetof(_cmsg, Reason)},
|
||||
/*2d */
|
||||
{_CWORD, offsetof(_cmsg, Reason_B3)},
|
||||
/*2e */
|
||||
{_CWORD, offsetof(_cmsg, Reject)},
|
||||
/*2f */
|
||||
{_CSTRUCT, offsetof(_cmsg, Useruserdata)}
|
||||
};
|
||||
|
||||
static unsigned char *cpars[] =
|
||||
{
|
||||
/*00 */ 0,
|
||||
/*01 ALERT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
|
||||
/*02 CONNECT_REQ */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
|
||||
/*03 */ 0,
|
||||
/*04 DISCONNECT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
|
||||
/*05 LISTEN_REQ */ (unsigned char *) "\x03\x25\x12\x13\x10\x11\x01",
|
||||
/*06 */ 0,
|
||||
/*07 */ 0,
|
||||
/*08 INFO_REQ */ (unsigned char *) "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01",
|
||||
/*09 FACILITY_REQ */ (unsigned char *) "\x03\x1f\x1e\x01",
|
||||
/*0a SELECT_B_PROTOCOL_REQ */ (unsigned char *) "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01",
|
||||
/*0b CONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
|
||||
/*0c */ 0,
|
||||
/*0d DISCONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
|
||||
/*0e */ 0,
|
||||
/*0f DATA_B3_REQ */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01",
|
||||
/*10 RESET_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
|
||||
/*11 */ 0,
|
||||
/*12 */ 0,
|
||||
/*13 ALERT_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*14 CONNECT_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*15 */ 0,
|
||||
/*16 DISCONNECT_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*17 LISTEN_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*18 MANUFACTURER_REQ */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
|
||||
/*19 */ 0,
|
||||
/*1a INFO_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*1b FACILITY_CONF */ (unsigned char *) "\x03\x23\x1f\x1b\x01",
|
||||
/*1c SELECT_B_PROTOCOL_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*1d CONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*1e */ 0,
|
||||
/*1f DISCONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*20 */ 0,
|
||||
/*21 DATA_B3_CONF */ (unsigned char *) "\x03\x19\x23\x01",
|
||||
/*22 RESET_B3_CONF */ (unsigned char *) "\x03\x23\x01",
|
||||
/*23 */ 0,
|
||||
/*24 */ 0,
|
||||
/*25 */ 0,
|
||||
/*26 CONNECT_IND */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
|
||||
/*27 CONNECT_ACTIVE_IND */ (unsigned char *) "\x03\x16\x17\x28\x01",
|
||||
/*28 DISCONNECT_IND */ (unsigned char *) "\x03\x2c\x01",
|
||||
/*29 */ 0,
|
||||
/*2a MANUFACTURER_CONF */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
|
||||
/*2b */ 0,
|
||||
/*2c INFO_IND */ (unsigned char *) "\x03\x26\x24\x01",
|
||||
/*2d FACILITY_IND */ (unsigned char *) "\x03\x1f\x1d\x01",
|
||||
/*2e */ 0,
|
||||
/*2f CONNECT_B3_IND */ (unsigned char *) "\x03\x2b\x01",
|
||||
/*30 CONNECT_B3_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01",
|
||||
/*31 DISCONNECT_B3_IND */ (unsigned char *) "\x03\x2d\x2b\x01",
|
||||
/*32 */ 0,
|
||||
/*33 DATA_B3_IND */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01",
|
||||
/*34 RESET_B3_IND */ (unsigned char *) "\x03\x2b\x01",
|
||||
/*35 CONNECT_B3_T90_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01",
|
||||
/*36 */ 0,
|
||||
/*37 */ 0,
|
||||
/*38 CONNECT_RESP */ (unsigned char *) "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01",
|
||||
/*39 CONNECT_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
|
||||
/*3a DISCONNECT_RESP */ (unsigned char *) "\x03\x01",
|
||||
/*3b */ 0,
|
||||
/*3c MANUFACTURER_IND */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
|
||||
/*3d */ 0,
|
||||
/*3e INFO_RESP */ (unsigned char *) "\x03\x01",
|
||||
/*3f FACILITY_RESP */ (unsigned char *) "\x03\x1f\x01",
|
||||
/*40 */ 0,
|
||||
/*41 CONNECT_B3_RESP */ (unsigned char *) "\x03\x2e\x2b\x01",
|
||||
/*42 CONNECT_B3_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
|
||||
/*43 DISCONNECT_B3_RESP */ (unsigned char *) "\x03\x01",
|
||||
/*44 */ 0,
|
||||
/*45 DATA_B3_RESP */ (unsigned char *) "\x03\x19\x01",
|
||||
/*46 RESET_B3_RESP */ (unsigned char *) "\x03\x01",
|
||||
/*47 CONNECT_B3_T90_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
|
||||
/*48 */ 0,
|
||||
/*49 */ 0,
|
||||
/*4a */ 0,
|
||||
/*4b */ 0,
|
||||
/*4c */ 0,
|
||||
/*4d */ 0,
|
||||
/*4e MANUFACTURER_RESP */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
|
||||
#define byteTLcpy(x,y) *(__u8 *)(x)=*(__u8 *)(y);
|
||||
#define wordTLcpy(x,y) *(__u16 *)(x)=*(__u16 *)(y);
|
||||
#define dwordTLcpy(x,y) memcpy(x,y,4);
|
||||
#define structTLcpy(x,y,l) memcpy (x,y,l)
|
||||
#define structTLcpyovl(x,y,l) memmove (x,y,l)
|
||||
|
||||
#define byteTRcpy(x,y) *(__u8 *)(y)=*(__u8 *)(x);
|
||||
#define wordTRcpy(x,y) *(__u16 *)(y)=*(__u16 *)(x);
|
||||
#define dwordTRcpy(x,y) memcpy(y,x,4);
|
||||
#define structTRcpy(x,y,l) memcpy (y,x,l)
|
||||
#define structTRcpyovl(x,y,l) memmove (y,x,l)
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
static unsigned command_2_index(unsigned c, unsigned sc)
|
||||
{
|
||||
if (c & 0x80)
|
||||
c = 0x9 + (c & 0x0f);
|
||||
else if (c <= 0x0f);
|
||||
else if (c == 0x41)
|
||||
c = 0x9 + 0x1;
|
||||
else if (c == 0xff)
|
||||
c = 0x00;
|
||||
return (sc & 3) * (0x9 + 0x9) + c;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
#define TYP (cdef[cmsg->par[cmsg->p]].typ)
|
||||
#define OFF (((__u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off)
|
||||
|
||||
static void jumpcstruct(_cmsg * cmsg)
|
||||
{
|
||||
unsigned layer;
|
||||
for (cmsg->p++, layer = 1; layer;) {
|
||||
/* $$$$$ assert (cmsg->p); */
|
||||
cmsg->p++;
|
||||
switch (TYP) {
|
||||
case _CMSTRUCT:
|
||||
layer++;
|
||||
break;
|
||||
case _CEND:
|
||||
layer--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------*/
|
||||
static void pars_2_message(_cmsg * cmsg)
|
||||
{
|
||||
|
||||
for (; TYP != _CEND; cmsg->p++) {
|
||||
switch (TYP) {
|
||||
case _CBYTE:
|
||||
byteTLcpy(cmsg->m + cmsg->l, OFF);
|
||||
cmsg->l++;
|
||||
break;
|
||||
case _CWORD:
|
||||
wordTLcpy(cmsg->m + cmsg->l, OFF);
|
||||
cmsg->l += 2;
|
||||
break;
|
||||
case _CDWORD:
|
||||
dwordTLcpy(cmsg->m + cmsg->l, OFF);
|
||||
cmsg->l += 4;
|
||||
break;
|
||||
case _CSTRUCT:
|
||||
if (*(__u8 **) OFF == 0) {
|
||||
*(cmsg->m + cmsg->l) = '\0';
|
||||
cmsg->l++;
|
||||
} else if (**(_cstruct *) OFF != 0xff) {
|
||||
structTLcpy(cmsg->m + cmsg->l, *(_cstruct *) OFF, 1 + **(_cstruct *) OFF);
|
||||
cmsg->l += 1 + **(_cstruct *) OFF;
|
||||
} else {
|
||||
_cstruct s = *(_cstruct *) OFF;
|
||||
structTLcpy(cmsg->m + cmsg->l, s, 3 + *(__u16 *) (s + 1));
|
||||
cmsg->l += 3 + *(__u16 *) (s + 1);
|
||||
}
|
||||
break;
|
||||
case _CMSTRUCT:
|
||||
/*----- Metastruktur 0 -----*/
|
||||
if (*(_cmstruct *) OFF == CAPI_DEFAULT) {
|
||||
*(cmsg->m + cmsg->l) = '\0';
|
||||
cmsg->l++;
|
||||
jumpcstruct(cmsg);
|
||||
}
|
||||
/*----- Metastruktur wird composed -----*/
|
||||
else {
|
||||
unsigned _l = cmsg->l;
|
||||
unsigned _ls;
|
||||
cmsg->l++;
|
||||
cmsg->p++;
|
||||
pars_2_message(cmsg);
|
||||
_ls = cmsg->l - _l - 1;
|
||||
if (_ls < 255)
|
||||
(cmsg->m + _l)[0] = (__u8) _ls;
|
||||
else {
|
||||
structTLcpyovl(cmsg->m + _l + 3, cmsg->m + _l + 1, _ls);
|
||||
(cmsg->m + _l)[0] = 0xff;
|
||||
wordTLcpy(cmsg->m + _l + 1, &_ls);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg)
|
||||
{
|
||||
cmsg->m = msg;
|
||||
cmsg->l = 8;
|
||||
cmsg->p = 0;
|
||||
cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
|
||||
|
||||
pars_2_message(cmsg);
|
||||
|
||||
wordTLcpy(msg + 0, &cmsg->l);
|
||||
byteTLcpy(cmsg->m + 4, &cmsg->Command);
|
||||
byteTLcpy(cmsg->m + 5, &cmsg->Subcommand);
|
||||
wordTLcpy(cmsg->m + 2, &cmsg->ApplId);
|
||||
wordTLcpy(cmsg->m + 6, &cmsg->Messagenumber);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
static void message_2_pars(_cmsg * cmsg)
|
||||
{
|
||||
for (; TYP != _CEND; cmsg->p++) {
|
||||
|
||||
switch (TYP) {
|
||||
case _CBYTE:
|
||||
byteTRcpy(cmsg->m + cmsg->l, OFF);
|
||||
cmsg->l++;
|
||||
break;
|
||||
case _CWORD:
|
||||
wordTRcpy(cmsg->m + cmsg->l, OFF);
|
||||
cmsg->l += 2;
|
||||
break;
|
||||
case _CDWORD:
|
||||
dwordTRcpy(cmsg->m + cmsg->l, OFF);
|
||||
cmsg->l += 4;
|
||||
break;
|
||||
case _CSTRUCT:
|
||||
*(__u8 **) OFF = cmsg->m + cmsg->l;
|
||||
|
||||
if (cmsg->m[cmsg->l] != 0xff)
|
||||
cmsg->l += 1 + cmsg->m[cmsg->l];
|
||||
else
|
||||
cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1);
|
||||
break;
|
||||
case _CMSTRUCT:
|
||||
/*----- Metastruktur 0 -----*/
|
||||
if (cmsg->m[cmsg->l] == '\0') {
|
||||
*(_cmstruct *) OFF = CAPI_DEFAULT;
|
||||
cmsg->l++;
|
||||
jumpcstruct(cmsg);
|
||||
} else {
|
||||
unsigned _l = cmsg->l;
|
||||
*(_cmstruct *) OFF = CAPI_COMPOSE;
|
||||
cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
|
||||
cmsg->p++;
|
||||
message_2_pars(cmsg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg)
|
||||
{
|
||||
memset(cmsg, 0, sizeof(_cmsg));
|
||||
cmsg->m = msg;
|
||||
cmsg->l = 8;
|
||||
cmsg->p = 0;
|
||||
byteTRcpy(cmsg->m + 4, &cmsg->Command);
|
||||
byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
|
||||
cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
|
||||
|
||||
message_2_pars(cmsg);
|
||||
|
||||
wordTRcpy(msg + 0, &cmsg->l);
|
||||
wordTRcpy(cmsg->m + 2, &cmsg->ApplId);
|
||||
wordTRcpy(cmsg->m + 6, &cmsg->Messagenumber);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId,
|
||||
__u8 _Command, __u8 _Subcommand,
|
||||
__u16 _Messagenumber, __u32 _Controller)
|
||||
{
|
||||
memset(cmsg, 0, sizeof(_cmsg));
|
||||
cmsg->ApplId = _ApplId;
|
||||
cmsg->Command = _Command;
|
||||
cmsg->Subcommand = _Subcommand;
|
||||
cmsg->Messagenumber = _Messagenumber;
|
||||
cmsg->adr.adrController = _Controller;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
|
||||
static char *mnames[] =
|
||||
{
|
||||
0,
|
||||
"ALERT_REQ",
|
||||
"CONNECT_REQ",
|
||||
0,
|
||||
"DISCONNECT_REQ",
|
||||
"LISTEN_REQ",
|
||||
0,
|
||||
0,
|
||||
"INFO_REQ",
|
||||
"FACILITY_REQ",
|
||||
"SELECT_B_PROTOCOL_REQ",
|
||||
"CONNECT_B3_REQ",
|
||||
0,
|
||||
"DISCONNECT_B3_REQ",
|
||||
0,
|
||||
"DATA_B3_REQ",
|
||||
"RESET_B3_REQ",
|
||||
0,
|
||||
0,
|
||||
"ALERT_CONF",
|
||||
"CONNECT_CONF",
|
||||
0,
|
||||
"DISCONNECT_CONF",
|
||||
"LISTEN_CONF",
|
||||
"MANUFACTURER_REQ",
|
||||
0,
|
||||
"INFO_CONF",
|
||||
"FACILITY_CONF",
|
||||
"SELECT_B_PROTOCOL_CONF",
|
||||
"CONNECT_B3_CONF",
|
||||
0,
|
||||
"DISCONNECT_B3_CONF",
|
||||
0,
|
||||
"DATA_B3_CONF",
|
||||
"RESET_B3_CONF",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"CONNECT_IND",
|
||||
"CONNECT_ACTIVE_IND",
|
||||
"DISCONNECT_IND",
|
||||
0,
|
||||
"MANUFACTURER_CONF",
|
||||
0,
|
||||
"INFO_IND",
|
||||
"FACILITY_IND",
|
||||
0,
|
||||
"CONNECT_B3_IND",
|
||||
"CONNECT_B3_ACTIVE_IND",
|
||||
"DISCONNECT_B3_IND",
|
||||
0,
|
||||
"DATA_B3_IND",
|
||||
"RESET_B3_IND",
|
||||
"CONNECT_B3_T90_ACTIVE_IND",
|
||||
0,
|
||||
0,
|
||||
"CONNECT_RESP",
|
||||
"CONNECT_ACTIVE_RESP",
|
||||
"DISCONNECT_RESP",
|
||||
0,
|
||||
"MANUFACTURER_IND",
|
||||
0,
|
||||
"INFO_RESP",
|
||||
"FACILITY_RESP",
|
||||
0,
|
||||
"CONNECT_B3_RESP",
|
||||
"CONNECT_B3_ACTIVE_RESP",
|
||||
"DISCONNECT_B3_RESP",
|
||||
0,
|
||||
"DATA_B3_RESP",
|
||||
"RESET_B3_RESP",
|
||||
"CONNECT_B3_T90_ACTIVE_RESP",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"MANUFACTURER_RESP"
|
||||
};
|
||||
|
||||
char *capi_cmd2str(__u8 cmd, __u8 subcmd)
|
||||
{
|
||||
return mnames[command_2_index(cmd, subcmd)];
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
/*-------------------------------------------------------*/
|
||||
|
||||
static char *pnames[] =
|
||||
{
|
||||
/*00 */ 0,
|
||||
/*01 */ 0,
|
||||
/*02 */ 0,
|
||||
/*03 */ "Controller/PLCI/NCCI",
|
||||
/*04 */ "AdditionalInfo",
|
||||
/*05 */ "B1configuration",
|
||||
/*06 */ "B1protocol",
|
||||
/*07 */ "B2configuration",
|
||||
/*08 */ "B2protocol",
|
||||
/*09 */ "B3configuration",
|
||||
/*0a */ "B3protocol",
|
||||
/*0b */ "BC",
|
||||
/*0c */ "BChannelinformation",
|
||||
/*0d */ "BProtocol",
|
||||
/*0e */ "CalledPartyNumber",
|
||||
/*0f */ "CalledPartySubaddress",
|
||||
/*10 */ "CallingPartyNumber",
|
||||
/*11 */ "CallingPartySubaddress",
|
||||
/*12 */ "CIPmask",
|
||||
/*13 */ "CIPmask2",
|
||||
/*14 */ "CIPValue",
|
||||
/*15 */ "Class",
|
||||
/*16 */ "ConnectedNumber",
|
||||
/*17 */ "ConnectedSubaddress",
|
||||
/*18 */ "Data",
|
||||
/*19 */ "DataHandle",
|
||||
/*1a */ "DataLength",
|
||||
/*1b */ "FacilityConfirmationParameter",
|
||||
/*1c */ "Facilitydataarray",
|
||||
/*1d */ "FacilityIndicationParameter",
|
||||
/*1e */ "FacilityRequestParameter",
|
||||
/*1f */ "FacilitySelector",
|
||||
/*20 */ "Flags",
|
||||
/*21 */ "Function",
|
||||
/*22 */ "HLC",
|
||||
/*23 */ "Info",
|
||||
/*24 */ "InfoElement",
|
||||
/*25 */ "InfoMask",
|
||||
/*26 */ "InfoNumber",
|
||||
/*27 */ "Keypadfacility",
|
||||
/*28 */ "LLC",
|
||||
/*29 */ "ManuData",
|
||||
/*2a */ "ManuID",
|
||||
/*2b */ "NCPI",
|
||||
/*2c */ "Reason",
|
||||
/*2d */ "Reason_B3",
|
||||
/*2e */ "Reject",
|
||||
/*2f */ "Useruserdata"
|
||||
};
|
||||
|
||||
|
||||
static char buf[8192];
|
||||
static char *p = 0;
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
static void bufprint(char *fmt,...)
|
||||
{
|
||||
va_list f;
|
||||
va_start(f, fmt);
|
||||
vsprintf(p, fmt, f);
|
||||
va_end(f);
|
||||
p += strlen(p);
|
||||
}
|
||||
|
||||
static void printstructlen(__u8 * m, unsigned len)
|
||||
{
|
||||
unsigned hex = 0;
|
||||
for (; len; len--, m++)
|
||||
if (isalnum(*m) || *m == ' ') {
|
||||
if (hex)
|
||||
bufprint(">");
|
||||
bufprint("%c", *m);
|
||||
hex = 0;
|
||||
} else {
|
||||
if (!hex)
|
||||
bufprint("<%02x", *m);
|
||||
else
|
||||
bufprint(" %02x", *m);
|
||||
hex = 1;
|
||||
}
|
||||
if (hex)
|
||||
bufprint(">");
|
||||
}
|
||||
|
||||
static void printstruct(__u8 * m)
|
||||
{
|
||||
unsigned len;
|
||||
if (m[0] != 0xff) {
|
||||
len = m[0];
|
||||
m += 1;
|
||||
} else {
|
||||
len = ((__u16 *) (m + 1))[0];
|
||||
m += 3;
|
||||
}
|
||||
printstructlen(m, len);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
#define NAME (pnames[cmsg->par[cmsg->p]])
|
||||
|
||||
static void protocol_message_2_pars(_cmsg * cmsg, int level)
|
||||
{
|
||||
for (; TYP != _CEND; cmsg->p++) {
|
||||
int slen = 29 + 3 - level;
|
||||
int i;
|
||||
|
||||
bufprint(" ");
|
||||
for (i = 0; i < level - 1; i++)
|
||||
bufprint(" ");
|
||||
|
||||
switch (TYP) {
|
||||
case _CBYTE:
|
||||
bufprint("%-*s = 0x%x\n", slen, NAME, *(__u8 *) (cmsg->m + cmsg->l));
|
||||
cmsg->l++;
|
||||
break;
|
||||
case _CWORD:
|
||||
bufprint("%-*s = 0x%x\n", slen, NAME, *(__u16 *) (cmsg->m + cmsg->l));
|
||||
cmsg->l += 2;
|
||||
break;
|
||||
case _CDWORD:
|
||||
if (strcmp(NAME, "Data") == 0) {
|
||||
bufprint("%-*s = ", slen, NAME);
|
||||
printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l),
|
||||
*(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32)));
|
||||
bufprint("\n");
|
||||
} else
|
||||
bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
|
||||
cmsg->l += 4;
|
||||
break;
|
||||
case _CSTRUCT:
|
||||
bufprint("%-*s = ", slen, NAME);
|
||||
if (cmsg->m[cmsg->l] == '\0')
|
||||
bufprint("default");
|
||||
else
|
||||
printstruct(cmsg->m + cmsg->l);
|
||||
bufprint("\n");
|
||||
if (cmsg->m[cmsg->l] != 0xff)
|
||||
cmsg->l += 1 + cmsg->m[cmsg->l];
|
||||
else
|
||||
cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1);
|
||||
|
||||
break;
|
||||
|
||||
case _CMSTRUCT:
|
||||
/*----- Metastruktur 0 -----*/
|
||||
if (cmsg->m[cmsg->l] == '\0') {
|
||||
bufprint("%-*s = default\n", slen, NAME);
|
||||
cmsg->l++;
|
||||
jumpcstruct(cmsg);
|
||||
} else {
|
||||
char *name = NAME;
|
||||
unsigned _l = cmsg->l;
|
||||
bufprint("%-*s\n", slen, name);
|
||||
cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
|
||||
cmsg->p++;
|
||||
protocol_message_2_pars(cmsg, level + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------*/
|
||||
char *capi_message2str(__u8 * msg)
|
||||
{
|
||||
|
||||
_cmsg cmsg;
|
||||
p = buf;
|
||||
p[0] = 0;
|
||||
|
||||
cmsg.m = msg;
|
||||
cmsg.l = 8;
|
||||
cmsg.p = 0;
|
||||
byteTRcpy(cmsg.m + 4, &cmsg.Command);
|
||||
byteTRcpy(cmsg.m + 5, &cmsg.Subcommand);
|
||||
cmsg.par = cpars[command_2_index(cmsg.Command, cmsg.Subcommand)];
|
||||
|
||||
bufprint("%-26s ID=%03d #0x%04x LEN=%04d\n",
|
||||
mnames[command_2_index(cmsg.Command, cmsg.Subcommand)],
|
||||
((unsigned short *) msg)[1],
|
||||
((unsigned short *) msg)[3],
|
||||
((unsigned short *) msg)[0]);
|
||||
|
||||
protocol_message_2_pars(&cmsg, 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *capi_cmsg2str(_cmsg * cmsg)
|
||||
{
|
||||
p = buf;
|
||||
p[0] = 0;
|
||||
cmsg->l = 8;
|
||||
cmsg->p = 0;
|
||||
bufprint("%s ID=%03d #0x%04x LEN=%04d\n",
|
||||
mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
|
||||
((__u16 *) cmsg->m)[1],
|
||||
((__u16 *) cmsg->m)[3],
|
||||
((__u16 *) cmsg->m)[0]);
|
||||
protocol_message_2_pars(cmsg, 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(capi_cmsg2message);
|
||||
EXPORT_SYMBOL(capi_message2cmsg);
|
||||
EXPORT_SYMBOL(capi_cmsg_header);
|
||||
EXPORT_SYMBOL(capi_cmd2str);
|
||||
EXPORT_SYMBOL(capi_cmsg2str);
|
||||
EXPORT_SYMBOL(capi_message2str);
|
||||
EXPORT_SYMBOL(capi_info2str);
|
||||
|
||||
#ifdef MODULE
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,504 +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.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_LEN(m) (m[0] | (m[1] << 8))
|
||||
#define CAPIMSG_APPID(m) (m[2] | (m[3] << 8))
|
||||
#define CAPIMSG_COMMAND(m) (m[4])
|
||||
#define CAPIMSG_SUBCOMMAND(m) (m[5])
|
||||
#define CAPIMSG_MSGID(m) (m[6] | (m[7] << 8))
|
||||
#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f)
|
||||
#define CAPIMSG_CONTROL(m) (m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24))
|
||||
#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m)
|
||||
#define CAPIMSG_DATA(m) (m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24))
|
||||
#define CAPIMSG_DATALEN(m) (m[16] | (m[17]<<8))
|
||||
|
||||
#define CAPIMSG_SETAPPID(m, applid) \
|
||||
do { \
|
||||
((__u8 *)m)[2] = (__u16)(applid) & 0xff; \
|
||||
((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \
|
||||
} while (0)
|
||||
|
||||
#define CAPIMSG_SETLEN(m, len) \
|
||||
do { \
|
||||
((__u8 *)m)[0] = (__u16)(len) & 0xff; \
|
||||
((__u8 *)m)[1] = ((__u16)(len) >> 8) & 0xff; \
|
||||
} while (0)
|
||||
|
||||
/*----- 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
|
@ -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
|
|
@ -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, ¶m);
|
||||
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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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__ */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
|
@ -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
|
@ -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 */
|
||||
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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__ */
|
|
@ -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
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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
|
||||
}
|
|
@ -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
|
@ -1,145 +0,0 @@
|
|||
/* $Id$
|
||||
|
||||
* header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
|
||||
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
|
||||
*
|
||||
* 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.17 1999/10/27 21:21:17 detabc
|
||||
* Added support for building logically-bind-group's per interface.
|
||||
* usefull for outgoing call's with more then one isdn-card.
|
||||
*
|
||||
* Switchable support to dont reset the hangup-timeout for
|
||||
* receive frames. Most part's of the timru-rules for receiving frames
|
||||
* are now obsolete. If the input- or forwarding-firewall deny
|
||||
* the frame, the line will be not hold open.
|
||||
*
|
||||
* Revision 1.16 1999/07/01 08:29:54 keil
|
||||
* compatibility to 2.3 kernel
|
||||
*
|
||||
* Revision 1.15 1999/04/18 14:06:50 fritz
|
||||
* Removed TIMRU stuff.
|
||||
*
|
||||
* Revision 1.14 1999/04/12 12:33:18 fritz
|
||||
* Changes from 2.0 tree.
|
||||
*
|
||||
* Revision 1.13 1999/03/02 12:04:47 armin
|
||||
* -added ISDN_STAT_ADDCH to increase supported channels after
|
||||
* register_isdn().
|
||||
* -ttyI now goes on-hook on ATZ when B-Ch is connected.
|
||||
* -added timer-function for register S7 (Wait for Carrier).
|
||||
* -analog modem (ISDN_PROTO_L2_MODEM) implementations.
|
||||
* -on L2_MODEM a string will be appended to the CONNECT-Message,
|
||||
* which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN.
|
||||
* -variable "dialing" used for ATA also, for interrupting call
|
||||
* establishment and register S7.
|
||||
*
|
||||
* Revision 1.12 1998/06/26 15:12:27 fritz
|
||||
* Added handling of STAT_ICALL with incomplete CPN.
|
||||
* Added AT&L for ttyI emulator.
|
||||
* Added more locking stuff in tty_write.
|
||||
*
|
||||
* Revision 1.11 1998/04/14 16:28:47 he
|
||||
* Fixed user space access with interrupts off and remaining
|
||||
* copy_{to,from}_user() -> -EFAULT return codes
|
||||
*
|
||||
* Revision 1.10 1998/03/07 18:21:03 cal
|
||||
* Dynamic Timeout-Rule-Handling vs. 971110 included
|
||||
*
|
||||
* Revision 1.9 1998/02/20 17:19:01 fritz
|
||||
* Added common stub for sending commands to lowlevel.
|
||||
*
|
||||
* Revision 1.8 1997/10/09 21:28:49 fritz
|
||||
* New HL<->LL interface:
|
||||
* New BSENT callback with nr. of bytes included.
|
||||
* Sending without ACK.
|
||||
* New L1 error status (not yet in use).
|
||||
* Cleaned up obsolete structures.
|
||||
* Implemented Cisco-SLARP.
|
||||
* Changed local net-interface data to be dynamically allocated.
|
||||
* Removed old 2.0 compatibility stuff.
|
||||
*
|
||||
* Revision 1.7 1997/10/01 09:20:30 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.6 1997/02/28 02:32:44 fritz
|
||||
* Cleanup: Moved some tty related stuff from isdn_common.c
|
||||
* to isdn_tty.c
|
||||
* Bugfix: Bisync protocol did not behave like documented.
|
||||
*
|
||||
* Revision 1.5 1997/02/10 10:05:45 fritz
|
||||
* More changes for Kernel 2.1.X
|
||||
* Symbol information moved to isdn_syms.c
|
||||
*
|
||||
* Revision 1.4 1997/02/03 22:56:50 fritz
|
||||
* Removed isdn_writebuf_stub prototype.
|
||||
*
|
||||
* Revision 1.3 1996/05/19 00:13:05 fritz
|
||||
* Removed debug flag.
|
||||
*
|
||||
* Revision 1.2 1996/04/20 16:20:40 fritz
|
||||
* Misc. typos.
|
||||
*
|
||||
* Revision 1.1 1996/01/10 21:37:19 fritz
|
||||
* Initial revision
|
||||
*
|
||||
*/
|
||||
|
||||
#undef ISDN_DEBUG_MODEM_OPEN
|
||||
#undef ISDN_DEBUG_MODEM_IOCTL
|
||||
#undef ISDN_DEBUG_MODEM_WAITSENT
|
||||
#undef ISDN_DEBUG_MODEM_HUP
|
||||
#undef ISDN_DEBUG_MODEM_ICALL
|
||||
#undef ISDN_DEBUG_MODEM_DUMP
|
||||
#undef ISDN_DEBUG_MODEM_VOICE
|
||||
#undef ISDN_DEBUG_AT
|
||||
#undef ISDN_DEBUG_NET_DUMP
|
||||
#undef ISDN_DEBUG_NET_DIAL
|
||||
#undef ISDN_DEBUG_NET_ICALL
|
||||
|
||||
#ifdef CONFIG_ISDN_WITH_ABC
|
||||
int isdn_net_force_dial_lp(isdn_net_local *);
|
||||
#endif
|
||||
/* Prototypes */
|
||||
extern void isdn_MOD_INC_USE_COUNT(void);
|
||||
extern void isdn_MOD_DEC_USE_COUNT(void);
|
||||
extern void isdn_free_channel(int di, int ch, int usage);
|
||||
extern void isdn_all_eaz(int di, int ch);
|
||||
extern int isdn_command(isdn_ctrl *);
|
||||
extern int isdn_dc2minor(int di, int ch);
|
||||
extern void isdn_info_update(void);
|
||||
extern char *isdn_map_eaz2msn(char *msn, int di);
|
||||
extern void isdn_timer_ctrl(int tf, int onoff);
|
||||
extern void isdn_unexclusive_channel(int di, int ch);
|
||||
extern int isdn_getnum(char **);
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
|
||||
#else
|
||||
extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**);
|
||||
#endif
|
||||
extern int isdn_get_free_channel(int, int, int, int, int, char *);
|
||||
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
|
||||
extern int register_isdn(isdn_if * i);
|
||||
extern int isdn_wildmat(char *, char *);
|
||||
extern int isdn_add_channels(driver *, int, int, int);
|
||||
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
|
||||
extern void isdn_dumppkt(char *, u_char *, int, int);
|
||||
#endif
|
|
@ -1,114 +0,0 @@
|
|||
/* $Id$
|
||||
|
||||
* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
|
||||
* stuff goes here. Stuff that depends only on the concap protocol goes to
|
||||
* another -- protocol specific -- source file.
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.5 1998/10/30 18:44:48 he
|
||||
* pass return value from isdn_net_dial_req for dialmode change
|
||||
*
|
||||
* Revision 1.4 1998/10/30 17:55:24 he
|
||||
* dialmode for x25iface and multulink ppp
|
||||
*
|
||||
* Revision 1.3 1998/05/26 22:39:22 he
|
||||
* sync'ed with 2.1.102 where appropriate (CAPABILITY changes)
|
||||
* concap typo
|
||||
* cleared dev.tbusy in isdn_net BCONN status callback
|
||||
*
|
||||
* Revision 1.2 1998/01/31 22:49:21 keil
|
||||
* correct comments
|
||||
*
|
||||
* Revision 1.1 1998/01/31 22:27:57 keil
|
||||
* New files from Henner Eisen for X.25 support
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include "isdn_x25iface.h"
|
||||
#include "isdn_net.h"
|
||||
#include <linux/concap.h>
|
||||
#include "isdn_concap.h"
|
||||
|
||||
|
||||
/* The following set of device service operations are for encapsulation
|
||||
protocols that require for reliable datalink semantics. That means:
|
||||
|
||||
- before any data is to be submitted the connection must explicitly
|
||||
be set up.
|
||||
- after the successful set up of the connection is signalled the
|
||||
connection is considered to be reliably up.
|
||||
|
||||
Auto-dialing ist not compatible with this requirements. Thus, auto-dialing
|
||||
is completely bypassed.
|
||||
|
||||
It might be possible to implement a (non standardized) datalink protocol
|
||||
that provides a reliable data link service while using some auto dialing
|
||||
mechanism. Such a protocol would need an auxiliary channel (i.e. user-user-
|
||||
signaling on the D-channel) while the B-channel is down.
|
||||
*/
|
||||
|
||||
|
||||
int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
|
||||
{
|
||||
int tmp;
|
||||
struct net_device *ndev = concap -> net_dev;
|
||||
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
|
||||
|
||||
IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
|
||||
lp->huptimer = 0;
|
||||
tmp=isdn_net_send_skb(ndev, lp, skb);
|
||||
IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
int isdn_concap_dl_connect_req(struct concap_proto *concap)
|
||||
{
|
||||
struct net_device *ndev = concap -> net_dev;
|
||||
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
|
||||
int ret;
|
||||
IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name);
|
||||
|
||||
/* dial ... */
|
||||
ret = isdn_net_dial_req( lp );
|
||||
if ( ret ) IX25DEBUG("dialing failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int isdn_concap_dl_disconn_req(struct concap_proto *concap)
|
||||
{
|
||||
IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
|
||||
|
||||
isdn_net_hangup( concap -> net_dev );
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct concap_device_ops isdn_concap_reliable_dl_dops = {
|
||||
&isdn_concap_dl_data_req,
|
||||
&isdn_concap_dl_connect_req,
|
||||
&isdn_concap_dl_disconn_req
|
||||
};
|
||||
|
||||
struct concap_device_ops isdn_concap_demand_dial_dops = {
|
||||
NULL, /* set this first entry to something like &isdn_net_start_xmit,
|
||||
but the entry part of the current isdn_net_start_xmit must be
|
||||
separated first. */
|
||||
/* no connection control for demand dial semantics */
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* The following should better go into a dedicated source file such that
|
||||
this sourcefile does not need to include any protocol specific header
|
||||
files. For now:
|
||||
*/
|
||||
struct concap_proto * isdn_concap_new( int encap )
|
||||
{
|
||||
switch ( encap ) {
|
||||
case ISDN_NET_ENCAP_X25IFACE:
|
||||
return isdn_x25iface_proto_new();
|
||||
}
|
||||
return NULL;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue