This commit was manufactured by cvs2git to create tag 'T24'.
This commit is contained in:
parent
da2c081b06
commit
2374a791f2
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,115 +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 a BRI card with E-DSS1 Protocol with PtP configuration.
|
||||
|
||||
eiconctrl [-d DriverId] load etsi -n -t0 -s1
|
||||
|
||||
|
||||
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,147 +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 'CAPI2.0 support' CONFIG_ISDN_CAPI $CONFIG_ISDN
|
||||
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
|
||||
bool 'CAPI2.0 Middleware support' CONFIG_ISDN_CAPI_MIDDLEWARE
|
||||
if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" != "n" ]; then
|
||||
bool 'CAPI2.0 filesystem support' CONFIG_ISDN_CAPIFS
|
||||
fi
|
||||
fi
|
||||
if [ "$CONFIG_ISDN_CAPI" != "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,175 +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.13 2000/03/08 17:06:33 calle
|
||||
# - changes for devfs and 2.3.49
|
||||
# - capifs now configurable (no need with devfs)
|
||||
# - New Middleware ioctl CAPI_NCCI_GETUNIT
|
||||
# - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
|
||||
#
|
||||
# Revision 1.12 2000/03/06 18:00:23 calle
|
||||
# - Middleware extention now working with 2.3.49 (capifs).
|
||||
# - Fixed typos in debug section of capi.c
|
||||
# - Bugfix: Makefile corrected for b1pcmcia.c
|
||||
#
|
||||
# Revision 1.11 2000/03/06 09:17:07 calle
|
||||
# - capifs: fileoperations now in inode (change for 2.3.49)
|
||||
# - Config.in: Middleware extention not a tristate, uups.
|
||||
#
|
||||
# Revision 1.10 2000/03/03 16:48:38 calle
|
||||
# - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
|
||||
# It is now possible to create a connection with a CAPI2.0 applikation
|
||||
# and than to handle the data connection from /dev/capi/ (capifs) and also
|
||||
# using async or sync PPP on this connection.
|
||||
# The two major device number 190 and 191 are not confirmed yet,
|
||||
# but I want to save the code in cvs, before I go on.
|
||||
#
|
||||
# Revision 1.9 2000/03/03 15:50:42 calle
|
||||
# - kernel CAPI:
|
||||
# - Changed parameter "param" in capi_signal from __u32 to void *.
|
||||
# - rewrote notifier handling in kcapi.c
|
||||
# - new notifier NCCI_UP and NCCI_DOWN
|
||||
# - User CAPI:
|
||||
# - /dev/capi20 is now a cloning device.
|
||||
# - middleware extentions prepared.
|
||||
# - capidrv.c
|
||||
# - locking of list operations and module count updates.
|
||||
#
|
||||
# Revision 1.8 2000/01/25 14:33:38 calle
|
||||
# - Added Support AVM B1 PCI V4.0 (tested with prototype)
|
||||
# - splitted up t1pci.c into b1dma.c for common function with b1pciv4
|
||||
# - support for revision register
|
||||
#
|
||||
# Revision 1.7 1999/09/15 08:16:03 calle
|
||||
# Implementation of 64Bit extention complete.
|
||||
#
|
||||
# Revision 1.6 1999/07/20 06:41:44 calle
|
||||
# Bugfix: After the redesign of the AVM B1 driver, the driver didn't even
|
||||
# compile, if not selected as modules.
|
||||
#
|
||||
# Revision 1.5 1999/07/01 15:26:20 calle
|
||||
# complete new version (I love it):
|
||||
# + new hardware independed "capi_driver" interface that will make it easy to:
|
||||
# - support other controllers with CAPI-2.0 (i.e. USB Controller)
|
||||
# - write a CAPI-2.0 for the passive cards
|
||||
# - support serial link CAPI-2.0 boxes.
|
||||
# + wrote "capi_driver" for all supported cards.
|
||||
# + "capi_driver" (supported cards) now have to be configured with
|
||||
# make menuconfig, in the past all supported cards where included
|
||||
# at once.
|
||||
# + new and better informations in /proc/capi/
|
||||
# + new ioctl to switch trace of capi messages per controller
|
||||
# using "avmcapictrl trace [contr] on|off|...."
|
||||
# + complete testcircle with all supported cards and also the
|
||||
# PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
|
||||
#
|
||||
# Revision 1.4 1997/03/30 17:10:40 calle
|
||||
# added support for AVM-B1-PCI card.
|
||||
#
|
||||
# Revision 1.3 1997/03/22 02:00:57 fritz
|
||||
# -Reworked toplevel Makefile. From now on, no different Makefiles
|
||||
# for standalone- and in-kernel-compilation are needed any more.
|
||||
# -Added local Rules.make for above reason.
|
||||
# -Experimental changes in teles3.c for enhanced IRQ-checking with
|
||||
# 2.1.X and SMP kernels.
|
||||
# -Removed diffstd-script, same functionality is in stddiff -r.
|
||||
# -Enhanced scripts std2kern and stddiff.
|
||||
#
|
||||
# Revision 1.1 1997/03/05 21:26:14 fritz
|
||||
# Renamed, according naming conventions in CVS tree.
|
||||
#
|
||||
# Revision 1.1 1997/03/04 21:50:26 calle
|
||||
# Frirst version in isdn4linux
|
||||
#
|
||||
# Revision 2.2 1997/02/12 09:31:39 calle
|
||||
#
|
||||
# Revision 1.1 1997/01/31 10:32:20 calle
|
||||
# Initial revision
|
||||
#
|
||||
#
|
||||
|
||||
#
|
||||
# Objects that don't export a symtab
|
||||
#
|
||||
L_OBJS := # used as component of an L_TARGET
|
||||
O_OBJS := # used as component of an O_TARGET
|
||||
M_OBJS := # used as module
|
||||
#
|
||||
# Objects that do export a symtab
|
||||
#
|
||||
LX_OBJS := # used as component of an L_TARGET
|
||||
OX_OBJS := # used as component of an O_TARGET
|
||||
MX_OBJS := # used as module
|
||||
#
|
||||
# Targets, created by linking others
|
||||
#
|
||||
O_TARGET := # used for .o targets (from O and OX objects)
|
||||
L_TARGET := # used for .a targets (from L and LX objects)
|
||||
|
||||
ifeq ($(CONFIG_ISDN_CAPI),y)
|
||||
O_TARGET += avmb1.o
|
||||
OX_OBJS += kcapi.o
|
||||
O_OBJS += capi.o
|
||||
ifdef CONFIG_ISDN_CAPIFS
|
||||
OX_OBJS += capifs.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
|
||||
O_OBJS += b1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
|
||||
O_OBJS += b1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
|
||||
O_OBJS += t1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
|
||||
OX_OBJS += b1pcmcia.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
|
||||
O_OBJS += t1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_C4
|
||||
O_OBJS += c4.o
|
||||
endif
|
||||
OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
|
||||
else
|
||||
ifeq ($(CONFIG_ISDN_CAPI),m)
|
||||
O_TARGET += kernelcapi.o
|
||||
OX_OBJS += kcapi.o
|
||||
M_OBJS += capi.o kernelcapi.o
|
||||
ifdef CONFIG_ISDN_CAPIFS
|
||||
MX_OBJS += capifs.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
|
||||
M_OBJS += b1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
|
||||
M_OBJS += b1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
|
||||
M_OBJS += t1isa.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
|
||||
MX_OBJS += b1pcmcia.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
|
||||
M_OBJS += t1pci.o
|
||||
endif
|
||||
ifdef CONFIG_ISDN_DRV_AVMB1_C4
|
||||
M_OBJS += c4.o
|
||||
endif
|
||||
MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
|
@ -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,330 +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.8 2000/03/06 18:00:23 calle
|
||||
* - Middleware extention now working with 2.3.49 (capifs).
|
||||
* - Fixed typos in debug section of capi.c
|
||||
* - Bugfix: Makefile corrected for b1pcmcia.c
|
||||
*
|
||||
* Revision 1.7 2000/02/02 18:36:03 calle
|
||||
* - Modules are now locked while init_module is running
|
||||
* - fixed problem with memory mapping if address is not aligned
|
||||
*
|
||||
* 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/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 <asm/io.h>
|
||||
#include <linux/capi.h>
|
||||
#include <linux/b1pcmcia.h>
|
||||
#include <linux/isdn_compat.h>
|
||||
#include "capicmd.h"
|
||||
#include "capiutil.h"
|
||||
#include "capilli.h"
|
||||
#include "avmcard.h"
|
||||
|
||||
static char *revision = "$Revision$";
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static struct capi_driver_interface *di;
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static void b1pcmcia_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
|
||||
{
|
||||
avmcard *card;
|
||||
|
||||
card = (avmcard *) devptr;
|
||||
|
||||
if (!card) {
|
||||
printk(KERN_WARNING "b1pcmcia: interrupt: wrong device\n");
|
||||
return;
|
||||
}
|
||||
if (card->interrupt) {
|
||||
printk(KERN_ERR "%s: reentering interrupt hander.\n",
|
||||
card->name);
|
||||
return;
|
||||
}
|
||||
|
||||
card->interrupt = 1;
|
||||
|
||||
b1_handle_interrupt(card);
|
||||
|
||||
card->interrupt = 0;
|
||||
}
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
|
||||
{
|
||||
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
|
||||
avmcard *card = cinfo->card;
|
||||
unsigned int port = card->port;
|
||||
|
||||
b1_reset(port);
|
||||
b1_reset(port);
|
||||
|
||||
di->detach_ctr(ctrl);
|
||||
free_irq(card->irq, card);
|
||||
/* io addrsses managent by CardServices
|
||||
* release_region(card->port, AVMB1_PORTLEN);
|
||||
*/
|
||||
kfree(card);
|
||||
|
||||
MOD_DEC_USE_COUNT;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static int b1pcmcia_add_card(struct capi_driver *driver,
|
||||
unsigned int port,
|
||||
unsigned irq,
|
||||
enum avmcardtype cardtype)
|
||||
{
|
||||
avmctrl_info *cinfo;
|
||||
avmcard *card;
|
||||
char *cardname;
|
||||
int retval;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
|
||||
card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
|
||||
|
||||
if (!card) {
|
||||
printk(KERN_WARNING "%s: no memory.\n", driver->name);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(card, 0, sizeof(avmcard));
|
||||
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
|
||||
if (!cinfo) {
|
||||
printk(KERN_WARNING "%s: no memory.\n", driver->name);
|
||||
kfree(card);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(cinfo, 0, sizeof(avmctrl_info));
|
||||
card->ctrlinfo = cinfo;
|
||||
cinfo->card = card;
|
||||
switch (cardtype) {
|
||||
case avm_m1: sprintf(card->name, "m1-%x", port); break;
|
||||
case avm_m2: sprintf(card->name, "m2-%x", port); break;
|
||||
default: sprintf(card->name, "b1pcmcia-%x", port); break;
|
||||
}
|
||||
card->port = port;
|
||||
card->irq = irq;
|
||||
card->cardtype = cardtype;
|
||||
|
||||
b1_reset(card->port);
|
||||
if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
|
||||
printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
|
||||
driver->name, card->port, retval);
|
||||
kfree(card->ctrlinfo);
|
||||
kfree(card);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -EIO;
|
||||
}
|
||||
b1_reset(card->port);
|
||||
b1_getrevision(card);
|
||||
|
||||
retval = request_irq(card->irq, b1pcmcia_interrupt, 0, card->name, card);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "%s: unable to get IRQ %d.\n",
|
||||
driver->name, card->irq);
|
||||
kfree(card->ctrlinfo);
|
||||
kfree(card);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
|
||||
if (!cinfo->capi_ctrl) {
|
||||
printk(KERN_ERR "%s: attach controller failed.\n",
|
||||
driver->name);
|
||||
free_irq(card->irq, card);
|
||||
kfree(card->ctrlinfo);
|
||||
kfree(card);
|
||||
MOD_DEC_USE_COUNT;
|
||||
return -EBUSY;
|
||||
}
|
||||
switch (cardtype) {
|
||||
case avm_m1: cardname = "M1"; break;
|
||||
case avm_m2: cardname = "M2"; break;
|
||||
default : cardname = "B1 PCMCIA"; break;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
"%s: AVM %s at i/o %#x, irq %d, revision %d\n",
|
||||
driver->name, cardname, card->port, card->irq, card->revision);
|
||||
|
||||
return cinfo->capi_ctrl->cnr;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
|
||||
{
|
||||
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
|
||||
|
||||
if (!cinfo)
|
||||
return "";
|
||||
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
|
||||
cinfo->cardname[0] ? cinfo->cardname : "-",
|
||||
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
|
||||
cinfo->card ? cinfo->card->port : 0x0,
|
||||
cinfo->card ? cinfo->card->irq : 0,
|
||||
cinfo->card ? cinfo->card->revision : 0
|
||||
);
|
||||
return cinfo->infobuf;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static struct capi_driver b1pcmcia_driver = {
|
||||
"b1pcmcia",
|
||||
"0.0",
|
||||
b1_load_firmware,
|
||||
b1_reset_ctr,
|
||||
b1pcmcia_remove_ctr,
|
||||
b1_register_appl,
|
||||
b1_release_appl,
|
||||
b1_send_message,
|
||||
|
||||
b1pcmcia_procinfo,
|
||||
b1ctl_read_proc,
|
||||
0, /* use standard driver_read_proc */
|
||||
|
||||
0,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
int b1pcmcia_addcard_b1(unsigned int port, unsigned irq)
|
||||
{
|
||||
return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_b1pcmcia);
|
||||
}
|
||||
|
||||
int b1pcmcia_addcard_m1(unsigned int port, unsigned irq)
|
||||
{
|
||||
return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m1);
|
||||
}
|
||||
|
||||
int b1pcmcia_addcard_m2(unsigned int port, unsigned irq)
|
||||
{
|
||||
return b1pcmcia_add_card(&b1pcmcia_driver, port, irq, avm_m2);
|
||||
}
|
||||
|
||||
int b1pcmcia_delcard(unsigned int port, unsigned irq)
|
||||
{
|
||||
struct capi_ctr *ctrl;
|
||||
avmcard *card;
|
||||
|
||||
for (ctrl = b1pcmcia_driver.controller; ctrl; ctrl = ctrl->next) {
|
||||
card = ((avmctrl_info *)(ctrl->driverdata))->card;
|
||||
if (card->port == port && card->irq == irq) {
|
||||
b1pcmcia_remove_ctr(ctrl);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(b1pcmcia_addcard_b1);
|
||||
EXPORT_SYMBOL(b1pcmcia_addcard_m1);
|
||||
EXPORT_SYMBOL(b1pcmcia_addcard_m2);
|
||||
EXPORT_SYMBOL(b1pcmcia_delcard);
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
#ifdef MODULE
|
||||
#define b1pcmcia_init init_module
|
||||
void cleanup_module(void);
|
||||
#endif
|
||||
|
||||
int b1pcmcia_init(void)
|
||||
{
|
||||
struct capi_driver *driver = &b1pcmcia_driver;
|
||||
char *p;
|
||||
|
||||
if ((p = strchr(revision, ':'))) {
|
||||
strncpy(driver->revision, p + 1, sizeof(driver->revision));
|
||||
p = strchr(driver->revision, '$');
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
|
||||
|
||||
di = attach_capi_driver(driver);
|
||||
|
||||
if (!di) {
|
||||
printk(KERN_ERR "%s: failed to attach capi_driver\n",
|
||||
driver->name);
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
void cleanup_module(void)
|
||||
{
|
||||
detach_capi_driver(&b1pcmcia_driver);
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* CAPI 2.0 Interface for Linux
|
||||
*
|
||||
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.2 2000/03/03 15:50:42 calle
|
||||
* - kernel CAPI:
|
||||
* - Changed parameter "param" in capi_signal from __u32 to void *.
|
||||
* - rewrote notifier handling in kcapi.c
|
||||
* - new notifier NCCI_UP and NCCI_DOWN
|
||||
* - User CAPI:
|
||||
* - /dev/capi20 is now a cloning device.
|
||||
* - middleware extentions prepared.
|
||||
* - capidrv.c
|
||||
* - locking of list operations and module count updates.
|
||||
*
|
||||
* Revision 1.1 1997/03/04 21:50:30 calle
|
||||
* Frirst version in isdn4linux
|
||||
*
|
||||
* Revision 2.2 1997/02/12 09:31:39 calle
|
||||
* new version
|
||||
*
|
||||
* Revision 1.1 1997/01/31 10:32:20 calle
|
||||
* Initial revision
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef __CAPICMD_H__
|
||||
#define __CAPICMD_H__
|
||||
|
||||
#define CAPI_MSG_BASELEN 8
|
||||
#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2)
|
||||
#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2)
|
||||
|
||||
/*----- CAPI commands -----*/
|
||||
#define CAPI_ALERT 0x01
|
||||
#define CAPI_CONNECT 0x02
|
||||
#define CAPI_CONNECT_ACTIVE 0x03
|
||||
#define CAPI_CONNECT_B3_ACTIVE 0x83
|
||||
#define CAPI_CONNECT_B3 0x82
|
||||
#define CAPI_CONNECT_B3_T90_ACTIVE 0x88
|
||||
#define CAPI_DATA_B3 0x86
|
||||
#define CAPI_DISCONNECT_B3 0x84
|
||||
#define CAPI_DISCONNECT 0x04
|
||||
#define CAPI_FACILITY 0x80
|
||||
#define CAPI_INFO 0x08
|
||||
#define CAPI_LISTEN 0x05
|
||||
#define CAPI_MANUFACTURER 0xff
|
||||
#define CAPI_RESET_B3 0x87
|
||||
#define CAPI_SELECT_B_PROTOCOL 0x41
|
||||
|
||||
/*----- CAPI subcommands -----*/
|
||||
|
||||
#define CAPI_REQ 0x80
|
||||
#define CAPI_CONF 0x81
|
||||
#define CAPI_IND 0x82
|
||||
#define CAPI_RESP 0x83
|
||||
|
||||
/*----- CAPI combined commands -----*/
|
||||
|
||||
#define CAPICMD(cmd,subcmd) (((cmd)<<8)|(subcmd))
|
||||
|
||||
#define CAPI_DISCONNECT_REQ CAPICMD(CAPI_DISCONNECT,CAPI_REQ)
|
||||
#define CAPI_DISCONNECT_CONF CAPICMD(CAPI_DISCONNECT,CAPI_CONF)
|
||||
#define CAPI_DISCONNECT_IND CAPICMD(CAPI_DISCONNECT,CAPI_IND)
|
||||
#define CAPI_DISCONNECT_RESP CAPICMD(CAPI_DISCONNECT,CAPI_RESP)
|
||||
|
||||
#define CAPI_ALERT_REQ CAPICMD(CAPI_ALERT,CAPI_REQ)
|
||||
#define CAPI_ALERT_CONF CAPICMD(CAPI_ALERT,CAPI_CONF)
|
||||
|
||||
#define CAPI_CONNECT_REQ CAPICMD(CAPI_CONNECT,CAPI_REQ)
|
||||
#define CAPI_CONNECT_CONF CAPICMD(CAPI_CONNECT,CAPI_CONF)
|
||||
#define CAPI_CONNECT_IND CAPICMD(CAPI_CONNECT,CAPI_IND)
|
||||
#define CAPI_CONNECT_RESP CAPICMD(CAPI_CONNECT,CAPI_RESP)
|
||||
|
||||
#define CAPI_CONNECT_ACTIVE_REQ CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ)
|
||||
#define CAPI_CONNECT_ACTIVE_CONF CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF)
|
||||
#define CAPI_CONNECT_ACTIVE_IND CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND)
|
||||
#define CAPI_CONNECT_ACTIVE_RESP CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP)
|
||||
|
||||
#define CAPI_SELECT_B_PROTOCOL_REQ CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ)
|
||||
#define CAPI_SELECT_B_PROTOCOL_CONF CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF)
|
||||
|
||||
#define CAPI_CONNECT_B3_ACTIVE_REQ CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ)
|
||||
#define CAPI_CONNECT_B3_ACTIVE_CONF CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF)
|
||||
#define CAPI_CONNECT_B3_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND)
|
||||
#define CAPI_CONNECT_B3_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP)
|
||||
|
||||
#define CAPI_CONNECT_B3_REQ CAPICMD(CAPI_CONNECT_B3,CAPI_REQ)
|
||||
#define CAPI_CONNECT_B3_CONF CAPICMD(CAPI_CONNECT_B3,CAPI_CONF)
|
||||
#define CAPI_CONNECT_B3_IND CAPICMD(CAPI_CONNECT_B3,CAPI_IND)
|
||||
#define CAPI_CONNECT_B3_RESP CAPICMD(CAPI_CONNECT_B3,CAPI_RESP)
|
||||
|
||||
|
||||
#define CAPI_CONNECT_B3_T90_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND)
|
||||
#define CAPI_CONNECT_B3_T90_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP)
|
||||
|
||||
#define CAPI_DATA_B3_REQ CAPICMD(CAPI_DATA_B3,CAPI_REQ)
|
||||
#define CAPI_DATA_B3_CONF CAPICMD(CAPI_DATA_B3,CAPI_CONF)
|
||||
#define CAPI_DATA_B3_IND CAPICMD(CAPI_DATA_B3,CAPI_IND)
|
||||
#define CAPI_DATA_B3_RESP CAPICMD(CAPI_DATA_B3,CAPI_RESP)
|
||||
|
||||
#define CAPI_DISCONNECT_B3_REQ CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ)
|
||||
#define CAPI_DISCONNECT_B3_CONF CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF)
|
||||
#define CAPI_DISCONNECT_B3_IND CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND)
|
||||
#define CAPI_DISCONNECT_B3_RESP CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP)
|
||||
|
||||
#define CAPI_RESET_B3_REQ CAPICMD(CAPI_RESET_B3,CAPI_REQ)
|
||||
#define CAPI_RESET_B3_CONF CAPICMD(CAPI_RESET_B3,CAPI_CONF)
|
||||
#define CAPI_RESET_B3_IND CAPICMD(CAPI_RESET_B3,CAPI_IND)
|
||||
#define CAPI_RESET_B3_RESP CAPICMD(CAPI_RESET_B3,CAPI_RESP)
|
||||
|
||||
#define CAPI_LISTEN_REQ CAPICMD(CAPI_LISTEN,CAPI_REQ)
|
||||
#define CAPI_LISTEN_CONF CAPICMD(CAPI_LISTEN,CAPI_CONF)
|
||||
|
||||
#define CAPI_MANUFACTURER_REQ CAPICMD(CAPI_MANUFACTURER,CAPI_REQ)
|
||||
#define CAPI_MANUFACTURER_CONF CAPICMD(CAPI_MANUFACTURER,CAPI_CONF)
|
||||
#define CAPI_MANUFACTURER_IND CAPICMD(CAPI_MANUFACTURER,CAPI_IND)
|
||||
#define CAPI_MANUFACTURER_RESP CAPICMD(CAPI_MANUFACTURER,CAPI_RESP)
|
||||
|
||||
#define CAPI_FACILITY_REQ CAPICMD(CAPI_FACILITY,CAPI_REQ)
|
||||
#define CAPI_FACILITY_CONF CAPICMD(CAPI_FACILITY,CAPI_CONF)
|
||||
#define CAPI_FACILITY_IND CAPICMD(CAPI_FACILITY,CAPI_IND)
|
||||
#define CAPI_FACILITY_RESP CAPICMD(CAPI_FACILITY,CAPI_RESP)
|
||||
|
||||
#define CAPI_INFO_REQ CAPICMD(CAPI_INFO,CAPI_REQ)
|
||||
#define CAPI_INFO_CONF CAPICMD(CAPI_INFO,CAPI_CONF)
|
||||
#define CAPI_INFO_IND CAPICMD(CAPI_INFO,CAPI_IND)
|
||||
#define CAPI_INFO_RESP CAPICMD(CAPI_INFO,CAPI_RESP)
|
||||
|
||||
#endif /* __CAPICMD_H__ */
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* CAPI 2.0 Interface for Linux
|
||||
*
|
||||
* (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.5 2000/03/03 15:50:42 calle
|
||||
* - kernel CAPI:
|
||||
* - Changed parameter "param" in capi_signal from __u32 to void *.
|
||||
* - rewrote notifier handling in kcapi.c
|
||||
* - new notifier NCCI_UP and NCCI_DOWN
|
||||
* - User CAPI:
|
||||
* - /dev/capi20 is now a cloning device.
|
||||
* - middleware extentions prepared.
|
||||
* - capidrv.c
|
||||
* - locking of list operations and module count updates.
|
||||
*
|
||||
* Revision 1.4 1999/07/01 15:26:32 calle
|
||||
* complete new version (I love it):
|
||||
* + new hardware independed "capi_driver" interface that will make it easy to:
|
||||
* - support other controllers with CAPI-2.0 (i.e. USB Controller)
|
||||
* - write a CAPI-2.0 for the passive cards
|
||||
* - support serial link CAPI-2.0 boxes.
|
||||
* + wrote "capi_driver" for all supported cards.
|
||||
* + "capi_driver" (supported cards) now have to be configured with
|
||||
* make menuconfig, in the past all supported cards where included
|
||||
* at once.
|
||||
* + new and better informations in /proc/capi/
|
||||
* + new ioctl to switch trace of capi messages per controller
|
||||
* using "avmcapictrl trace [contr] on|off|...."
|
||||
* + complete testcircle with all supported cards and also the
|
||||
* PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
|
||||
*
|
||||
* Revision 1.3 1999/07/01 08:22:58 keil
|
||||
* compatibility macros now in <linux/isdn_compat.h>
|
||||
*
|
||||
* Revision 1.2 1999/06/21 15:24:13 calle
|
||||
* extend information in /proc.
|
||||
*
|
||||
* Revision 1.1 1997/03/04 21:50:30 calle
|
||||
* Frirst version in isdn4linux
|
||||
*
|
||||
* Revision 2.2 1997/02/12 09:31:39 calle
|
||||
* new version
|
||||
*
|
||||
* Revision 1.1 1997/01/31 10:32:20 calle
|
||||
* Initial revision
|
||||
*
|
||||
*/
|
||||
|
||||
struct capidev {
|
||||
struct capidev *next;
|
||||
struct file *file;
|
||||
__u16 applid;
|
||||
__u16 errcode;
|
||||
unsigned int minor;
|
||||
|
||||
struct sk_buff_head recv_queue;
|
||||
#ifdef COMPAT_HAS_NEW_WAITQ
|
||||
wait_queue_head_t recv_wait;
|
||||
#else
|
||||
struct wait_queue *recv_wait;
|
||||
#endif
|
||||
|
||||
/* Statistic */
|
||||
unsigned long nrecvctlpkt;
|
||||
unsigned long nrecvdatapkt;
|
||||
unsigned long nsentctlpkt;
|
||||
unsigned long nsentdatapkt;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -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,603 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
|
||||
*
|
||||
* Heavily based on devpts filesystem from H. Peter Anvin
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.4 2000/03/08 17:06:33 calle
|
||||
* - changes for devfs and 2.3.49
|
||||
* - capifs now configurable (no need with devfs)
|
||||
* - New Middleware ioctl CAPI_NCCI_GETUNIT
|
||||
* - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
|
||||
*
|
||||
* Revision 1.3 2000/03/06 18:00:23 calle
|
||||
* - Middleware extention now working with 2.3.49 (capifs).
|
||||
* - Fixed typos in debug section of capi.c
|
||||
* - Bugfix: Makefile corrected for b1pcmcia.c
|
||||
*
|
||||
* Revision 1.2 2000/03/06 09:17:07 calle
|
||||
* - capifs: fileoperations now in inode (change for 2.3.49)
|
||||
* - Config.in: Middleware extention not a tristate, uups.
|
||||
*
|
||||
* Revision 1.1 2000/03/03 16:48:38 calle
|
||||
* - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
|
||||
* It is now possible to create a connection with a CAPI2.0 applikation
|
||||
* and than to handle the data connection from /dev/capi/ (capifs) and also
|
||||
* using async or sync PPP on this connection.
|
||||
* The two major device number 190 and 191 are not confirmed yet,
|
||||
* but I want to save the code in cvs, before I go on.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/locks.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/malloc.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
|
||||
|
||||
static char *revision = "$Revision$";
|
||||
|
||||
struct capifs_ncci {
|
||||
struct inode *inode;
|
||||
char used;
|
||||
char type;
|
||||
unsigned int num;
|
||||
kdev_t kdev;
|
||||
};
|
||||
|
||||
struct capifs_sb_info {
|
||||
u32 magic;
|
||||
struct super_block *next;
|
||||
struct super_block **back;
|
||||
int setuid;
|
||||
int setgid;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
umode_t mode;
|
||||
|
||||
unsigned int max_ncci;
|
||||
struct capifs_ncci *nccis;
|
||||
};
|
||||
|
||||
#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
|
||||
#define CAPIFS_SBI_MAGIC (('C'<<24)|('A'<<16)|('P'<<8)|'I')
|
||||
|
||||
static inline struct capifs_sb_info *SBI(struct super_block *sb)
|
||||
{
|
||||
return (struct capifs_sb_info *)(sb->u.generic_sbp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int capifs_root_readdir(struct file *,void *,filldir_t);
|
||||
static struct dentry *capifs_root_lookup(struct inode *,struct dentry *);
|
||||
static int capifs_revalidate(struct dentry *, int);
|
||||
|
||||
static struct file_operations capifs_root_operations = {
|
||||
#ifdef COMPAT_has_generic_read_dir
|
||||
read: generic_read_dir,
|
||||
#endif
|
||||
readdir: capifs_root_readdir,
|
||||
};
|
||||
|
||||
struct inode_operations capifs_root_inode_operations = {
|
||||
#ifndef COMPAT_has_fileops_in_inode
|
||||
&capifs_root_operations, /* file operations */
|
||||
#endif
|
||||
lookup: capifs_root_lookup,
|
||||
};
|
||||
|
||||
struct inode_operations capifs_inode_operations;
|
||||
|
||||
static struct dentry_operations capifs_dentry_operations = {
|
||||
capifs_revalidate, /* d_revalidate */
|
||||
NULL, /* d_hash */
|
||||
NULL, /* d_compare */
|
||||
};
|
||||
|
||||
/*
|
||||
* /dev/capi/%d
|
||||
* /dev/capi/r%d
|
||||
*/
|
||||
|
||||
static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
{
|
||||
struct inode * inode = filp->f_dentry->d_inode;
|
||||
struct capifs_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb);
|
||||
off_t nr;
|
||||
char numbuf[32];
|
||||
|
||||
nr = filp->f_pos;
|
||||
|
||||
switch(nr)
|
||||
{
|
||||
case 0:
|
||||
if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
|
||||
return 0;
|
||||
filp->f_pos = ++nr;
|
||||
/* fall through */
|
||||
case 1:
|
||||
if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
|
||||
return 0;
|
||||
filp->f_pos = ++nr;
|
||||
/* fall through */
|
||||
default:
|
||||
while (nr < sbi->max_ncci) {
|
||||
int n = nr - 2;
|
||||
struct capifs_ncci *np = &sbi->nccis[n];
|
||||
if (np->inode && np->used) {
|
||||
char *p = numbuf;
|
||||
if (np->type) *p++ = np->type;
|
||||
sprintf(p, "%u", np->num);
|
||||
if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
|
||||
return 0;
|
||||
}
|
||||
filp->f_pos = ++nr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Revalidate is called on every cache lookup. We use it to check that
|
||||
* the ncci really does still exist. Never revalidate negative dentries;
|
||||
* for simplicity (fix later?)
|
||||
*/
|
||||
static int capifs_revalidate(struct dentry * dentry, int flags)
|
||||
{
|
||||
struct capifs_sb_info *sbi;
|
||||
|
||||
if ( !dentry->d_inode )
|
||||
return 0;
|
||||
|
||||
sbi = SBI(dentry->d_inode->i_sb);
|
||||
|
||||
return ( sbi->nccis[dentry->d_inode->i_ino - 2].inode == dentry->d_inode );
|
||||
}
|
||||
|
||||
static struct dentry *capifs_root_lookup(struct inode * dir, struct dentry * dentry)
|
||||
{
|
||||
struct capifs_sb_info *sbi = SBI(dir->i_sb);
|
||||
struct capifs_ncci *np;
|
||||
unsigned int i;
|
||||
char numbuf[32];
|
||||
char *p, *tmp;
|
||||
unsigned int num;
|
||||
char type = 0;
|
||||
|
||||
dentry->d_inode = NULL; /* Assume failure */
|
||||
dentry->d_op = &capifs_dentry_operations;
|
||||
|
||||
if (dentry->d_name.len >= sizeof(numbuf) )
|
||||
return NULL;
|
||||
strncpy(numbuf, dentry->d_name.name, dentry->d_name.len);
|
||||
numbuf[dentry->d_name.len] = 0;
|
||||
p = numbuf;
|
||||
if (!isdigit(*p)) type = *p++;
|
||||
tmp = p;
|
||||
num = (unsigned int)simple_strtoul(p, &tmp, 10);
|
||||
if (tmp == p || *tmp)
|
||||
return NULL;
|
||||
|
||||
for (i = 0, np = sbi->nccis ; i < sbi->max_ncci; i++, np++) {
|
||||
if (np->used && np->num == num && np->type == type)
|
||||
break;
|
||||
}
|
||||
|
||||
if ( i >= sbi->max_ncci )
|
||||
return NULL;
|
||||
|
||||
dentry->d_inode = np->inode;
|
||||
if ( dentry->d_inode )
|
||||
dentry->d_inode->i_count++;
|
||||
|
||||
d_add(dentry, dentry->d_inode);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static struct super_block *mounts = NULL;
|
||||
|
||||
static void capifs_put_super(struct super_block *sb)
|
||||
{
|
||||
struct capifs_sb_info *sbi = SBI(sb);
|
||||
struct inode *inode;
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < sbi->max_ncci ; i++ ) {
|
||||
if ( (inode = sbi->nccis[i].inode) ) {
|
||||
if ( inode->i_count != 1 )
|
||||
printk("capifs_put_super: badness: entry %d count %d\n",
|
||||
i, inode->i_count);
|
||||
inode->i_nlink--;
|
||||
iput(inode);
|
||||
}
|
||||
}
|
||||
|
||||
*sbi->back = sbi->next;
|
||||
if ( sbi->next )
|
||||
SBI(sbi->next)->back = sbi->back;
|
||||
|
||||
kfree(sbi->nccis);
|
||||
kfree(sbi);
|
||||
|
||||
MOD_DEC_USE_COUNT;
|
||||
}
|
||||
|
||||
static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
|
||||
static void capifs_read_inode(struct inode *inode);
|
||||
static void capifs_write_inode(struct inode *inode);
|
||||
|
||||
static struct super_operations capifs_sops = {
|
||||
read_inode: capifs_read_inode,
|
||||
write_inode: capifs_write_inode,
|
||||
put_super: capifs_put_super,
|
||||
statfs: capifs_statfs,
|
||||
};
|
||||
|
||||
static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
|
||||
{
|
||||
int setuid = 0;
|
||||
int setgid = 0;
|
||||
uid_t uid = 0;
|
||||
gid_t gid = 0;
|
||||
umode_t mode = 0600;
|
||||
unsigned int maxncci = 512;
|
||||
char *this_char, *value;
|
||||
|
||||
this_char = NULL;
|
||||
if ( options )
|
||||
this_char = strtok(options,",");
|
||||
for ( ; this_char; this_char = strtok(NULL,",")) {
|
||||
if ((value = strchr(this_char,'=')) != NULL)
|
||||
*value++ = 0;
|
||||
if (!strcmp(this_char,"uid")) {
|
||||
if (!value || !*value)
|
||||
return 1;
|
||||
uid = simple_strtoul(value,&value,0);
|
||||
if (*value)
|
||||
return 1;
|
||||
setuid = 1;
|
||||
}
|
||||
else if (!strcmp(this_char,"gid")) {
|
||||
if (!value || !*value)
|
||||
return 1;
|
||||
gid = simple_strtoul(value,&value,0);
|
||||
if (*value)
|
||||
return 1;
|
||||
setgid = 1;
|
||||
}
|
||||
else if (!strcmp(this_char,"mode")) {
|
||||
if (!value || !*value)
|
||||
return 1;
|
||||
mode = simple_strtoul(value,&value,8);
|
||||
if (*value)
|
||||
return 1;
|
||||
}
|
||||
else if (!strcmp(this_char,"maxncci")) {
|
||||
if (!value || !*value)
|
||||
return 1;
|
||||
maxncci = simple_strtoul(value,&value,8);
|
||||
if (*value)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
sbi->setuid = setuid;
|
||||
sbi->setgid = setgid;
|
||||
sbi->uid = uid;
|
||||
sbi->gid = gid;
|
||||
sbi->mode = mode & ~S_IFMT;
|
||||
sbi->max_ncci = maxncci;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct super_block *capifs_read_super(struct super_block *s, void *data,
|
||||
int silent)
|
||||
{
|
||||
struct inode * root_inode;
|
||||
struct dentry * root;
|
||||
struct capifs_sb_info *sbi;
|
||||
|
||||
MOD_INC_USE_COUNT;
|
||||
|
||||
lock_super(s);
|
||||
/* Super block already completed? */
|
||||
if (s->s_root) {
|
||||
unlock_super(s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sbi = (struct capifs_sb_info *) kmalloc(sizeof(struct capifs_sb_info), GFP_KERNEL);
|
||||
if ( !sbi ) {
|
||||
unlock_super(s);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memset(sbi, 0, sizeof(struct capifs_sb_info));
|
||||
sbi->magic = CAPIFS_SBI_MAGIC;
|
||||
|
||||
/* Can this call block? (It shouldn't) */
|
||||
if ( capifs_parse_options(data,sbi) ) {
|
||||
kfree(sbi);
|
||||
unlock_super(s);
|
||||
printk("capifs: called with bogus options\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sbi->nccis = kmalloc(sizeof(struct capifs_ncci) * sbi->max_ncci, GFP_KERNEL);
|
||||
if ( !sbi->nccis ) {
|
||||
kfree(sbi);
|
||||
unlock_super(s);
|
||||
goto fail;
|
||||
}
|
||||
memset(sbi->nccis, 0, sizeof(struct capifs_ncci) * sbi->max_ncci);
|
||||
|
||||
s->u.generic_sbp = (void *) sbi;
|
||||
s->s_blocksize = 1024;
|
||||
s->s_blocksize_bits = 10;
|
||||
s->s_magic = CAPIFS_SUPER_MAGIC;
|
||||
s->s_op = &capifs_sops;
|
||||
s->s_root = NULL;
|
||||
unlock_super(s); /* shouldn't we keep it locked a while longer? */
|
||||
|
||||
/*
|
||||
* Get the root inode and dentry, but defer checking for errors.
|
||||
*/
|
||||
root_inode = iget(s, 1); /* inode 1 == root directory */
|
||||
#ifdef COMPAT_d_alloc_root_one_parameter
|
||||
root = d_alloc_root(root_inode);
|
||||
#else
|
||||
root = d_alloc_root(root_inode, NULL);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check whether somebody else completed the super block.
|
||||
*/
|
||||
if (s->s_root) {
|
||||
if (root) dput(root);
|
||||
else iput(root_inode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
printk("capifs: get root dentry failed\n");
|
||||
/*
|
||||
* iput() can block, so we clear the super block first.
|
||||
*/
|
||||
s->s_dev = 0;
|
||||
iput(root_inode);
|
||||
kfree(sbi->nccis);
|
||||
kfree(sbi);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether somebody else completed the super block.
|
||||
*/
|
||||
if (s->s_root)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Success! Install the root dentry now to indicate completion.
|
||||
*/
|
||||
lock_super(s);
|
||||
s->s_root = root;
|
||||
|
||||
sbi->next = mounts;
|
||||
if ( sbi->next )
|
||||
SBI(sbi->next)->back = &(sbi->next);
|
||||
sbi->back = &mounts;
|
||||
mounts = s;
|
||||
|
||||
unlock_super(s);
|
||||
return s;
|
||||
|
||||
/*
|
||||
* Success ... somebody else completed the super block for us.
|
||||
*/
|
||||
out:
|
||||
MOD_DEC_USE_COUNT;
|
||||
return s;
|
||||
fail:
|
||||
s->s_dev = 0;
|
||||
MOD_DEC_USE_COUNT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
|
||||
{
|
||||
struct statfs tmp;
|
||||
|
||||
tmp.f_type = CAPIFS_SUPER_MAGIC;
|
||||
tmp.f_bsize = 1024;
|
||||
tmp.f_blocks = 0;
|
||||
tmp.f_bfree = 0;
|
||||
tmp.f_bavail = 0;
|
||||
tmp.f_files = 0;
|
||||
tmp.f_ffree = 0;
|
||||
tmp.f_namelen = NAME_MAX;
|
||||
return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static void capifs_read_inode(struct inode *inode)
|
||||
{
|
||||
ino_t ino = inode->i_ino;
|
||||
struct capifs_sb_info *sbi = SBI(inode->i_sb);
|
||||
|
||||
inode->i_op = NULL;
|
||||
inode->i_mode = 0;
|
||||
inode->i_nlink = 0;
|
||||
inode->i_size = 0;
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
||||
inode->i_blocks = 0;
|
||||
inode->i_blksize = 1024;
|
||||
inode->i_uid = inode->i_gid = 0;
|
||||
|
||||
if ( ino == 1 ) {
|
||||
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
|
||||
inode->i_op = &capifs_root_inode_operations;
|
||||
#ifdef COMPAT_has_fileops_in_inode
|
||||
inode->i_fop = &capifs_root_operations;
|
||||
#endif
|
||||
inode->i_nlink = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef COMPAT_has_fileops_in_inode
|
||||
/* need dummy inode operations .... */
|
||||
inode->i_op = &capifs_inode_operations;
|
||||
#endif
|
||||
|
||||
ino -= 2;
|
||||
if ( ino >= sbi->max_ncci )
|
||||
return; /* Bogus */
|
||||
|
||||
#ifdef COMPAT_HAS_init_special_inode
|
||||
init_special_inode(inode, S_IFCHR, 0);
|
||||
#else
|
||||
inode->i_mode = S_IFCHR;
|
||||
inode->i_op = &chrdev_inode_operations;
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void capifs_write_inode(struct inode *inode)
|
||||
{
|
||||
}
|
||||
|
||||
static struct file_system_type capifs_fs_type = {
|
||||
"capifs",
|
||||
0,
|
||||
capifs_read_super,
|
||||
NULL
|
||||
};
|
||||
|
||||
void capifs_new_ncci(char type, unsigned int num, kdev_t device)
|
||||
{
|
||||
struct super_block *sb;
|
||||
struct capifs_sb_info *sbi;
|
||||
struct capifs_ncci *np;
|
||||
ino_t ino;
|
||||
|
||||
for ( sb = mounts ; sb ; sb = sbi->next ) {
|
||||
sbi = SBI(sb);
|
||||
|
||||
for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
|
||||
if (np->used == 0) {
|
||||
np->used = 1;
|
||||
np->type = type;
|
||||
np->num = num;
|
||||
np->kdev = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((np->inode = iget(sb, ino+2)) != 0) {
|
||||
struct inode *inode = np->inode;
|
||||
inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
|
||||
inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
|
||||
inode->i_mode = sbi->mode | S_IFCHR;
|
||||
inode->i_rdev = np->kdev;
|
||||
inode->i_nlink++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void capifs_free_ncci(char type, unsigned int num)
|
||||
{
|
||||
struct super_block *sb;
|
||||
struct capifs_sb_info *sbi;
|
||||
struct inode *inode;
|
||||
struct capifs_ncci *np;
|
||||
ino_t ino;
|
||||
|
||||
for ( sb = mounts ; sb ; sb = sbi->next ) {
|
||||
sbi = SBI(sb);
|
||||
|
||||
for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
|
||||
if (!np->used || np->type != type || np->num != num)
|
||||
continue;
|
||||
if (np->inode) {
|
||||
inode = np->inode;
|
||||
np->used = 0;
|
||||
inode->i_nlink--;
|
||||
iput(inode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __init capifs_init(void)
|
||||
{
|
||||
char rev[10];
|
||||
char *p;
|
||||
int err;
|
||||
|
||||
if ((p = strchr(revision, ':'))) {
|
||||
strcpy(rev, p + 1);
|
||||
p = strchr(rev, '$');
|
||||
*p = 0;
|
||||
} else
|
||||
strcpy(rev, "1.0");
|
||||
|
||||
err = register_filesystem(&capifs_fs_type);
|
||||
if (err)
|
||||
return err;
|
||||
#ifdef MODULE
|
||||
printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev);
|
||||
#else
|
||||
printk(KERN_NOTICE "capifs: Rev%s: started\n", rev);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void capifs_exit(void)
|
||||
{
|
||||
unregister_filesystem(&capifs_fs_type);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(capifs_new_ncci);
|
||||
EXPORT_SYMBOL(capifs_free_ncci);
|
||||
|
||||
#ifdef MODULE
|
||||
|
||||
int init_module(void)
|
||||
{
|
||||
return capifs_init();
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
{
|
||||
capifs_exit();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.2 2000/03/08 17:06:33 calle
|
||||
* - changes for devfs and 2.3.49
|
||||
* - capifs now configurable (no need with devfs)
|
||||
* - New Middleware ioctl CAPI_NCCI_GETUNIT
|
||||
* - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
|
||||
*
|
||||
* Revision 1.1 2000/03/03 16:48:38 calle
|
||||
* - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
|
||||
* It is now possible to create a connection with a CAPI2.0 applikation
|
||||
* and than to handle the data connection from /dev/capi/ (capifs) and also
|
||||
* using async or sync PPP on this connection.
|
||||
* The two major device number 190 and 191 are not confirmed yet,
|
||||
* but I want to save the code in cvs, before I go on.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
void capifs_new_ncci(char type, unsigned int num, kdev_t device);
|
||||
void capifs_free_ncci(char type, unsigned int num);
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Kernel CAPI 2.0 Driver Interface for Linux
|
||||
*
|
||||
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
*/
|
||||
#ifndef __CAPILLI_H__
|
||||
#define __CAPILLI_H__
|
||||
|
||||
typedef struct capiloaddatapart {
|
||||
int user; /* data in userspace ? */
|
||||
int len;
|
||||
unsigned char *data;
|
||||
} capiloaddatapart;
|
||||
|
||||
typedef struct capiloaddata {
|
||||
capiloaddatapart firmware;
|
||||
capiloaddatapart configuration;
|
||||
} capiloaddata;
|
||||
|
||||
typedef struct capicardparams {
|
||||
unsigned int port;
|
||||
unsigned irq;
|
||||
int cardtype;
|
||||
int cardnr;
|
||||
unsigned int membase;
|
||||
} capicardparams;
|
||||
|
||||
struct capi_driver;
|
||||
|
||||
struct capi_ctr {
|
||||
struct capi_ctr *next; /* next ctr of same driver */
|
||||
struct capi_driver *driver;
|
||||
int cnr; /* controller number */
|
||||
char name[32]; /* name of controller */
|
||||
volatile unsigned short cardstate; /* controller state */
|
||||
volatile int blocked; /* output blocked */
|
||||
int traceflag; /* capi trace */
|
||||
|
||||
void *driverdata; /* driver specific */
|
||||
|
||||
/* filled before calling ready callback */
|
||||
__u8 manu[CAPI_MANUFACTURER_LEN]; /* CAPI_GET_MANUFACTURER */
|
||||
capi_version version; /* CAPI_GET_VERSION */
|
||||
capi_profile profile; /* CAPI_GET_PROFILE */
|
||||
__u8 serial[CAPI_SERIAL_LEN]; /* CAPI_GET_SERIAL */
|
||||
|
||||
/* functions */
|
||||
void (*ready)(struct capi_ctr * card);
|
||||
void (*reseted)(struct capi_ctr * card);
|
||||
void (*suspend_output)(struct capi_ctr * card);
|
||||
void (*resume_output)(struct capi_ctr * card);
|
||||
void (*handle_capimsg)(struct capi_ctr * card,
|
||||
__u16 appl, struct sk_buff *skb);
|
||||
void (*appl_registered)(struct capi_ctr * card, __u16 appl);
|
||||
void (*appl_released)(struct capi_ctr * card, __u16 appl);
|
||||
|
||||
void (*new_ncci)(struct capi_ctr * card,
|
||||
__u16 appl, __u32 ncci, __u32 winsize);
|
||||
void (*free_ncci)(struct capi_ctr * card, __u16 appl, __u32 ncci);
|
||||
|
||||
/* management information for kcapi */
|
||||
|
||||
unsigned long nrecvctlpkt;
|
||||
unsigned long nrecvdatapkt;
|
||||
unsigned long nsentctlpkt;
|
||||
unsigned long nsentdatapkt;
|
||||
|
||||
struct proc_dir_entry *procent;
|
||||
char procfn[128];
|
||||
};
|
||||
|
||||
struct capi_driver_interface {
|
||||
struct capi_ctr *(*attach_ctr)(struct capi_driver *driver, char *name, void *data);
|
||||
int (*detach_ctr)(struct capi_ctr *);
|
||||
};
|
||||
|
||||
struct capi_driver {
|
||||
char name[32]; /* driver name */
|
||||
char revision[32];
|
||||
int (*load_firmware)(struct capi_ctr *, capiloaddata *);
|
||||
void (*reset_ctr)(struct capi_ctr *);
|
||||
void (*remove_ctr)(struct capi_ctr *);
|
||||
void (*register_appl)(struct capi_ctr *, __u16 appl,
|
||||
capi_register_params *);
|
||||
void (*release_appl)(struct capi_ctr *, __u16 appl);
|
||||
void (*send_message)(struct capi_ctr *, struct sk_buff *skb);
|
||||
|
||||
char *(*procinfo)(struct capi_ctr *);
|
||||
int (*ctr_read_proc)(char *page, char **start, off_t off,
|
||||
int count, int *eof, struct capi_ctr *card);
|
||||
int (*driver_read_proc)(char *page, char **start, off_t off,
|
||||
int count, int *eof, struct capi_driver *driver);
|
||||
|
||||
int (*add_card)(struct capi_driver *driver, capicardparams *data);
|
||||
|
||||
/* intitialized by kcapi */
|
||||
struct capi_ctr *controller; /* list of controllers */
|
||||
struct capi_driver *next;
|
||||
int ncontroller;
|
||||
struct proc_dir_entry *procent;
|
||||
char procfn[128];
|
||||
};
|
||||
|
||||
struct capi_driver_interface *attach_capi_driver(struct capi_driver *driver);
|
||||
void detach_capi_driver(struct capi_driver *driver);
|
||||
|
||||
#endif /* __CAPILLI_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,537 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* CAPI 2.0 defines & types
|
||||
*
|
||||
* From CAPI 2.0 Development Kit AVM 1995 (capi20.h)
|
||||
* Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.5 2000/03/03 15:50:42 calle
|
||||
* - kernel CAPI:
|
||||
* - Changed parameter "param" in capi_signal from __u32 to void *.
|
||||
* - rewrote notifier handling in kcapi.c
|
||||
* - new notifier NCCI_UP and NCCI_DOWN
|
||||
* - User CAPI:
|
||||
* - /dev/capi20 is now a cloning device.
|
||||
* - middleware extentions prepared.
|
||||
* - capidrv.c
|
||||
* - locking of list operations and module count updates.
|
||||
*
|
||||
* Revision 1.4 1999/09/15 08:16:03 calle
|
||||
* Implementation of 64Bit extention complete.
|
||||
*
|
||||
* Revision 1.3 1999/09/07 09:02:53 calle
|
||||
* SETDATA removed. Now inside the kernel the datapart of DATA_B3_REQ and
|
||||
* DATA_B3_IND is always directly after the CAPI message. The "Data" member
|
||||
* ist never used inside the kernel.
|
||||
*
|
||||
* Revision 1.2 1997/05/18 09:24:19 calle
|
||||
* added verbose disconnect reason reporting to avmb1.
|
||||
* some fixes in capi20 interface.
|
||||
* changed info messages for B1-PCI
|
||||
*
|
||||
* Revision 1.1 1997/03/04 21:50:35 calle
|
||||
* Frirst version in isdn4linux
|
||||
*
|
||||
* Revision 2.2 1997/02/12 09:31:39 calle
|
||||
* new version
|
||||
*
|
||||
* Revision 1.1 1997/01/31 10:32:20 calle
|
||||
* Initial revision
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef __CAPIUTIL_H__
|
||||
#define __CAPIUTIL_H__
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
#define CAPIMSG_BASELEN 8
|
||||
#define CAPIMSG_U8(m, off) (m[off])
|
||||
#define CAPIMSG_U16(m, off) (m[off]|(m[(off)+1]<<8))
|
||||
#define CAPIMSG_U32(m, off) (m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24))
|
||||
#define CAPIMSG_LEN(m) CAPIMSG_U16(m,0)
|
||||
#define CAPIMSG_APPID(m) CAPIMSG_U16(m,2)
|
||||
#define CAPIMSG_COMMAND(m) CAPIMSG_U8(m,4)
|
||||
#define CAPIMSG_SUBCOMMAND(m) CAPIMSG_U8(m,5)
|
||||
#define CAPIMSG_CMD(m) (((m[4])<<8)|(m[5]))
|
||||
#define CAPIMSG_MSGID(m) CAPIMSG_U16(m,6)
|
||||
#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f)
|
||||
#define CAPIMSG_CONTROL(m) CAPIMSG_U32(m, 8)
|
||||
#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m)
|
||||
#define CAPIMSG_DATALEN(m) CAPIMSG_U16(m,16) /* DATA_B3_REQ */
|
||||
|
||||
static inline void capimsg_setu8(void *m, int off, __u8 val)
|
||||
{
|
||||
((__u8 *)m)[off] = val;
|
||||
}
|
||||
|
||||
static inline void capimsg_setu16(void *m, int off, __u16 val)
|
||||
{
|
||||
((__u8 *)m)[off] = val & 0xff;
|
||||
((__u8 *)m)[off+1] = (val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static inline void capimsg_setu32(void *m, int off, __u32 val)
|
||||
{
|
||||
((__u8 *)m)[off] = val & 0xff;
|
||||
((__u8 *)m)[off+1] = (val >> 8) & 0xff;
|
||||
((__u8 *)m)[off+2] = (val >> 16) & 0xff;
|
||||
((__u8 *)m)[off+3] = (val >> 24) & 0xff;
|
||||
}
|
||||
|
||||
#define CAPIMSG_SETLEN(m, len) capimsg_setu16(m, 0, len)
|
||||
#define CAPIMSG_SETAPPID(m, applid) capimsg_setu16(m, 2, applid)
|
||||
#define CAPIMSG_SETCOMMAND(m,cmd) capimsg_setu8(m, 4, cmd)
|
||||
#define CAPIMSG_SETSUBCOMMAND(m, cmd) capimsg_setu8(m, 5, cmd)
|
||||
#define CAPIMSG_SETMSGID(m, msgid) capimsg_setu16(m, 6, msgid)
|
||||
#define CAPIMSG_SETCONTROL(m, contr) capimsg_setu32(m, 8, contr)
|
||||
#define CAPIMSG_SETDATALEN(m, len) capimsg_setu16(m, 16, len)
|
||||
|
||||
/*----- basic-type definitions -----*/
|
||||
|
||||
typedef __u8 *_cstruct;
|
||||
|
||||
typedef enum {
|
||||
CAPI_COMPOSE,
|
||||
CAPI_DEFAULT
|
||||
} _cmstruct;
|
||||
|
||||
/*
|
||||
The _cmsg structure contains all possible CAPI 2.0 parameter.
|
||||
All parameters are stored here first. The function CAPI_CMSG_2_MESSAGE
|
||||
assembles the parameter and builds CAPI2.0 conform messages.
|
||||
CAPI_MESSAGE_2_CMSG disassembles CAPI 2.0 messages and stores the
|
||||
parameter in the _cmsg structure
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
/* Header */
|
||||
__u16 ApplId;
|
||||
__u8 Command;
|
||||
__u8 Subcommand;
|
||||
__u16 Messagenumber;
|
||||
|
||||
/* Parameter */
|
||||
union {
|
||||
__u32 adrController;
|
||||
__u32 adrPLCI;
|
||||
__u32 adrNCCI;
|
||||
} adr;
|
||||
|
||||
_cmstruct AdditionalInfo;
|
||||
_cstruct B1configuration;
|
||||
__u16 B1protocol;
|
||||
_cstruct B2configuration;
|
||||
__u16 B2protocol;
|
||||
_cstruct B3configuration;
|
||||
__u16 B3protocol;
|
||||
_cstruct BC;
|
||||
_cstruct BChannelinformation;
|
||||
_cmstruct BProtocol;
|
||||
_cstruct CalledPartyNumber;
|
||||
_cstruct CalledPartySubaddress;
|
||||
_cstruct CallingPartyNumber;
|
||||
_cstruct CallingPartySubaddress;
|
||||
__u32 CIPmask;
|
||||
__u32 CIPmask2;
|
||||
__u16 CIPValue;
|
||||
__u32 Class;
|
||||
_cstruct ConnectedNumber;
|
||||
_cstruct ConnectedSubaddress;
|
||||
__u32 Data;
|
||||
__u16 DataHandle;
|
||||
__u16 DataLength;
|
||||
_cstruct FacilityConfirmationParameter;
|
||||
_cstruct Facilitydataarray;
|
||||
_cstruct FacilityIndicationParameter;
|
||||
_cstruct FacilityRequestParameter;
|
||||
__u16 FacilitySelector;
|
||||
__u16 Flags;
|
||||
__u32 Function;
|
||||
_cstruct HLC;
|
||||
__u16 Info;
|
||||
_cstruct InfoElement;
|
||||
__u32 InfoMask;
|
||||
__u16 InfoNumber;
|
||||
_cstruct Keypadfacility;
|
||||
_cstruct LLC;
|
||||
_cstruct ManuData;
|
||||
__u32 ManuID;
|
||||
_cstruct NCPI;
|
||||
__u16 Reason;
|
||||
__u16 Reason_B3;
|
||||
__u16 Reject;
|
||||
_cstruct Useruserdata;
|
||||
|
||||
/* intern */
|
||||
unsigned l, p;
|
||||
unsigned char *par;
|
||||
__u8 *m;
|
||||
|
||||
/* buffer to construct message */
|
||||
__u8 buf[180];
|
||||
|
||||
} _cmsg;
|
||||
|
||||
/*
|
||||
* capi_cmsg2message() assembles the parameter from _cmsg to a CAPI 2.0
|
||||
* conform message
|
||||
*/
|
||||
unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg);
|
||||
|
||||
/*
|
||||
* capi_message2cmsg disassembles a CAPI message an writes the parameter
|
||||
* into _cmsg for easy access
|
||||
*/
|
||||
unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg);
|
||||
|
||||
/*
|
||||
* capi_cmsg_header() fills the _cmsg structure with default values, so only
|
||||
* parameter with non default values must be changed before sending the
|
||||
* message.
|
||||
*/
|
||||
unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId,
|
||||
__u8 _Command, __u8 _Subcommand,
|
||||
__u16 _Messagenumber, __u32 _Controller);
|
||||
|
||||
/*
|
||||
* capi_info2str generated a readable string for Capi2.0 reasons.
|
||||
*/
|
||||
char *capi_info2str(__u16 reason);
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Debugging / Tracing functions
|
||||
*/
|
||||
char *capi_cmd2str(__u8 cmd, __u8 subcmd);
|
||||
char *capi_cmsg2str(_cmsg * cmsg);
|
||||
char *capi_message2str(__u8 * msg);
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static inline void capi_cmsg_answer(_cmsg * cmsg)
|
||||
{
|
||||
cmsg->Subcommand |= 0x01;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static inline void capi_fill_CONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
_cstruct NCPI)
|
||||
{
|
||||
capi_cmsg_header(cmsg, ApplId, 0x82, 0x80, Messagenumber, adr);
|
||||
cmsg->NCPI = NCPI;
|
||||
}
|
||||
|
||||
static inline void capi_fill_FACILITY_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u16 FacilitySelector,
|
||||
_cstruct FacilityRequestParameter)
|
||||
{
|
||||
capi_cmsg_header(cmsg, ApplId, 0x80, 0x80, Messagenumber, adr);
|
||||
cmsg->FacilitySelector = FacilitySelector;
|
||||
cmsg->FacilityRequestParameter = FacilityRequestParameter;
|
||||
}
|
||||
|
||||
static inline void capi_fill_INFO_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
_cstruct CalledPartyNumber,
|
||||
_cstruct BChannelinformation,
|
||||
_cstruct Keypadfacility,
|
||||
_cstruct Useruserdata,
|
||||
_cstruct Facilitydataarray)
|
||||
{
|
||||
capi_cmsg_header(cmsg, ApplId, 0x08, 0x80, Messagenumber, adr);
|
||||
cmsg->CalledPartyNumber = CalledPartyNumber;
|
||||
cmsg->BChannelinformation = BChannelinformation;
|
||||
cmsg->Keypadfacility = Keypadfacility;
|
||||
cmsg->Useruserdata = Useruserdata;
|
||||
cmsg->Facilitydataarray = Facilitydataarray;
|
||||
}
|
||||
|
||||
static inline void capi_fill_LISTEN_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u32 InfoMask,
|
||||
__u32 CIPmask,
|
||||
__u32 CIPmask2,
|
||||
_cstruct CallingPartyNumber,
|
||||
_cstruct CallingPartySubaddress)
|
||||
{
|
||||
capi_cmsg_header(cmsg, ApplId, 0x05, 0x80, Messagenumber, adr);
|
||||
cmsg->InfoMask = InfoMask;
|
||||
cmsg->CIPmask = CIPmask;
|
||||
cmsg->CIPmask2 = CIPmask2;
|
||||
cmsg->CallingPartyNumber = CallingPartyNumber;
|
||||
cmsg->CallingPartySubaddress = CallingPartySubaddress;
|
||||
}
|
||||
|
||||
static inline void capi_fill_ALERT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
_cstruct BChannelinformation,
|
||||
_cstruct Keypadfacility,
|
||||
_cstruct Useruserdata,
|
||||
_cstruct Facilitydataarray)
|
||||
{
|
||||
capi_cmsg_header(cmsg, ApplId, 0x01, 0x80, Messagenumber, adr);
|
||||
cmsg->BChannelinformation = BChannelinformation;
|
||||
cmsg->Keypadfacility = Keypadfacility;
|
||||
cmsg->Useruserdata = Useruserdata;
|
||||
cmsg->Facilitydataarray = Facilitydataarray;
|
||||
}
|
||||
|
||||
static inline void capi_fill_CONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u16 CIPValue,
|
||||
_cstruct CalledPartyNumber,
|
||||
_cstruct CallingPartyNumber,
|
||||
_cstruct CalledPartySubaddress,
|
||||
_cstruct CallingPartySubaddress,
|
||||
__u16 B1protocol,
|
||||
__u16 B2protocol,
|
||||
__u16 B3protocol,
|
||||
_cstruct B1configuration,
|
||||
_cstruct B2configuration,
|
||||
_cstruct B3configuration,
|
||||
_cstruct BC,
|
||||
_cstruct LLC,
|
||||
_cstruct HLC,
|
||||
_cstruct BChannelinformation,
|
||||
_cstruct Keypadfacility,
|
||||
_cstruct Useruserdata,
|
||||
_cstruct Facilitydataarray)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x02, 0x80, Messagenumber, adr);
|
||||
cmsg->CIPValue = CIPValue;
|
||||
cmsg->CalledPartyNumber = CalledPartyNumber;
|
||||
cmsg->CallingPartyNumber = CallingPartyNumber;
|
||||
cmsg->CalledPartySubaddress = CalledPartySubaddress;
|
||||
cmsg->CallingPartySubaddress = CallingPartySubaddress;
|
||||
cmsg->B1protocol = B1protocol;
|
||||
cmsg->B2protocol = B2protocol;
|
||||
cmsg->B3protocol = B3protocol;
|
||||
cmsg->B1configuration = B1configuration;
|
||||
cmsg->B2configuration = B2configuration;
|
||||
cmsg->B3configuration = B3configuration;
|
||||
cmsg->BC = BC;
|
||||
cmsg->LLC = LLC;
|
||||
cmsg->HLC = HLC;
|
||||
cmsg->BChannelinformation = BChannelinformation;
|
||||
cmsg->Keypadfacility = Keypadfacility;
|
||||
cmsg->Useruserdata = Useruserdata;
|
||||
cmsg->Facilitydataarray = Facilitydataarray;
|
||||
}
|
||||
|
||||
static inline void capi_fill_DATA_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u32 Data,
|
||||
__u16 DataLength,
|
||||
__u16 DataHandle,
|
||||
__u16 Flags)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x86, 0x80, Messagenumber, adr);
|
||||
cmsg->Data = Data;
|
||||
cmsg->DataLength = DataLength;
|
||||
cmsg->DataHandle = DataHandle;
|
||||
cmsg->Flags = Flags;
|
||||
}
|
||||
|
||||
static inline void capi_fill_DISCONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
_cstruct BChannelinformation,
|
||||
_cstruct Keypadfacility,
|
||||
_cstruct Useruserdata,
|
||||
_cstruct Facilitydataarray)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x04, 0x80, Messagenumber, adr);
|
||||
cmsg->BChannelinformation = BChannelinformation;
|
||||
cmsg->Keypadfacility = Keypadfacility;
|
||||
cmsg->Useruserdata = Useruserdata;
|
||||
cmsg->Facilitydataarray = Facilitydataarray;
|
||||
}
|
||||
|
||||
static inline void capi_fill_DISCONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
_cstruct NCPI)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x84, 0x80, Messagenumber, adr);
|
||||
cmsg->NCPI = NCPI;
|
||||
}
|
||||
|
||||
static inline void capi_fill_MANUFACTURER_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u32 ManuID,
|
||||
__u32 Class,
|
||||
__u32 Function,
|
||||
_cstruct ManuData)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0xff, 0x80, Messagenumber, adr);
|
||||
cmsg->ManuID = ManuID;
|
||||
cmsg->Class = Class;
|
||||
cmsg->Function = Function;
|
||||
cmsg->ManuData = ManuData;
|
||||
}
|
||||
|
||||
static inline void capi_fill_RESET_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
_cstruct NCPI)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x87, 0x80, Messagenumber, adr);
|
||||
cmsg->NCPI = NCPI;
|
||||
}
|
||||
|
||||
static inline void capi_fill_SELECT_B_PROTOCOL_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u16 B1protocol,
|
||||
__u16 B2protocol,
|
||||
__u16 B3protocol,
|
||||
_cstruct B1configuration,
|
||||
_cstruct B2configuration,
|
||||
_cstruct B3configuration)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x41, 0x80, Messagenumber, adr);
|
||||
cmsg->B1protocol = B1protocol;
|
||||
cmsg->B2protocol = B2protocol;
|
||||
cmsg->B3protocol = B3protocol;
|
||||
cmsg->B1configuration = B1configuration;
|
||||
cmsg->B2configuration = B2configuration;
|
||||
cmsg->B3configuration = B3configuration;
|
||||
}
|
||||
|
||||
static inline void capi_fill_CONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u16 Reject,
|
||||
__u16 B1protocol,
|
||||
__u16 B2protocol,
|
||||
__u16 B3protocol,
|
||||
_cstruct B1configuration,
|
||||
_cstruct B2configuration,
|
||||
_cstruct B3configuration,
|
||||
_cstruct ConnectedNumber,
|
||||
_cstruct ConnectedSubaddress,
|
||||
_cstruct LLC,
|
||||
_cstruct BChannelinformation,
|
||||
_cstruct Keypadfacility,
|
||||
_cstruct Useruserdata,
|
||||
_cstruct Facilitydataarray)
|
||||
{
|
||||
capi_cmsg_header(cmsg, ApplId, 0x02, 0x83, Messagenumber, adr);
|
||||
cmsg->Reject = Reject;
|
||||
cmsg->B1protocol = B1protocol;
|
||||
cmsg->B2protocol = B2protocol;
|
||||
cmsg->B3protocol = B3protocol;
|
||||
cmsg->B1configuration = B1configuration;
|
||||
cmsg->B2configuration = B2configuration;
|
||||
cmsg->B3configuration = B3configuration;
|
||||
cmsg->ConnectedNumber = ConnectedNumber;
|
||||
cmsg->ConnectedSubaddress = ConnectedSubaddress;
|
||||
cmsg->LLC = LLC;
|
||||
cmsg->BChannelinformation = BChannelinformation;
|
||||
cmsg->Keypadfacility = Keypadfacility;
|
||||
cmsg->Useruserdata = Useruserdata;
|
||||
cmsg->Facilitydataarray = Facilitydataarray;
|
||||
}
|
||||
|
||||
static inline void capi_fill_CONNECT_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x03, 0x83, Messagenumber, adr);
|
||||
}
|
||||
|
||||
static inline void capi_fill_CONNECT_B3_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x83, 0x83, Messagenumber, adr);
|
||||
}
|
||||
|
||||
static inline void capi_fill_CONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u16 Reject,
|
||||
_cstruct NCPI)
|
||||
{
|
||||
capi_cmsg_header(cmsg, ApplId, 0x82, 0x83, Messagenumber, adr);
|
||||
cmsg->Reject = Reject;
|
||||
cmsg->NCPI = NCPI;
|
||||
}
|
||||
|
||||
static inline void capi_fill_CONNECT_B3_T90_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x88, 0x83, Messagenumber, adr);
|
||||
}
|
||||
|
||||
static inline void capi_fill_DATA_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u16 DataHandle)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x86, 0x83, Messagenumber, adr);
|
||||
cmsg->DataHandle = DataHandle;
|
||||
}
|
||||
|
||||
static inline void capi_fill_DISCONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x84, 0x83, Messagenumber, adr);
|
||||
}
|
||||
|
||||
static inline void capi_fill_DISCONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x04, 0x83, Messagenumber, adr);
|
||||
}
|
||||
|
||||
static inline void capi_fill_FACILITY_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u16 FacilitySelector)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x80, 0x83, Messagenumber, adr);
|
||||
cmsg->FacilitySelector = FacilitySelector;
|
||||
}
|
||||
|
||||
static inline void capi_fill_INFO_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x08, 0x83, Messagenumber, adr);
|
||||
}
|
||||
|
||||
static inline void capi_fill_MANUFACTURER_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr,
|
||||
__u32 ManuID,
|
||||
__u32 Class,
|
||||
__u32 Function,
|
||||
_cstruct ManuData)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0xff, 0x83, Messagenumber, adr);
|
||||
cmsg->ManuID = ManuID;
|
||||
cmsg->Class = Class;
|
||||
cmsg->Function = Function;
|
||||
cmsg->ManuData = ManuData;
|
||||
}
|
||||
|
||||
static inline void capi_fill_RESET_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
|
||||
__u32 adr)
|
||||
{
|
||||
|
||||
capi_cmsg_header(cmsg, ApplId, 0x87, 0x83, Messagenumber, adr);
|
||||
}
|
||||
|
||||
#endif /* __CAPIUTIL_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -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
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue