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
(mgetty+sendfax by gert@greenie.muc.de with an extension, available
with the ISDN utility package for example), you will be able
to use your Linux box as an ISDN-answering machine. Of course, this
- must be supported by the lowlevel driver also. Currently, the Teles
- driver is the only voice-supporting one. See
+ must be supported by the lowlevel driver also. Currently HiSax
+ driver is the only voice-supporting drivers. See
Documentation/isdn/README.audio for more information.
ICN 2B and 4B support
separately. See Documentation/isdn/README and README.icn for more
information.
-Teles, NICCY1016PC, Creatix support
-CONFIG_ISDN_DRV_TELES
- This enables support for the Teles ISDN-cards S0-16.0, S0-16.3, S0-8
- and many compatibles. By default, the driver is configured to
- support a 16.0-type using EDSS1-protocol. See
- 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 driver replaces the old Teles driver. It supports the Siemens
+ chipset in a more general way. This chipset is used 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.
+ 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. (not working yet, under developement)
+
+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
Documentation/isdn/README and Documentation/isdn/README.pcbit for
more information.
+Spellcaster support (EXPERIMENTAL)
+CONFIG_ISDN_DRV_SC
+ This enables support for the Spellcaster BRI boards. This driver
+ currently builds in a modularized version only.
+ See Documentation/isdn/README.sc and http://www.spellcast.com
+ for more information.
+
+AVM-B1 with CAPI2.0 support
+CONFIG_ISDN_DRV_AVMB1
+ This enables support for the AVM B1 card and also adds a CAPI2.0
+ interface for this card. For running this card, additional firmware
+ is necessary, which has to be downloaded into the card using a
+ utility which is distributed separately.
+ See Documentation/isdn/README.avmb1 for more information.
+
Support for AP1000 multicomputer
CONFIG_AP1000
This enables support for a sparc based parallel multi-computer
- info for running audio 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.pcbit
- info on the PCBIT-D ISDN adapter and driver.
README.syncppp
- info on running Sync PPP over ISDN.
-README.teles
- - info on driver for Teles compatible ISDN cards.
syncPPP.FAQ
- frequently asked questions about running PPP over ISDN.
-
+README.avmb1
+ - info on driver for AVM-B1 ISDN card
For contribution of man-pages, the imontty-tool and a perfect
maintaining of the mailing-list at hub-wue.
+Bernhard Hailer (Bernhard.Hailer@lrz.uni-muenchen.de)
+ For maintaining the FAQ.
+
+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 (isdn4@temic-ech.spacenet.de)
For adding 1TR6-support to the Teles-driver.
+ For the HiSax-driver.
Michael Knigge (knick@cove.han.de)
For contributing the imon-tool
Gerhard 'Fido' Schneider (fido@wuff.franken.de)
For heavy-duty-beta-testing with his BBS ;)
-Thomas Uhl (uhl@hn-net.de)
+Thomas Uhl (uhl@think.de)
For distributing the cards.
For pushing me to work ;-)
+Carsten Paeth (calle@calle.in-berlin.de)
+ For the AVM-B1-CAPI2.0 driver
-$Id: INTERFACE,v 1.5 1996/11/06 17:40:47 keil Exp $
+$Id: INTERFACE,v 1.6 1997/02/10 22:40:57 fritz Exp $
Description of the Interface between Linklevel and Hardwarelevel
of isdn4linux:
int (*writebuf)(int, int, u_char*, int, int);
- ***CHANGEc1.14: Declared obsolete. Do NOT use this field/function
+ ***CHANGED1.14: Declared obsolete. Do NOT use this field/function
anymore, since it will be removed when all current
LL drivers have been changed accordingly. Set this
field to NULL and use writebuf_skb instead.
int driver-Id.
int channel-number locally to the HL-driver. (starts with 0)
-***CHANGEc1.14: The driver-Id and channel-number are new since this revision.
+***CHANGED1.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 driver-Id.
int channel-number locally to the HL-driver. (starts with 0)
-***CHANGEc1.14: The driver-Id and channel-number are new since this revision.
+***CHANGED1.14: The driver-Id and channel-number are new since this revision.
Returnvalue:
Length of data on success, else error-code (-EINVAL etc.)
Until now, the following commands are defined:
+***CHANGED1.34: The parameter "num" has been replaced by a union "para" containing
+ the old "num" and a new setup_type struct used for ISDN_CMD_DIAL
+ and ISDN_STAT_ICALL callback.
ISDN_CMD_IOCTL:
called with the field command set to 1.
Parameter:
- driver = driver-Id.
- command = ISDN_CMD_IOCTL
- arg = Original ioctl-cmd - IIOCDRVCTL
- num = first bytes filled with (unsigned long)arg
+ driver = driver-Id.
+ command = ISDN_CMD_IOCTL
+ arg = Original ioctl-cmd - IIOCDRVCTL
+ para.num = first bytes filled with (unsigned long)arg
Returnvalue:
Depending on driver.
driver = driver-Id.
command = ISDN_CMD_DIAL
arg = channel-number locally to the driver. (starting with 0)
- num = An ASCII-String containing the number to dial, the own
- EAZ or MSN, the Service-Indicator and the Additional
- Info. Format:
- "%s,%s,%d,%d" RemotePhoneNumber,EazOrMsn,SI,AI
+
+ para.setup.phone = An ASCII-String containing the number to dial.
+ para.setup.eazmsn = An ASCII-Sting containing the own EAZ or MSN.
+ para.setup.si1 = The Service-Indicator.
+ para.setup.si2 = Additional Service-Indicator.
+
If the Line has been designed as SPV (a special german
- feature, meaning semi-leased-line) the number has to
+ 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.
driver = driver-Id.
command = ISDN_CMD_ACCEPTD
arg = channel-number locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_CMD_ACCEPTB:
driver = driver-Id.
command = ISDN_CMD_ACCEPTB
arg = channel-number locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_CMD_HANGUP:
driver = driver-Id.
command = ISDN_CMD_HANGUP
arg = channel-number locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_CMD_CLREAZ:
driver = driver-Id.
command = ISDN_CMD_CLREAZ
arg = channel-number locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_CMD_SETEAZ:
driver = driver-Id.
command = ISDN_CMD_SETEAZ
arg = channel-number locally to the driver. (starting with 0)
- num = ASCII-String, containing the desired EAZ's/MSN's
+ para.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.
driver = driver-Id.
command = ISDN_CMD_GETEAZ
arg = channel-number locally to the driver. (starting with 0)
- num = ASCII-String, containing the current EAZ's/MSN's
+ para.num = ASCII-String, containing the current EAZ's/MSN's
ISDN_CMD_SETSIL: (currently unused)
driver = driver-Id.
command = ISDN_CMD_SETSIL
arg = channel-number locally to the driver. (starting with 0)
- num = ASCII-String, containing the desired Service-Indicators.
+ para.num = ASCII-String, containing the desired Service-Indicators.
ISDN_CMD_GETSIL: (currently unused)
driver = driver-Id.
command = ISDN_CMD_SETSIL
arg = channel-number locally to the driver. (starting with 0)
- num = ASCII-String, containing the current Service-Indicators.
+ para.num = ASCII-String, containing the current Service-Indicators.
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...
- num = unused.
+ para = unused.
ISDN_CMD_GETL2: (currently unused)
driver = driver-Id.
command = ISDN_CMD_GETL2
arg = channel-number locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
Returnvalue:
current protocol-Id (one of the constants ISDN_L2_PROTO)
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...
- num = unused.
+ para = unused.
ISDN_CMD_GETL2: (currently unused)
driver = driver-Id.
command = ISDN_CMD_GETL3
arg = channel-number locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
Returnvalue:
current protocol-Id (one of the constants ISDN_L3_PROTO)
driver = driver-Id.
command = ISDN_CMD_LOCK
arg = unused.
- num = unused.
+ para = unused.
ISDN_CMD_UNLOCK:
driver = driver-Id.
command = ISDN_CMD_UNLOCK
arg = unused.
- num = unused.
+ para = unused.
3. Description of the events to be signaled by the HL-driver to th LL.
driver = driver-Id
command = ISDN_STAT_STAVAIL
arg = length of available data.
- num = unused.
+ para = unused.
ISDN_STAT_ICALL:
With this call, the HL-driver signals an incoming call to the LL.
Parameter:
- driver = driver-Id
- command = ISDN_STAT_ICALL
- arg = channel-number, locally to the driver. (starting with 0)
- num = ASCII-String in the following format:
- "%s,%d,%d,%s",CallerNumber,ServiceIndicator,AddInfo,
- CalledNumber.
+ 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).
driver = driver-Id
command = ISDN_STAT_RUN
arg = unused.
- num = unused.
+ para = unused.
ISDN_STAT_STOP:
driver = driver-Id
command = ISDN_STAT_STOP
arg = unused.
- num = unused.
+ para = unused.
ISDN_STAT_DCONN:
driver = driver-Id
command = ISDN_STAT_DCONN
arg = channel-number, locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_STAT_BCONN:
driver = driver-Id
command = ISDN_STAT_BCONN
arg = channel-number, locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_STAT_DHUP:
driver = driver-Id
command = ISDN_STAT_DHUP
arg = channel-number, locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_STAT_BHUP:
driver = driver-Id
command = ISDN_STAT_BHUP
arg = channel-number, locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_STAT_CINF:
driver = driver-Id
command = ISDN_STAT_CINF
arg = channel-number, locally to the driver. (starting with 0)
- num = ASCII string containing charge-units (digits only).
+ para.num = ASCII string containing charge-units (digits only).
ISDN_STAT_LOAD: (currently unused)
driver = driver-Id
command = ISDN_STAT_UNLOAD
arg = unused.
- num = unused.
+ para = unused.
ISDN_STAT_BSENT:
driver = driver-Id
command = ISDN_STAT_BSENT
arg = channel-number, locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_STAT_NODCH:
driver = driver-Id
command = ISDN_STAT_NODCH
arg = channel-number, locally to the driver. (starting with 0)
- num = unused.
+ para = unused.
ISDN_STAT_ADDCH: (currently unused)
driver = driver-Id
command = ISDN_STAT_ADDCH
arg = to be defined.
- num = to be defined.
+ para = to be defined.
ISDN_STAT_CAUSE:
driver = driver-Id
command = ISDN_STAT_NODCH
arg = channel-number, locally to the driver. (starting with 0)
- num = ASCII string containing CAUSE-message.
+ para.num = ASCII string containing CAUSE-message.
subscribe isdn4linux <your_email_address>
To write to the mailing-list, write to isdn4linux@hub-wue.franken.de
+
+ This mailinglist is bidirectionally gated to the newsgroup
+
+ de.alt.comm.isdn4linux
+ There is also a well maintained FAQ (both english and german) available
+ at ftp.franken.de in /pub/isdn4linux/FAQ/
+ This FAQ is also available at http://www.lrz-muenchen.de/~ui161ab/www/isdn/
1.1 Technical details
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, for the ICN-driver, the base-address of
+ 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 an the protocol software can be loaded into
the card.
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).
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. i.e.: the Teles-Module-
+ low-level-driver used. i.e.: 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
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&Sx Set window-size for Teles-driver (x = 1..8) (not yet
- implemented)
+ 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).
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.
14 0 Layer-2 protocol:
0 = X75/LAPB with I-frames
1 = X75/LAPB with UI-frames
15 0 Layer-3 protocol: (at the moment always 0)
0 = transparent
16 250 Send-Packet-size/16
- 17 8 Window-size for Teles-driver (not yet implemented)
+ 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.
20 0 Bit coded register (readonly)
Service-Octet-1 of last call.
Bit mapping is the same like 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
Last but not least a (at the moment fairly primitive) device to request
the line-status (/dev/isdninfo) is made available.
2 System prerequisites:
- ATTENTION! The program "insmod" from the Package "modules-1.2.8" (It's
- on nearly all newer distributions) has a bug, which makes
- it impossible to set both driver-Id's when loading the
- icn-module for the Double-ICN-Card. A patch is supplied
- in the utility-package called "insmod-1.2.8.patch". Change into
- the source-directory of insmod, and type
- "patch < insmod-1.2.8.patch". Then recompile it. This will fix
- the bug.
- This bug does NOT occur when using insmod with the Teles-driver
- or a single ICN-card.
+ 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.
-
- 3.1 Drivers built into the kernel.
-
- 3.1.1 Teles driver.
-
- The Teles driver can be configured using the commandline-feature
- while loading the kernel with LILO or LOADLIN. It accepts the
- following syntax:
-
- teles=p0,i0,m0,d0[,p1,i1,m1,d1 ... ,pn,in,mn,dn][,idstring]
-
- where
-
- p0 = portbase of 1st card. (default: 0xd80)
- i0 = irq of 1st card. (default: 15)
- m0 = shared memory of 1st card. (default: 0xd0000)
- d0 = D-channel protocol of 1st card. 1=1TR6, 2=EDSS1 (default: 2)
-
- p1,i1,m1,d1 = Parameters of second card (defaults: none)
- pn,in,mn,d1 = Parameters of n'th card (up to 16 cards are supported)
-
- idstring = Driver-Id for accessing with utilities and identification
- when using a Line-monitor. (default: none)
- idstring must start with a character!
-
- The type of the card is determined by the port, irq and shared memory:
-
- port == 0, shared memory != 0 -> Teles S0-8
- port != 0, shared memory != 0 -> Teles S0-16.0
- port != 0, shared memory == 0 -> Teles S0-16.3
-
- ATTENTION:
-
- Due to limited hardware-capabilities, there is no way to check the
- existence of a card. Therefore you need to be sure your card's setup
- is correct. Also there are bugs in the printed manual of some newer
- 16.3 cards. Have a look to the kernel-syslog. With most of the cards,
- you should see a line "HSCX version A:5 B:5" there.
-
- 3.1.2 ICN driver.
-
- 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, you MUST define TWO idstrings.
- idstring must start with a character!
-
- 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.
-
-
- 3.2 Drivers built as modules.
-
- 3.2.1 Teles driver.
-
- The module teles.o can be configured during "insmod'ing" it by
- appending its parameters to the insmod-commandline. The following
- syntax is accepted:
-
- io=m0,i0,p0,d0[,m1,i1,p1,d1 ... ,mn,in,pn,dn] teles_id=idstring
-
- where
-
- m0,i0,p0,d0 ... mn,in,pn,dn have the same meanings like the
- parameters described for the kernel-
- version above. Watch out: different
- sequence!
-
- 3.2.2 ICN driver.
-
- 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 like
- parameters described for the kernel-
- version above.
-
- When using the ICN double card, you MUST define TWO idstrings.
- idstring must start with a character!
-
- 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.
+ Configuration depends on how the drivers are built. See the
+ README.<yourDriver> for information on driver-specific setup.
4. Device-inodes
44 for the ISDN-callout-tty's.
45 for control/info/debug devices.
-
5. Application
- a) (Only for ICN-cards) Load the firmware into the card:
-
- cd icn
- For 1TR6:
- icnctrl [-d IDstring] load download/loadpg.bin download/pc_1t_ca.bin
- For Euro-ISDN:
- icnctrl [-d IDstring] load download/loadpg.bin download/pc_eu_ca.bin
-
- When using the ICN-4B, the protocol-software for the second half of
- the card must be appended to the command line.
-
- -> 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 loading pcbit-firmware, refer to Documentation/isdn/README.pcbit
- and the pcbit manpage, included in the utility-package.
+ a) For some card-types, firmware has to be loaded into the cards, before
+ proceeding with device-independant setup. See README.<yourDriver>
+ for how to do that.
b) If you only intend to use ttys, you are nearly ready now.
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, it does NOT work
- with the Teles on an EDSS1-Line.):
+ the charge-info during and after the connection):
isdnctrl chargehup isdn0 on
i) Setup the interface with ifconfig as usual, and set a route to it.
"isdnctrl l2_prot <InterfaceName> <L2-ProtocolName>"
Selects a layer-2-protocol.
- (With the ICN-driver and the Teles-driver, "x75i" and "hdlc" is available.
+ (With the ICN-driver and the HiSax-driver, "x75i" and "hdlc" is available.
With other drivers, "x75ui", "x75bui" may be possible too.)
isdnctrl l3_prot <InterfaceName> <L3-ProtocolName>
--- /dev/null
+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 S0/PCMCIA
+Creatix PnP S0
+AVM A1 (Fritz)
+ELSA Microlink PCC-16, PCF, PCF-Pro, PCC-8
+ELSA Quickstep 1000
+ELSA PCMCIA
+ITK ix1-micro Rev.2
+
+Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
+ PCC-8: not tested yet
+ Teles PCMCIA is 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), with one exception: The ELSA PCMCIA cannot work with an other
+non PCMCIA ELSA card at the same time. You cannot select ELSA ISA and ELSA
+PCMCIA support at the same time during kernel config.
+
+
+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 enclose 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)
+ 7 ELSA PCMCIA irq, io (set with card manager)
+ 8 Teles 16.3 PCMCIA irq, io
+ 9 ITK ix1-micro Rev.2 irq, io
+
+At the moment IRQ sharing is not possible. Please make sure that your IRQ
+is free and enabled for ISA use.
+Note: For using the ELSA PCMCIA you need the cardmanager under MSDOS for
+enabling in the moment, then boot linux with loadlin.
+
+
+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 !
+ 7 ELSA PCMCIA irq, io (set with card manager)
+ 8 Teles S0 PCMCIA pa=irq pb=iobase
+ 9 ITK ix1-micro Rev.2 pa=irq pb=iobase
+
+
+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.1
+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 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 telesctrl tool:
+
+ telesctrl <DriverId> DebugCmd <debugging_flags>
+
+<DriverId> default is HiSax, if you didn't specified 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:
+
+ 1 Link-level <--> hardware-level communication
+ 2 Top state machine
+ 4 D-Channel Q.931 (call control messages)
+ 8 D-Channel Q.921
+ 16 B-Channel X.75
+ 32 D-Channel l2
+ 64 B-Channel l2
+ 128 D-Channel link state debugging
+ 256 B-Channel link state debugging
+ 512 TEI debug
+ 1024 LOCK debug in callc.c
+ 2048 More paranoid debug in callc.c (not for normal use)
+
+With DebugCmd set to 11:
+
+ 1 Warnings (default: on)
+ 2 IRQ status
+ 4 ISAC
+ 8 ISAC FIFO
+ 16 HSCX
+ 32 HSCX FIFO (attention: full B-Channel output!)
+ 64 D-Channel LAPD frame types
+
+With DebugCmd set to 13:
+
+ 1 Warnings (default: on)
+ 2 l3 protocol discriptor errors
+ 4 l3 state machine
+ 8 charge info debugging (1TR6)
+
+For example, 'telesctrl HiSax 1 0x3ff' enables full generic debugging.
+
+
+Warning
+-------
+HiSax is a work in progress and may crash your machine. It has not been
+certified and therefore operation on your PTT's ISDN network is probably
+illegal.
+
+
+Limitations
+-----------
+At this time, HiSax only works on Euro ISDN lines and German 1TR6 lines.
+
+
+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
+ and more people who are hunting bugs. (If I forgot somebody, please
+ send me a mail).
+
+ Firma ELSA GmbH
+
+ My girl friend and partner in life Ute for her patience with me.
+
+
+Enjoy,
+
+Karsten Keil
+keil@temic-ech.spacenet.de
+
+
+Appendix: Teles PCMCIA driver
+-----------------------------
+
+See
+ http://www.stud.uni-wuppertal.de/~ea0141/pcmcia.html
+for instructions.
-$Id: README.audio,v 1.3 1996/06/05 02:19:36 fritz Exp $
+$Id: README.audio,v 1.5 1997/02/23 23:53:46 fritz Exp $
ISDN subsystem for Linux.
Description of audio mode.
AT+FCLASS=8 Enable audio mode.
This affects the following registers:
- S18: Bits 0 and 3 are set.
+ 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.
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. Emulator stops
+ <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>s silence. Silence detected from the
start of recording.
- Any character sent by the application, except XON (0x11) or XOFF (0x13)
- immediately stops recording.
-
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>.
--- /dev/null
+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 Author can be reached at calle@calle.in-berlin.de
+The command avmcapictrl is part of the isdn4linux-utils.
+t4-files can be found at ftp.avm.de.
+
+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 not compile the driver as modules, you have to add the
+card(s) and load them after booting:
+
+avmcapictrl add 0x150 15
+avmcapictrl load /lib/isdn/b1.t4 1
+
+if you configure as modules you have two possibilities:
+
+insmod /lib/modules/current/misc/capiutil.o
+insmod /lib/modules/current/misc/kernelcapi.o portbase=0x150 irq=15
+insmod /lib/modules/current/misc/capidrv.o
+insmod /lib/modules/current/misc/capi.o
+avmcapictrl load /lib/isdn/b1.t4
+
+or
+
+insmod /lib/modules/current/misc/capiutil.o
+insmod /lib/modules/current/misc/kernelcapi.o
+insmod /lib/modules/current/misc/capidrv.o
+insmod /lib/modules/current/misc/capi.o
+avmcapictrl add 0x150 15
+avmcapictrl load /lib/isdn/b1.t4
+
+Questions
+---------
+Check out the FAQ (ftp.franken.de).
+
+Bugs
+----
+If you find any please let me know.
+
+Enjoy,
+
+Carsten Paeth (calle@calle.in-berlin.de)
-$Id: README.icn,v 1.4 1996/06/03 19:57:07 fritz Exp $
+$Id: README.icn,v 1.5 1997/04/23 18:55:55 fritz Exp $
You can get the ICN-ISDN-card from:
Thinking Objects Software GmbH
-Obere Heerbergstr. 17
+Versbacher Röthe 159
97078 Würzburg
Tel: +49 931 2877950
Fax: +49 931 2877951
1 1 1 0 0x368
1 1 1 1 NOT ALLOWED!
+The ICN driver either may be build into kernel or as a module. Initialization
+depends on how the drive 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 like
+ 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.
+
+ Assumed 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 of 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.
+
--- /dev/null
+Welcome to Beta Release 2 of the combination ISDN driver for SpellCaster's
+ISA ISDN adapters. Please note this release 2 includes support for the
+DataCommute/BRI and TeleCommute/BRI adapters only and any other use is
+guaranteed to fail. If you have a DataCommute/PRI installed in the test
+computer, we recommend removing it as it will be detected but will not
+be usable. To see what we have done to Beta Release 2, see section 3.
+
+Speaking of guarantees, THIS IS BETA SOFTWARE and as such contains
+bugs and defects either known or unknown. Use this software at your own
+risk. There is NO SUPPORT for this software. Some help may be available
+through the web site or the mailing list but such support is totally at
+our own option and without warrantee. If you choose to assume all and
+total risk by using this driver, we encourage you to join the beta
+mailing list.
+
+To join the Linux beta mailing list, send a message to:
+majordomo@spellcast.com with the words "subscribe linux-beta" as the only
+contents of the message. Do not include a signature. If you choose to
+remove yourself from this list at a later date, send another message to
+the same address with the words "unsubscribe linux-beta" as it's only
+contents.
+
+TABLE OF CONTENTS
+-----------------
+ 1. Introduction
+ 1.1 What is ISDN4Linux?
+ 1.2 What is different between this driver and previous drivers?
+ 1.3 How do I setup my system with the correct software to use
+ this driver release?
+
+ 2. Basic Operations
+ 2.1 Unpacking and installing the driver
+ 2.2 Read the man pages!!!
+ 2.3 Installing the driver
+ 2.4 Removing the driver
+ 2.5 What to do if it doesn't load
+ 2.6 How to setup ISDN4Linux with the driver
+
+ 3. Beta Change Summaries and Miscellaneous Notes
+
+1. Introduction
+---------------
+
+The revision 2 Linux driver for SpellCaster ISA ISDN adapters is built
+upon ISDN4Linux available seperately or as included in Linux 2.0 and later.
+The driver will support a maximum of 4 adapters in any one system of any
+type including DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI for a
+maximum of 92 channels for host. The driver is supplied as a module in
+source form and needs to be complied before it can be used. It has been
+tested on Linux 2.0.20.
+
+1.1 What Is ISDN4Linux
+
+ISDN4Linux is a driver and set of tools used to access and use ISDN devices
+on a Linux platform in a common and standard way. It supports HDLC and PPP
+protocols and offers channel bundling and MLPPP support. To use ISDN4Linux
+you need to configure your kernel for ISDN support and get the ISDN4Linux
+tool kit from our web site.
+
+ISDN4Linux creates a channel pool from all of the available ISDN channels
+and therefore can function across adapters. When an ISDN4Linux compliant
+driver (such as ours) is loaded, all of the channels go into a pool and
+are used on a first-come first-served basis. In addition, individual
+channels can be specifically bound to particular interfaces.
+
+1.2 What is different between this driver and previous drivers?
+
+The revision 2 driver besides adopting the ISDN4Linux architecture has many
+subtle and not so subtle functional differences from previous releases. These
+include:
+ - More efficient shared memory management combined with a simpler
+ configuration. All adapters now use only 16Kbytes of shared RAM
+ versus between 16K and 64K. New methods for using the shared RAM
+ allow us to utilize all of the available RAM on the adapter through
+ only one 16K page.
+ - Better detection of available upper memory. The probing routines
+ have been improved to better detect avaialble shared RAM pages and
+ used pages are now locked.
+ - Decreased loading time and a wider range of I/O ports probed.
+ We have significantly reduced the amount of time it takes to load
+ the driver and at the same time doubled the number of I/O ports
+ probed increasing the likelyhood of finding an adapter.
+ - We now support all ISA adapter models with a single driver instead
+ of seperate drivers for each model. The revision 2 driver supports
+ the DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI in any
+ combination up to a maximum of four adapters per system.
+ - On board PPP protocol support has been removed in favour of the
+ sync-PPP support used in ISDN4Linux. This means more control of
+ the protocol parameters, faster negotiation time and a more
+ familiar interface.
+
+1.3 How do I setup my system with the correct software to use
+ this driver release?
+
+Before you can compile, install and use the SpellCaster ISA ISDN driver, you
+must ensure that the following software is installed, configuraed and running:
+
+ - Linux kernel 2.0.20 or later with the required init and ps
+ versions. Please see your distribution vendor for the correct
+ utility packages. The latest kernel is available from
+ ftp://sunsite.unc.edu/pub/Linux/kernel/v2.0/
+
+ - The latest modules package (modules-2.0.0.tar.gz) from
+ ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
+
+ - The ISDN4Linux tools available from
+ ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz
+ This package may fail to compile for you so you can alternatively
+ get a pre-compiled version from
+ ftp://ftp.spellcast.com/pub/drivers/isdn4linux/isdn4k-bin-2.0.tar.gz
+
+
+2. Basic Operations
+-------------------
+
+2.1 Unpacking and installing the driver
+
+ 1. As root, create a directory in a convienient place. We suggest
+ /usr/src/spellcaster.
+
+ 2. Unpack the archive with :
+ tar xzf sc-n.nn.tar.gz -C /usr/src/spellcaster
+
+ 3. Change directory to /usr/src/spellcaster
+
+ 4. Read the README and RELNOTES files.
+
+ 5. Run 'make' and if all goes well, run 'make install'.
+
+2.2 Read the man pages!!!
+
+Make sure you read the scctrl(8) and sc(4) manual pages before continuing
+any further. Type 'man 8 scctrl' and 'man 4 sc'.
+
+2.3 Installing the driver
+
+To install the driver, type '/sbin/insmod sc' as root. sc(4) details options
+you can specify but you shouldn't need to use any unless this doesn't work.
+
+Make sure the driver loaded and detected all of the adapters by typing
+'dmesg'.
+
+The driver can be configured so that it is loaded upon startup. To do this,
+edit the file "/etc/modules/'uname -f'/'uname -v'" and insert the driver name
+"sc" into this file.
+
+2.4 Removing the driver
+
+To remove the driver, delete any interfaces that may exist (see isdnctrl(8)
+for more on this) and then type '/sbin/rmmod sc'.
+
+2.5 What to do if it doesn't load
+
+If, when you try to install the driver, you get a message mentioning
+'register_isdn' then you do not have the ISDN4Linux system installed. Please
+make sure that ISDN support is configured in the kernel.
+
+If you get a message that says 'initialization of sc failed', then the
+driver failed to detect an adapter or failed to find resources needed such
+as a free IRQ line or shared memory segment. If you are sure there are free
+resources available, use the insmod options detailed in sc(4) to override
+the probing function.
+
+Upon testing, the following problem was noted, the driver would load without
+problems, but the board would not respond beyond that point. When a check was
+done with 'cat /proc/interrupts' the interrupt count for sc was 0. In the event
+of this problem, change the BIOS settings so that the interrupts in question are
+reserved for ISA use only.
+
+
+2.6 How to setup ISDN4Linux with the driver
+
+There are two main configurations which you can use with the driver:
+
+A) Basic HDLC connection
+B) PPP connection
+C) MLPPP connection
+
+It should be mentioned here that you may also use a tty connection if you desire.
+The Documentation directory of the isdn4linux subsystem offers a good documentation
+on this feature.
+
+A) 10 steps to the establishment of a basic HDLC connection
+-----------------------------------------------------------
+
+- please open the isdn-hdlc file in the examples directory and follow along...
+
+ This file is a script used to configure a BRI ISDN TA to establish a basic HDLC
+ connection between its two channels. There two network interfaces which are
+ created and two routes added between the channels.
+
+ i) using the isdnctrl utitity, add an interface with "addif" and name it "isdn0"
+ ii) add the outgoing and inbound telephone numbers
+ iii) set the Layer 2 protocol to hdlc
+ iv) set the eaz of the interface to be the phone number of that specific channel
+ v) to turn the callback features off, set the callback to "off" and
+ the callback delay (cbdelay) to 0.
+ vi) the hangup timeout can be set to a specified number of seconds
+ vii) the hangup upon incomming call can be set on or off
+ viii) use the ifconfig command to bring-up the network interface with a specific
+ IP address and point to point address
+ viv) add a route to the IP address through the isdn0 interface
+ x) a ping should result in the establishment of the connection
+
+
+B) Establishment of a PPP connection
+------------------------------------
+
+- please open the isdn-ppp file in the examples directory and follow along...
+
+ This file is a script used to configure a BRI ISDN TA to establish a PPP connection
+ between the two channels. The file is almost identical to the HDLC connection
+ example except that the packet ecapsulation type has to be set.
+
+ use the same procedure as in the HDLC connection from steps i) to iii) then,
+ after the Layer 2 protocol is set, set the encapsulation "encap" to syncppp.
+ With this done, the rest of the steps, iv) to x) can be followed from above.
+
+ Then, the ipppd (ippp daemon) must be setup:
+
+ xi) use the ipppd function found in /sbin/ipppd to set the following:
+ xii) take out (minus) VJ compression and bsd compression
+ xiii) set the mru size to 2000
+ xiv) link the two /dev interfaces to the daemon
+
+NOTE: A "*" in the inbound telephone number specifies that a call can be accepted
+ on any number.
+
+C) Establishment of a MLPPP connection
+--------------------------------------
+
+- please open the isdn-mppp file in the examples directory and follow along...
+
+ This file is a script used to configure a BRI ISDN TA to accept a Multi Link PPP
+ connection.
+
+ i) using the isdnctrl utitity, add an interface with "addif" and name it "ippp0"
+ ii) add the inbound telephone number
+ iii) set the Layer 2 protocol to hdlc and the Layer 3 protocol to trans (transparent)
+ iv) set the packet encapsulation to syncppp
+ v) set the eaz of the interface to be the phone number of that specific channel
+ vi) to turn the callback features off, set the callback to "off" and
+ the callback delay (cbdelay) to 0.
+ vi) the hangup timeout can be set to a specified number of seconds
+ vii) the hangup upon incomming call can be set on or off
+ viii) add a slave interface and name it "ippp32" for example
+ viv) set the similar parameters for the ippp32 interface
+ x) use the ifconfig command to bring-up the ippp0 interface with a specific
+ IP address and point to point address
+ xi) add a route to the IP address through the ippp0 interface
+ xii) use the ipppd function found in /sbin/ipppd to set the following:
+ xiii) take out (minus) bsd compression
+ xiv) set the mru size to 2000
+ xv) add (+) the multi-link function "+mp"
+ xv) link the two /dev interfaces to the daemon
+
+NOTE: To use the MLPPP connection to dial OUT to a MLPPP connection, change the
+ inbound telephone numbers to the outgoing telephone numbers of the MLPPP
+ host.
+
+
+3. Beta Change Summaries and Miscellaneous Notes
+------------------------------------------------
+When using the "scctrl" utility to upload firmware revisions on the board, please
+note that the byte count displayed at the end of the operation may be different
+than the total number of bytes in the "dcbfwn.nn.sr" file. Please disregard the
+displayed byte count.
+
+It was noted that in Beta Release 1, the module would fail to load and result in a
+segmentation fault when insmod"ed". This problem was created when one of the
+isdn4linux parameters, (isdn_ctrl, data field) was filled in. In some cases, this
+data field was NULL, and was left unchecked, so when it was referenced.. segv.
+The bug has been fixed around line 63-68 of event.c.
+
+++ /dev/null
-This is my Linux hardware level driver for Teles compatible ISDN cards. It is
-meant to be used with isdn4isdn4linux, an ISDN Link-level module for Linux written
-by Fritz Elfert.
-
-Isdn4linux can be obtained from ftp.franken.de:/pub/isdn4linux. The most recent
-Teles driver can be found on my homepage, http://www.xs4all.nl:/~jdo.
-
-Warning
--------
-Teles4isdn4linux is a work in progress and may crash your machine. It has not
-been certified and therefore operation on your PTT's ISDN network is probably
-illegal.
-
-Limitations
------------
-Teles4isdn4linux only works on Euro ISDN lines and german 1TR6-lines.
-
-For the B channel transparent (HDLC) protocol and X.75 have been implemented.
-
-Running
--------
-When you insmod isdn.o and teles.o (or with the kernel-version, during boottime)
-a few lines should appear in your syslog. Look for something like:
-
-Oct 11 16:53:30 jedi kernel: channels 2
-Oct 11 16:53:31 jedi kernel: Teles module installed
-
-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 teles_id=<SomeString> to the insmod-commandline. 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. Debugging messages are enabled with the telesctrl tool:
-
- teles/telesctrl <DriverId> 1 <debugging_flags>
-
-where <debugging_flags> is the integer sum of the following debugging
-options you wish enabled:
-
- 1 Link-level <--> Hardware-level communication
- 2 Top state machine
- 4 D channel Q.931 (call control messages)
- 8 D channel Q.921
- 16 B channel X.75
- 32 Lowlevel (irq and Layer1 stuff)
-
-For example 'teles/telesctrl MyTeles 1 63' enables full
-debugging.
-
-Questions
----------
-Check out the FAQ (ftp.franken.de).
-
-Bugs
-----
-If you find any please let me know.
-
-Thanks
-------
-Special thanks to:
-
- Erik Bos,Beat Doebeli,Fritz Elfert,
- Pauline Middelink,Paula de Nie,
- Bernd Oerding,Stephan Seidl,Matthias Urlichs,
- Rogier Wolff
-
-
-
-Enjoy,
-
-Jan den Ouden denouden@groovin.xs4all.nl
-
# ISDN subsystem
#
# CONFIG_ISDN is not set
+CONFIG_HISAX_EURO=y
#
# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
# ISDN subsystem
#
# CONFIG_ISDN is not set
+CONFIG_HISAX_EURO=y
#
# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO
dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN
+dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
+ bool 'HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+ bool 'HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+ bool 'HiSax Support for Teles 16.0/8.0' CONFIG_HISAX_16_0
+ bool 'HiSax Support for Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+ bool 'HiSax Support for AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+ bool 'HiSax Support for Elsa ISA cards' CONFIG_HISAX_ELSA_PCC
+ bool 'HiSax Support for Elsa PCMCIA card' CONFIG_HISAX_ELSA_PCMCIA
+ bool 'HiSax Support for ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+fi
+if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+fi
+dep_tristate 'AVM-B1 with CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
+if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
+ bool 'Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+fi
SUB_DIRS :=
MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn teles pcbit
+ALL_SUB_DIRS := icn pcbit hisax avmb1
L_OBJS :=
LX_OBJS :=
ifeq ($(CONFIG_ISDN),y)
L_TARGET := isdn.a
- L_OBJS += isdn_net.o isdn_tty.o isdn_cards.o
- LX_OBJS += isdn_common.o
+ L_OBJS += isdn_common.o isdn_net.o isdn_tty.o isdn_cards.o
+ LX_OBJS += isdn_syms.o
ifdef CONFIG_ISDN_PPP
L_OBJS += isdn_ppp.o
endif
ifeq ($(CONFIG_ISDN),m)
M_OBJS += isdn.o
O_TARGET += isdn.o
- O_OBJS += isdn_net.o isdn_tty.o
- OX_OBJS += isdn_common.o
+ O_OBJS += isdn_common.o isdn_net.o isdn_tty.o
+ OX_OBJS += isdn_syms.o
ifdef CONFIG_ISDN_PPP
O_OBJS += isdn_ppp.o
endif
endif
endif
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
- L_OBJS += teles/teles.o
- SUB_DIRS += teles
- MOD_SUB_DIRS += teles
+ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
+ L_OBJS += hisax/hisax.o
+ SUB_DIRS += hisax
+ MOD_SUB_DIRS += hisax
else
- ifeq ($(CONFIG_ISDN_DRV_TELES),m)
- MOD_SUB_DIRS += teles
+ ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
+ MOD_SUB_DIRS += hisax
endif
endif
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
+
include $(TOPDIR)/Rules.make
--- /dev/null
+#
+# $Id: Makefile,v 1.4 1997/03/30 17:10:40 calle Exp $
+#
+# 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: Makefile,v $
+# Revision 1.4 1997/03/30 17:10:40 calle
+# added support for AVM-B1-PCI card.
+#
+# Revision 1.3 1997/03/22 02:00:57 fritz
+# -Reworked toplevel Makefile. From now on, no different Makefiles
+# for standalone- and in-kernel-compilation are needed any more.
+# -Added local Rules.make for above reason.
+# -Experimental changes in teles3.c for enhanced IRQ-checking with
+# 2.1.X and SMP kernels.
+# -Removed diffstd-script, same functionality is in stddiff -r.
+# -Enhanced scripts std2kern and stddiff.
+#
+# Revision 1.1 1997/03/05 21:26:14 fritz
+# Renamed, according naming conventions in CVS tree.
+#
+# Revision 1.1 1997/03/04 21:50:26 calle
+# Frirst version in isdn4linux
+#
+# Revision 2.2 1997/02/12 09:31:39 calle
+#
+# Revision 1.1 1997/01/31 10:32:20 calle
+# Initial revision
+#
+#
+
+#
+# Objects that don't export a symtab
+#
+L_OBJS := # used as component of an L_TARGET
+O_OBJS := # used as component of an O_TARGET
+M_OBJS := # used as module
+#
+# Objects that do export a symtab
+#
+LX_OBJS := # used as component of an L_TARGET
+OX_OBJS := # used as component of an O_TARGET
+MX_OBJS := # used as module
+#
+# Targets, created by linking others
+#
+O_TARGET := # used for .o targets (from O and OX objects)
+L_TARGET := # used for .a targets (from L and LX objects)
+
+ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
+ O_TARGET += avmb1.o
+ O_OBJS += capi.o b1lli.o
+ OX_OBJS += capiutil.o b1capi.o capidrv.o
+ ifdef CONFIG_PCI
+ OX_OBJS += b1pci.o
+ endif
+else
+ ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
+ O_TARGET += kernelcapi.o
+ O_OBJS += b1lli.o
+ OX_OBJS += b1capi.o
+ M_OBJS += capi.o kernelcapi.o
+ MX_OBJS += capiutil.o capidrv.o
+ ifdef CONFIG_PCI
+ MX_OBJS += b1pci.o
+ endif
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * $Id: b1capi.c,v 1.4 1997/05/27 15:17:45 fritz Exp $
+ *
+ * CAPI 2.0 Module for AVM B1-card.
+ *
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1capi.c,v $
+ * Revision 1.4 1997/05/27 15:17:45 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.3 1997/05/18 09:24:09 calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.2 1997/03/05 21:20:41 fritz
+ * Removed include of config.h (mkdep stated this is unneded).
+ *
+ * Revision 1.1 1997/03/04 21:50:27 calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <asm/segment.h>
+#include <linux/skbuff.h>
+#include <linux/tqueue.h>
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+#include <linux/kernelcapi.h>
+#include "compat.h"
+#include "capicmd.h"
+#include "capiutil.h"
+
+static char *revision = "$Revision: 1.4 $";
+
+/* ------------------------------------------------------------- */
+
+int portbase = 0x150;
+int irq = 15;
+int showcapimsgs = 0; /* used in lli.c */
+int loaddebug = 0;
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+MODULE_PARM(portbase, "i");
+MODULE_PARM(irq, "2-15i");
+MODULE_PARM(showcapimsgs, "0-3i");
+MODULE_PARM(loaddebug, "0-1i");
+#endif
+
+/* ------------------------------------------------------------- */
+
+struct msgidqueue {
+ struct msgidqueue *next;
+ __u16 msgid;
+};
+
+typedef struct avmb1_ncci {
+ struct avmb1_ncci *next;
+ __u16 applid;
+ __u32 ncci;
+ __u32 winsize;
+ struct msgidqueue *msgidqueue;
+ struct msgidqueue *msgidlast;
+ struct msgidqueue *msgidfree;
+ struct msgidqueue msgidpool[CAPI_MAXDATAWINDOW];
+} avmb1_ncci;
+
+typedef struct avmb1_appl {
+ __u16 applid;
+ capi_register_params rparam;
+ int releasing;
+ __u32 param;
+ void (*signal) (__u16 applid, __u32 param);
+ struct sk_buff_head recv_queue;
+ struct avmb1_ncci *nccilist;
+} avmb1_appl;
+
+/* ------------------------------------------------------------- */
+
+static struct capi_version driver_version = {2, 0, 0, 9};
+static char driver_serial[CAPI_SERIAL_LEN] = "4711";
+static char capi_manufakturer[64] = "AVM Berlin";
+
+#define APPL(a) (&applications[(a)-1])
+#define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
+#define APPL_IS_FREE(a) (APPL(a)->applid == 0)
+#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);
+#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);
+
+#define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
+
+#define VALID_CARD(c) ((c) > 0 && (c) <= ncards)
+#define CARD(c) (&cards[(c)-1])
+#define CARDNR(cp) ((cards-(cp))+1)
+
+static avmb1_appl applications[CAPI_MAXAPPL];
+static avmb1_card cards[CAPI_MAXCONTR];
+static int ncards = 0;
+static struct sk_buff_head recv_queue;
+static struct capi_interface_user *capi_users = 0;
+static long notify_up_set = 0;
+static long notify_down_set = 0;
+
+static struct tq_struct tq_state_notify;
+static struct tq_struct tq_recv_notify;
+
+/* -------- util functions ------------------------------------ */
+
+static inline int capi_cmd_valid(__u8 cmd)
+{
+ switch (cmd) {
+ case CAPI_ALERT:
+ case CAPI_CONNECT:
+ case CAPI_CONNECT_ACTIVE:
+ case CAPI_CONNECT_B3_ACTIVE:
+ case CAPI_CONNECT_B3:
+ case CAPI_CONNECT_B3_T90_ACTIVE:
+ case CAPI_DATA_B3:
+ case CAPI_DISCONNECT_B3:
+ case CAPI_DISCONNECT:
+ case CAPI_FACILITY:
+ case CAPI_INFO:
+ case CAPI_LISTEN:
+ case CAPI_MANUFACTURER:
+ case CAPI_RESET_B3:
+ case CAPI_SELECT_B_PROTOCOL:
+ return 1;
+ }
+ return 0;
+}
+
+static inline int capi_subcmd_valid(__u8 subcmd)
+{
+ switch (subcmd) {
+ case CAPI_REQ:
+ case CAPI_CONF:
+ case CAPI_IND:
+ case CAPI_RESP:
+ return 1;
+ }
+ return 0;
+}
+
+/* -------- NCCI Handling ------------------------------------- */
+
+static inline void mq_init(avmb1_ncci * np)
+{
+ int i;
+ np->msgidqueue = 0;
+ np->msgidlast = 0;
+ memset(np->msgidpool, 0, sizeof(np->msgidpool));
+ np->msgidfree = &np->msgidpool[0];
+ for (i = 1; i < np->winsize; i++) {
+ np->msgidpool[i].next = np->msgidfree;
+ np->msgidfree = &np->msgidpool[i];
+ }
+}
+
+static inline int mq_enqueue(avmb1_ncci * np, __u16 msgid)
+{
+ struct msgidqueue *mq;
+ if ((mq = np->msgidfree) == 0)
+ return 0;
+ np->msgidfree = mq->next;
+ mq->msgid = msgid;
+ mq->next = 0;
+ if (np->msgidlast)
+ np->msgidlast->next = mq;
+ np->msgidlast = mq;
+ if (!np->msgidqueue)
+ np->msgidqueue = mq;
+ return 1;
+}
+
+static inline int mq_dequeue(avmb1_ncci * np, __u16 msgid)
+{
+ struct msgidqueue **pp;
+ for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
+ if ((*pp)->msgid == msgid) {
+ struct msgidqueue *mq = *pp;
+ *pp = mq->next;
+ if (mq == np->msgidlast)
+ np->msgidlast = 0;
+ mq->next = np->msgidfree;
+ np->msgidfree = mq;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void avmb1_handle_new_ncci(avmb1_card * card,
+ __u16 appl, __u32 ncci, __u32 winsize)
+{
+ avmb1_ncci *np;
+ if (!VALID_APPLID(appl)) {
+ printk(KERN_ERR "avmb1_handle_new_ncci: illegal appl %d\n", appl);
+ return;
+ }
+ if ((np = (avmb1_ncci *) kmalloc(sizeof(avmb1_ncci), GFP_ATOMIC)) == 0) {
+ printk(KERN_ERR "avmb1_handle_new_ncci: alloc failed ncci 0x%x\n", ncci);
+ return;
+ }
+ if (winsize > CAPI_MAXDATAWINDOW) {
+ printk(KERN_ERR "avmb1_handle_new_ncci: winsize %d too big, set to %d\n",
+ winsize, CAPI_MAXDATAWINDOW);
+ winsize = CAPI_MAXDATAWINDOW;
+ }
+ np->applid = appl;
+ np->ncci = ncci;
+ np->winsize = winsize;
+ mq_init(np);
+ np->next = APPL(appl)->nccilist;
+ APPL(appl)->nccilist = np;
+ printk(KERN_INFO "b1capi: appl %d ncci 0x%x up\n", appl, ncci);
+
+}
+
+void avmb1_handle_free_ncci(avmb1_card * card,
+ __u16 appl, __u32 ncci)
+{
+ if (!VALID_APPLID(appl)) {
+ printk(KERN_ERR "avmb1_handle_free_ncci: illegal appl %d\n", appl);
+ return;
+ }
+ if (ncci != 0xffffffff) {
+ avmb1_ncci **pp;
+ for (pp = &APPL(appl)->nccilist; *pp; pp = &(*pp)->next) {
+ if ((*pp)->ncci == ncci) {
+ avmb1_ncci *np = *pp;
+ *pp = np->next;
+ kfree(np);
+ printk(KERN_INFO "b1capi: appl %d ncci 0x%x down\n", appl, ncci);
+ return;
+ }
+ }
+ printk(KERN_ERR "avmb1_handle_free_ncci: ncci 0x%x not found\n", ncci);
+ } else {
+ avmb1_ncci **pp, **nextpp;
+ for (pp = &APPL(appl)->nccilist; *pp; pp = nextpp) {
+ if (NCCI2CTRL((*pp)->ncci) == card->cnr) {
+ avmb1_ncci *np = *pp;
+ *pp = np->next;
+ printk(KERN_INFO "b1capi: appl %d ncci 0x%x down!\n", appl, np->ncci);
+ kfree(np);
+ nextpp = pp;
+ } else {
+ nextpp = &(*pp)->next;
+ }
+ }
+ APPL(appl)->releasing--;
+ if (APPL(appl)->releasing == 0) {
+ APPL(appl)->signal = 0;
+ APPL_MARK_FREE(appl);
+ printk(KERN_INFO "b1capi: appl %d down\n", appl);
+ }
+ }
+}
+
+static avmb1_ncci *find_ncci(avmb1_appl * app, __u32 ncci)
+{
+ avmb1_ncci *np;
+ for (np = app->nccilist; np; np = np->next) {
+ if (np->ncci == ncci)
+ return np;
+ }
+ return 0;
+}
+
+/* -------- Receiver ------------------------------------------ */
+
+
+static void recv_handler(void *dummy)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&recv_queue)) != 0) {
+ __u16 appl = CAPIMSG_APPID(skb->data);
+ struct avmb1_ncci *np;
+ if (!VALID_APPLID(appl)) {
+ printk(KERN_ERR "b1capi: recv_handler: applid %d ? (%s)\n",
+ appl, capi_message2str(skb->data));
+ kfree_skb(skb, FREE_READ);
+ continue;
+ }
+ if (APPL(appl)->signal == 0) {
+ printk(KERN_ERR "b1capi: recv_handler: applid %d has no signal function\n",
+ appl);
+ kfree_skb(skb, FREE_READ);
+ continue;
+ }
+ if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+ && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF
+ && (np = find_ncci(APPL(appl), CAPIMSG_NCCI(skb->data))) != 0
+ && mq_dequeue(np, CAPIMSG_MSGID(skb->data)) == 0) {
+ printk(KERN_ERR "b1capi: msgid %hu ncci 0x%x not on queue\n",
+ CAPIMSG_MSGID(skb->data), np->ncci);
+ }
+ skb_queue_tail(&APPL(appl)->recv_queue, skb);
+ (APPL(appl)->signal) (APPL(appl)->applid, APPL(appl)->param);
+ }
+}
+
+
+void avmb1_handle_capimsg(avmb1_card * card, __u16 appl, struct sk_buff *skb)
+{
+ if (card->cardstate != CARD_RUNNING) {
+ printk(KERN_INFO "b1capi: controller %d not active, got: %s",
+ card->cnr, capi_message2str(skb->data));
+ goto error;
+ return;
+ }
+ skb_queue_tail(&recv_queue, skb);
+ queue_task(&tq_recv_notify, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return;
+
+ error:
+ kfree_skb(skb, FREE_READ);
+}
+
+void avmb1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+ avmb1_card *card;
+
+ card = (avmb1_card *) devptr;
+
+ if (!card) {
+ printk(KERN_WARNING "avmb1_interrupt: wrong device\n");
+ return;
+ }
+ if (card->interrupt) {
+ printk(KERN_ERR "avmb1_interrupt: reentering interrupt hander\n");
+ return;
+ }
+
+ card->interrupt = 1;
+
+ B1_handle_interrupt(card);
+
+ card->interrupt = 0;
+}
+
+/* -------- Notifier ------------------------------------------ */
+
+static void notify_up(__u16 contr)
+{
+ struct capi_interface_user *p;
+
+ for (p = capi_users; p; p = p->next) {
+ if (p->callback)
+ (*p->callback) (KCI_CONTRUP, contr,
+ (capi_profile *)
+ CARD(contr)->version[VER_PROFILE]);
+ }
+}
+
+static void notify_down(__u16 contr)
+{
+ struct capi_interface_user *p;
+ for (p = capi_users; p; p = p->next) {
+ if (p->callback)
+ (*p->callback) (KCI_CONTRDOWN, contr, 0);
+ }
+}
+
+static void notify_handler(void *dummy)
+{
+ __u16 contr;
+
+ for (contr=1; VALID_CARD(contr); contr++)
+ if (test_and_clear_bit(contr, ¬ify_up_set))
+ notify_up(contr);
+ for (contr=1; VALID_CARD(contr); contr++)
+ if (test_and_clear_bit(contr, ¬ify_down_set))
+ notify_down(contr);
+}
+
+/* -------- card ready callback ------------------------------- */
+
+void avmb1_card_ready(avmb1_card * card)
+{
+ __u16 appl;
+
+ card->cversion.majorversion = 2;
+ card->cversion.minorversion = 0;
+ card->cversion.majormanuversion = (card->version[VER_DRIVER][0] - '0') << 4;
+ card->cversion.majormanuversion |= (card->version[VER_DRIVER][2] - '0');
+ card->cversion.minormanuversion = (card->version[VER_DRIVER][3] - '0') << 4;
+ card->cversion.minormanuversion |= (card->version[VER_DRIVER][5] - '0') * 10;
+ card->cversion.minormanuversion |= (card->version[VER_DRIVER][6] - '0');
+ card->cardstate = CARD_RUNNING;
+
+
+ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+ if (VALID_APPLID(appl) && !APPL(appl)->releasing) {
+ B1_send_register(card->port, appl,
+ 1024 * (APPL(appl)->rparam.level3cnt+1),
+ APPL(appl)->rparam.level3cnt,
+ APPL(appl)->rparam.datablkcnt,
+ APPL(appl)->rparam.datablklen);
+ }
+ }
+
+ set_bit(CARDNR(card), ¬ify_up_set);
+ queue_task(&tq_state_notify, &tq_scheduler);
+}
+
+/* ------------------------------------------------------------- */
+
+int avmb1_addcard(int port, int irq)
+{
+ struct avmb1_card *card;
+ int irqval;
+
+
+ card = &cards[ncards];
+ memset(card, 0, sizeof(avmb1_card));
+ sprintf(card->name, "avmb1-%d", ncards + 1);
+
+ request_region(port, AVMB1_PORTLEN, card->name);
+
+ if ((irqval = request_irq(irq, avmb1_interrupt, SA_SHIRQ, card->name, card)) != 0) {
+ printk(KERN_ERR "b1capi: unable to get IRQ %d (irqval=%d).\n",
+ irq, irqval);
+ release_region((unsigned short) port, AVMB1_PORTLEN);
+ return -EIO;
+ }
+ ncards++;
+ card->cnr = ncards;
+ card->port = port;
+ card->irq = irq;
+ card->cardstate = CARD_DETECTED;
+ return 0;
+}
+
+int avmb1_probecard(int port, int irq)
+{
+ int rc;
+
+ if (check_region((unsigned short) port, AVMB1_PORTLEN)) {
+ printk(KERN_WARNING
+ "b1capi: ports 0x%03x-0x%03x in use.\n",
+ portbase, portbase + AVMB1_PORTLEN);
+ return -EIO;
+ }
+ if (!B1_valid_irq(irq)) {
+ printk(KERN_WARNING "b1capi: irq %d not valid.\n", irq);
+ return -EIO;
+ }
+ if ((rc = B1_detect(port)) != 0) {
+ printk(KERN_NOTICE "b1capi: NO card at 0x%x (%d)\n", port, rc);
+ return -EIO;
+ }
+ B1_reset(port);
+ printk(KERN_NOTICE "b1capi: AVM-B1-Controller detected at 0x%x\n", port);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+/* -------- CAPI2.0 Interface ---------------------------------- */
+/* ------------------------------------------------------------- */
+
+static int capi_installed(void)
+{
+ int i;
+ for (i = 0; i < ncards; i++) {
+ if (cards[i].cardstate == CARD_RUNNING)
+ return 1;
+ }
+ return 0;
+}
+
+static __u16 capi_register(capi_register_params * rparam, __u16 * applidp)
+{
+ int i;
+ int appl;
+
+ if (rparam->datablklen < 128)
+ return CAPI_LOGBLKSIZETOSMALL;
+
+ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+ if (APPL_IS_FREE(appl))
+ break;
+ }
+ if (appl > CAPI_MAXAPPL)
+ return CAPI_TOOMANYAPPLS;
+
+ APPL_MARK_USED(appl);
+ skb_queue_head_init(&APPL(appl)->recv_queue);
+
+ memcpy(&APPL(appl)->rparam, rparam, sizeof(capi_register_params));
+
+ for (i = 0; i < ncards; i++) {
+ if (cards[i].cardstate != CARD_RUNNING)
+ continue;
+ B1_send_register(cards[i].port, appl,
+ 1024 * (APPL(appl)->rparam.level3cnt + 1),
+ APPL(appl)->rparam.level3cnt,
+ APPL(appl)->rparam.datablkcnt,
+ APPL(appl)->rparam.datablklen);
+ }
+ *applidp = appl;
+ printk(KERN_INFO "b1capi: appl %d up\n", appl);
+
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_release(__u16 applid)
+{
+ struct sk_buff *skb;
+ int i;
+
+ if (ncards == 0)
+ return CAPI_REGNOTINSTALLED;
+ if (!VALID_APPLID(applid) || APPL(applid)->releasing)
+ return CAPI_ILLAPPNR;
+ while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
+ kfree_skb(skb, FREE_READ);
+ for (i = 0; i < ncards; i++) {
+ if (cards[i].cardstate != CARD_RUNNING)
+ continue;
+ APPL(applid)->releasing++;
+ B1_send_release(cards[i].port, applid);
+ }
+ if (APPL(applid)->releasing == 0) {
+ APPL(applid)->signal = 0;
+ APPL_MARK_FREE(applid);
+ printk(KERN_INFO "b1capi: appl %d down\n", applid);
+ }
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_put_message(__u16 applid, struct sk_buff *skb)
+{
+ avmb1_ncci *np;
+ int contr;
+ if (ncards == 0)
+ return CAPI_REGNOTINSTALLED;
+ if (!VALID_APPLID(applid))
+ return CAPI_ILLAPPNR;
+ if (skb->len < 12
+ || !capi_cmd_valid(CAPIMSG_COMMAND(skb->data))
+ || !capi_subcmd_valid(CAPIMSG_SUBCOMMAND(skb->data)))
+ return CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
+ contr = CAPIMSG_CONTROLLER(skb->data);
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING) {
+ contr = 1;
+ if (CARD(contr)->cardstate != CARD_RUNNING)
+ return CAPI_REGNOTINSTALLED;
+ }
+ if (CARD(contr)->blocked)
+ return CAPI_SENDQUEUEFULL;
+
+ if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+ && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_REQ
+ && (np = find_ncci(APPL(applid), CAPIMSG_NCCI(skb->data))) != 0
+ && mq_enqueue(np, CAPIMSG_MSGID(skb->data)) == 0)
+ return CAPI_SENDQUEUEFULL;
+
+ B1_send_message(CARD(contr)->port, skb);
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_message(__u16 applid, struct sk_buff **msgp)
+{
+ struct sk_buff *skb;
+
+ if (!VALID_APPLID(applid))
+ return CAPI_ILLAPPNR;
+ if ((skb = skb_dequeue(&APPL(applid)->recv_queue)) == 0)
+ return CAPI_RECEIVEQUEUEEMPTY;
+ *msgp = skb;
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_set_signal(__u16 applid,
+ void (*signal) (__u16 applid, __u32 param),
+ __u32 param)
+{
+ if (!VALID_APPLID(applid))
+ return CAPI_ILLAPPNR;
+ APPL(applid)->signal = signal;
+ APPL(applid)->param = param;
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_manufacturer(__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN])
+{
+ if (contr == 0) {
+ strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
+ return CAPI_NOERROR;
+ }
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
+ return 0x2002;
+
+ strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_version(__u16 contr, struct capi_version *verp)
+{
+ if (contr == 0) {
+ *verp = driver_version;
+ return CAPI_NOERROR;
+ }
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
+ return 0x2002;
+
+ memcpy((void *) verp, CARD(contr)->version[VER_SERIAL],
+ sizeof(capi_version));
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_serial(__u16 contr, __u8 serial[CAPI_SERIAL_LEN])
+{
+ if (contr == 0) {
+ strncpy(serial, driver_serial, 8);
+ return CAPI_NOERROR;
+ }
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
+ return 0x2002;
+
+ memcpy((void *) serial, CARD(contr)->version[VER_SERIAL],
+ CAPI_SERIAL_LEN);
+ serial[CAPI_SERIAL_LEN - 1] = 0;
+ return CAPI_NOERROR;
+}
+
+static __u16 capi_get_profile(__u16 contr, struct capi_profile *profp)
+{
+ if (contr == 0) {
+ profp->ncontroller = ncards;
+ return CAPI_NOERROR;
+ }
+ if (!VALID_CARD(contr) || CARD(contr)->cardstate != CARD_RUNNING)
+ return 0x2002;
+
+ memcpy((void *) profp, CARD(contr)->version[VER_PROFILE],
+ sizeof(struct capi_profile));
+ return CAPI_NOERROR;
+}
+
+static int capi_manufacturer(unsigned int cmd, void *data)
+{
+ unsigned long flags;
+ avmb1_loaddef ldef;
+ avmb1_carddef cdef;
+ avmb1_resetdef rdef;
+ avmb1_card *card;
+ int rc;
+
+ switch (cmd) {
+ case AVMB1_ADDCARD:
+ if ((rc = copy_from_user((void *) &cdef, data,
+ sizeof(avmb1_carddef))))
+ return rc;
+ if (!B1_valid_irq(cdef.irq))
+ return -EINVAL;
+
+ if ((rc = avmb1_probecard(cdef.port, cdef.irq)) != 0)
+ return rc;
+
+ return avmb1_addcard(cdef.port, cdef.irq);
+
+ case AVMB1_LOAD:
+
+ if ((rc = copy_from_user((void *) &ldef, data,
+ sizeof(avmb1_loaddef))))
+ return rc;
+ if (!VALID_CARD(ldef.contr) || ldef.t4file.len <= 0) {
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: load: invalid parameter contr=%d len=%d\n", ldef.contr, ldef.t4file.len);
+ return -EINVAL;
+ }
+
+ card = CARD(ldef.contr);
+ save_flags(flags);
+ cli();
+ if (card->cardstate != CARD_DETECTED) {
+ restore_flags(flags);
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: load: contr=%d not in detect state\n", ldef.contr);
+ return -EBUSY;
+ }
+ card->cardstate = CARD_LOADING;
+ restore_flags(flags);
+
+ if (loaddebug) {
+ printk(KERN_DEBUG "b1capi: load: reseting contr %d\n",
+ ldef.contr);
+ }
+
+ B1_reset(card->port);
+ if ((rc = B1_load_t4file(card->port, &ldef.t4file))) {
+ B1_reset(card->port);
+ printk(KERN_ERR "b1capi: failed to load t4file!!\n");
+ card->cardstate = CARD_DETECTED;
+ return rc;
+ }
+ B1_disable_irq(card->port);
+ if (loaddebug) {
+ printk(KERN_DEBUG "b1capi: load: ready contr %d: checking\n",
+ ldef.contr);
+ }
+
+ if (!B1_loaded(card->port)) {
+ card->cardstate = CARD_DETECTED;
+ printk(KERN_ERR "b1capi: failed to load t4file.\n");
+ return -EIO;
+ }
+ /*
+ * enable interrupt
+ */
+
+ card->cardstate = CARD_INITSTATE;
+ save_flags(flags);
+ cli();
+ B1_assign_irq(card->port, card->irq);
+ B1_enable_irq(card->port);
+ restore_flags(flags);
+
+ if (loaddebug) {
+ printk(KERN_DEBUG "b1capi: load: irq enabled contr %d\n",
+ ldef.contr);
+ }
+
+ /*
+ * init card
+ */
+ B1_send_init(card->port, AVM_NAPPS, AVM_NNCCI, card->cnr - 1);
+
+ if (loaddebug) {
+ printk(KERN_DEBUG "b1capi: load: waiting for init reply contr %d\n",
+ ldef.contr);
+ }
+
+ while (card->cardstate != CARD_RUNNING) {
+
+ current->timeout = jiffies + HZ / 10; /* 0.1 sec */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+
+ if (current->signal & ~current->blocked)
+ return -EINTR;
+ }
+ return 0;
+ case AVMB1_RESETCARD:
+ if ((rc = copy_from_user((void *) &rdef, data,
+ sizeof(avmb1_resetdef))))
+ return rc;
+
+ if (!VALID_CARD(rdef.contr))
+ return -EINVAL;
+
+ card = CARD(rdef.contr);
+
+ if (card->cardstate == CARD_RUNNING)
+ return -EBUSY;
+
+ B1_reset(card->port);
+ B1_reset(card->port);
+
+ card->cardstate = CARD_DETECTED;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+struct capi_interface avmb1_interface =
+{
+ capi_installed,
+ capi_register,
+ capi_release,
+ capi_put_message,
+ capi_get_message,
+ capi_set_signal,
+ capi_get_manufacturer,
+ capi_get_version,
+ capi_get_serial,
+ capi_get_profile,
+ capi_manufacturer
+};
+
+/* ------------------------------------------------------------- */
+/* -------- Exported Functions --------------------------------- */
+/* ------------------------------------------------------------- */
+
+struct capi_interface *attach_capi_interface(struct capi_interface_user *userp)
+{
+ struct capi_interface_user *p;
+
+ for (p = capi_users; p; p = p->next) {
+ if (p == userp) {
+ printk(KERN_ERR "b1capi: double attach from %s\n",
+ userp->name);
+ return 0;
+ }
+ }
+ userp->next = capi_users;
+ capi_users = userp;
+ MOD_INC_USE_COUNT;
+
+ return &avmb1_interface;
+}
+
+int detach_capi_interface(struct capi_interface_user *userp)
+{
+ struct capi_interface_user **pp;
+
+ for (pp = &capi_users; *pp; pp = &(*pp)->next) {
+ if (*pp == userp) {
+ *pp = userp->next;
+ userp->next = 0;
+ MOD_DEC_USE_COUNT;
+ return 0;
+ }
+ }
+ printk(KERN_ERR "b1capi: double detach from %s\n", userp->name);
+ return -1;
+}
+
+/* ------------------------------------------------------------- */
+/* -------- Init & Cleanup ------------------------------------- */
+/* ------------------------------------------------------------- */
+
+#ifdef HAS_NEW_SYMTAB
+EXPORT_SYMBOL(attach_capi_interface);
+EXPORT_SYMBOL(detach_capi_interface);
+EXPORT_SYMBOL(avmb1_addcard);
+EXPORT_SYMBOL(avmb1_probecard);
+#else
+static struct symbol_table capidev_syms =
+{
+#include <linux/symtab_begin.h>
+ X(attach_capi_interface),
+ X(detach_capi_interface),
+ X(avmb1_addcard),
+ X(avmb1_probecard),
+#include <linux/symtab_end.h>
+};
+#endif
+
+
+/*
+ * init / exit functions
+ */
+
+#ifdef MODULE
+#define avmb1_init init_module
+#endif
+
+int avmb1_init(void)
+{
+ char *p;
+ char rev[10];
+
+
+#ifndef HAS_NEW_SYMTAB
+ /* No symbols to export, hide all symbols */
+ register_symtab(&capidev_syms);
+#endif
+ skb_queue_head_init(&recv_queue);
+ /* init_bh(CAPI_BH, do_capi_bh); */
+
+ tq_state_notify.routine = notify_handler;
+ tq_state_notify.data = 0;
+
+ tq_recv_notify.routine = recv_handler;
+ tq_recv_notify.data = 0;
+
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, " ??? ");
+
+#ifdef MODULE
+ if (portbase) {
+ int rc;
+ if ((rc = avmb1_probecard(portbase, irq)) != 0)
+ return rc;
+ if ((rc = avmb1_addcard(portbase, irq)) != 0)
+ return rc;
+ } else {
+ printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: loaded\n", rev);
+ }
+#else
+ printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: started\n", rev);
+#endif
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ char rev[10];
+ char *p;
+ int i;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else {
+ strcpy(rev, " ??? ");
+ }
+
+ for (i = 0; i < ncards; i++) {
+ /*
+ * disable card
+ */
+ B1_disable_irq(cards[i].port);
+ B1_reset(cards[i].port);
+ B1_reset(cards[i].port);
+ /*
+ * free kernel resources
+ */
+ free_irq(cards[i].irq, &cards[i]);
+ release_region(cards[i].port, AVMB1_PORTLEN);
+
+ }
+ printk(KERN_NOTICE "AVM-B1-CAPI-driver Rev%s: unloaded\n", rev);
+}
+#endif
--- /dev/null
+/*
+ * $Id: b1lli.c,v 1.1 1997/03/04 21:50:28 calle Exp $
+ *
+ * ISDN lowlevel-module for AVM B1-card.
+ *
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1lli.c,v $
+ * Revision 1.1 1997/03/04 21:50:28 calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+
+#include "compat.h"
+#include "capicmd.h"
+#include "capiutil.h"
+
+/*
+ * 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 ....
+ */
+
+/*
+ * 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
+ */
+
+/*
+ * port offsets
+ */
+
+#define B1_READ 0x00
+#define B1_WRITE 0x01
+#define B1_INSTAT 0x02
+#define B1_OUTSTAT 0x03
+#define B1_RESET 0x10
+#define B1_ANALYSE 0x04
+
+
+
+static inline unsigned char b1outp(unsigned short base,
+ unsigned short offset,
+ unsigned char value)
+{
+ outb(value, base + offset);
+ return inb(base + B1_ANALYSE);
+}
+
+static int 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_valid_irq(unsigned irq)
+{
+ return irq_table[irq] != 0;
+}
+
+unsigned char B1_assign_irq(unsigned short base, unsigned irq)
+{
+ return b1outp(base, B1_RESET, irq_table[irq]);
+}
+
+unsigned char B1_enable_irq(unsigned short base)
+{
+ return b1outp(base, B1_INSTAT, 0x02);
+}
+
+unsigned char B1_disable_irq(unsigned short base)
+{
+ return b1outp(base, B1_INSTAT, 0x00);
+}
+
+void B1_reset(unsigned short 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 */
+}
+
+int B1_detect(unsigned short base)
+{
+ /*
+ * 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;
+
+ return 0;
+}
+
+static inline int B1_rx_full(unsigned short base)
+{
+ return inb(base + B1_INSTAT) & 0x1;
+}
+
+static inline unsigned char B1_get_byte(unsigned short base)
+{
+ unsigned long i = jiffies + 5 * HZ; /* maximum wait time 5 sec */
+ while (!B1_rx_full(base) && i > jiffies);
+ if (B1_rx_full(base))
+ return inb(base + B1_READ);
+ printk(KERN_CRIT "b1lli: rx not full after 5 second\n");
+ return 0;
+}
+
+static inline unsigned int B1_get_word(unsigned short 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 short base)
+{
+ return inb(base + B1_OUTSTAT) & 0x1;
+}
+
+static inline void B1_put_byte(unsigned short base, unsigned char val)
+{
+ while (!B1_tx_empty(base));
+ b1outp(base, B1_WRITE, val);
+}
+
+static inline void B1_put_word(unsigned short 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 short 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 short base,
+ unsigned char *dp, unsigned int len)
+{
+ B1_put_word(base, len);
+ while (len-- > 0)
+ B1_put_byte(base, *dp++);
+}
+
+extern int loaddebug;
+
+int B1_load_t4file(unsigned short base, avmb1_t4file * t4file)
+{
+ /*
+ * Data is in user space !!!
+ */
+ unsigned char buf[256];
+ unsigned char *dp;
+ int i, left, retval;
+
+
+ dp = t4file->data;
+ left = t4file->len;
+ while (left > sizeof(buf)) {
+ retval = copy_from_user(buf, dp, sizeof(buf));
+ if (retval)
+ return -EFAULT;
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: loading: %d bytes ..", sizeof(buf));
+ for (i = 0; i < sizeof(buf); i++)
+ B1_put_byte(base, buf[i]);
+ if (loaddebug)
+ printk("ok\n");
+ left -= sizeof(buf);
+ dp += sizeof(buf);
+ }
+ if (left) {
+ retval = copy_from_user(buf, dp, left);
+ if (retval)
+ return -EFAULT;
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: loading: %d bytes ..", left);
+ for (i = 0; i < left; i++)
+ B1_put_byte(base, buf[i]);
+ if (loaddebug)
+ printk("ok\n");
+ }
+ return 0;
+}
+
+int B1_loaded(unsigned short base)
+{
+ int i;
+ unsigned char ans;
+
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: loaded: wait 1 ..\n");
+ for (i = jiffies + 10 * HZ; i > jiffies;) {
+ if (B1_tx_empty(base))
+ break;
+ }
+ if (!B1_tx_empty(base)) {
+ printk(KERN_ERR "b1lli: B1_loaded: timeout tx\n");
+ return 0;
+ }
+ B1_put_byte(base, SEND_POLL);
+ printk(KERN_DEBUG "b1capi: loaded: wait 2 ..\n");
+ for (i = jiffies + 10 * HZ; i > jiffies;) {
+ if (B1_rx_full(base)) {
+ if ((ans = B1_get_byte(base)) == RECEIVE_POLL) {
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: loaded: ok\n");
+ return 1;
+ }
+ printk(KERN_ERR "b1lli: B1_loaded: got 0x%x ???\n", ans);
+ return 0;
+ }
+ }
+ printk(KERN_ERR "b1lli: B1_loaded: timeout rx\n");
+ return 0;
+}
+
+/*
+ * -------------------------------------------------------------------
+ */
+static inline void parse_version(avmb1_card * card)
+{
+ int i, j;
+ for (j = 0; j < AVM_MAXVERSION; j++)
+ card->version[j] = "\0\0" + 1;
+ for (i = 0, j = 0;
+ j < AVM_MAXVERSION && i < card->versionlen;
+ j++, i += card->versionbuf[i] + 1)
+ card->version[j] = &card->versionbuf[i + 1];
+}
+/*
+ * -------------------------------------------------------------------
+ */
+
+void B1_send_init(unsigned short port,
+ unsigned int napps, unsigned int nncci, unsigned int cardnr)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_INIT);
+ B1_put_word(port, napps);
+ B1_put_word(port, nncci);
+ B1_put_word(port, cardnr);
+ restore_flags(flags);
+}
+
+void B1_send_register(unsigned short port,
+ __u16 appid, __u32 nmsg,
+ __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_REGISTER);
+ B1_put_word(port, appid);
+ B1_put_word(port, nmsg);
+ B1_put_word(port, nb3conn);
+ B1_put_word(port, nb3blocks);
+ B1_put_word(port, b3bsize);
+ restore_flags(flags);
+}
+
+void B1_send_release(unsigned short port,
+ __u16 appid)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_RELEASE);
+ B1_put_word(port, appid);
+ restore_flags(flags);
+}
+
+extern int showcapimsgs;
+
+void B1_send_message(unsigned short port, struct sk_buff *skb)
+{
+ unsigned long flags;
+ __u16 len = CAPIMSG_LEN(skb->data);
+ __u8 cmd = CAPIMSG_COMMAND(skb->data);
+ __u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+ __u32 contr = CAPIMSG_CONTROL(skb->data);
+
+ if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+
+ if (showcapimsgs > 2) {
+ if (showcapimsgs & 1) {
+ printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd), len);
+ } else {
+ printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data));
+ }
+
+ }
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_DATA_B3_REQ);
+ B1_put_slice(port, skb->data, len);
+ B1_put_slice(port, skb->data + len, dlen);
+ restore_flags(flags);
+ } else {
+ if (showcapimsgs) {
+
+ if (showcapimsgs & 1) {
+ printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd), len);
+ } else {
+ printk(KERN_DEBUG "b1lli: Put %s\n", capi_message2str(skb->data));
+ }
+ }
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_MESSAGE);
+ B1_put_slice(port, skb->data, len);
+ restore_flags(flags);
+ }
+ dev_kfree_skb(skb, FREE_WRITE);
+}
+
+/*
+ * -------------------------------------------------------------------
+ */
+
+void B1_handle_interrupt(avmb1_card * card)
+{
+ 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 (showcapimsgs > 2) {
+ __u8 cmd = CAPIMSG_COMMAND(card->msgbuf);
+ __u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf);
+ __u32 contr = CAPIMSG_CONTROL(card->msgbuf);
+ CAPIMSG_SETDATA(card->msgbuf, card->databuf);
+ if (showcapimsgs & 1) {
+ printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u/%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(card->msgbuf),
+ capi_cmd2str(cmd, subcmd),
+ MsgLen, DataB3Len);
+ } else {
+ printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf));
+ }
+ }
+ if (!(skb = dev_alloc_skb(DataB3Len + MsgLen))) {
+ printk(KERN_ERR "b1lli: incoming packet dropped\n");
+ } else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+ CAPIMSG_SETDATA(skb->data, skb->data + MsgLen);
+ avmb1_handle_capimsg(card, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_MESSAGE:
+
+ ApplId = (unsigned) B1_get_word(card->port);
+ MsgLen = B1_get_slice(card->port, card->msgbuf);
+ if (showcapimsgs) {
+ __u8 cmd = CAPIMSG_COMMAND(card->msgbuf);
+ __u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf);
+ __u32 contr = CAPIMSG_CONTROL(card->msgbuf);
+ if (showcapimsgs & 1) {
+ printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(card->msgbuf),
+ capi_cmd2str(cmd, subcmd),
+ MsgLen);
+ } else {
+ printk(KERN_DEBUG "b1lli: Got %s\n", capi_message2str(card->msgbuf));
+ }
+
+ }
+ if (!(skb = dev_alloc_skb(MsgLen))) {
+ printk(KERN_ERR "b1lli: incoming packet dropped\n");
+ } else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ avmb1_handle_capimsg(card, 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);
+
+ if (showcapimsgs)
+ printk(KERN_DEBUG "b1lli: NEW_NCCI app %u ncci 0x%x\n", ApplId, NCCI);
+
+ avmb1_handle_new_ncci(card, ApplId, NCCI, WindowSize);
+
+ break;
+
+ case RECEIVE_FREE_NCCI:
+
+ ApplId = B1_get_word(card->port);
+ NCCI = B1_get_word(card->port);
+
+ if (showcapimsgs)
+ printk(KERN_DEBUG "b1lli: FREE_NCCI app %u ncci 0x%x\n", ApplId, NCCI);
+
+ avmb1_handle_free_ncci(card, ApplId, NCCI);
+ break;
+
+ case RECEIVE_START:
+ if (card->blocked)
+ printk(KERN_DEBUG "b1lli: RESTART\n");
+ card->blocked = 0;
+ break;
+
+ case RECEIVE_STOP:
+ printk(KERN_DEBUG "b1lli: STOP\n");
+ card->blocked = 1;
+ break;
+
+ case RECEIVE_INIT:
+
+ card->versionlen = B1_get_slice(card->port, card->versionbuf);
+ card->cardstate = CARD_ACTIVE;
+ parse_version(card);
+ printk(KERN_INFO "b1lli: %s-card (%s) with %s now active\n",
+ card->version[VER_CARDTYPE],
+ card->version[VER_DRIVER],
+ card->version[VER_PROTO]);
+ avmb1_card_ready(card);
+ break;
+ default:
+ printk(KERN_ERR "b1lli: B1_handle_interrupt: 0x%x ???\n", b1cmd);
+ break;
+ }
+}
--- /dev/null
+/*
+ * $Id: b1pci.c,v 1.2 1997/05/18 09:24:13 calle Exp $
+ *
+ * Module for AVM B1 PCI-card.
+ *
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1pci.c,v $
+ * Revision 1.2 1997/05/18 09:24:13 calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.1 1997/03/30 17:10:42 calle
+ * added support for AVM-B1-PCI card.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/skbuff.h>
+#include "compat.h"
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+
+#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
+
+static char *revision = "$Revision: 1.2 $";
+
+/* ------------------------------------------------------------- */
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+#endif
+
+/* ------------------------------------------------------------- */
+
+/* ------------------------------------------------------------- */
+/* -------- Init & Cleanup ------------------------------------- */
+/* ------------------------------------------------------------- */
+
+/*
+ * init / exit functions
+ */
+
+#ifdef MODULE
+#define b1pci_init init_module
+#endif
+
+int b1pci_init(void)
+{
+ char *p;
+ char rev[10];
+ int rc;
+ int pci_index;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, " ??? ");
+
+
+#ifdef CONFIG_PCI
+ if (!pcibios_present()) {
+ printk(KERN_ERR "b1pci: no PCI-BIOS present\n");
+ return -EIO;
+ }
+
+ printk(KERN_INFO "b1pci: revision %s\n", rev);
+
+ for (pci_index = 0; pci_index < 8; pci_index++) {
+ unsigned char pci_bus, pci_device_fn;
+ unsigned int ioaddr;
+ unsigned char irq;
+
+ if (pcibios_find_device (PCI_VENDOR_ID_AVM,
+ PCI_DEVICE_ID_AVM_B1, pci_index,
+ &pci_bus, &pci_device_fn) != 0) {
+ continue;
+ }
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &irq);
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, &ioaddr);
+ /* Strip the I/O address out of the returned value */
+ ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+ printk(KERN_INFO
+ "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
+ ioaddr, irq);
+ if ((rc = avmb1_probecard(ioaddr, irq)) != 0) {
+ printk(KERN_ERR
+ "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
+ ioaddr, irq);
+ return rc;
+ }
+ if ((rc = avmb1_addcard(ioaddr, irq)) != 0)
+ return rc;
+ }
+ return 0;
+#else
+ printk(KERN_ERR "b1pci: kernel not compiled with PCI.\n");
+ return -EIO;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+}
+#endif
--- /dev/null
+/*
+ * $Id: capi.c,v 1.4 1997/05/27 15:17:50 fritz Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+ * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capi.c,v $
+ * Revision 1.4 1997/05/27 15:17:50 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.3 1997/05/18 09:24:14 calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.2 1997/03/05 21:17:59 fritz
+ * Added capi_poll for compiling under 2.1.27
+ *
+ * Revision 1.1 1997/03/04 21:50:29 calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/skbuff.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <asm/poll.h>
+#endif
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+
+#include "compat.h"
+#include "capiutil.h"
+#include "capicmd.h"
+#include "capidev.h"
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
+#endif
+
+/* -------- driver information -------------------------------------- */
+
+int capi_major = 68; /* allocated */
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_PARM(capi_major, "i");
+#endif
+
+/* -------- global variables ---------------------------------------- */
+
+static struct capidev capidevs[CAPI_MAXMINOR + 1];
+struct capi_interface *capifuncs;
+
+/* -------- function called by lower level -------------------------- */
+
+static void capi_signal(__u16 applid, __u32 minor)
+{
+ struct capidev *cdev;
+ struct sk_buff *skb = 0;
+
+ if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) {
+ printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor);
+ return;
+ }
+ cdev = &capidevs[minor];
+ (void) (*capifuncs->capi_get_message) (applid, &skb);
+ if (skb) {
+ skb_queue_tail(&cdev->recv_queue, skb);
+ wake_up_interruptible(&cdev->recv_wait);
+ } else {
+ printk(KERN_ERR "BUG: capi_signal: no skb\n");
+ }
+}
+
+/* -------- file_operations ----------------------------------------- */
+
+#if LINUX_VERSION_CODE < 0x020100
+static int capi_lseek(struct inode *inode, struct file *file,
+ off_t offset, int origin)
+{
+ return -ESPIPE;
+}
+#else
+static long long capi_llseek(struct inode *inode, struct file *file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+#endif
+
+#if LINUX_VERSION_CODE < 0x020100
+static int capi_read(struct inode *inode, struct file *file,
+ char *buf, int count)
+#else
+static long capi_read(struct inode *inode, struct file *file,
+ char *buf, unsigned long count)
+#endif
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct capidev *cdev;
+ struct sk_buff *skb;
+ int retval;
+ size_t copied;
+
+ if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ return -ENODEV;
+
+ cdev = &capidevs[minor];
+
+ if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) {
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ for (;;) {
+ interruptible_sleep_on(&cdev->recv_wait);
+ if ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
+ break;
+ if (current->signal & ~current->blocked)
+ break;
+ }
+ if (skb == 0)
+ return -ERESTARTNOHAND;
+ }
+ if (skb->len > count) {
+ skb_queue_head(&cdev->recv_queue, skb);
+ return -EMSGSIZE;
+ }
+ if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
+ && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)
+ CAPIMSG_SETDATA(skb->data, buf + CAPIMSG_LEN(skb->data));
+ retval = copy_to_user(buf, skb->data, skb->len);
+ if (retval) {
+ skb_queue_head(&cdev->recv_queue, skb);
+ return retval;
+ }
+ copied = skb->len;
+
+
+ kfree_skb(skb, FREE_READ);
+
+ return copied;
+}
+
+#if LINUX_VERSION_CODE < 0x020100
+static int capi_write(struct inode *inode, struct file *file,
+ const char *buf, int count)
+#else
+static long capi_write(struct inode *inode, struct file *file,
+ const char *buf, unsigned long count)
+#endif
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct capidev *cdev;
+ struct sk_buff *skb;
+ int retval;
+ __u8 cmd;
+ __u8 subcmd;
+ __u16 mlen;
+
+ if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ return -ENODEV;
+
+ cdev = &capidevs[minor];
+
+ skb = alloc_skb(count, GFP_USER);
+
+ if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
+ dev_kfree_skb(skb, FREE_WRITE);
+ return retval;
+ }
+ cmd = CAPIMSG_COMMAND(skb->data);
+ subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+ mlen = CAPIMSG_LEN(skb->data);
+ if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+ if (mlen + dlen != count) {
+ dev_kfree_skb(skb, FREE_WRITE);
+ return -EINVAL;
+ }
+ } else if (mlen != count) {
+ dev_kfree_skb(skb, FREE_WRITE);
+ return -EINVAL;
+ }
+ CAPIMSG_SETAPPID(skb->data, cdev->applid);
+
+ cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb);
+
+ if (cdev->errcode) {
+ dev_kfree_skb(skb, FREE_WRITE);
+ return -EIO;
+ }
+ return count;
+}
+
+#if (LINUX_VERSION_CODE < 0x020117)
+static int capi_select(struct inode *inode, struct file *file,
+ int sel_type, select_table * wait)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct capidev *cdev;
+
+ if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ return -ENODEV;
+
+ cdev = &capidevs[minor];
+
+ switch (sel_type) {
+ case SEL_IN:
+ if (!skb_queue_empty(&cdev->recv_queue))
+ return 1;
+ /* fall througth */
+ case SEL_EX:
+ /* error conditions ? */
+
+ select_wait(&cdev->recv_wait, wait);
+ return 0;
+ case SEL_OUT:
+ /*
+ if (!queue_full())
+ return 1;
+ select_wait(&cdev->send_wait, wait);
+ return 0;
+ */
+ return 1;
+ }
+ return 1;
+}
+#else
+static unsigned int
+capi_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask = 0;
+ unsigned int minor = MINOR(file->f_inode->i_rdev);
+ struct capidev *cdev;
+
+ if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+ return POLLERR;
+
+ cdev = &capidevs[minor];
+ poll_wait(&(cdev->recv_wait), wait);
+ mask = POLLOUT | POLLWRNORM;
+ if (!skb_queue_empty(&cdev->recv_queue))
+ mask |= POLLIN | POLLRDNORM;
+ return mask;
+}
+#endif
+
+static int capi_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct capidev *cdev;
+ capi_ioctl_struct data;
+ int retval;
+
+
+ if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open)
+ return -ENODEV;
+
+ cdev = &capidevs[minor];
+
+ switch (cmd) {
+ case CAPI_REGISTER:
+ {
+ if (!minor)
+ return -EINVAL;
+ retval = copy_from_user((void *) &data.rparams,
+ (void *) arg, sizeof(struct capi_register_params));
+ if (retval)
+ return -EFAULT;
+ if (cdev->is_registered)
+ return -EEXIST;
+ cdev->errcode = (*capifuncs->capi_register) (&data.rparams,
+ &cdev->applid);
+ if (cdev->errcode)
+ return -EIO;
+ (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor);
+ cdev->is_registered = 1;
+ }
+ return 0;
+
+ case CAPI_GET_VERSION:
+ {
+ retval = copy_from_user((void *) &data.contr,
+ (void *) arg,
+ sizeof(data.contr));
+ if (retval)
+ return -EFAULT;
+ cdev->errcode = (*capifuncs->capi_get_version) (data.contr, &data.version);
+ if (cdev->errcode)
+ return -EIO;
+ retval = copy_to_user((void *) arg,
+ (void *) &data.version,
+ sizeof(data.version));
+ if (retval)
+ return -EFAULT;
+ }
+ return 0;
+
+ case CAPI_GET_SERIAL:
+ {
+ retval = copy_from_user((void *) &data.contr,
+ (void *) arg,
+ sizeof(data.contr));
+ if (retval)
+ return -EFAULT;
+ cdev->errcode = (*capifuncs->capi_get_serial) (data.contr, data.serial);
+ if (cdev->errcode)
+ return -EIO;
+ retval = copy_to_user((void *) arg,
+ (void *) data.serial,
+ sizeof(data.serial));
+ if (retval)
+ return -EFAULT;
+ }
+ return 0;
+ case CAPI_GET_PROFILE:
+ {
+ retval = copy_from_user((void *) &data.contr,
+ (void *) arg,
+ sizeof(data.contr));
+ if (retval)
+ return -EFAULT;
+
+ if (data.contr == 0) {
+ cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile);
+ if (cdev->errcode)
+ return -EIO;
+
+ retval = copy_to_user((void *) arg,
+ (void *) &data.profile.ncontroller,
+ sizeof(data.profile.ncontroller));
+
+ } else {
+ cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile);
+ if (cdev->errcode)
+ return -EIO;
+
+ retval = copy_to_user((void *) arg,
+ (void *) &data.profile,
+ sizeof(data.profile));
+ }
+ if (retval)
+ return -EFAULT;
+ }
+ return 0;
+
+ case CAPI_GET_MANUFACTURER:
+ {
+ retval = copy_from_user((void *) &data.contr,
+ (void *) arg,
+ sizeof(data.contr));
+ if (retval)
+ return -EFAULT;
+ cdev->errcode = (*capifuncs->capi_get_manufacturer) (data.contr, data.manufacturer);
+ if (cdev->errcode)
+ return -EIO;
+
+ retval = copy_to_user((void *) arg, (void *) data.manufacturer,
+ sizeof(data.manufacturer));
+ if (retval)
+ return -EFAULT;
+
+ }
+ return 0;
+ case CAPI_GET_ERRCODE:
+ data.errcode = cdev->errcode;
+ cdev->errcode = CAPI_NOERROR;
+ if (arg) {
+ retval = copy_to_user((void *) arg,
+ (void *) &data.errcode,
+ sizeof(data.errcode));
+ if (retval)
+ return -EFAULT;
+ }
+ return data.errcode;
+
+ case CAPI_INSTALLED:
+ if ((*capifuncs->capi_installed) ())
+ return 0;
+ return -ENXIO;
+
+ case CAPI_MANUFACTURER_CMD:
+ {
+ struct capi_manufacturer_cmd mcmd;
+ if (minor)
+ return -EINVAL;
+ if (!suser())
+ return -EPERM;
+ retval = copy_from_user((void *) &mcmd, (void *) arg,
+ sizeof(mcmd));
+ if (retval)
+ return -EFAULT;
+ return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data);
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int capi_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+
+ if (minor >= CAPI_MAXMINOR)
+ return -ENXIO;
+
+ if (minor) {
+ if (capidevs[minor].is_open)
+ return -EEXIST;
+
+ capidevs[minor].is_open = 1;
+ skb_queue_head_init(&capidevs[minor].recv_queue);
+ MOD_INC_USE_COUNT;
+
+ } else {
+
+ if (!capidevs[minor].is_open) {
+ capidevs[minor].is_open = 1;
+ MOD_INC_USE_COUNT;
+ }
+ }
+
+
+ return 0;
+}
+
+static CLOSETYPE
+capi_release(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ struct capidev *cdev;
+ struct sk_buff *skb;
+
+ if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
+ printk(KERN_ERR "capi20: release minor %d ???\n", minor);
+ return CLOSEVAL;
+ }
+ cdev = &capidevs[minor];
+
+ if (minor) {
+
+ if (cdev->is_registered)
+ (*capifuncs->capi_release) (cdev->applid);
+
+ cdev->is_registered = 0;
+ cdev->applid = 0;
+
+ while ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
+ kfree_skb(skb, FREE_READ);
+ }
+ cdev->is_open = 0;
+
+ MOD_DEC_USE_COUNT;
+ return CLOSEVAL;
+}
+
+static struct file_operations capi_fops =
+{
+#if LINUX_VERSION_CODE < 0x020100
+ capi_lseek,
+#else
+ capi_llseek,
+#endif
+ capi_read,
+ capi_write,
+ NULL, /* capi_readdir */
+#if (LINUX_VERSION_CODE < 0x020117)
+ capi_select,
+#else
+ capi_poll,
+#endif
+ capi_ioctl,
+ NULL, /* capi_mmap */
+ capi_open,
+ capi_release,
+ NULL, /* capi_fsync */
+ NULL, /* capi_fasync */
+};
+
+
+/* -------- init function and module interface ---------------------- */
+
+#ifdef MODULE
+#define capi_init init_module
+#endif
+
+static struct capi_interface_user cuser = {
+ "capi20",
+ 0,
+};
+
+int capi_init(void)
+{
+ memset(capidevs, 0, sizeof(capidevs));
+
+ if (register_chrdev(capi_major, "capi20", &capi_fops)) {
+ printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
+ return -EIO;
+ }
+ printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
+
+ if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
+ unregister_chrdev(capi_major, "capi20");
+ return -EIO;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ unregister_chrdev(capi_major, "capi20");
+ (void) detach_capi_interface(&cuser);
+}
+
+#endif
--- /dev/null
+/*
+ * $Id: capicmd.h,v 1.1 1997/03/04 21:50:30 calle Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capicmd.h,v $
+ * 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__
+
+/*----- 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__ */
--- /dev/null
+/*
+ * $Id: capidev.h,v 1.1 1997/03/04 21:50:30 calle Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+ * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capidev.h,v $
+ * Revision 1.1 1997/03/04 21:50:30 calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ */
+
+struct capidev {
+ int is_open;
+ int is_registered;
+ __u16 applid;
+ struct sk_buff_head recv_queue;
+ struct wait_queue *recv_wait;
+ __u16 errcode;
+};
+
+#define CAPI_MAXMINOR CAPI_MAXAPPL
--- /dev/null
+/*
+ * $Id: capidrv.c,v 1.3 1997/05/18 09:24:15 calle Exp $
+ *
+ * ISDN4Linux Driver, using capi20 interface (kernelcapi)
+ *
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capidrv.c,v $
+ * Revision 1.3 1997/05/18 09:24:15 calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.2 1997/03/05 21:19:59 fritz
+ * Removed include of config.h (mkdep stated this is unneded).
+ *
+ * Revision 1.1 1997/03/04 21:50:31 calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/skbuff.h>
+#include <linux/isdn.h>
+#include <linux/isdnif.h>
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+
+#include "compat.h"
+#include "capiutil.h"
+#include "capicmd.h"
+#include "capidrv.h"
+
+static char *revision = "$Revision: 1.3 $";
+int debugmode = 0;
+
+#ifdef HAS_NEW_SYMTAB
+MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
+MODULE_PARM(debugmode, "i");
+#endif
+
+/* -------- type definitions ----------------------------------------- */
+
+
+struct capidrv_contr {
+
+ struct capidrv_contr *next;
+
+ __u32 contrnr;
+ char name[20];
+
+ /*
+ * for isdn4linux
+ */
+ isdn_if interface;
+ int myid;
+
+ /*
+ * LISTEN state
+ */
+ int state;
+ __u32 cipmask;
+ __u32 cipmask2;
+
+ /*
+ * ID of capi message sent
+ */
+ __u16 msgid;
+
+ /*
+ * B-Channels
+ */
+ int nbchan;
+ struct capidrv_bchan {
+ struct capidrv_contr *contr;
+ __u8 msn[ISDN_MSNLEN];
+ int l2;
+ int l3;
+ __u8 num[ISDN_MSNLEN];
+ __u8 mynum[ISDN_MSNLEN];
+ int si1;
+ int si2;
+ int incoming;
+ int disconnecting;
+ struct capidrv_plci {
+ struct capidrv_plci *next;
+ __u32 plci;
+ __u32 ncci; /* ncci for CONNECT_ACTIVE_IND */
+ __u16 msgid; /* to identfy CONNECT_CONF */
+ int chan;
+ int state;
+ struct capidrv_ncci {
+ struct capidrv_ncci *next;
+ struct capidrv_plci *plcip;
+ __u32 ncci;
+ __u16 msgid; /* to identfy CONNECT_B3_CONF */
+ int chan;
+ int state;
+ int oldstate;
+ /* */
+ __u16 datahandle;
+ } *ncci_list;
+ } *plcip;
+ struct capidrv_ncci *nccip;
+ } *bchans;
+
+ struct capidrv_plci *plci_list;
+};
+
+struct capidrv_data {
+ __u16 appid;
+ int ncontr;
+ struct capidrv_contr *contr_list;
+};
+
+typedef struct capidrv_plci capidrv_plci;
+typedef struct capidrv_ncci capidrv_ncci;
+typedef struct capidrv_contr capidrv_contr;
+typedef struct capidrv_data capidrv_data;
+typedef struct capidrv_bchan capidrv_bchan;
+
+/* -------- data definitions ----------------------------------------- */
+
+static capidrv_data global;
+static struct capi_interface *capifuncs;
+
+/* -------- convert functions ---------------------------------------- */
+
+static inline __u32 b1prot(int l2, int l3)
+{
+ switch (l2) {
+ case ISDN_PROTO_L2_X75I:
+ case ISDN_PROTO_L2_X75UI:
+ case ISDN_PROTO_L2_X75BUI:
+ return 0;
+ case ISDN_PROTO_L2_HDLC:
+ default:
+ return 0;
+ case ISDN_PROTO_L2_TRANS:
+ return 1;
+ }
+}
+
+static inline __u32 b2prot(int l2, int l3)
+{
+ switch (l2) {
+ case ISDN_PROTO_L2_X75I:
+ case ISDN_PROTO_L2_X75UI:
+ case ISDN_PROTO_L2_X75BUI:
+ default:
+ return 0;
+ case ISDN_PROTO_L2_HDLC:
+ return 1;
+ case ISDN_PROTO_L2_TRANS:
+ return 0;
+ }
+}
+
+static inline __u32 b3prot(int l2, int l3)
+{
+ switch (l2) {
+ case ISDN_PROTO_L2_X75I:
+ case ISDN_PROTO_L2_X75UI:
+ case ISDN_PROTO_L2_X75BUI:
+ case ISDN_PROTO_L2_HDLC:
+ case ISDN_PROTO_L2_TRANS:
+ default:
+ return 0;
+ }
+}
+
+static inline __u16 si2cip(__u8 si1, __u8 si2)
+{
+ static const __u8 cip[17][5] =
+ {
+ /* 0 1 2 3 4 */
+ {0, 0, 0, 0, 0}, /*0 */
+ {16, 16, 4, 26, 16}, /*1 */
+ {17, 17, 17, 4, 4}, /*2 */
+ {2, 2, 2, 2, 2}, /*3 */
+ {18, 18, 18, 18, 18}, /*4 */
+ {2, 2, 2, 2, 2}, /*5 */
+ {0, 0, 0, 0, 0}, /*6 */
+ {2, 2, 2, 2, 2}, /*7 */
+ {2, 2, 2, 2, 2}, /*8 */
+ {21, 21, 21, 21, 21}, /*9 */
+ {19, 19, 19, 19, 19}, /*10 */
+ {0, 0, 0, 0, 0}, /*11 */
+ {0, 0, 0, 0, 0}, /*12 */
+ {0, 0, 0, 0, 0}, /*13 */
+ {0, 0, 0, 0, 0}, /*14 */
+ {22, 22, 22, 22, 22}, /*15 */
+ {27, 27, 27, 28, 27} /*16 */
+ };
+ if (si1 > 16)
+ si1 = 0;
+ if (si2 > 4)
+ si2 = 0;
+
+ return (__u16) cip[si1][si2];
+}
+
+static inline __u8 cip2si1(__u16 cipval)
+{
+ static const __u8 si[32] =
+ {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */
+ 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */
+ 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */
+ 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */
+
+ if (cipval > 31)
+ cipval = 0; /* .... */
+ return si[cipval];
+}
+
+static inline __u8 cip2si2(__u16 cipval)
+{
+ static const __u8 si[32] =
+ {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */
+ 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */
+ 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */
+ 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */
+
+ if (cipval > 31)
+ cipval = 0; /* .... */
+ return si[cipval];
+}
+
+
+/* -------- controller managment ------------------------------------- */
+
+static inline capidrv_contr *findcontrbydriverid(int driverid)
+{
+ capidrv_contr *p = global.contr_list;
+
+ while (p) {
+ if (p->myid == driverid)
+ return p;
+ p = p->next;
+ }
+ return (capidrv_contr *) 0;
+}
+
+static capidrv_contr *findcontrbynumber(__u32 contr)
+{
+ capidrv_contr *p = global.contr_list;
+
+ while (p) {
+ if (p->contrnr == contr)
+ return p;
+ p = p->next;
+ }
+ return (capidrv_contr *) 0;
+}
+
+
+/* -------- plci management ------------------------------------------ */
+
+static capidrv_plci *new_plci(capidrv_contr * card, int chan)
+{
+ capidrv_plci *plcip;
+
+ plcip = (capidrv_plci *) kmalloc(sizeof(capidrv_plci), GFP_ATOMIC);
+
+ if (plcip == 0)
+ return 0;
+
+ memset(plcip, 0, sizeof(capidrv_plci));
+ plcip->state = ST_PLCI_NONE;
+ plcip->plci = 0;
+ plcip->msgid = 0;
+ plcip->chan = chan;
+ plcip->next = card->plci_list;
+ card->plci_list = plcip;
+ card->bchans[chan].plcip = plcip;
+
+ return plcip;
+}
+
+static capidrv_plci *find_plci_by_plci(capidrv_contr * card, __u32 plci)
+{
+ capidrv_plci *p;
+ for (p = card->plci_list; p; p = p->next)
+ if (p->plci == plci)
+ return p;
+ return 0;
+}
+
+static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, __u16 msgid)
+{
+ capidrv_plci *p;
+ for (p = card->plci_list; p; p = p->next)
+ if (p->msgid == msgid)
+ return p;
+ return 0;
+}
+
+static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, __u32 ncci)
+{
+ capidrv_plci *p;
+ for (p = card->plci_list; p; p = p->next)
+ if (p->plci == (ncci & 0xffff))
+ return p;
+ return 0;
+}
+
+static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
+{
+ capidrv_plci **pp;
+
+ for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
+ if (*pp == plcip) {
+ *pp = (*pp)->next;
+ card->bchans[plcip->chan].plcip = 0;
+ card->bchans[plcip->chan].disconnecting = 0;
+ card->bchans[plcip->chan].incoming = 0;
+ kfree(plcip);
+ return;
+ }
+ }
+ printk(KERN_ERR "capidrv: free_plci %p (0x%x) not found, Huh?\n",
+ plcip, plcip->plci);
+}
+
+/* -------- ncci management ------------------------------------------ */
+
+static inline capidrv_ncci *new_ncci(capidrv_contr * card,
+ capidrv_plci * plcip,
+ __u32 ncci)
+{
+ capidrv_ncci *nccip;
+
+ nccip = (capidrv_ncci *) kmalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
+
+ if (nccip == 0)
+ return 0;
+
+ memset(nccip, 0, sizeof(capidrv_ncci));
+ nccip->ncci = ncci;
+ nccip->state = ST_NCCI_NONE;
+ nccip->plcip = plcip;
+ nccip->chan = plcip->chan;
+ nccip->datahandle = 0;
+
+ nccip->next = plcip->ncci_list;
+ plcip->ncci_list = nccip;
+
+ card->bchans[plcip->chan].nccip = nccip;
+
+ return nccip;
+}
+
+static inline capidrv_ncci *find_ncci(capidrv_contr * card, __u32 ncci)
+{
+ capidrv_plci *plcip;
+ capidrv_ncci *p;
+
+ if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
+ return 0;
+
+ for (p = plcip->ncci_list; p; p = p->next)
+ if (p->ncci == ncci)
+ return p;
+ return 0;
+}
+
+static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
+ __u32 ncci, __u16 msgid)
+{
+ capidrv_plci *plcip;
+ capidrv_ncci *p;
+
+ if ((plcip = find_plci_by_ncci(card, ncci)) == 0)
+ return 0;
+
+ for (p = plcip->ncci_list; p; p = p->next)
+ if (p->msgid == msgid)
+ return p;
+ return 0;
+}
+
+static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
+{
+ struct capidrv_ncci **pp;
+
+ for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
+ if (*pp == nccip) {
+ *pp = (*pp)->next;
+ break;
+ }
+ }
+ card->bchans[nccip->chan].nccip = 0;
+ kfree(nccip);
+}
+
+/* -------- convert and send capi message ---------------------------- */
+
+static void send_message(capidrv_contr * card, _cmsg * cmsg)
+{
+ struct sk_buff *skb;
+ size_t len;
+ capi_cmsg2message(cmsg, cmsg->buf);
+ len = CAPIMSG_LEN(cmsg->buf);
+ skb = dev_alloc_skb(len);
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, len), cmsg->buf, len);
+ (*capifuncs->capi_put_message) (global.appid, skb);
+}
+
+/* -------- state machine -------------------------------------------- */
+
+struct listenstatechange {
+ int actstate;
+ int nextstate;
+ int event;
+};
+
+static struct listenstatechange listentable[] =
+{
+ {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
+ {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
+ {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
+ {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
+ {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
+ {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
+ {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
+ {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
+ {},
+};
+
+static void listen_change_state(capidrv_contr * card, int event)
+{
+ struct listenstatechange *p = listentable;
+ while (p->event) {
+ if (card->state == p->actstate && p->event == event) {
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: listen_change_state %d -> %d\n",
+ card->state, p->nextstate);
+ card->state = p->nextstate;
+ return;
+ }
+ p++;
+ }
+ printk(KERN_ERR "capidrv: listen_change_state state=%d event=%d ????\n",
+ card->state, event);
+
+}
+
+/* ------------------------------------------------------------------ */
+
+static void p0(capidrv_contr * card, capidrv_plci * plci)
+{
+ isdn_ctrl cmd;
+
+ card->bchans[plci->chan].contr = 0;
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.driver = card->myid;
+ cmd.arg = plci->chan;
+ card->interface.statcallb(&cmd);
+ free_plci(card, plci);
+}
+
+/* ------------------------------------------------------------------ */
+
+struct plcistatechange {
+ int actstate;
+ int nextstate;
+ int event;
+ void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
+};
+
+static struct plcistatechange plcitable[] =
+{
+ /* P-0 */
+ {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, 0},
+ {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, 0},
+ {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, 0},
+ /* P-0.1 */
+ {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
+ {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, 0},
+ {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+ {ST_PLCI_OUTGOING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+ /* P-1 */
+ {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+ {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+{ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+ {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+ /* P-ACT */
+ {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+ {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+ {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+ /* P-2 */
+ {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
+ {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, 0},
+ {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, 0},
+ {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+ {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+ {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+ /* P-3 */
+{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, 0},
+{ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+{ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+ {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+ {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+ /* P-4 */
+ {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, 0},
+ {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, 0},
+{ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, 0},
+ {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+ /* P-5 */
+{ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, 0},
+ /* P-6 */
+ {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
+ {},
+};
+
+static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
+{
+ struct plcistatechange *p = plcitable;
+ while (p->event) {
+ if (plci->state == p->actstate && p->event == event) {
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: plci_change_state:0x%x %d -> %d\n",
+ plci->plci, plci->state, p->nextstate);
+ plci->state = p->nextstate;
+ if (p->changefunc)
+ p->changefunc(card, plci);
+ return;
+ }
+ p++;
+ }
+ printk(KERN_ERR "capidrv: plci_change_state:0x%x state=%d event=%d ????\n",
+ plci->plci, plci->state, event);
+}
+
+/* ------------------------------------------------------------------ */
+
+static _cmsg cmsg;
+
+static void n0(capidrv_contr * card, capidrv_ncci * ncci)
+{
+ isdn_ctrl cmd;
+
+ capi_fill_DISCONNECT_REQ(&cmsg,
+ global.appid,
+ card->msgid++,
+ ncci->plcip->plci,
+ 0, /* BChannelinformation */
+ 0, /* Keypadfacility */
+ 0, /* Useruserdata */
+ 0 /* Facilitydataarray */
+ );
+ send_message(card, &cmsg);
+ plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
+
+ cmd.command = ISDN_STAT_BHUP;
+ cmd.driver = card->myid;
+ cmd.arg = ncci->chan;
+ card->interface.statcallb(&cmd);
+ free_ncci(card, ncci);
+}
+
+/* ------------------------------------------------------------------ */
+
+struct nccistatechange {
+ int actstate;
+ int nextstate;
+ int event;
+ void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
+};
+
+static struct nccistatechange nccitable[] =
+{
+ /* N-0 */
+ {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, 0},
+ {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, 0},
+ /* N-0.1 */
+ {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, 0},
+ {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, 0},
+ /* N-1 */
+ {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, 0},
+ {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, 0},
+ {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+ {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+ /* N-2 */
+ {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, 0},
+ {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+{ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+ /* N-ACT */
+ {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, 0},
+ {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+ {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+ /* N-3 */
+ {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, 0},
+ {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+ {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, 0},
+ /* N-4 */
+ {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, 0},
+ {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, 0},
+ /* N-5 */
+ {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
+ {},
+};
+
+static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
+{
+ struct nccistatechange *p = nccitable;
+ while (p->event) {
+ if (ncci->state == p->actstate && p->event == event) {
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ncci_change_state:0x%x %d -> %d\n",
+ ncci->ncci, ncci->state, p->nextstate);
+ if (p->nextstate == ST_NCCI_PREVIOUS) {
+ ncci->state = ncci->oldstate;
+ ncci->oldstate = p->actstate;
+ } else {
+ ncci->oldstate = p->actstate;
+ ncci->state = p->nextstate;
+ }
+ if (p->changefunc)
+ p->changefunc(card, ncci);
+ return;
+ }
+ p++;
+ }
+ printk(KERN_ERR "capidrv: ncci_change_state:0x%x state=%d event=%d ????\n",
+ ncci->ncci, ncci->state, event);
+}
+
+/* ------------------------------------------------------------------- */
+
+static inline int new_bchan(capidrv_contr * card)
+{
+ int i;
+ for (i = 0; i < card->nbchan; i++) {
+ if (card->bchans[i].plcip == 0) {
+ card->bchans[i].disconnecting = 0;
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* ------------------------------------------------------------------- */
+
+static void handle_controller(_cmsg * cmsg)
+{
+ capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
+
+ if (!card) {
+ printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrController & 0x7f);
+ return;
+ }
+ switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
+
+ case CAPI_LISTEN_CONF: /* Controller */
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
+ cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
+ if (cmsg->Info) {
+ listen_change_state(card, EV_LISTEN_CONF_ERROR);
+ } else if (card->cipmask == 0) {
+ listen_change_state(card, EV_LISTEN_CONF_EMPTY);
+ } else {
+ listen_change_state(card, EV_LISTEN_CONF_OK);
+ }
+ break;
+
+ case CAPI_MANUFACTURER_IND: /* Controller */
+ goto ignored;
+ case CAPI_MANUFACTURER_CONF: /* Controller */
+ goto ignored;
+ case CAPI_FACILITY_IND: /* Controller/plci/ncci */
+ goto ignored;
+ case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
+ goto ignored;
+ case CAPI_INFO_IND: /* Controller/plci */
+ goto ignored;
+ case CAPI_INFO_CONF: /* Controller/plci */
+ goto ignored;
+
+ default:
+ printk(KERN_ERR "capidrv: got %s from controller 0x%x ???",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrController);
+ }
+ return;
+
+ ignored:
+ printk(KERN_INFO "capidrv: %s from controller 0x%x ignored\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrController);
+}
+
+static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
+{
+ capidrv_plci *plcip;
+ capidrv_bchan *bchan;
+ isdn_ctrl cmd;
+ int chan;
+
+ if ((chan = new_bchan(card)) == -1) {
+ printk(KERN_ERR "capidrv: incoming call on not existing bchan ?\n");
+ return;
+ }
+ bchan = &card->bchans[chan];
+ if ((plcip = new_plci(card, chan)) == 0) {
+ printk(KERN_ERR "capidrv: incoming call: no memory, sorry.\n");
+ return;
+ }
+ bchan->incoming = 1;
+ plcip->plci = cmsg->adr.adrPLCI;
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
+
+ cmd.command = ISDN_STAT_ICALL;
+ cmd.driver = card->myid;
+ cmd.arg = chan;
+ memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
+ strncpy(cmd.parm.setup.phone,
+ cmsg->CallingPartyNumber + 3,
+ cmsg->CallingPartyNumber[0] - 2);
+ strncpy(cmd.parm.setup.eazmsn,
+ cmsg->CalledPartyNumber + 2,
+ cmsg->CalledPartyNumber[0] - 1);
+ cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
+ cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
+ cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
+ cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
+
+ printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s\n",
+ cmd.parm.setup.phone,
+ cmd.parm.setup.si1,
+ cmd.parm.setup.si2,
+ cmd.parm.setup.eazmsn);
+
+ switch (card->interface.statcallb(&cmd)) {
+ case 0:
+ /* No device matching this call.
+ * and isdn_common.c has send a HANGUP command
+ * which is ignored in state ST_PLCI_INCOMING,
+ * so we send RESP to ignore the call
+ */
+ capi_cmsg_answer(cmsg);
+ cmsg->Reject = 1; /* ignore */
+ send_message(card, cmsg);
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+ printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s ignored\n",
+ cmd.parm.setup.phone,
+ cmd.parm.setup.si1,
+ cmd.parm.setup.si2,
+ cmd.parm.setup.eazmsn);
+ break;
+ case 1:
+ /* At least one device matching this call (RING on ttyI)
+ * HL-driver may send ALERTING on the D-channel in this
+ * case.
+ * really means: RING on ttyI or a net interface
+ * accepted this call already.
+ *
+ * If the call was accepted, state has already changed,
+ * and CONNECT_RESP already sent.
+ */
+ if (plcip->state == ST_PLCI_INCOMING) {
+ printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s tty alerting\n",
+ cmd.parm.setup.phone,
+ cmd.parm.setup.si1,
+ cmd.parm.setup.si2,
+ cmd.parm.setup.eazmsn);
+ capi_fill_ALERT_REQ(cmsg,
+ global.appid,
+ card->msgid++,
+ plcip->plci, /* adr */
+ 0, /* BChannelinformation */
+ 0, /* Keypadfacility */
+ 0, /* Useruserdata */
+ 0 /* Facilitydataarray */
+ );
+ plcip->msgid = cmsg->Messagenumber;
+ send_message(card, cmsg);
+ } else {
+ printk(KERN_INFO "capidrv: incoming call %s,%d,%d,%s on netdev\n",
+ cmd.parm.setup.phone,
+ cmd.parm.setup.si1,
+ cmd.parm.setup.si2,
+ cmd.parm.setup.eazmsn);
+ }
+ break;
+
+ case 2: /* Call will be rejected. */
+ capi_cmsg_answer(cmsg);
+ cmsg->Reject = 2; /* reject call, normal call clearing */
+ send_message(card, cmsg);
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+ break;
+
+ default:
+ /* An error happened. (Invalid parameters for example.) */
+ capi_cmsg_answer(cmsg);
+ cmsg->Reject = 8; /* reject call,
+ destination out of order */
+ send_message(card, cmsg);
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+ break;
+ }
+ return;
+}
+
+static void handle_plci(_cmsg * cmsg)
+{
+ capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
+ capidrv_plci *plcip;
+ isdn_ctrl cmd;
+
+ if (!card) {
+ printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrController & 0x7f);
+ return;
+ }
+ switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
+
+ case CAPI_DISCONNECT_IND: /* plci */
+ if (cmsg->Reason) {
+ printk(KERN_INFO "capidrv: %s reason 0x%x (%s) for plci 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
+ }
+ if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+ goto notfound;
+ }
+ card->bchans[plcip->chan].disconnecting = 1;
+ plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+ plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
+ break;
+
+ case CAPI_DISCONNECT_CONF: /* plci */
+ if (cmsg->Info) {
+ printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->Info, capi_info2str(cmsg->Info),
+ cmsg->adr.adrPLCI);
+ }
+ if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
+ goto notfound;
+
+ card->bchans[plcip->chan].disconnecting = 1;
+ break;
+
+ case CAPI_ALERT_CONF: /* plci */
+ if (cmsg->Info) {
+ printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->Info, capi_info2str(cmsg->Info),
+ cmsg->adr.adrPLCI);
+ }
+ break;
+
+ case CAPI_CONNECT_IND: /* plci */
+ handle_incoming_call(card, cmsg);
+ break;
+
+ case CAPI_CONNECT_CONF: /* plci */
+ if (cmsg->Info) {
+ printk(KERN_INFO "capidrv: %s info 0x%x (%s) for plci 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->Info, capi_info2str(cmsg->Info),
+ cmsg->adr.adrPLCI);
+ }
+ if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
+ goto notfound;
+
+ plcip->plci = cmsg->adr.adrPLCI;
+ if (cmsg->Info) {
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
+ } else {
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
+ }
+ break;
+
+ case CAPI_CONNECT_ACTIVE_IND: /* plci */
+
+ if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
+ goto notfound;
+
+ if (card->bchans[plcip->chan].incoming) {
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
+ } else {
+ capidrv_ncci *nccip;
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+
+ nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
+
+ if (!nccip) {
+ printk(KERN_ERR "capidrv: no mem for ncci, sorry\n");
+ break; /* $$$$ */
+ }
+ capi_fill_CONNECT_B3_REQ(cmsg,
+ global.appid,
+ card->msgid++,
+ plcip->plci, /* adr */
+ 0 /* NCPI */
+ );
+ nccip->msgid = cmsg->Messagenumber;
+ send_message(card, cmsg);
+ cmd.command = ISDN_STAT_DCONN;
+ cmd.driver = card->myid;
+ cmd.arg = plcip->chan;
+ card->interface.statcallb(&cmd);
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
+ ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
+ }
+ break;
+
+ case CAPI_INFO_IND: /* Controller/plci */
+
+ if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
+ goto notfound;
+
+ if (cmsg->InfoNumber == 0x4000) {
+ if (cmsg->InfoElement[0] == 4) {
+ cmd.command = ISDN_STAT_CINF;
+ cmd.driver = card->myid;
+ cmd.arg = plcip->chan;
+ sprintf(cmd.parm.num, "%lu",
+ (unsigned long)
+ ((__u32) cmsg->InfoElement[1]
+ | ((__u32) (cmsg->InfoElement[2]) << 8)
+ | ((__u32) (cmsg->InfoElement[3]) << 16)
+ | ((__u32) (cmsg->InfoElement[4]) << 24)));
+ card->interface.statcallb(&cmd);
+ break;
+ }
+ }
+ printk(KERN_ERR "capidrv: %s\n", capi_cmsg2str(cmsg));
+ break;
+
+ case CAPI_CONNECT_ACTIVE_CONF: /* plci */
+ goto ignored;
+ case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */
+ goto ignored;
+ case CAPI_FACILITY_IND: /* Controller/plci/ncci */
+ goto ignored;
+ case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
+ goto ignored;
+
+ case CAPI_INFO_CONF: /* Controller/plci */
+ goto ignored;
+
+ default:
+ printk(KERN_ERR "capidrv: got %s for plci 0x%x ???",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrPLCI);
+ }
+ return;
+ ignored:
+ printk(KERN_INFO "capidrv: %s for plci 0x%x ignored\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrPLCI);
+ return;
+ notfound:
+ printk(KERN_ERR "capidrv: %s: plci 0x%x not found\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrPLCI);
+ return;
+}
+
+static void handle_ncci(_cmsg * cmsg)
+{
+ capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
+ capidrv_plci *plcip;
+ capidrv_ncci *nccip;
+ isdn_ctrl cmd;
+
+ if (!card) {
+ printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrController & 0x7f);
+ return;
+ }
+ switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
+
+ case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */
+ if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+ goto notfound;
+
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+ ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
+
+ cmd.command = ISDN_STAT_BCONN;
+ cmd.driver = card->myid;
+ cmd.arg = nccip->chan;
+ card->interface.statcallb(&cmd);
+
+ printk(KERN_INFO "capidrv: chan %d up with ncci 0x%x\n",
+ nccip->chan, nccip->ncci);
+ break;
+
+ case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */
+ goto ignored;
+
+ case CAPI_CONNECT_B3_IND: /* ncci */
+
+ plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
+ if (plcip) {
+ nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
+ if (nccip) {
+ ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
+ capi_fill_CONNECT_B3_RESP(cmsg,
+ global.appid,
+ card->msgid++,
+ nccip->ncci, /* adr */
+ 0, /* Reject */
+ 0 /* NCPI */
+ );
+ send_message(card, cmsg);
+ ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
+ break;
+ }
+ printk(KERN_ERR "capidrv: no mem for ncci, sorry\n");
+ } else {
+ printk(KERN_ERR "capidrv: %s: plci for ncci 0x%x not found\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrNCCI);
+ }
+ capi_fill_CONNECT_B3_RESP(cmsg,
+ global.appid,
+ card->msgid++,
+ cmsg->adr.adrNCCI,
+ 2, /* Reject */
+ 0 /* NCPI */
+ );
+ send_message(card, cmsg);
+ break;
+
+ case CAPI_CONNECT_B3_CONF: /* ncci */
+
+ if (!(nccip = find_ncci_by_msgid(card,
+ cmsg->adr.adrNCCI,
+ cmsg->Messagenumber)))
+ goto notfound;
+
+ nccip->ncci = cmsg->adr.adrNCCI;
+ if (cmsg->Info) {
+ printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->Info, capi_info2str(cmsg->Info),
+ cmsg->adr.adrNCCI);
+ }
+
+ if (cmsg->Info)
+ ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
+ else
+ ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
+ break;
+
+ case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+ break;
+
+ case CAPI_DATA_B3_IND: /* ncci */
+ /* handled in handle_data() */
+ goto ignored;
+
+ case CAPI_DATA_B3_CONF: /* ncci */
+ if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+ goto notfound;
+
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.driver = card->myid;
+ cmd.arg = nccip->chan;
+ card->interface.statcallb(&cmd);
+
+ break;
+
+ case CAPI_DISCONNECT_B3_IND: /* ncci */
+ if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+ goto notfound;
+
+ card->bchans[nccip->chan].disconnecting = 1;
+ ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+ ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
+ break;
+
+ case CAPI_DISCONNECT_B3_CONF: /* ncci */
+ if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
+ goto notfound;
+ if (cmsg->Info) {
+ printk(KERN_INFO "capidrv: %s info 0x%x (%s) for ncci 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->Info, capi_info2str(cmsg->Info),
+ cmsg->adr.adrNCCI);
+ ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
+ }
+ break;
+
+ case CAPI_RESET_B3_IND: /* ncci */
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+ break;
+
+ case CAPI_RESET_B3_CONF: /* ncci */
+ goto ignored; /* $$$$ */
+
+ case CAPI_FACILITY_IND: /* Controller/plci/ncci */
+ goto ignored;
+ case CAPI_FACILITY_CONF: /* Controller/plci/ncci */
+ goto ignored;
+
+ default:
+ printk(KERN_ERR "capidrv: got %s for ncci 0x%x ???",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrNCCI);
+ }
+ return;
+ ignored:
+ printk(KERN_INFO "capidrv: %s for ncci 0x%x ignored\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrNCCI);
+ return;
+ notfound:
+ printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrNCCI);
+}
+
+
+static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
+{
+ capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
+ capidrv_ncci *nccip;
+
+ if (!card) {
+ printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrController & 0x7f);
+ return;
+ }
+ if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
+ printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n",
+ capi_cmd2str(cmsg->Command, cmsg->Subcommand),
+ cmsg->adr.adrNCCI);
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+ (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
+ card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
+ capi_cmsg_answer(cmsg);
+ send_message(card, cmsg);
+}
+
+static _cmsg s_cmsg;
+
+static void capidrv_signal(__u16 applid, __u32 dummy)
+{
+ struct sk_buff *skb = 0;
+
+ while ((*capifuncs->capi_get_message) (global.appid, &skb) == CAPI_NOERROR) {
+ capi_message2cmsg(&s_cmsg, skb->data);
+ if (debugmode > 1)
+ printk(KERN_DEBUG "capidrv_signal: %s\n", capi_cmsg2str(&s_cmsg));
+
+ if (s_cmsg.Command == CAPI_DATA_B3
+ && s_cmsg.Subcommand == CAPI_IND) {
+ handle_data(&s_cmsg, skb);
+ continue;
+ }
+ kfree_skb(skb, FREE_READ);
+ if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
+ handle_controller(&s_cmsg);
+ else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
+ handle_plci(&s_cmsg);
+ else
+ handle_ncci(&s_cmsg);
+ }
+}
+
+/* ------------------------------------------------------------------- */
+
+static _cmsg cmdcmsg;
+
+static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
+{
+ switch (c->arg) {
+ default:
+ printk(KERN_DEBUG "capidrv: capidrv_ioctl(%ld) called ??\n", c->arg);
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
+{
+ isdn_ctrl cmd;
+ struct capidrv_bchan *bchan;
+ struct capidrv_plci *plcip;
+
+ if (c->command == ISDN_CMD_IOCTL)
+ return capidrv_ioctl(c, card);
+
+ switch (c->command) {
+ case ISDN_CMD_DIAL:{
+ __u8 calling[ISDN_MSNLEN + 3];
+ __u8 called[ISDN_MSNLEN + 2];
+
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
+ c->arg,
+ c->parm.setup.phone,
+ c->parm.setup.si1,
+ c->parm.setup.si2,
+ c->parm.setup.eazmsn);
+
+ bchan = &card->bchans[c->arg % card->nbchan];
+
+ if (bchan->plcip) {
+ printk(KERN_ERR "capidrv: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
+ c->arg,
+ c->parm.setup.phone,
+ c->parm.setup.si1,
+ c->parm.setup.si2,
+ c->parm.setup.eazmsn,
+ bchan->plcip->plci);
+ return 0;
+ }
+ bchan->si1 = c->parm.setup.si1;
+ bchan->si2 = c->parm.setup.si2;
+
+ strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
+ strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
+
+ calling[0] = strlen(bchan->mynum) + 2;
+ calling[1] = 0;
+ calling[2] = 0x80;
+ strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
+
+ called[0] = strlen(bchan->num) + 1;
+ called[1] = 0x80;
+ strncpy(called + 2, bchan->num, ISDN_MSNLEN);
+
+ capi_fill_CONNECT_REQ(&cmdcmsg,
+ global.appid,
+ card->msgid++,
+ 1, /* adr */
+ si2cip(bchan->si1, bchan->si2), /* cipvalue */
+ called, /* CalledPartyNumber */
+ calling, /* CallingPartyNumber */
+ 0, /* CalledPartySubaddress */
+ 0, /* CallingPartySubaddress */
+ b1prot(bchan->l2, bchan->l3), /* B1protocol */
+ b2prot(bchan->l2, bchan->l3), /* B2protocol */
+ b3prot(bchan->l2, bchan->l3), /* B3protocol */
+ 0, /* B1configuration */
+ 0, /* B2configuration */
+ 0, /* B3configuration */
+ 0, /* BC */
+ 0, /* LLC */
+ 0, /* HLC */
+ 0, /* BChannelinformation */
+ 0, /* Keypadfacility */
+ 0, /* Useruserdata */
+ 0 /* Facilitydataarray */
+ );
+ if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) {
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.driver = card->myid;
+ cmd.arg = (c->arg % card->nbchan);
+ card->interface.statcallb(&cmd);
+ return -1;
+ }
+ plcip->msgid = cmdcmsg.Messagenumber;
+ plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
+ send_message(card, &cmdcmsg);
+ return 0;
+ }
+
+ case ISDN_CMD_ACCEPTD:
+
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTD(ch=%ld)\n",
+ c->arg);
+ bchan = &card->bchans[c->arg % card->nbchan];
+
+ capi_fill_CONNECT_RESP(&cmdcmsg,
+ global.appid,
+ card->msgid++,
+ bchan->plcip->plci, /* adr */
+ 0, /* Reject */
+ b1prot(bchan->l2, bchan->l3), /* B1protocol */
+ b2prot(bchan->l2, bchan->l3), /* B2protocol */
+ b3prot(bchan->l2, bchan->l3), /* B3protocol */
+ 0, /* B1configuration */
+ 0, /* B2configuration */
+ 0, /* B3configuration */
+ 0, /* ConnectedNumber */
+ 0, /* ConnectedSubaddress */
+ 0, /* LLC */
+ 0, /* BChannelinformation */
+ 0, /* Keypadfacility */
+ 0, /* Useruserdata */
+ 0 /* Facilitydataarray */
+ );
+ capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
+ plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
+ send_message(card, &cmdcmsg);
+ return 0;
+
+ case ISDN_CMD_ACCEPTB:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_ACCEPTB(ch=%ld)\n",
+ c->arg);
+ return -ENOSYS;
+
+ case ISDN_CMD_HANGUP:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_HANGUP(ch=%ld)\n",
+ c->arg);
+ bchan = &card->bchans[c->arg % card->nbchan];
+
+ if (bchan->disconnecting) {
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: chan %ld already disconnecting ...\n",
+ c->arg);
+ return 0;
+ }
+ if (bchan->nccip) {
+ bchan->disconnecting = 1;
+ capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
+ global.appid,
+ card->msgid++,
+ bchan->nccip->ncci,
+ 0 /* NCPI */
+ );
+ ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
+ send_message(card, &cmdcmsg);
+ } else if (bchan->plcip) {
+ bchan->disconnecting = 1;
+ if (bchan->plcip->state == ST_PLCI_INCOMING) {
+ /* just ignore, we a called from isdn_status_callback(),
+ * which will return 0 or 2, this is handled by the
+ * CONNECT_IND handler
+ */
+ } else {
+ capi_fill_DISCONNECT_REQ(&cmdcmsg,
+ global.appid,
+ card->msgid++,
+ bchan->plcip->plci,
+ 0, /* BChannelinformation */
+ 0, /* Keypadfacility */
+ 0, /* Useruserdata */
+ 0 /* Facilitydataarray */
+ );
+ plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
+ send_message(card, &cmdcmsg);
+ }
+ }
+/* ready */
+
+ case ISDN_CMD_SETL2:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: set L2 on chan %ld to %ld\n",
+ (c->arg & 0xff), (c->arg >> 8));
+ bchan = &card->bchans[c->arg % card->nbchan];
+ bchan->l2 = (c->arg >> 8);
+ return 0;
+
+ case ISDN_CMD_SETL3:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: set L3 on chan %ld to %ld\n",
+ (c->arg & 0xff), (c->arg >> 8));
+ bchan = &card->bchans[c->arg % card->nbchan];
+ bchan->l3 = (c->arg >> 8);
+ return 0;
+
+ case ISDN_CMD_SETEAZ:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: set EAZ \"%s\" on chan %ld\n",
+ c->parm.num, c->arg);
+ bchan = &card->bchans[c->arg % card->nbchan];
+ strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
+ return 0;
+
+ case ISDN_CMD_CLREAZ:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: clearing EAZ on chan %ld\n", c->arg);
+ bchan = &card->bchans[c->arg % card->nbchan];
+ bchan->msn[0] = 0;
+ return 0;
+
+ case ISDN_CMD_LOCK:
+ if (debugmode > 1)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_LOCK (%ld)\n", c->arg);
+ MOD_INC_USE_COUNT;
+ break;
+
+ case ISDN_CMD_UNLOCK:
+ if (debugmode > 1)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_UNLOCK (%ld)\n", c->arg);
+ MOD_DEC_USE_COUNT;
+ break;
+
+/* never called */
+ case ISDN_CMD_GETL2:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL2\n");
+ return -ENODEV;
+ case ISDN_CMD_GETL3:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_GETL3\n");
+ return -ENODEV;
+ case ISDN_CMD_GETEAZ:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_GETEAZ\n");
+ return -ENODEV;
+ case ISDN_CMD_SETSIL:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_SETSIL\n");
+ return -ENODEV;
+ case ISDN_CMD_GETSIL:
+ if (debugmode)
+ printk(KERN_DEBUG "capidrv: ISDN_CMD_GETSIL\n");
+ return -ENODEV;
+ default:
+ printk(KERN_ERR "capidrv: ISDN_CMD_%d, Huh?\n", c->command);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int if_command(isdn_ctrl * c)
+{
+ capidrv_contr *card = findcontrbydriverid(c->driver);
+
+ if (card)
+ return capidrv_command(c, card);
+
+ printk(KERN_ERR
+ "capidrv: if_command %d called with invalid driverId %d!\n",
+ c->command, c->driver);
+ return -ENODEV;
+}
+
+static _cmsg sendcmsg;
+
+static int if_sendbuf(int id, int channel, struct sk_buff *skb)
+{
+ capidrv_contr *card = findcontrbydriverid(id);
+ capidrv_bchan *bchan;
+ capidrv_ncci *nccip;
+ int len = skb->len;
+ size_t msglen;
+ __u16 errcode;
+
+ if (!card) {
+ printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
+ id);
+ return 0;
+ }
+ bchan = &card->bchans[channel % card->nbchan];
+ nccip = bchan->nccip;
+ if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
+ printk(KERN_ERR "capidrv: if_sendbuf: %s:%d: chan not up!\n",
+ card->name, channel);
+ return 0;
+ }
+ capi_fill_DATA_B3_REQ(&sendcmsg, global.appid, card->msgid++,
+ nccip->ncci, /* adr */
+ (__u32) skb->data, /* Data */
+ skb->len, /* DataLength */
+ nccip->datahandle++, /* DataHandle */
+ 0 /* Flags */
+ );
+ capi_cmsg2message(&sendcmsg, sendcmsg.buf);
+ msglen = CAPIMSG_LEN(sendcmsg.buf);
+ if (skb_headroom(skb) < msglen) {
+ struct sk_buff *nskb = dev_alloc_skb(msglen + skb->len);
+ if (!nskb) {
+ printk(KERN_ERR "capidrv: if_sendbuf: no memory\n");
+ return 0;
+ }
+#if 0
+ printk(KERN_DEBUG "capidrv: only %d bytes headroom\n",
+ skb_headroom(skb));
+#endif
+ SET_SKB_FREE(nskb);
+ memcpy(skb_put(nskb, msglen), sendcmsg.buf, msglen);
+ memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
+ errcode = (*capifuncs->capi_put_message) (global.appid, nskb);
+ switch (errcode) {
+ case CAPI_NOERROR:
+ dev_kfree_skb(skb, FREE_WRITE);
+ return len;
+ case CAPI_SENDQUEUEFULL:
+ dev_kfree_skb(nskb, FREE_WRITE);
+ return 0;
+ default:
+ return -1;
+ }
+ } else {
+ memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
+ errcode = (*capifuncs->capi_put_message) (global.appid, skb);
+ switch (errcode) {
+ case CAPI_NOERROR:
+ return len;
+ case CAPI_SENDQUEUEFULL:
+ return 0;
+ default:
+ return -1;
+ }
+ }
+}
+
+static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
+{
+ capidrv_contr *card;
+ isdn_ctrl cmd;
+ char id[20];
+ int i;
+
+ sprintf(id, "capidrv-%d", contr);
+ if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "capidrv: (%s) Could not allocate contr-struct.\n", id);
+ return -1;
+ }
+ memset(card, 0, sizeof(capidrv_contr));
+ strcpy(card->name, id);
+ card->contrnr = contr;
+ card->nbchan = profp->nbchannel;
+ card->bchans = (capidrv_bchan *) kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
+ if (!card->bchans) {
+ printk(KERN_WARNING
+ "capidrv: (%s) Could not allocate bchan-structs.\n", id);
+ kfree(card);
+ return -1;
+ }
+ card->interface.channels = profp->nbchannel;
+ card->interface.maxbufsize = 2048;
+ card->interface.command = if_command;
+ card->interface.writebuf_skb = if_sendbuf;
+ card->interface.writecmd = 0;
+ card->interface.readstat = 0;
+ card->interface.features = ISDN_FEATURE_L2_X75I |
+ ISDN_FEATURE_L2_X75UI |
+ ISDN_FEATURE_L2_X75BUI |
+ ISDN_FEATURE_L2_HDLC |
+ ISDN_FEATURE_L2_TRANS |
+ ISDN_FEATURE_L3_TRANS |
+ ISDN_FEATURE_P_UNKNOWN;
+ card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
+ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+ card->next = global.contr_list;
+ global.contr_list = card;
+ global.ncontr++;
+
+ if (!register_isdn(&card->interface)) {
+ global.contr_list = global.contr_list->next;
+ printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
+ kfree(card->bchans);
+ kfree(card);
+ return -1;
+ }
+ card->myid = card->interface.channels;
+
+ memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
+ for (i = 0; i < card->nbchan; i++) {
+ card->bchans[i].contr = card;
+ }
+
+ cmd.driver = card->myid;
+ cmd.command = ISDN_STAT_RUN;
+ card->interface.statcallb(&cmd);
+
+ card->cipmask = 1; /* any */
+ card->cipmask2 = 0;
+
+ capi_fill_LISTEN_REQ(&cmdcmsg, global.appid,
+ card->msgid++,
+ contr, /* controller */
+ 1 << 6, /* Infomask */
+ card->cipmask,
+ card->cipmask2,
+ 0, 0);
+ send_message(card, &cmdcmsg);
+ listen_change_state(card, EV_LISTEN_REQ);
+
+ printk(KERN_INFO "%s: now up (%d B channels)\n",
+ card->name, card->nbchan);
+
+ return 0;
+}
+
+static int capidrv_delcontr(__u16 contr)
+{
+ capidrv_contr **pp, *card;
+ isdn_ctrl cmd;
+ int i;
+
+ for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
+ if ((*pp)->contrnr == contr)
+ break;
+ }
+ if (!*pp) {
+ printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
+ return -1;
+ }
+ card = *pp;
+ *pp = (*pp)->next;
+ global.ncontr--;
+
+ for (i = 0; i < card->nbchan; i++) {
+ if (card->bchans[i].nccip)
+ free_ncci(card, card->bchans[i].nccip);
+ if (card->bchans[i].plcip)
+ free_plci(card, card->bchans[i].plcip);
+ if (card->plci_list)
+ printk(KERN_ERR "capidrv: bug in free_plci()\n");
+ }
+ kfree(card->bchans);
+
+ cmd.command = ISDN_STAT_UNLOAD;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+
+ printk(KERN_INFO "%s: now down.\n", card->name);
+
+ kfree(card);
+
+ return 0;
+}
+
+
+static void lower_callback(unsigned int cmd, __u16 contr, void *data)
+{
+ switch (cmd) {
+ case KCI_CONTRUP:
+ (void) capidrv_addcontr(contr, (capi_profile *) data);
+ break;
+ case KCI_CONTRDOWN:
+ (void) capidrv_delcontr(contr);
+ break;
+ }
+}
+
+static struct capi_interface_user cuser = {
+ "capidrv",
+ lower_callback
+};
+
+#ifdef MODULE
+#define capidrv_init init_module
+#endif
+
+int capidrv_init(void)
+{
+ struct capi_register_params rparam;
+ capi_profile profile;
+ char rev[10];
+ char *p;
+ __u32 ncontr, contr;
+ __u16 errcode;
+
+ capifuncs = attach_capi_interface(&cuser);
+
+ if (!capifuncs)
+ return -EIO;
+
+#ifndef HAS_NEW_SYMTAB
+ /* No symbols to export, hide all symbols */
+ register_symtab(NULL);
+#endif
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, " ??? ");
+
+ rparam.level3cnt = 2;
+ rparam.datablkcnt = 8;
+ rparam.datablklen = 2048;
+ errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
+ if (errcode) {
+ detach_capi_interface(&cuser);
+ return -EIO;
+ }
+
+ errcode = (*capifuncs->capi_get_profile) (0, &profile);
+ if (errcode != CAPI_NOERROR) {
+ (void) (*capifuncs->capi_release) (global.appid);
+ detach_capi_interface(&cuser);
+ return -EIO;
+ }
+
+ (void) (*capifuncs->capi_set_signal) (global.appid, capidrv_signal, 0);
+
+ ncontr = profile.ncontroller;
+ for (contr = 1; contr <= ncontr; contr++) {
+ errcode = (*capifuncs->capi_get_profile) (contr, &profile);
+ if (errcode != CAPI_NOERROR)
+ continue;
+ (void) capidrv_addcontr(contr, &profile);
+ }
+
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ capidrv_contr *card, *next;
+ char rev[10];
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else {
+ strcpy(rev, " ??? ");
+ }
+
+ for (card = global.contr_list; card; card = next) {
+ next = card->next;
+ capidrv_delcontr(card->contrnr);
+ }
+
+ (void) (*capifuncs->capi_release) (global.appid);
+ detach_capi_interface(&cuser);
+
+ printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
+}
+
+#endif
--- /dev/null
+/*
+ * $Id: capidrv.h,v 1.1 1997/03/04 21:50:33 calle Exp $
+ *
+ * ISDN4Linux Driver, using capi20 interface (kernelcapi)
+ *
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capidrv.h,v $
+ * 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 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 */
+#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 */
+#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 */
+
+/*
+ * 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__ */
--- /dev/null
+/*
+ * $Id: capiutil.c,v 1.3 1997/05/18 09:24:18 calle Exp $
+ *
+ * CAPI 2.0 convert capi message to capi message struct
+ *
+ * From CAPI 2.0 Development Kit AVM 1995 (msg.c)
+ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capiutil.c,v $
+ * Revision 1.3 1997/05/18 09:24:18 calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.2 1997/03/05 21:22:13 fritz
+ * Fix: Symbols have to be exported unconditionally.
+ *
+ * Revision 1.1 1997/03/04 21:50:34 calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+
+#include "compat.h"
+#include "capiutil.h"
+
+/* from CAPI2.0 DDK AVM Berlin GmbH */
+
+#ifndef CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+char *capi_info2str(__u16 reason)
+{
+ return "..";
+}
+#else
+char *capi_info2str(__u16 reason)
+{
+ switch (reason) {
+
+/*-- informative values (corresponding message was processed) -----*/
+ case 0x0001:
+ return "NCPI not supported by current protocol, NCPI ignored";
+ case 0x0002:
+ return "Flags not supported by current protocol, flags ignored";
+ case 0x0003:
+ return "Alert already sent by another application";
+
+/*-- error information concerning CAPI_REGISTER -----*/
+ case 0x1001:
+ return "Too many applications";
+ case 0x1002:
+ return "Logical block size to small, must be at least 128 Bytes";
+ case 0x1003:
+ return "Buffer exceeds 64 kByte";
+ case 0x1004:
+ return "Message buffer size too small, must be at least 1024 Bytes";
+ case 0x1005:
+ return "Max. number of logical connections not supported";
+ case 0x1006:
+ return "Reserved";
+ case 0x1007:
+ return "The message could not be accepted because of an internal busy condition";
+ case 0x1008:
+ return "OS resource error (no memory ?)";
+ case 0x1009:
+ return "CAPI not installed";
+ case 0x100A:
+ return "Controller does not support external equipment";
+ case 0x100B:
+ return "Controller does only support external equipment";
+
+/*-- error information concerning message exchange functions -----*/
+ case 0x1101:
+ return "Illegal application number";
+ case 0x1102:
+ return "Illegal command or subcommand or message length less than 12 bytes";
+ case 0x1103:
+ return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI";
+ case 0x1104:
+ return "Queue is empty";
+ case 0x1105:
+ return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE";
+ case 0x1106:
+ return "Unknown notification parameter";
+ case 0x1107:
+ return "The Message could not be accepted because of an internal busy condition";
+ case 0x1108:
+ return "OS Resource error (no memory ?)";
+ case 0x1109:
+ return "CAPI not installed";
+ case 0x110A:
+ return "Controller does not support external equipment";
+ case 0x110B:
+ return "Controller does only support external equipment";
+
+/*-- error information concerning resource / coding problems -----*/
+ case 0x2001:
+ return "Message not supported in current state";
+ case 0x2002:
+ return "Illegal Controller / PLCI / NCCI";
+ case 0x2003:
+ return "Out of PLCI";
+ case 0x2004:
+ return "Out of NCCI";
+ case 0x2005:
+ return "Out of LISTEN";
+ case 0x2006:
+ return "Out of FAX resources (protocol T.30)";
+ case 0x2007:
+ return "Illegal message parameter coding";
+
+/*-- error information concerning requested services -----*/
+ case 0x3001:
+ return "B1 protocol not supported";
+ case 0x3002:
+ return "B2 protocol not supported";
+ case 0x3003:
+ return "B3 protocol not supported";
+ case 0x3004:
+ return "B1 protocol parameter not supported";
+ case 0x3005:
+ return "B2 protocol parameter not supported";
+ case 0x3006:
+ return "B3 protocol parameter not supported";
+ case 0x3007:
+ return "B protocol combination not supported";
+ case 0x3008:
+ return "NCPI not supported";
+ case 0x3009:
+ return "CIP Value unknown";
+ case 0x300A:
+ return "Flags not supported (reserved bits)";
+ case 0x300B:
+ return "Facility not supported";
+ case 0x300C:
+ return "Data length not supported by current protocol";
+ case 0x300D:
+ return "Reset procedure not supported by current protocol";
+
+/*-- informations about the clearing of a physical connection -----*/
+ case 0x3301:
+ return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)";
+ case 0x3302:
+ return "Protocol error layer 2";
+ case 0x3303:
+ return "Protocol error layer 3";
+ case 0x3304:
+ return "Another application got that call";
+/*-- T.30 specific reasons -----*/
+ case 0x3311:
+ return "Connecting not successful (remote station is no FAX G3 machine)";
+ case 0x3312:
+ return "Connecting not successful (training error)";
+ case 0x3313:
+ return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)";
+ case 0x3314:
+ return "Disconnected during transfer (remote abort)";
+ case 0x3315:
+ return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)";
+ case 0x3316:
+ return "Disconnected during transfer (local tx data underrun)";
+ case 0x3317:
+ return "Disconnected during transfer (local rx data overflow)";
+ case 0x3318:
+ return "Disconnected during transfer (local abort)";
+ case 0x3319:
+ return "Illegal parameter coding (e.g. SFF coding error)";
+
+/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/
+ case 0x3481: return "Unallocated (unassigned) number";
+ case 0x3482: return "No route to specified transit network";
+ case 0x3483: return "No route to destination";
+ case 0x3486: return "Channel unacceptable";
+ case 0x3487:
+ return "Call awarded and being delivered in an established channel";
+ case 0x3490: return "Normal call clearing";
+ case 0x3491: return "User busy";
+ case 0x3492: return "No user responding";
+ case 0x3493: return "No answer from user (user alerted)";
+ case 0x3495: return "Call rejected";
+ case 0x3496: return "Number changed";
+ case 0x349A: return "Non-selected user clearing";
+ case 0x349B: return "Destination out of order";
+ case 0x349C: return "Invalid number format";
+ case 0x349D: return "Facility rejected";
+ case 0x349E: return "Response to STATUS ENQUIRY";
+ case 0x349F: return "Normal, unspecified";
+ case 0x34A2: return "No circuit / channel available";
+ case 0x34A6: return "Network out of order";
+ case 0x34A9: return "Temporary failure";
+ case 0x34AA: return "Switching equipment congestion";
+ case 0x34AB: return "Access information discarded";
+ case 0x34AC: return "Requested circuit / channel not available";
+ case 0x34AF: return "Resources unavailable, unspecified";
+ case 0x34B1: return "Quality of service unavailable";
+ case 0x34B2: return "Requested facility not subscribed";
+ case 0x34B9: return "Bearer capability not authorized";
+ case 0x34BA: return "Bearer capability not presently available";
+ case 0x34BF: return "Service or option not available, unspecified";
+ case 0x34C1: return "Bearer capability not implemented";
+ case 0x34C2: return "Channel type not implemented";
+ case 0x34C5: return "Requested facility not implemented";
+ case 0x34C6: return "Only restricted digital information bearer capability is available";
+ case 0x34CF: return "Service or option not implemented, unspecified";
+ case 0x34D1: return "Invalid call reference value";
+ case 0x34D2: return "Identified channel does not exist";
+ case 0x34D3: return "A suspended call exists, but this call identity does not";
+ case 0x34D4: return "Call identity in use";
+ case 0x34D5: return "No call suspended";
+ case 0x34D6: return "Call having the requested call identity has been cleared";
+ case 0x34D8: return "Incompatible destination";
+ case 0x34DB: return "Invalid transit network selection";
+ case 0x34DF: return "Invalid message, unspecified";
+ case 0x34E0: return "Mandatory information element is missing";
+ case 0x34E1: return "Message type non-existent or not implemented";
+ case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented";
+ case 0x34E3: return "Information element non-existent or not implemented";
+ case 0x34E4: return "Invalid information element contents";
+ case 0x34E5: return "Message not compatible with call state";
+ case 0x34E6: return "Recovery on timer expiry";
+ case 0x34EF: return "Protocol error, unspecified";
+ case 0x34FF: return "Interworking, unspecified";
+
+ default: return "No additional information";
+ }
+}
+#endif
+
+typedef struct {
+ int typ;
+ size_t off;
+} _cdef;
+
+#define _CBYTE 1
+#define _CWORD 2
+#define _CDWORD 3
+#define _CSTRUCT 4
+#define _CMSTRUCT 5
+#define _CEND 6
+
+static _cdef cdef[] =
+{
+ /*00 */
+ {_CEND},
+ /*01 */
+ {_CEND},
+ /*02 */
+ {_CEND},
+ /*03 */
+ {_CDWORD, offsetof(_cmsg, adr.adrController)},
+ /*04 */
+ {_CMSTRUCT, offsetof(_cmsg, AdditionalInfo)},
+ /*05 */
+ {_CSTRUCT, offsetof(_cmsg, B1configuration)},
+ /*06 */
+ {_CWORD, offsetof(_cmsg, B1protocol)},
+ /*07 */
+ {_CSTRUCT, offsetof(_cmsg, B2configuration)},
+ /*08 */
+ {_CWORD, offsetof(_cmsg, B2protocol)},
+ /*09 */
+ {_CSTRUCT, offsetof(_cmsg, B3configuration)},
+ /*0a */
+ {_CWORD, offsetof(_cmsg, B3protocol)},
+ /*0b */
+ {_CSTRUCT, offsetof(_cmsg, BC)},
+ /*0c */
+ {_CSTRUCT, offsetof(_cmsg, BChannelinformation)},
+ /*0d */
+ {_CMSTRUCT, offsetof(_cmsg, BProtocol)},
+ /*0e */
+ {_CSTRUCT, offsetof(_cmsg, CalledPartyNumber)},
+ /*0f */
+ {_CSTRUCT, offsetof(_cmsg, CalledPartySubaddress)},
+ /*10 */
+ {_CSTRUCT, offsetof(_cmsg, CallingPartyNumber)},
+ /*11 */
+ {_CSTRUCT, offsetof(_cmsg, CallingPartySubaddress)},
+ /*12 */
+ {_CDWORD, offsetof(_cmsg, CIPmask)},
+ /*13 */
+ {_CDWORD, offsetof(_cmsg, CIPmask2)},
+ /*14 */
+ {_CWORD, offsetof(_cmsg, CIPValue)},
+ /*15 */
+ {_CDWORD, offsetof(_cmsg, Class)},
+ /*16 */
+ {_CSTRUCT, offsetof(_cmsg, ConnectedNumber)},
+ /*17 */
+ {_CSTRUCT, offsetof(_cmsg, ConnectedSubaddress)},
+ /*18 */
+ {_CDWORD, offsetof(_cmsg, Data)},
+ /*19 */
+ {_CWORD, offsetof(_cmsg, DataHandle)},
+ /*1a */
+ {_CWORD, offsetof(_cmsg, DataLength)},
+ /*1b */
+ {_CSTRUCT, offsetof(_cmsg, FacilityConfirmationParameter)},
+ /*1c */
+ {_CSTRUCT, offsetof(_cmsg, Facilitydataarray)},
+ /*1d */
+ {_CSTRUCT, offsetof(_cmsg, FacilityIndicationParameter)},
+ /*1e */
+ {_CSTRUCT, offsetof(_cmsg, FacilityRequestParameter)},
+ /*1f */
+ {_CWORD, offsetof(_cmsg, FacilitySelector)},
+ /*20 */
+ {_CWORD, offsetof(_cmsg, Flags)},
+ /*21 */
+ {_CDWORD, offsetof(_cmsg, Function)},
+ /*22 */
+ {_CSTRUCT, offsetof(_cmsg, HLC)},
+ /*23 */
+ {_CWORD, offsetof(_cmsg, Info)},
+ /*24 */
+ {_CSTRUCT, offsetof(_cmsg, InfoElement)},
+ /*25 */
+ {_CDWORD, offsetof(_cmsg, InfoMask)},
+ /*26 */
+ {_CWORD, offsetof(_cmsg, InfoNumber)},
+ /*27 */
+ {_CSTRUCT, offsetof(_cmsg, Keypadfacility)},
+ /*28 */
+ {_CSTRUCT, offsetof(_cmsg, LLC)},
+ /*29 */
+ {_CSTRUCT, offsetof(_cmsg, ManuData)},
+ /*2a */
+ {_CDWORD, offsetof(_cmsg, ManuID)},
+ /*2b */
+ {_CSTRUCT, offsetof(_cmsg, NCPI)},
+ /*2c */
+ {_CWORD, offsetof(_cmsg, Reason)},
+ /*2d */
+ {_CWORD, offsetof(_cmsg, Reason_B3)},
+ /*2e */
+ {_CWORD, offsetof(_cmsg, Reject)},
+ /*2f */
+ {_CSTRUCT, offsetof(_cmsg, Useruserdata)}
+};
+
+static unsigned char *cpars[] =
+{
+ /*00 */ 0,
+ /*01 ALERT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
+ /*02 CONNECT_REQ */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0d\x06\x08\x0a\x05\x07\x09\x01\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
+ /*03 */ 0,
+ /*04 DISCONNECT_REQ */ (unsigned char *) "\x03\x04\x0c\x27\x2f\x1c\x01\x01",
+ /*05 LISTEN_REQ */ (unsigned char *) "\x03\x25\x12\x13\x10\x11\x01",
+ /*06 */ 0,
+ /*07 */ 0,
+ /*08 INFO_REQ */ (unsigned char *) "\x03\x0e\x04\x0c\x27\x2f\x1c\x01\x01",
+ /*09 FACILITY_REQ */ (unsigned char *) "\x03\x1f\x1e\x01",
+ /*0a SELECT_B_PROTOCOL_REQ */ (unsigned char *) "\x03\x0d\x06\x08\x0a\x05\x07\x09\x01\x01",
+ /*0b CONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
+ /*0c */ 0,
+ /*0d DISCONNECT_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
+ /*0e */ 0,
+ /*0f DATA_B3_REQ */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01",
+ /*10 RESET_B3_REQ */ (unsigned char *) "\x03\x2b\x01",
+ /*11 */ 0,
+ /*12 */ 0,
+ /*13 ALERT_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*14 CONNECT_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*15 */ 0,
+ /*16 DISCONNECT_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*17 LISTEN_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*18 MANUFACTURER_REQ */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
+ /*19 */ 0,
+ /*1a INFO_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*1b FACILITY_CONF */ (unsigned char *) "\x03\x23\x1f\x1b\x01",
+ /*1c SELECT_B_PROTOCOL_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*1d CONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*1e */ 0,
+ /*1f DISCONNECT_B3_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*20 */ 0,
+ /*21 DATA_B3_CONF */ (unsigned char *) "\x03\x19\x23\x01",
+ /*22 RESET_B3_CONF */ (unsigned char *) "\x03\x23\x01",
+ /*23 */ 0,
+ /*24 */ 0,
+ /*25 */ 0,
+ /*26 CONNECT_IND */ (unsigned char *) "\x03\x14\x0e\x10\x0f\x11\x0b\x28\x22\x04\x0c\x27\x2f\x1c\x01\x01",
+ /*27 CONNECT_ACTIVE_IND */ (unsigned char *) "\x03\x16\x17\x28\x01",
+ /*28 DISCONNECT_IND */ (unsigned char *) "\x03\x2c\x01",
+ /*29 */ 0,
+ /*2a MANUFACTURER_CONF */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
+ /*2b */ 0,
+ /*2c INFO_IND */ (unsigned char *) "\x03\x26\x24\x01",
+ /*2d FACILITY_IND */ (unsigned char *) "\x03\x1f\x1d\x01",
+ /*2e */ 0,
+ /*2f CONNECT_B3_IND */ (unsigned char *) "\x03\x2b\x01",
+ /*30 CONNECT_B3_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01",
+ /*31 DISCONNECT_B3_IND */ (unsigned char *) "\x03\x2d\x2b\x01",
+ /*32 */ 0,
+ /*33 DATA_B3_IND */ (unsigned char *) "\x03\x18\x1a\x19\x20\x01",
+ /*34 RESET_B3_IND */ (unsigned char *) "\x03\x2b\x01",
+ /*35 CONNECT_B3_T90_ACTIVE_IND */ (unsigned char *) "\x03\x2b\x01",
+ /*36 */ 0,
+ /*37 */ 0,
+ /*38 CONNECT_RESP */ (unsigned char *) "\x03\x2e\x0d\x06\x08\x0a\x05\x07\x09\x01\x16\x17\x28\x04\x0c\x27\x2f\x1c\x01\x01",
+ /*39 CONNECT_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
+ /*3a DISCONNECT_RESP */ (unsigned char *) "\x03\x01",
+ /*3b */ 0,
+ /*3c MANUFACTURER_IND */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
+ /*3d */ 0,
+ /*3e INFO_RESP */ (unsigned char *) "\x03\x01",
+ /*3f FACILITY_RESP */ (unsigned char *) "\x03\x1f\x01",
+ /*40 */ 0,
+ /*41 CONNECT_B3_RESP */ (unsigned char *) "\x03\x2e\x2b\x01",
+ /*42 CONNECT_B3_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
+ /*43 DISCONNECT_B3_RESP */ (unsigned char *) "\x03\x01",
+ /*44 */ 0,
+ /*45 DATA_B3_RESP */ (unsigned char *) "\x03\x19\x01",
+ /*46 RESET_B3_RESP */ (unsigned char *) "\x03\x01",
+ /*47 CONNECT_B3_T90_ACTIVE_RESP */ (unsigned char *) "\x03\x01",
+ /*48 */ 0,
+ /*49 */ 0,
+ /*4a */ 0,
+ /*4b */ 0,
+ /*4c */ 0,
+ /*4d */ 0,
+ /*4e MANUFACTURER_RESP */ (unsigned char *) "\x03\x2a\x15\x21\x29\x01",
+};
+
+/*-------------------------------------------------------*/
+
+#define byteTLcpy(x,y) *(__u8 *)(x)=*(__u8 *)(y);
+#define wordTLcpy(x,y) *(__u16 *)(x)=*(__u16 *)(y);
+#define dwordTLcpy(x,y) memcpy(x,y,4);
+#define structTLcpy(x,y,l) memcpy (x,y,l)
+#define structTLcpyovl(x,y,l) memmove (x,y,l)
+
+#define byteTRcpy(x,y) *(__u8 *)(y)=*(__u8 *)(x);
+#define wordTRcpy(x,y) *(__u16 *)(y)=*(__u16 *)(x);
+#define dwordTRcpy(x,y) memcpy(y,x,4);
+#define structTRcpy(x,y,l) memcpy (y,x,l)
+#define structTRcpyovl(x,y,l) memmove (y,x,l)
+
+/*-------------------------------------------------------*/
+static unsigned command_2_index(unsigned c, unsigned sc)
+{
+ if (c & 0x80)
+ c = 0x9 + (c & 0x0f);
+ else if (c <= 0x0f);
+ else if (c == 0x41)
+ c = 0x9 + 0x1;
+ else if (c == 0xff)
+ c = 0x00;
+ return (sc & 3) * (0x9 + 0x9) + c;
+}
+
+/*-------------------------------------------------------*/
+#define TYP (cdef[cmsg->par[cmsg->p]].typ)
+#define OFF (((__u8 *)cmsg)+cdef[cmsg->par[cmsg->p]].off)
+
+static void jumpcstruct(_cmsg * cmsg)
+{
+ unsigned layer;
+ for (cmsg->p++, layer = 1; layer;) {
+ /* $$$$$ assert (cmsg->p); */
+ cmsg->p++;
+ switch (TYP) {
+ case _CMSTRUCT:
+ layer++;
+ break;
+ case _CEND:
+ layer--;
+ break;
+ }
+ }
+}
+/*-------------------------------------------------------*/
+static void pars_2_message(_cmsg * cmsg)
+{
+
+ for (; TYP != _CEND; cmsg->p++) {
+ switch (TYP) {
+ case _CBYTE:
+ byteTLcpy(cmsg->m + cmsg->l, OFF);
+ cmsg->l++;
+ break;
+ case _CWORD:
+ wordTLcpy(cmsg->m + cmsg->l, OFF);
+ cmsg->l += 2;
+ break;
+ case _CDWORD:
+ dwordTLcpy(cmsg->m + cmsg->l, OFF);
+ cmsg->l += 4;
+ break;
+ case _CSTRUCT:
+ if (*(__u8 **) OFF == 0) {
+ *(cmsg->m + cmsg->l) = '\0';
+ cmsg->l++;
+ } else if (**(_cstruct *) OFF != 0xff) {
+ structTLcpy(cmsg->m + cmsg->l, *(_cstruct *) OFF, 1 + **(_cstruct *) OFF);
+ cmsg->l += 1 + **(_cstruct *) OFF;
+ } else {
+ _cstruct s = *(_cstruct *) OFF;
+ structTLcpy(cmsg->m + cmsg->l, s, 3 + *(__u16 *) (s + 1));
+ cmsg->l += 3 + *(__u16 *) (s + 1);
+ }
+ break;
+ case _CMSTRUCT:
+/*----- Metastruktur 0 -----*/
+ if (*(_cmstruct *) OFF == CAPI_DEFAULT) {
+ *(cmsg->m + cmsg->l) = '\0';
+ cmsg->l++;
+ jumpcstruct(cmsg);
+ }
+/*----- Metastruktur wird composed -----*/
+ else {
+ unsigned _l = cmsg->l;
+ unsigned _ls;
+ cmsg->l++;
+ cmsg->p++;
+ pars_2_message(cmsg);
+ _ls = cmsg->l - _l - 1;
+ if (_ls < 255)
+ (cmsg->m + _l)[0] = (__u8) _ls;
+ else {
+ structTLcpyovl(cmsg->m + _l + 3, cmsg->m + _l + 1, _ls);
+ (cmsg->m + _l)[0] = 0xff;
+ wordTLcpy(cmsg->m + _l + 1, &_ls);
+ }
+ }
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------------*/
+unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg)
+{
+ cmsg->m = msg;
+ cmsg->l = 8;
+ cmsg->p = 0;
+ cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
+
+ pars_2_message(cmsg);
+
+ wordTLcpy(msg + 0, &cmsg->l);
+ byteTLcpy(cmsg->m + 4, &cmsg->Command);
+ byteTLcpy(cmsg->m + 5, &cmsg->Subcommand);
+ wordTLcpy(cmsg->m + 2, &cmsg->ApplId);
+ wordTLcpy(cmsg->m + 6, &cmsg->Messagenumber);
+
+ return 0;
+}
+
+/*-------------------------------------------------------*/
+static void message_2_pars(_cmsg * cmsg)
+{
+ for (; TYP != _CEND; cmsg->p++) {
+
+ switch (TYP) {
+ case _CBYTE:
+ byteTRcpy(cmsg->m + cmsg->l, OFF);
+ cmsg->l++;
+ break;
+ case _CWORD:
+ wordTRcpy(cmsg->m + cmsg->l, OFF);
+ cmsg->l += 2;
+ break;
+ case _CDWORD:
+ dwordTRcpy(cmsg->m + cmsg->l, OFF);
+ cmsg->l += 4;
+ break;
+ case _CSTRUCT:
+ *(__u8 **) OFF = cmsg->m + cmsg->l;
+
+ if (cmsg->m[cmsg->l] != 0xff)
+ cmsg->l += 1 + cmsg->m[cmsg->l];
+ else
+ cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1);
+ break;
+ case _CMSTRUCT:
+/*----- Metastruktur 0 -----*/
+ if (cmsg->m[cmsg->l] == '\0') {
+ *(_cmstruct *) OFF = CAPI_DEFAULT;
+ cmsg->l++;
+ jumpcstruct(cmsg);
+ } else {
+ unsigned _l = cmsg->l;
+ *(_cmstruct *) OFF = CAPI_COMPOSE;
+ cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
+ cmsg->p++;
+ message_2_pars(cmsg);
+ }
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------------*/
+unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg)
+{
+ memset(cmsg, 0, sizeof(_cmsg));
+ cmsg->m = msg;
+ cmsg->l = 8;
+ cmsg->p = 0;
+ byteTRcpy(cmsg->m + 4, &cmsg->Command);
+ byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
+ cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
+
+ message_2_pars(cmsg);
+
+ wordTRcpy(msg + 0, &cmsg->l);
+ wordTRcpy(cmsg->m + 2, &cmsg->ApplId);
+ wordTRcpy(cmsg->m + 6, &cmsg->Messagenumber);
+
+ return 0;
+}
+
+/*-------------------------------------------------------*/
+unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId,
+ __u8 _Command, __u8 _Subcommand,
+ __u16 _Messagenumber, __u32 _Controller)
+{
+ memset(cmsg, 0, sizeof(_cmsg));
+ cmsg->ApplId = _ApplId;
+ cmsg->Command = _Command;
+ cmsg->Subcommand = _Subcommand;
+ cmsg->Messagenumber = _Messagenumber;
+ cmsg->adr.adrController = _Controller;
+ return 0;
+}
+
+/*-------------------------------------------------------*/
+
+static char *mnames[] =
+{
+ 0,
+ "ALERT_REQ",
+ "CONNECT_REQ",
+ 0,
+ "DISCONNECT_REQ",
+ "LISTEN_REQ",
+ 0,
+ 0,
+ "INFO_REQ",
+ "FACILITY_REQ",
+ "SELECT_B_PROTOCOL_REQ",
+ "CONNECT_B3_REQ",
+ 0,
+ "DISCONNECT_B3_REQ",
+ 0,
+ "DATA_B3_REQ",
+ "RESET_B3_REQ",
+ 0,
+ 0,
+ "ALERT_CONF",
+ "CONNECT_CONF",
+ 0,
+ "DISCONNECT_CONF",
+ "LISTEN_CONF",
+ "MANUFACTURER_REQ",
+ 0,
+ "INFO_CONF",
+ "FACILITY_CONF",
+ "SELECT_B_PROTOCOL_CONF",
+ "CONNECT_B3_CONF",
+ 0,
+ "DISCONNECT_B3_CONF",
+ 0,
+ "DATA_B3_CONF",
+ "RESET_B3_CONF",
+ 0,
+ 0,
+ 0,
+ "CONNECT_IND",
+ "CONNECT_ACTIVE_IND",
+ "DISCONNECT_IND",
+ 0,
+ "MANUFACTURER_CONF",
+ 0,
+ "INFO_IND",
+ "FACILITY_IND",
+ 0,
+ "CONNECT_B3_IND",
+ "CONNECT_B3_ACTIVE_IND",
+ "DISCONNECT_B3_IND",
+ 0,
+ "DATA_B3_IND",
+ "RESET_B3_IND",
+ "CONNECT_B3_T90_ACTIVE_IND",
+ 0,
+ 0,
+ "CONNECT_RESP",
+ "CONNECT_ACTIVE_RESP",
+ "DISCONNECT_RESP",
+ 0,
+ "MANUFACTURER_IND",
+ 0,
+ "INFO_RESP",
+ "FACILITY_RESP",
+ 0,
+ "CONNECT_B3_RESP",
+ "CONNECT_B3_ACTIVE_RESP",
+ "DISCONNECT_B3_RESP",
+ 0,
+ "DATA_B3_RESP",
+ "RESET_B3_RESP",
+ "CONNECT_B3_T90_ACTIVE_RESP",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "MANUFACTURER_RESP"
+};
+
+char *capi_cmd2str(__u8 cmd, __u8 subcmd)
+{
+ return mnames[command_2_index(cmd, subcmd)];
+}
+
+
+/*-------------------------------------------------------*/
+/*-------------------------------------------------------*/
+
+static char *pnames[] =
+{
+ /*00 */ 0,
+ /*01 */ 0,
+ /*02 */ 0,
+ /*03 */ "Controller/PLCI/NCCI",
+ /*04 */ "AdditionalInfo",
+ /*05 */ "B1configuration",
+ /*06 */ "B1protocol",
+ /*07 */ "B2configuration",
+ /*08 */ "B2protocol",
+ /*09 */ "B3configuration",
+ /*0a */ "B3protocol",
+ /*0b */ "BC",
+ /*0c */ "BChannelinformation",
+ /*0d */ "BProtocol",
+ /*0e */ "CalledPartyNumber",
+ /*0f */ "CalledPartySubaddress",
+ /*10 */ "CallingPartyNumber",
+ /*11 */ "CallingPartySubaddress",
+ /*12 */ "CIPmask",
+ /*13 */ "CIPmask2",
+ /*14 */ "CIPValue",
+ /*15 */ "Class",
+ /*16 */ "ConnectedNumber",
+ /*17 */ "ConnectedSubaddress",
+ /*18 */ "Data",
+ /*19 */ "DataHandle",
+ /*1a */ "DataLength",
+ /*1b */ "FacilityConfirmationParameter",
+ /*1c */ "Facilitydataarray",
+ /*1d */ "FacilityIndicationParameter",
+ /*1e */ "FacilityRequestParameter",
+ /*1f */ "FacilitySelector",
+ /*20 */ "Flags",
+ /*21 */ "Function",
+ /*22 */ "HLC",
+ /*23 */ "Info",
+ /*24 */ "InfoElement",
+ /*25 */ "InfoMask",
+ /*26 */ "InfoNumber",
+ /*27 */ "Keypadfacility",
+ /*28 */ "LLC",
+ /*29 */ "ManuData",
+ /*2a */ "ManuID",
+ /*2b */ "NCPI",
+ /*2c */ "Reason",
+ /*2d */ "Reason_B3",
+ /*2e */ "Reject",
+ /*2f */ "Useruserdata"
+};
+
+
+static char buf[8192];
+static char *p = 0;
+
+#include <stdarg.h>
+
+/*-------------------------------------------------------*/
+static void bufprint(char *fmt,...)
+{
+ va_list f;
+ va_start(f, fmt);
+ vsprintf(p, fmt, f);
+ va_end(f);
+ p += strlen(p);
+}
+
+static void printstructlen(__u8 * m, unsigned len)
+{
+ unsigned hex = 0;
+ for (; len; len--, m++)
+ if (isalnum(*m) || *m == ' ') {
+ if (hex)
+ bufprint(">");
+ bufprint("%c", *m);
+ hex = 0;
+ } else {
+ if (!hex)
+ bufprint("<%02x", *m);
+ else
+ bufprint(" %02x", *m);
+ hex = 1;
+ }
+ if (hex)
+ bufprint(">");
+}
+
+static void printstruct(__u8 * m)
+{
+ unsigned len;
+ if (m[0] != 0xff) {
+ len = m[0];
+ m += 1;
+ } else {
+ len = ((__u16 *) (m + 1))[0];
+ m += 3;
+ }
+ printstructlen(m, len);
+}
+
+/*-------------------------------------------------------*/
+#define NAME (pnames[cmsg->par[cmsg->p]])
+
+static void protocol_message_2_pars(_cmsg * cmsg, int level)
+{
+ for (; TYP != _CEND; cmsg->p++) {
+ int slen = 29 + 3 - level;
+ int i;
+
+ bufprint(" ");
+ for (i = 0; i < level - 1; i++)
+ bufprint(" ");
+
+ switch (TYP) {
+ case _CBYTE:
+ bufprint("%-*s = 0x%x\n", slen, NAME, *(__u8 *) (cmsg->m + cmsg->l));
+ cmsg->l++;
+ break;
+ case _CWORD:
+ bufprint("%-*s = 0x%x\n", slen, NAME, *(__u16 *) (cmsg->m + cmsg->l));
+ cmsg->l += 2;
+ break;
+ case _CDWORD:
+ if (strcmp(NAME, "Data") == 0) {
+ bufprint("%-*s = ", slen, NAME);
+ printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l),
+ *(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32)));
+ bufprint("\n");
+ } else
+ bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
+ cmsg->l += 4;
+ break;
+ case _CSTRUCT:
+ bufprint("%-*s = ", slen, NAME);
+ if (cmsg->m[cmsg->l] == '\0')
+ bufprint("default");
+ else
+ printstruct(cmsg->m + cmsg->l);
+ bufprint("\n");
+ if (cmsg->m[cmsg->l] != 0xff)
+ cmsg->l += 1 + cmsg->m[cmsg->l];
+ else
+ cmsg->l += 3 + *(__u16 *) (cmsg->m + cmsg->l + 1);
+
+ break;
+
+ case _CMSTRUCT:
+/*----- Metastruktur 0 -----*/
+ if (cmsg->m[cmsg->l] == '\0') {
+ bufprint("%-*s = default\n", slen, NAME);
+ cmsg->l++;
+ jumpcstruct(cmsg);
+ } else {
+ char *name = NAME;
+ unsigned _l = cmsg->l;
+ bufprint("%-*s\n", slen, name);
+ cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
+ cmsg->p++;
+ protocol_message_2_pars(cmsg, level + 1);
+ }
+ break;
+ }
+ }
+}
+/*-------------------------------------------------------*/
+char *capi_message2str(__u8 * msg)
+{
+
+ _cmsg cmsg;
+ p = buf;
+ p[0] = 0;
+
+ cmsg.m = msg;
+ cmsg.l = 8;
+ cmsg.p = 0;
+ byteTRcpy(cmsg.m + 4, &cmsg.Command);
+ byteTRcpy(cmsg.m + 5, &cmsg.Subcommand);
+ cmsg.par = cpars[command_2_index(cmsg.Command, cmsg.Subcommand)];
+
+ bufprint("%-26s ID=%03d #0x%04x LEN=%04d\n",
+ mnames[command_2_index(cmsg.Command, cmsg.Subcommand)],
+ ((unsigned short *) msg)[1],
+ ((unsigned short *) msg)[3],
+ ((unsigned short *) msg)[0]);
+
+ protocol_message_2_pars(&cmsg, 1);
+ return buf;
+}
+
+char *capi_cmsg2str(_cmsg * cmsg)
+{
+ p = buf;
+ p[0] = 0;
+ cmsg->l = 8;
+ cmsg->p = 0;
+ bufprint("%s ID=%03d #0x%04x LEN=%04d\n",
+ mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
+ ((__u16 *) cmsg->m)[1],
+ ((__u16 *) cmsg->m)[3],
+ ((__u16 *) cmsg->m)[0]);
+ protocol_message_2_pars(cmsg, 1);
+ return buf;
+}
+
+
+#ifdef HAS_NEW_SYMTAB
+EXPORT_SYMBOL(capi_cmsg2message);
+EXPORT_SYMBOL(capi_message2cmsg);
+EXPORT_SYMBOL(capi_cmsg_header);
+EXPORT_SYMBOL(capi_cmd2str);
+EXPORT_SYMBOL(capi_cmsg2str);
+EXPORT_SYMBOL(capi_message2str);
+#else
+static struct symbol_table capifunc_syms =
+{
+#include <linux/symtab_begin.h>
+ X(capi_cmsg2message),
+ X(capi_message2cmsg),
+ X(capi_cmsg_header),
+ X(capi_cmd2str),
+ X(capi_cmsg2str),
+ X(capi_message2str),
+ X(capi_info2str),
+#include <linux/symtab_end.h>
+};
+#endif
+
+#ifdef MODULE
+
+int init_module(void)
+{
+#ifndef HAS_NEW_SYMTAB
+ register_symtab(&capifunc_syms);
+#endif
+ return 0;
+}
+
+void cleanup_module(void)
+{
+}
+
+#endif
--- /dev/null
+/*
+ * $Id: capiutil.h,v 1.2 1997/05/18 09:24:19 calle Exp $
+ *
+ * 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: capiutil.h,v $
+ * Revision 1.2 1997/05/18 09:24:19 calle
+ * added verbose disconnect reason reporting to avmb1.
+ * some fixes in capi20 interface.
+ * changed info messages for B1-PCI
+ *
+ * Revision 1.1 1997/03/04 21:50:35 calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ *
+ */
+#ifndef __CAPIUTIL_H__
+#define __CAPIUTIL_H__
+
+#include <asm/types.h>
+
+#define CAPIMSG_LEN(m) (m[0] | (m[1] << 8))
+#define CAPIMSG_APPID(m) (m[2] | (m[3] << 8))
+#define CAPIMSG_COMMAND(m) (m[4])
+#define CAPIMSG_SUBCOMMAND(m) (m[5])
+#define CAPIMSG_MSGID(m) (m[6] | (m[7] << 8))
+#define CAPIMSG_CONTROLLER(m) (m[8] & 0x7f)
+#define CAPIMSG_CONTROL(m) (m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24))
+#define CAPIMSG_NCCI(m) CAPIMSG_CONTROL(m)
+#define CAPIMSG_DATA(m) (m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24))
+#define CAPIMSG_DATALEN(m) (m[16] | (m[17]<<8))
+
+#define CAPIMSG_SETAPPID(m, applid) \
+ do { \
+ ((__u8 *)m)[2] = (__u16)(applid) & 0xff; \
+ ((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \
+ } while (0)
+
+#define CAPIMSG_SETDATA(m, data) \
+ do { \
+ ((__u8 *)m)[12] = (__u32)(data) & 0xff; \
+ ((__u8 *)m)[13] = ((__u32)(data) >> 8) & 0xff; \
+ ((__u8 *)m)[14] = ((__u32)(data) >> 16) & 0xff; \
+ ((__u8 *)m)[15] = ((__u32)(data) >> 24) & 0xff; \
+ } while (0)
+
+/*----- basic-type definitions -----*/
+
+typedef __u8 *_cstruct;
+
+typedef enum {
+ CAPI_COMPOSE,
+ CAPI_DEFAULT
+} _cmstruct;
+
+/*
+ The _cmsg structure contains all possible CAPI 2.0 parameter.
+ All parameters are stored here first. The function CAPI_CMSG_2_MESSAGE
+ assembles the parameter and builds CAPI2.0 conform messages.
+ CAPI_MESSAGE_2_CMSG disassembles CAPI 2.0 messages and stores the
+ parameter in the _cmsg structure
+ */
+
+typedef struct {
+ /* Header */
+ __u16 ApplId;
+ __u8 Command;
+ __u8 Subcommand;
+ __u16 Messagenumber;
+
+ /* Parameter */
+ union {
+ __u32 adrController;
+ __u32 adrPLCI;
+ __u32 adrNCCI;
+ } adr;
+
+ _cmstruct AdditionalInfo;
+ _cstruct B1configuration;
+ __u16 B1protocol;
+ _cstruct B2configuration;
+ __u16 B2protocol;
+ _cstruct B3configuration;
+ __u16 B3protocol;
+ _cstruct BC;
+ _cstruct BChannelinformation;
+ _cmstruct BProtocol;
+ _cstruct CalledPartyNumber;
+ _cstruct CalledPartySubaddress;
+ _cstruct CallingPartyNumber;
+ _cstruct CallingPartySubaddress;
+ __u32 CIPmask;
+ __u32 CIPmask2;
+ __u16 CIPValue;
+ __u32 Class;
+ _cstruct ConnectedNumber;
+ _cstruct ConnectedSubaddress;
+ __u32 Data;
+ __u16 DataHandle;
+ __u16 DataLength;
+ _cstruct FacilityConfirmationParameter;
+ _cstruct Facilitydataarray;
+ _cstruct FacilityIndicationParameter;
+ _cstruct FacilityRequestParameter;
+ __u16 FacilitySelector;
+ __u16 Flags;
+ __u32 Function;
+ _cstruct HLC;
+ __u16 Info;
+ _cstruct InfoElement;
+ __u32 InfoMask;
+ __u16 InfoNumber;
+ _cstruct Keypadfacility;
+ _cstruct LLC;
+ _cstruct ManuData;
+ __u32 ManuID;
+ _cstruct NCPI;
+ __u16 Reason;
+ __u16 Reason_B3;
+ __u16 Reject;
+ _cstruct Useruserdata;
+
+ /* intern */
+ unsigned l, p;
+ unsigned char *par;
+ __u8 *m;
+
+ /* buffer to construct message */
+ __u8 buf[180];
+
+} _cmsg;
+
+/*
+ * capi_cmsg2message() assembles the parameter from _cmsg to a CAPI 2.0
+ * conform message
+ */
+unsigned capi_cmsg2message(_cmsg * cmsg, __u8 * msg);
+
+/*
+ * capi_message2cmsg disassembles a CAPI message an writes the parameter
+ * into _cmsg for easy access
+ */
+unsigned capi_message2cmsg(_cmsg * cmsg, __u8 * msg);
+
+/*
+ * capi_cmsg_header() fills the _cmsg structure with default values, so only
+ * parameter with non default values must be changed before sending the
+ * message.
+ */
+unsigned capi_cmsg_header(_cmsg * cmsg, __u16 _ApplId,
+ __u8 _Command, __u8 _Subcommand,
+ __u16 _Messagenumber, __u32 _Controller);
+
+/*
+ * capi_info2str generated a readable string for Capi2.0 reasons.
+ */
+char *capi_info2str(__u16 reason);
+
+/*-----------------------------------------------------------------------*/
+
+/*
+ * Debugging / Tracing functions
+ */
+char *capi_cmd2str(__u8 cmd, __u8 subcmd);
+char *capi_cmsg2str(_cmsg * cmsg);
+char *capi_message2str(__u8 * msg);
+
+/*-----------------------------------------------------------------------*/
+
+static inline void capi_cmsg_answer(_cmsg * cmsg)
+{
+ cmsg->Subcommand |= 0x01;
+}
+
+/*-----------------------------------------------------------------------*/
+
+static inline void capi_fill_CONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ _cstruct NCPI)
+{
+ capi_cmsg_header(cmsg, ApplId, 0x82, 0x80, Messagenumber, adr);
+ cmsg->NCPI = NCPI;
+}
+
+static inline void capi_fill_FACILITY_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u16 FacilitySelector,
+ _cstruct FacilityRequestParameter)
+{
+ capi_cmsg_header(cmsg, ApplId, 0x80, 0x80, Messagenumber, adr);
+ cmsg->FacilitySelector = FacilitySelector;
+ cmsg->FacilityRequestParameter = FacilityRequestParameter;
+}
+
+static inline void capi_fill_INFO_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ _cstruct CalledPartyNumber,
+ _cstruct BChannelinformation,
+ _cstruct Keypadfacility,
+ _cstruct Useruserdata,
+ _cstruct Facilitydataarray)
+{
+ capi_cmsg_header(cmsg, ApplId, 0x08, 0x80, Messagenumber, adr);
+ cmsg->CalledPartyNumber = CalledPartyNumber;
+ cmsg->BChannelinformation = BChannelinformation;
+ cmsg->Keypadfacility = Keypadfacility;
+ cmsg->Useruserdata = Useruserdata;
+ cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_LISTEN_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u32 InfoMask,
+ __u32 CIPmask,
+ __u32 CIPmask2,
+ _cstruct CallingPartyNumber,
+ _cstruct CallingPartySubaddress)
+{
+ capi_cmsg_header(cmsg, ApplId, 0x05, 0x80, Messagenumber, adr);
+ cmsg->InfoMask = InfoMask;
+ cmsg->CIPmask = CIPmask;
+ cmsg->CIPmask2 = CIPmask2;
+ cmsg->CallingPartyNumber = CallingPartyNumber;
+ cmsg->CallingPartySubaddress = CallingPartySubaddress;
+}
+
+static inline void capi_fill_ALERT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ _cstruct BChannelinformation,
+ _cstruct Keypadfacility,
+ _cstruct Useruserdata,
+ _cstruct Facilitydataarray)
+{
+ capi_cmsg_header(cmsg, ApplId, 0x01, 0x80, Messagenumber, adr);
+ cmsg->BChannelinformation = BChannelinformation;
+ cmsg->Keypadfacility = Keypadfacility;
+ cmsg->Useruserdata = Useruserdata;
+ cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_CONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u16 CIPValue,
+ _cstruct CalledPartyNumber,
+ _cstruct CallingPartyNumber,
+ _cstruct CalledPartySubaddress,
+ _cstruct CallingPartySubaddress,
+ __u16 B1protocol,
+ __u16 B2protocol,
+ __u16 B3protocol,
+ _cstruct B1configuration,
+ _cstruct B2configuration,
+ _cstruct B3configuration,
+ _cstruct BC,
+ _cstruct LLC,
+ _cstruct HLC,
+ _cstruct BChannelinformation,
+ _cstruct Keypadfacility,
+ _cstruct Useruserdata,
+ _cstruct Facilitydataarray)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x02, 0x80, Messagenumber, adr);
+ cmsg->CIPValue = CIPValue;
+ cmsg->CalledPartyNumber = CalledPartyNumber;
+ cmsg->CallingPartyNumber = CallingPartyNumber;
+ cmsg->CalledPartySubaddress = CalledPartySubaddress;
+ cmsg->CallingPartySubaddress = CallingPartySubaddress;
+ cmsg->B1protocol = B1protocol;
+ cmsg->B2protocol = B2protocol;
+ cmsg->B3protocol = B3protocol;
+ cmsg->B1configuration = B1configuration;
+ cmsg->B2configuration = B2configuration;
+ cmsg->B3configuration = B3configuration;
+ cmsg->BC = BC;
+ cmsg->LLC = LLC;
+ cmsg->HLC = HLC;
+ cmsg->BChannelinformation = BChannelinformation;
+ cmsg->Keypadfacility = Keypadfacility;
+ cmsg->Useruserdata = Useruserdata;
+ cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_DATA_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u32 Data,
+ __u16 DataLength,
+ __u16 DataHandle,
+ __u16 Flags)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x86, 0x80, Messagenumber, adr);
+ cmsg->Data = Data;
+ cmsg->DataLength = DataLength;
+ cmsg->DataHandle = DataHandle;
+ cmsg->Flags = Flags;
+}
+
+static inline void capi_fill_DISCONNECT_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ _cstruct BChannelinformation,
+ _cstruct Keypadfacility,
+ _cstruct Useruserdata,
+ _cstruct Facilitydataarray)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x04, 0x80, Messagenumber, adr);
+ cmsg->BChannelinformation = BChannelinformation;
+ cmsg->Keypadfacility = Keypadfacility;
+ cmsg->Useruserdata = Useruserdata;
+ cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_DISCONNECT_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ _cstruct NCPI)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x84, 0x80, Messagenumber, adr);
+ cmsg->NCPI = NCPI;
+}
+
+static inline void capi_fill_MANUFACTURER_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u32 ManuID,
+ __u32 Class,
+ __u32 Function,
+ _cstruct ManuData)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0xff, 0x80, Messagenumber, adr);
+ cmsg->ManuID = ManuID;
+ cmsg->Class = Class;
+ cmsg->Function = Function;
+ cmsg->ManuData = ManuData;
+}
+
+static inline void capi_fill_RESET_B3_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ _cstruct NCPI)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x87, 0x80, Messagenumber, adr);
+ cmsg->NCPI = NCPI;
+}
+
+static inline void capi_fill_SELECT_B_PROTOCOL_REQ(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u16 B1protocol,
+ __u16 B2protocol,
+ __u16 B3protocol,
+ _cstruct B1configuration,
+ _cstruct B2configuration,
+ _cstruct B3configuration)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x41, 0x80, Messagenumber, adr);
+ cmsg->B1protocol = B1protocol;
+ cmsg->B2protocol = B2protocol;
+ cmsg->B3protocol = B3protocol;
+ cmsg->B1configuration = B1configuration;
+ cmsg->B2configuration = B2configuration;
+ cmsg->B3configuration = B3configuration;
+}
+
+static inline void capi_fill_CONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u16 Reject,
+ __u16 B1protocol,
+ __u16 B2protocol,
+ __u16 B3protocol,
+ _cstruct B1configuration,
+ _cstruct B2configuration,
+ _cstruct B3configuration,
+ _cstruct ConnectedNumber,
+ _cstruct ConnectedSubaddress,
+ _cstruct LLC,
+ _cstruct BChannelinformation,
+ _cstruct Keypadfacility,
+ _cstruct Useruserdata,
+ _cstruct Facilitydataarray)
+{
+ capi_cmsg_header(cmsg, ApplId, 0x02, 0x83, Messagenumber, adr);
+ cmsg->Reject = Reject;
+ cmsg->B1protocol = B1protocol;
+ cmsg->B2protocol = B2protocol;
+ cmsg->B3protocol = B3protocol;
+ cmsg->B1configuration = B1configuration;
+ cmsg->B2configuration = B2configuration;
+ cmsg->B3configuration = B3configuration;
+ cmsg->ConnectedNumber = ConnectedNumber;
+ cmsg->ConnectedSubaddress = ConnectedSubaddress;
+ cmsg->LLC = LLC;
+ cmsg->BChannelinformation = BChannelinformation;
+ cmsg->Keypadfacility = Keypadfacility;
+ cmsg->Useruserdata = Useruserdata;
+ cmsg->Facilitydataarray = Facilitydataarray;
+}
+
+static inline void capi_fill_CONNECT_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x03, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_CONNECT_B3_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x83, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_CONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u16 Reject,
+ _cstruct NCPI)
+{
+ capi_cmsg_header(cmsg, ApplId, 0x82, 0x83, Messagenumber, adr);
+ cmsg->Reject = Reject;
+ cmsg->NCPI = NCPI;
+}
+
+static inline void capi_fill_CONNECT_B3_T90_ACTIVE_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x88, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_DATA_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u16 DataHandle)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x86, 0x83, Messagenumber, adr);
+ cmsg->DataHandle = DataHandle;
+}
+
+static inline void capi_fill_DISCONNECT_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x84, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_DISCONNECT_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x04, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_FACILITY_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u16 FacilitySelector)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x80, 0x83, Messagenumber, adr);
+ cmsg->FacilitySelector = FacilitySelector;
+}
+
+static inline void capi_fill_INFO_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x08, 0x83, Messagenumber, adr);
+}
+
+static inline void capi_fill_MANUFACTURER_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr,
+ __u32 ManuID,
+ __u32 Class,
+ __u32 Function,
+ _cstruct ManuData)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0xff, 0x83, Messagenumber, adr);
+ cmsg->ManuID = ManuID;
+ cmsg->Class = Class;
+ cmsg->Function = Function;
+ cmsg->ManuData = ManuData;
+}
+
+static inline void capi_fill_RESET_B3_RESP(_cmsg * cmsg, __u16 ApplId, __u16 Messagenumber,
+ __u32 adr)
+{
+
+ capi_cmsg_header(cmsg, ApplId, 0x87, 0x83, Messagenumber, adr);
+}
+
+#endif /* __CAPIUTIL_H__ */
--- /dev/null
+/*
+ * $Id: compat.h,v 1.1 1997/03/04 21:50:36 calle Exp $
+ *
+ * Headerfile for Compartibility between different kernel versions
+ *
+ * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: compat.h,v $
+ * Revision 1.1 1997/03/04 21:50:36 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 __COMPAT_H__
+#define __COMPAT_H__
+
+#include <linux/version.h>
+#include <linux/isdnif.h>
+
+#if LINUX_VERSION_CODE >= 0x020112 /* 2.1.18 */
+#define HAS_NEW_SYMTAB
+#endif
+
+#endif /* __COMPAT_H__ */
--- /dev/null
+L_OBJS :=
+M_OBJS :=
+O_OBJS := isdnl1.o config.o tei.o isdnl2.o isdnl3.o \
+ q931.o callc.o fsm.o
+
+# EXTRA_CFLAGS += -S
+
+ifeq ($(CONFIG_HISAX_EURO),y)
+ O_OBJS += l3dss1.o
+endif
+
+ifeq ($(CONFIG_HISAX_NI1),y)
+ O_OBJS += l3ni1.o
+endif
+
+ifeq ($(CONFIG_HISAX_1TR6),y)
+ O_OBJS += l3_1tr6.o
+endif
+
+ifeq ($(CONFIG_HISAX_16_0),y)
+ O_OBJS += teles0.o
+endif
+
+ifeq ($(CONFIG_HISAX_16_3),y)
+ O_OBJS += teles3.o
+endif
+
+ifeq ($(CONFIG_HISAX_AVM_A1),y)
+ O_OBJS += avm_a1.o
+endif
+
+ifeq ($(CONFIG_HISAX_ELSA_PCC),y)
+ O_OBJS += elsa.o
+endif
+
+ifeq ($(CONFIG_HISAX_ELSA_PCMCIA),y)
+ O_OBJS += elsa.o
+endif
+
+ifeq ($(CONFIG_HISAX_IX1MICROR2),y)
+ O_OBJS += ix1_micro.o
+endif
+
+O_TARGET :=
+ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
+ O_TARGET += hisax.o
+else
+ ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
+ O_TARGET += hisax.o
+ M_OBJS += hisax.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/* $Id: avm_a1.c,v 1.6 1997/04/13 19:54:07 keil Exp $
+
+ * avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: avm_a1.c,v $
+ * Revision 1.6 1997/04/13 19:54:07 keil
+ * Change in IRQ check delay for SMP
+ *
+ * Revision 1.5 1997/04/06 22:54:10 keil
+ * Using SKB's
+ *
+ * Revision 1.4 1997/01/27 15:50:21 keil
+ * SMP proof,cosmetics
+ *
+ * Revision 1.3 1997/01/21 22:14:20 keil
+ * cleanups
+ *
+ * Revision 1.2 1996/10/27 22:07:31 keil
+ * cosmetic changes
+ *
+ * Revision 1.1 1996/10/13 20:04:49 keil
+ * Initial revision
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "avm_a1.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+const char *avm_revision = "$Revision: 1.6 $";
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline u_char
+readreg(unsigned int adr, u_char off)
+{
+ return (bytein(adr + off));
+}
+
+static inline void
+writereg(unsigned int adr, u_char off, u_char data)
+{
+ byteout(adr + off, data);
+}
+
+
+static inline void
+read_fifo(unsigned int adr, u_char * data, int size)
+{
+ insb(adr - 0x400, data, size);
+}
+
+static void
+write_fifo(unsigned int adr, u_char * data, int size)
+{
+ outsb(adr - 0x400, data, size);
+}
+
+static inline void
+waitforCEC(int adr)
+{
+ int to = 50;
+
+ while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "AVM A1: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr)
+{
+ int to = 50;
+
+ while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "AVM A1: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ waitforCEC(adr);
+ writereg(adr, HSCX_CMDR, data);
+ restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+ printk(KERN_DEBUG "HSCX %d\n", hscx);
+ printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
+}
+
+void
+avm_a1_report(struct IsdnCardState *sp)
+{
+ printk(KERN_DEBUG "ISAC\n");
+ printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
+ hscxreport(sp, 0);
+ hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+ u_char *ptr;
+ struct IsdnCardState *sp = hsp->sp;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_empty_fifo");
+
+ if (hsp->rcvidx + count > HSCX_BUFMAX) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+ hsp->rcvidx = 0;
+ return;
+ }
+ ptr = hsp->rcvbuf + hsp->rcvidx;
+ hsp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ read_fifo(sp->hscx[hsp->hscx], ptr, count);
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+ struct IsdnCardState *sp = hsp->sp;
+ int more, count;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_fill_fifo");
+
+ if (!hsp->tx_skb)
+ return;
+ if (hsp->tx_skb->len <= 0)
+ return;
+
+ more = (hsp->mode == 1) ? 1 : 0;
+ if (hsp->tx_skb->len > 32) {
+ more = !0;
+ count = 32;
+ } else
+ count = hsp->tx_skb->len;
+
+ waitforXFW(sp->hscx[hsp->hscx]);
+ save_flags(flags);
+ cli();
+ ptr = hsp->tx_skb->data;
+ skb_pull(hsp->tx_skb, count);
+ hsp->tx_cnt -= count;
+ hsp->count += count;
+ write_fifo(sp->hscx[hsp->hscx], ptr, count);
+ writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+ u_char r;
+ struct HscxState *hsp = sp->hs + hscx;
+ struct sk_buff *skb;
+ int count;
+ char tmp[32];
+
+ if (!hsp->init)
+ return;
+
+ if (val & 0x80) { /* RME */
+
+ r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
+ if ((r & 0xf0) != 0xa0) {
+ if (!r & 0x80)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX invalid frame");
+ if ((r & 0x40) && hsp->mode)
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX RDO mode=%d",
+ hsp->mode);
+ debugl1(sp, tmp);
+ }
+ if (!r & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX CRC error");
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+ } else {
+ count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ hscx_empty_fifo(hsp, count);
+ if ((count = hsp->rcvidx - 1) > 0) {
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "AVM: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ }
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ hscx_empty_fifo(hsp, 32);
+ if (hsp->mode == 1) {
+ /* receive audio data */
+ if (!(skb = dev_alloc_skb(32)))
+ printk(KERN_WARNING "AVM: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ }
+ if (val & 0x10) { /* XPR */
+ if (hsp->tx_skb)
+ if (hsp->tx_skb->len) {
+ hscx_fill_fifo(hsp);
+ return;
+ } else {
+ dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+ hsp->count = 0;
+ if (hsp->st->l4.l1writewakeup)
+ hsp->st->l4.l1writewakeup(hsp->st);
+ hsp->tx_skb = NULL;
+ }
+ if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+ hsp->count = 0;
+ hscx_fill_fifo(hsp);
+ } else
+ hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+ }
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ if (sp->debug & L1_DEB_ISAC)
+ debugl1(sp, "isac_empty_fifo");
+
+ if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+ if (sp->debug & L1_DEB_WARN) {
+ char tmp[40];
+ sprintf(tmp, "isac_empty_fifo overrun %d",
+ sp->rcvidx + count);
+ debugl1(sp, tmp);
+ }
+ writereg(sp->isac, ISAC_CMDR, 0x80);
+ sp->rcvidx = 0;
+ return;
+ }
+ ptr = sp->rcvbuf + sp->rcvidx;
+ sp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ read_fifo(sp->isac, ptr, count);
+ writereg(sp->isac, ISAC_CMDR, 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_empty_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+ int count, more;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ debugl1(sp, "isac_fill_fifo");
+
+ if (!sp->tx_skb)
+ return;
+
+ count = sp->tx_skb->len;
+ if (count <= 0)
+ return;
+
+ more = 0;
+ if (count > 32) {
+ more = !0;
+ count = 32;
+ }
+ save_flags(flags);
+ cli();
+ ptr = sp->tx_skb->data;
+ skb_pull(sp->tx_skb, count);
+ sp->tx_cnt += count;
+ write_fifo(sp->isac, ptr, count);
+ writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_fill_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+ if (sp->debug & L1_DEB_ISAC) {
+ char tmp[32];
+ sprintf(tmp, "ph_command %d", command);
+ debugl1(sp, tmp);
+ }
+ writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+ u_char exval;
+ struct sk_buff *skb;
+ unsigned int count;
+ char tmp[32];
+
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "ISAC interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ if (val & 0x80) { /* RME */
+ exval = readreg(sp->isac, ISAC_RSTA);
+ if ((exval & 0x70) != 0x20) {
+ if (exval & 0x40)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RDO");
+ if (!exval & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC CRC error");
+ writereg(sp->isac, ISAC_CMDR, 0x80);
+ } else {
+ count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(sp, count);
+ if ((count = sp->rcvidx) > 0) {
+ if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+ printk(KERN_WARNING "AVM: D receive out of memory\n");
+ else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, count), sp->rcvbuf, count);
+ skb_queue_tail(&sp->rq, skb);
+ }
+ }
+ }
+ sp->rcvidx = 0;
+ isac_sched_event(sp, ISAC_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ isac_empty_fifo(sp, 32);
+ }
+ if (val & 0x20) { /* RSC */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RSC interrupt");
+ }
+ if (val & 0x10) { /* XPR */
+ if (sp->tx_skb)
+ if (sp->tx_skb->len) {
+ isac_fill_fifo(sp);
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+ sp->tx_cnt = 0;
+ sp->tx_skb = NULL;
+ }
+ if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+ sp->tx_cnt = 0;
+ isac_fill_fifo(sp);
+ } else
+ isac_sched_event(sp, ISAC_XMTBUFREADY);
+ }
+ afterXPR:
+ if (val & 0x04) { /* CISQ */
+ sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
+ & 0xf;
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "l1state %d", sp->ph_state);
+ debugl1(sp, tmp);
+ }
+ isac_new_ph(sp);
+ }
+ if (val & 0x02) { /* SIN */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC SIN interrupt");
+ }
+ if (val & 0x01) { /* EXI */
+ exval = readreg(sp->isac, ISAC_EXIR);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC EXIR %02x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+ u_char exval;
+ struct HscxState *hsp;
+ char tmp[32];
+
+
+ if (val & 0x01) {
+ hsp = sp->hs + 1;
+ exval = readreg(sp->hscx[1], HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0xf8) {
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, val, 1);
+ }
+ if (val & 0x02) {
+ hsp = sp->hs;
+ exval = readreg(sp->hscx[0], HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0x04) {
+ exval = readreg(sp->hscx[0], HSCX_ISTA);
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A interrupt %x", exval);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, exval, 0);
+ }
+}
+
+static void
+avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *sp;
+ u_char val, sval, stat = 0;
+ char tmp[32];
+
+ sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+ if (!sp) {
+ printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
+ return;
+ }
+ while (((sval = bytein(sp->cfg_reg)) & 0xf) != 0x7) {
+ if (!(sval & AVM_A1_STAT_TIMER)) {
+ byteout(sp->cfg_reg, 0x14);
+ byteout(sp->cfg_reg, 0x18);
+ sval = bytein(sp->cfg_reg);
+ } else if (sp->debug & L1_DEB_INTSTAT) {
+ sprintf(tmp, "avm IntStatus %x", sval);
+ debugl1(sp, tmp);
+ }
+ if (!(sval & AVM_A1_STAT_HSCX)) {
+ val = readreg(sp->hscx[1], HSCX_ISTA);
+ if (val) {
+ hscx_int_main(sp, val);
+ stat |= 1;
+ }
+ }
+ if (!(sval & AVM_A1_STAT_ISAC)) {
+ val = readreg(sp->isac, ISAC_ISTA);
+ if (val) {
+ isac_interrupt(sp, val);
+ stat |= 2;
+ }
+ }
+ }
+ if (stat & 1) {
+ writereg(sp->hscx[0], HSCX_MASK, 0xFF);
+ writereg(sp->hscx[1], HSCX_MASK, 0xFF);
+ writereg(sp->hscx[0], HSCX_MASK, 0x0);
+ writereg(sp->hscx[1], HSCX_MASK, 0x0);
+ }
+ if (stat & 2) {
+ writereg(sp->isac, ISAC_MASK, 0xFF);
+ writereg(sp->isac, ISAC_MASK, 0x0);
+ }
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+ unsigned int adr = sp->isac;
+
+ /* 16.3 IOM 2 Mode */
+ writereg(adr, ISAC_MASK, 0xff);
+ writereg(adr, ISAC_ADF2, 0x80);
+ writereg(adr, ISAC_SQXR, 0x2f);
+ writereg(adr, ISAC_SPCR, 0x0);
+ writereg(adr, ISAC_ADF1, 0x2);
+ writereg(adr, ISAC_STCR, 0x70);
+ writereg(adr, ISAC_MODE, 0xc9);
+ writereg(adr, ISAC_TIMR, 0x0);
+ writereg(adr, ISAC_ADF1, 0x0);
+ writereg(adr, ISAC_CMDR, 0x41);
+ writereg(adr, ISAC_CIX0, (1 << 2) | 3);
+ writereg(adr, ISAC_MASK, 0xff);
+ writereg(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+ struct IsdnCardState *sp = hs->sp;
+ int hscx = hs->hscx;
+
+ if (sp->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "hscx %c mode %d ichan %d",
+ 'A' + hscx, mode, ichan);
+ debugl1(sp, tmp);
+ }
+ hs->mode = mode;
+ writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
+ writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
+ writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
+ writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
+ writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
+ writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
+
+ switch (mode) {
+ case (0):
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
+ break;
+ case (1):
+ if (ichan == 0) {
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ } else {
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ }
+ writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
+ writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+ break;
+ case (2):
+ if (ichan == 0) {
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ } else {
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ }
+ writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
+ writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+ break;
+ }
+ writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
+}
+
+inline static void
+release_ioregs(struct IsdnCard *card, int mask)
+{
+ release_region(card->sp->cfg_reg, 8);
+ if (mask & 1)
+ release_region(card->sp->isac, 32);
+ if (mask & 2)
+ release_region(card->sp->isac - 0x400, 1);
+ if (mask & 4)
+ release_region(card->sp->hscx[0], 32);
+ if (mask & 8)
+ release_region(card->sp->hscx[0] - 0x400, 1);
+ if (mask & 0x10)
+ release_region(card->sp->hscx[1], 32);
+ if (mask & 0x20)
+ release_region(card->sp->hscx[1] - 0x400, 1);
+}
+
+void
+release_io_avm_a1(struct IsdnCard *card)
+{
+ release_ioregs(card, 0x3f);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+ int val;
+ char tmp[64];
+
+ val = readreg(sp->hscx[1], HSCX_ISTA);
+ sprintf(tmp, "HSCX B ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = readreg(sp->hscx[1], HSCX_EXIR);
+ sprintf(tmp, "HSCX B EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x02) {
+ val = readreg(sp->hscx[0], HSCX_EXIR);
+ sprintf(tmp, "HSCX A EXIR %x", val);
+ debugl1(sp, tmp);
+ }
+ val = readreg(sp->hscx[0], HSCX_ISTA);
+ sprintf(tmp, "HSCX A ISTA %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->hscx[1], HSCX_STAR);
+ sprintf(tmp, "HSCX B STAR %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->hscx[0], HSCX_STAR);
+ sprintf(tmp, "HSCX A STAR %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->isac, ISAC_STAR);
+ sprintf(tmp, "ISAC STAR %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->isac, ISAC_MODE);
+ sprintf(tmp, "ISAC MODE %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->isac, ISAC_ADF2);
+ sprintf(tmp, "ISAC ADF2 %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->isac, ISAC_ISTA);
+ sprintf(tmp, "ISAC ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = readreg(sp->isac, ISAC_EXIR);
+ sprintf(tmp, "ISAC EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x04) {
+ val = readreg(sp->isac, ISAC_CIR0);
+ sprintf(tmp, "ISAC CIR0 %x", val);
+ debugl1(sp, tmp);
+ }
+ writereg(sp->isac, ISAC_MASK, 0);
+ writereg(sp->isac, ISAC_CMDR, 0x41);
+}
+
+int
+initavm_a1(struct IsdnCardState *sp)
+{
+ int ret;
+ int loop = 0;
+ char tmp[40];
+
+ sp->counter = kstat.interrupts[sp->irq];
+ sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+ debugl1(sp, tmp);
+ clear_pending_ints(sp);
+ ret = get_irq(sp->cardnr, &avm_a1_interrupt);
+ if (ret) {
+ initisac(sp);
+ sp->modehscx(sp->hs, 0, 0);
+ sp->modehscx(sp->hs + 1, 0, 0);
+ while (loop++ < 10) {
+ /* At least 1-3 irqs must happen
+ * (one from HSCX A, one from HSCX B, 3rd from ISAC)
+ */
+ if (kstat.interrupts[sp->irq] > sp->counter)
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ }
+ sprintf(tmp, "IRQ %d count %d", sp->irq,
+ kstat.interrupts[sp->irq]);
+ debugl1(sp, tmp);
+ if (kstat.interrupts[sp->irq] == sp->counter) {
+ printk(KERN_WARNING
+ "AVM A1: IRQ(%d) getting no interrupts during init\n",
+ sp->irq);
+ irq2dev_map[sp->irq] = NULL;
+ free_irq(sp->irq, NULL);
+ return (0);
+ }
+ }
+ return (ret);
+}
+
+int
+setup_avm_a1(struct IsdnCard *card)
+{
+ u_char val, verA, verB;
+ struct IsdnCardState *sp = card->sp;
+ long flags;
+ char tmp[64];
+
+ strcpy(tmp, avm_revision);
+ printk(KERN_NOTICE "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
+ if (sp->typ != ISDN_CTYPE_A1)
+ return (0);
+
+ sp->cfg_reg = card->para[1] + 0x1800;
+ sp->isac = card->para[1] + 0x1400;
+ sp->hscx[0] = card->para[1] + 0x400;
+ sp->hscx[1] = card->para[1] + 0xc00;
+ sp->irq = card->para[0];
+ if (check_region((sp->cfg_reg), 8)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ sp->cfg_reg,
+ sp->cfg_reg + 8);
+ return (0);
+ } else {
+ request_region(sp->cfg_reg, 8, "avm cfg");
+ }
+ if (check_region((sp->isac), 32)) {
+ printk(KERN_WARNING
+ "HiSax: %s isac ports %x-%x already in use\n",
+ CardType[sp->typ],
+ sp->isac,
+ sp->isac + 32);
+ release_ioregs(card, 0);
+ return (0);
+ } else {
+ request_region(sp->isac, 32, "HiSax isac");
+ }
+ if (check_region((sp->isac - 0x400), 1)) {
+ printk(KERN_WARNING
+ "HiSax: %s isac fifo port %x already in use\n",
+ CardType[sp->typ],
+ sp->isac - 0x400);
+ release_ioregs(card, 1);
+ return (0);
+ } else {
+ request_region(sp->isac - 0x400, 1, "HiSax isac fifo");
+ }
+ if (check_region((sp->hscx[0]), 32)) {
+ printk(KERN_WARNING
+ "HiSax: %s hscx A ports %x-%x already in use\n",
+ CardType[sp->typ],
+ sp->hscx[0],
+ sp->hscx[0] + 32);
+ release_ioregs(card, 3);
+ return (0);
+ } else {
+ request_region(sp->hscx[0], 32, "HiSax hscx A");
+ }
+ if (check_region((sp->hscx[0] - 0x400), 1)) {
+ printk(KERN_WARNING
+ "HiSax: %s hscx A fifo port %x already in use\n",
+ CardType[sp->typ],
+ sp->hscx[0] - 0x400);
+ release_ioregs(card, 7);
+ return (0);
+ } else {
+ request_region(sp->hscx[0] - 0x400, 1, "HiSax hscx A fifo");
+ }
+ if (check_region((sp->hscx[1]), 32)) {
+ printk(KERN_WARNING
+ "HiSax: %s hscx B ports %x-%x already in use\n",
+ CardType[sp->typ],
+ sp->hscx[1],
+ sp->hscx[1] + 32);
+ release_ioregs(card, 0xf);
+ return (0);
+ } else {
+ request_region(sp->hscx[1], 32, "HiSax hscx B");
+ }
+ if (check_region((sp->hscx[1] - 0x400), 1)) {
+ printk(KERN_WARNING
+ "HiSax: %s hscx B fifo port %x already in use\n",
+ CardType[sp->typ],
+ sp->hscx[1] - 0x400);
+ release_ioregs(card, 0x1f);
+ return (0);
+ } else {
+ request_region(sp->hscx[1] - 0x400, 1, "HiSax hscx B fifo");
+ }
+ save_flags(flags);
+ byteout(sp->cfg_reg, 0x0);
+ sti();
+ HZDELAY(HZ / 5 + 1);
+ byteout(sp->cfg_reg, 0x1);
+ HZDELAY(HZ / 5 + 1);
+ byteout(sp->cfg_reg, 0x0);
+ HZDELAY(HZ / 5 + 1);
+ val = sp->irq;
+ if (val == 9)
+ val = 2;
+ byteout(sp->cfg_reg + 1, val);
+ HZDELAY(HZ / 5 + 1);
+ byteout(sp->cfg_reg, 0x0);
+ HZDELAY(HZ / 5 + 1);
+ restore_flags(flags);
+
+ val = bytein(sp->cfg_reg);
+ printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+ sp->cfg_reg, val);
+ val = bytein(sp->cfg_reg + 3);
+ printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+ sp->cfg_reg + 3, val);
+ val = bytein(sp->cfg_reg + 2);
+ printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+ sp->cfg_reg + 2, val);
+ byteout(sp->cfg_reg, 0x14);
+ byteout(sp->cfg_reg, 0x18);
+ val = bytein(sp->cfg_reg);
+ printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
+ sp->cfg_reg, val);
+
+ printk(KERN_NOTICE
+ "HiSax: %s config irq:%d cfg:%x\n",
+ CardType[sp->typ], sp->irq,
+ sp->cfg_reg);
+ printk(KERN_NOTICE
+ "HiSax: isac:%x/%x\n",
+ sp->isac, sp->isac - 0x400);
+ printk(KERN_NOTICE
+ "HiSax: hscx A:%x/%x hscx B:%x/%x\n",
+ sp->hscx[0], sp->hscx[0] - 0x400,
+ sp->hscx[1], sp->hscx[1] - 0x400);
+ verA = readreg(sp->hscx[0], HSCX_VSTR) & 0xf;
+ verB = readreg(sp->hscx[1], HSCX_VSTR) & 0xf;
+ printk(KERN_INFO "AVM A1: HSCX version A: %s B: %s\n",
+ HscxVersion(verA), HscxVersion(verB));
+ val = readreg(sp->isac, ISAC_RBCH);
+ printk(KERN_INFO "AVM A1: ISAC %s\n",
+ ISACVersion(val));
+ if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ printk(KERN_WARNING
+ "AVM A1: wrong HSCX versions check IO address\n");
+ release_io_avm_a1(card);
+ return (0);
+ }
+ sp->modehscx = &modehscx;
+ sp->ph_command = &ph_command;
+ sp->hscx_fill_fifo = &hscx_fill_fifo;
+ sp->isac_fill_fifo = &isac_fill_fifo;
+ return (1);
+}
--- /dev/null
+/* $Id: avm_a1.h,v 1.2 1997/01/21 22:14:36 keil Exp $
+ *
+ * avm_a1.h Header for AVM A1 (Fritz) ISDN card
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: avm_a1.h,v $
+ * Revision 1.2 1997/01/21 22:14:36 keil
+ * cleanups
+ *
+ * Revision 1.1 1996/10/12 21:42:40 keil
+ * Initial revision
+ *
+ *
+*/
+
+#define AVM_A1_STAT_ISAC 0x01
+#define AVM_A1_STAT_HSCX 0x02
+#define AVM_A1_STAT_TIMER 0x04
+
+extern void avm_a1_report(struct IsdnCardState *sp);
+extern void release_io_avm_a1(struct IsdnCard *card);
+extern int setup_avm_a1(struct IsdnCard *card);
+extern int initavm_a1(struct IsdnCardState *sp);
--- /dev/null
+/* $Id: callc.c,v 1.30 1997/05/29 10:40:43 keil Exp $
+
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * based on the teles driver from Jan den Ouden
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ *
+ * $Log: callc.c,v $
+ * Revision 1.30 1997/05/29 10:40:43 keil
+ * chanp->impair was uninitialised
+ *
+ * Revision 1.29 1997/04/23 20:09:49 fritz
+ * Removed tmp, used by removed debugging code.
+ *
+ * Revision 1.28 1997/04/21 13:42:25 keil
+ * Remove unneeded debug
+ *
+ * Revision 1.27 1997/04/16 14:21:01 keil
+ * remove unused variable
+ *
+ * Revision 1.26 1997/04/13 19:55:21 keil
+ * Changes in debugging code
+ *
+ * Revision 1.25 1997/04/06 22:54:08 keil
+ * Using SKB's
+ *
+ * Revision 1.24 1997/03/05 11:28:03 keil
+ * fixed undefined l2tei procedure
+ * a layer1 release delete now the drel timer
+ *
+ * Revision 1.23 1997/03/04 23:07:42 keil
+ * bugfix dial parameter
+ *
+ * Revision 1.22 1997/02/27 13:51:55 keil
+ * Reset B-channel (dlc) statemachine in every release
+ *
+ * Revision 1.21 1997/02/19 09:24:27 keil
+ * Bugfix: Hangup to LL if a ttyI rings
+ *
+ * Revision 1.20 1997/02/17 00:32:47 keil
+ * Bugfix: No Busy reported to LL
+ *
+ * Revision 1.19 1997/02/14 12:23:10 fritz
+ * Added support for new insmod parameter handling.
+ *
+ * Revision 1.18 1997/02/11 01:36:58 keil
+ * Changed setup-interface (incoming and outgoing), cause reporting
+ *
+ * Revision 1.17 1997/02/09 00:23:10 keil
+ * new interface handling, one interface per card
+ * some changes in debug and leased line mode
+ *
+ * Revision 1.16 1997/01/27 23:17:03 keil
+ * delete timers while unloading
+ *
+ * Revision 1.15 1997/01/27 16:00:38 keil
+ * D-channel shutdown delay; improved callback
+ *
+ * Revision 1.14 1997/01/21 22:16:39 keil
+ * new statemachine; leased line support; cleanup for 2.0
+ *
+ * Revision 1.13 1996/12/08 19:51:17 keil
+ * bugfixes from Pekka Sarnila
+ *
+ * Revision 1.12 1996/11/26 20:20:03 keil
+ * fixed warning while compile
+ *
+ * Revision 1.11 1996/11/26 18:43:17 keil
+ * change ioctl 555 --> 55 (555 didn't work)
+ *
+ * Revision 1.10 1996/11/26 18:06:07 keil
+ * fixed missing break statement,ioctl 555 reset modcount
+ *
+ * Revision 1.9 1996/11/18 20:23:19 keil
+ * log writebuf channel not open changed
+ *
+ * Revision 1.8 1996/11/06 17:43:17 keil
+ * more changes for 2.1.X;block fixed ST_PRO_W
+ *
+ * Revision 1.7 1996/11/06 15:13:51 keil
+ * typo 0x64 --->64 in debug code
+ *
+ * Revision 1.6 1996/11/05 19:40:33 keil
+ * X.75 windowsize
+ *
+ * Revision 1.5 1996/10/30 10:11:06 keil
+ * debugging LOCK changed;ST_REL_W EV_HANGUP added
+ *
+ * Revision 1.4 1996/10/27 22:20:16 keil
+ * alerting bugfixes
+ * no static b-channel<->channel mapping
+ *
+ * Revision 1.2 1996/10/16 21:29:45 keil
+ * compile bug as "not module"
+ * Callback with euro
+ *
+ * Revision 1.1 1996/10/13 20:04:50 keil
+ * Initial revision
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE < 0x020111)
+extern long mod_use_count_;
+#define MOD_USE_COUNT mod_use_count_
+#else
+#define MOD_USE_COUNT ((&__this_module)->usecount)
+#endif
+#endif /* MODULE */
+
+const char *l4_revision = "$Revision: 1.30 $";
+
+extern struct IsdnCard cards[];
+extern int nrcards;
+extern void HiSax_mod_dec_use_count(void);
+extern void HiSax_mod_inc_use_count(void);
+
+static int init_ds(struct Channel *chanp, int incoming);
+static void release_ds(struct Channel *chanp);
+
+static struct Fsm callcfsm =
+{NULL, 0, 0};
+static struct Fsm lcfsm =
+{NULL, 0, 0};
+
+static int chancount = 0;
+
+/* Flags for remembering action done in l4 */
+
+#define FLG_START_D 0x0001
+#define FLG_ESTAB_D 0x0002
+#define FLG_CALL_SEND 0x0004
+#define FLG_CALL_REC 0x0008
+#define FLG_CALL_ALERT 0x0010
+#define FLG_START_B 0x0020
+#define FLG_CONNECT_B 0x0040
+#define FLG_LL_DCONN 0x0080
+#define FLG_LL_BCONN 0x0100
+#define FLG_DISC_SEND 0x0200
+#define FLG_DISC_REC 0x0400
+#define FLG_REL_REC 0x0800
+
+#define SETBIT(flg, item) flg |= item
+#define RESBIT(flg, item) flg &= (~item)
+
+/*
+ * Because of callback it's a good idea to delay the shutdown of the d-channel
+ */
+#define DREL_TIMER_VALUE 30000
+
+/*
+ * Find card with given driverId
+ */
+static inline struct IsdnCardState
+*
+hisax_findcard(int driverid)
+{
+ int i;
+
+ for (i = 0; i < nrcards; i++)
+ if (cards[i].sp)
+ if (cards[i].sp->myid == driverid)
+ return (cards[i].sp);
+ return (struct IsdnCardState *) 0;
+}
+
+static void
+link_debug(struct Channel *chanp, char *s, int direction)
+{
+ char tmp[100], tm[32];
+
+ jiftime(tm, jiffies);
+ sprintf(tmp, "%s Channel %d %s %s\n", tm, chanp->chan,
+ direction ? "LL->HL" : "HL->LL", s);
+ HiSax_putstatus(chanp->sp, tmp);
+}
+
+
+enum {
+ ST_NULL, /* 0 inactive */
+ ST_OUT_WAIT_D, /* 1 outgoing, awaiting d-channel establishment */
+ ST_IN_WAIT_D, /* 2 incoming, awaiting d-channel establishment */
+ ST_OUT_DIAL, /* 3 outgoing, SETUP send; awaiting confirm */
+ ST_IN_WAIT_LL, /* 4 incoming call received; wait for LL confirm */
+ ST_IN_ALERT_SEND, /* 5 incoming call received; ALERT send */
+ ST_IN_WAIT_CONN_ACK, /* 6 incoming CONNECT send; awaiting CONN_ACK */
+ ST_WAIT_BCONN, /* 7 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */
+ ST_ACTIVE, /* 8 active, b channel prot. established */
+ ST_WAIT_BRELEASE, /* 9 call clear. (initiator), awaiting b channel prot. rel. */
+ ST_WAIT_BREL_DISC, /* 10 call clear. (receiver), DISCONNECT req. received */
+ ST_WAIT_DCOMMAND, /* 11 call clear. (receiver), awaiting DCHANNEL message */
+ ST_WAIT_DRELEASE, /* 12 DISCONNECT sent, awaiting RELEASE */
+ ST_WAIT_D_REL_CNF, /* 13 RELEASE sent, awaiting RELEASE confirm */
+ ST_WAIT_DSHUTDOWN, /* 14 awaiting d-channel shutdown */
+};
+
+#define STATE_COUNT (ST_WAIT_DSHUTDOWN +1)
+
+static char *strState[] =
+{
+ "ST_NULL",
+ "ST_OUT_WAIT_D",
+ "ST_IN_WAIT_D",
+ "ST_OUT_DIAL",
+ "ST_IN_WAIT_LL",
+ "ST_IN_ALERT_SEND",
+ "ST_IN_WAIT_CONN_ACK",
+ "ST_WAIT_BCONN",
+ "ST_ACTIVE",
+ "ST_WAIT_BRELEASE",
+ "ST_WAIT_BREL_DISC",
+ "ST_WAIT_DCOMMAND",
+ "ST_WAIT_DRELEASE",
+ "ST_WAIT_D_REL_CNF",
+ "ST_WAIT_DSHUTDOWN",
+};
+
+enum {
+ EV_DIAL, /* 0 */
+ EV_SETUP_CNF, /* 1 */
+ EV_ACCEPTB, /* 2 */
+ EV_DISCONNECT_IND, /* 3 */
+ EV_RELEASE_CNF, /* 4 */
+ EV_DLEST, /* 5 */
+ EV_DLRL, /* 6 */
+ EV_SETUP_IND, /* 7 */
+ EV_RELEASE_IND, /* 8 */
+ EV_ACCEPTD, /* 9 */
+ EV_SETUP_CMPL_IND, /* 10 */
+ EV_BC_EST, /* 11 */
+ EV_WRITEBUF, /* 12 */
+ EV_DATAIN, /* 13 */
+ EV_HANGUP, /* 14 */
+ EV_BC_REL, /* 15 */
+ EV_CINF, /* 16 */
+ EV_SUSPEND, /* 17 */
+ EV_RESUME, /* 18 */
+ EV_SHUTDOWN_D, /* 19 */
+ EV_NOSETUP_RSP, /* 20 */
+ EV_SETUP_ERR, /* 21 */
+ EV_CONNECT_ERR, /* 22 */
+ EV_RELEASE_ERR, /* 23 */
+};
+
+#define EVENT_COUNT (EV_RELEASE_ERR +1)
+
+static char *strEvent[] =
+{
+ "EV_DIAL",
+ "EV_SETUP_CNF",
+ "EV_ACCEPTB",
+ "EV_DISCONNECT_IND",
+ "EV_RELEASE_CNF",
+ "EV_DLEST",
+ "EV_DLRL",
+ "EV_SETUP_IND",
+ "EV_RELEASE_IND",
+ "EV_ACCEPTD",
+ "EV_SETUP_CMPL_IND",
+ "EV_BC_EST",
+ "EV_WRITEBUF",
+ "EV_DATAIN",
+ "EV_HANGUP",
+ "EV_BC_REL",
+ "EV_CINF",
+ "EV_SUSPEND",
+ "EV_RESUME",
+ "EV_SHUTDOWN_D",
+ "EV_NOSETUP_RSP",
+ "EV_SETUP_ERR",
+ "EV_CONNECT_ERR",
+ "EV_RELEASE_ERR",
+};
+
+enum {
+ ST_LC_NULL,
+ ST_LC_ACTIVATE_WAIT,
+ ST_LC_DELAY,
+ ST_LC_ESTABLISH_WAIT,
+ ST_LC_CONNECTED,
+ ST_LC_FLUSH_WAIT,
+ ST_LC_FLUSH_DELAY,
+ ST_LC_RELEASE_WAIT,
+};
+
+#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
+
+static char *strLcState[] =
+{
+ "ST_LC_NULL",
+ "ST_LC_ACTIVATE_WAIT",
+ "ST_LC_DELAY",
+ "ST_LC_ESTABLISH_WAIT",
+ "ST_LC_CONNECTED",
+ "ST_LC_FLUSH_WAIT",
+ "ST_LC_FLUSH_DELAY",
+ "ST_LC_RELEASE_WAIT",
+};
+
+enum {
+ EV_LC_ESTABLISH,
+ EV_LC_PH_ACTIVATE,
+ EV_LC_PH_DEACTIVATE,
+ EV_LC_DL_ESTABLISH,
+ EV_LC_TIMER,
+ EV_LC_DL_FLUSH,
+ EV_LC_DL_RELEASE,
+ EV_LC_FLUSH,
+ EV_LC_RELEASE,
+};
+
+#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
+
+static char *strLcEvent[] =
+{
+ "EV_LC_ESTABLISH",
+ "EV_LC_PH_ACTIVATE",
+ "EV_LC_PH_DEACTIVATE",
+ "EV_LC_DL_ESTABLISH",
+ "EV_LC_TIMER",
+ "EV_LC_DL_FLUSH",
+ "EV_LC_DL_RELEASE",
+ "EV_LC_FLUSH",
+ "EV_LC_RELEASE",
+};
+
+#define LC_D 0
+#define LC_B 1
+
+static inline void
+l4_deliver_cause(struct Channel *chanp)
+{
+ isdn_ctrl ic;
+
+ if (chanp->para.cause < 0)
+ return;
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_CAUSE;
+ ic.arg = chanp->chan;
+ if (chanp->sp->protocol == ISDN_PTYPE_EURO)
+ sprintf(ic.parm.num, "E%02X%02X", chanp->para.loc & 0x7f,
+ chanp->para.cause & 0x7f);
+ else
+ sprintf(ic.parm.num, "%02X%02X", chanp->para.loc & 0x7f,
+ chanp->para.cause & 0x7f);
+ chanp->sp->iif.statcallb(&ic);
+}
+
+/*
+ * Dial out
+ */
+static void
+l4_prep_dialout(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_OUT_WAIT_D);
+ FsmDelTimer(&chanp->drel_timer, 60);
+ FsmDelTimer(&chanp->dial_timer, 73);
+
+ chanp->l2_active_protocol = chanp->l2_protocol;
+ chanp->incoming = 0;
+ chanp->lc_b.l2_start = !0;
+ switch (chanp->l2_active_protocol) {
+ case (ISDN_PROTO_L2_X75I):
+ chanp->lc_b.l2_establish = !0;
+ break;
+ case (ISDN_PROTO_L2_HDLC):
+ case (ISDN_PROTO_L2_TRANS):
+ chanp->lc_b.l2_establish = 0;
+ break;
+ default:
+ printk(KERN_WARNING "l4_prep_dialout unknown protocol\n");
+ break;
+ }
+ if (chanp->Flags & FLG_ESTAB_D) {
+ FsmEvent(fi, EV_DLEST, NULL);
+ } else {
+ chanp->Flags = FLG_START_D;
+ if (chanp->leased) {
+ chanp->lc_d.l2_establish = 0;
+ }
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+ }
+}
+
+static void
+l4_do_dialout(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_OUT_DIAL);
+ if (chanp->leased) {
+ chanp->para.bchannel = (chanp->chan & 1) + 1;
+ FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
+ } else {
+ SETBIT(chanp->Flags, FLG_ESTAB_D);
+ chanp->para.callref = chanp->outcallref;
+ chanp->outcallref++;
+ if (chanp->outcallref == 128)
+ chanp->outcallref = 64;
+ chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
+ SETBIT(chanp->Flags, FLG_CALL_SEND);
+ }
+}
+
+static void
+l4_init_bchan_out(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ FsmChangeState(fi, ST_WAIT_BCONN);
+ SETBIT(chanp->Flags, FLG_LL_DCONN);
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DCONN", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DCONN;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ init_ds(chanp, 0);
+ SETBIT(chanp->Flags, FLG_START_B);
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+static void
+l4_go_active(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ FsmChangeState(fi, ST_ACTIVE);
+ chanp->data_open = !0;
+ SETBIT(chanp->Flags, FLG_CONNECT_B);
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_BCONN", 0);
+ SETBIT(chanp->Flags, FLG_LL_BCONN);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BCONN;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+}
+
+/* incomming call */
+
+static void
+l4_start_dchan(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_IN_WAIT_D);
+ FsmDelTimer(&chanp->drel_timer, 61);
+ if (chanp->Flags & FLG_ESTAB_D) {
+ FsmEvent(fi, EV_DLEST, NULL);
+ } else {
+ chanp->Flags = FLG_START_D;
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
+ }
+}
+
+static void
+l4_deliver_call(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+ int ret;
+ char txt[32];
+
+ /*
+ * Report incoming calls only once to linklevel, use CallFlags
+ * which is set to 3 with each broadcast message in isdnl1.c
+ * and resetted if a interface answered the STAT_ICALL.
+ */
+ if ((chanp->sp) && (chanp->sp->CallFlags == 3)) {
+ FsmChangeState(fi, ST_IN_WAIT_LL);
+ SETBIT(chanp->Flags, FLG_ESTAB_D);
+ SETBIT(chanp->Flags, FLG_CALL_REC);
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_ICALL", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_ICALL;
+ ic.arg = chanp->chan;
+ /*
+ * No need to return "unknown" for calls without OAD,
+ * cause that's handled in linklevel now (replaced by '0')
+ */
+ ic.parm.setup = chanp->para.setup;
+ ret = chanp->sp->iif.statcallb(&ic);
+ if (chanp->debug & 1) {
+ sprintf(txt, "statcallb ret=%d", ret);
+ link_debug(chanp, txt, 1);
+ }
+ if (ret) /* if a interface knows this call, reset the CallFlag
+ * to avoid a second Call report to the linklevel
+ */
+ chanp->sp->CallFlags &= ~(chanp->chan + 1);
+ switch (ret) {
+ case 1: /* OK, anybody likes this call */
+ FsmChangeState(fi, ST_IN_ALERT_SEND);
+ SETBIT(chanp->Flags, FLG_CALL_ALERT);
+ chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
+ break;
+ case 2: /* Rejecting Call */
+ RESBIT(chanp->Flags, FLG_CALL_REC);
+ break;
+ case 0: /* OK, nobody likes this call */
+ default: /* statcallb problems */
+ chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+ FsmChangeState(fi, ST_NULL);
+ chanp->Flags = FLG_ESTAB_D;
+ FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 61);
+ break;
+ }
+ } else {
+ chanp->is.l4.l4l3(&chanp->is, CC_IGNORE, NULL);
+ FsmChangeState(fi, ST_NULL);
+ chanp->Flags = FLG_ESTAB_D;
+ FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 62);
+ }
+}
+
+static void
+l4_send_dconnect(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_IN_WAIT_CONN_ACK);
+ chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
+}
+
+static void
+l4_init_bchan_in(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ FsmChangeState(fi, ST_WAIT_BCONN);
+ SETBIT(chanp->Flags, FLG_LL_DCONN);
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DCONN", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DCONN;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ chanp->l2_active_protocol = chanp->l2_protocol;
+ chanp->incoming = !0;
+ chanp->lc_b.l2_start = 0;
+ switch (chanp->l2_active_protocol) {
+ case (ISDN_PROTO_L2_X75I):
+ chanp->lc_b.l2_establish = !0;
+ break;
+ case (ISDN_PROTO_L2_HDLC):
+ case (ISDN_PROTO_L2_TRANS):
+ chanp->lc_b.l2_establish = 0;
+ break;
+ default:
+ printk(KERN_WARNING "r9 unknown protocol\n");
+ break;
+ }
+ init_ds(chanp, !0);
+ SETBIT(chanp->Flags, FLG_START_B);
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
+}
+
+/* Call clearing */
+
+static void
+l4_reject_call(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ chanp->para.cause = 0x15; /* Call Rejected */
+ chanp->is.l4.l4l3(&chanp->is, CC_REJECT_REQ, NULL);
+ SETBIT(chanp->Flags, FLG_DISC_SEND);
+}
+
+static void
+l4_cancel_call(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ if (chanp->Flags & FLG_LL_BCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_BHUP", 0);
+ RESBIT(chanp->Flags, FLG_LL_BCONN);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ if (chanp->Flags & FLG_START_B) {
+ release_ds(chanp);
+ RESBIT(chanp->Flags, FLG_START_B);
+ }
+ chanp->para.cause = 0x10; /* Normal Call Clearing */
+ chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
+ SETBIT(chanp->Flags, FLG_DISC_SEND);
+}
+
+static void
+l4_shutdown_d(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+ FsmDelTimer(&chanp->drel_timer, 62);
+ RESBIT(chanp->Flags, FLG_ESTAB_D);
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_timeout_d(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ if (chanp->Flags & FLG_LL_DCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ RESBIT(chanp->Flags, FLG_LL_DCONN);
+ l4_deliver_cause(chanp);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ FsmChangeState(fi, ST_NULL);
+ chanp->Flags = FLG_ESTAB_D;
+ FsmAddTimer(&chanp->drel_timer, DREL_TIMER_VALUE, EV_SHUTDOWN_D, NULL, 60);
+}
+
+static void
+l4_go_null(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ FsmChangeState(fi, ST_NULL);
+ chanp->Flags = 0;
+ FsmDelTimer(&chanp->drel_timer, 63);
+}
+
+static void
+l4_disconn_bchan(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ chanp->data_open = 0;
+ FsmChangeState(fi, ST_WAIT_BRELEASE);
+ RESBIT(chanp->Flags, FLG_CONNECT_B);
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_send_d_disc(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+
+ if (chanp->Flags & (FLG_DISC_REC | FLG_REL_REC))
+ return;
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ if (chanp->Flags & FLG_LL_BCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_BHUP", 0);
+ RESBIT(chanp->Flags, FLG_LL_BCONN);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ if (chanp->Flags & FLG_START_B) {
+ release_ds(chanp);
+ RESBIT(chanp->Flags, FLG_START_B);
+ }
+ chanp->para.cause = 0x10; /* Normal Call Clearing */
+ chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
+ SETBIT(chanp->Flags, FLG_DISC_SEND);
+}
+
+static void
+l4_released_bchan(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ FsmChangeState(fi, ST_WAIT_DCOMMAND);
+ chanp->data_open = 0;
+ if (chanp->Flags & FLG_LL_BCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_BHUP", 0);
+ RESBIT(chanp->Flags, FLG_LL_BCONN);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ release_ds(chanp);
+ RESBIT(chanp->Flags, FLG_START_B);
+}
+
+
+static void
+l4_release_bchan(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ chanp->data_open = 0;
+ SETBIT(chanp->Flags, FLG_DISC_REC);
+ FsmChangeState(fi, ST_WAIT_BREL_DISC);
+ RESBIT(chanp->Flags, FLG_CONNECT_B);
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_received_d_rel(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ chanp->data_open = 0;
+ FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+ SETBIT(chanp->Flags, FLG_REL_REC);
+ if (chanp->Flags & FLG_CONNECT_B) {
+ chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+ RESBIT(chanp->Flags, FLG_CONNECT_B);
+ }
+ if (chanp->Flags & FLG_LL_BCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_BHUP", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ RESBIT(chanp->Flags, FLG_LL_BCONN);
+ }
+ if (chanp->Flags & FLG_START_B) {
+ release_ds(chanp);
+ RESBIT(chanp->Flags, FLG_START_B);
+ }
+ if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ l4_deliver_cause(chanp);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_FLUSH, NULL);
+ RESBIT(chanp->Flags, FLG_ESTAB_D);
+ RESBIT(chanp->Flags, FLG_DISC_SEND);
+ RESBIT(chanp->Flags, FLG_CALL_REC);
+ RESBIT(chanp->Flags, FLG_CALL_ALERT);
+ RESBIT(chanp->Flags, FLG_LL_DCONN);
+ RESBIT(chanp->Flags, FLG_CALL_SEND);
+}
+
+static void
+l4_received_d_relcnf(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ chanp->data_open = 0;
+ FsmChangeState(fi, ST_WAIT_DSHUTDOWN);
+ if (chanp->Flags & FLG_CONNECT_B) {
+ chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+ RESBIT(chanp->Flags, FLG_CONNECT_B);
+ }
+ if (chanp->Flags & FLG_LL_BCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_BHUP", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ RESBIT(chanp->Flags, FLG_LL_BCONN);
+ }
+ if (chanp->Flags & FLG_START_B) {
+ release_ds(chanp);
+ RESBIT(chanp->Flags, FLG_START_B);
+ }
+ if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ l4_deliver_cause(chanp);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+ RESBIT(chanp->Flags, FLG_ESTAB_D);
+ RESBIT(chanp->Flags, FLG_DISC_SEND);
+ RESBIT(chanp->Flags, FLG_CALL_REC);
+ RESBIT(chanp->Flags, FLG_CALL_ALERT);
+ RESBIT(chanp->Flags, FLG_LL_DCONN);
+ RESBIT(chanp->Flags, FLG_CALL_SEND);
+}
+
+static void
+l4_received_d_disc(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ chanp->data_open = 0;
+ FsmChangeState(fi, ST_WAIT_D_REL_CNF);
+ SETBIT(chanp->Flags, FLG_DISC_REC);
+ if (chanp->Flags & FLG_LL_BCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_BHUP", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ RESBIT(chanp->Flags, FLG_LL_BCONN);
+ }
+ if (chanp->Flags & FLG_START_B) {
+ release_ds(chanp);
+ RESBIT(chanp->Flags, FLG_START_B);
+ }
+ if (chanp->Flags & (FLG_LL_DCONN | FLG_CALL_SEND | FLG_CALL_ALERT)) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ l4_deliver_cause(chanp);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ RESBIT(chanp->Flags, FLG_LL_DCONN);
+ RESBIT(chanp->Flags, FLG_CALL_SEND);
+ RESBIT(chanp->Flags, FLG_CALL_ALERT);
+ chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
+}
+
+/* processing charge info */
+static void
+l4_charge_info(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_CINF;
+ ic.arg = chanp->chan;
+ sprintf(ic.parm.num, "%d", chanp->para.chargeinfo);
+ chanp->sp->iif.statcallb(&ic);
+}
+
+/* error procedures */
+
+static void
+l4_no_dchan(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_NODCH", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_NODCH;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ chanp->Flags = 0;
+ FsmChangeState(fi, ST_NULL);
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_no_dchan_ready(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+}
+
+static void
+l4_no_dchan_in(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+
+ chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
+ chanp->Flags = 0;
+ FsmChangeState(fi, ST_NULL);
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+}
+
+static void
+l4_no_setup_rsp(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ chanp->Flags = 0;
+ FsmChangeState(fi, ST_NULL);
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+}
+
+static void
+l4_setup_err(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ if (chanp->Flags & FLG_LL_DCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ RESBIT(chanp->Flags, FLG_LL_DCONN);
+ l4_deliver_cause(chanp);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ SETBIT(chanp->Flags, FLG_DISC_SEND); /* DISCONN was sent from L3 */
+}
+
+static void
+l4_connect_err(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ FsmChangeState(fi, ST_WAIT_DRELEASE);
+ if (chanp->Flags & FLG_LL_DCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ RESBIT(chanp->Flags, FLG_LL_DCONN);
+ l4_deliver_cause(chanp);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ SETBIT(chanp->Flags, FLG_DISC_SEND); /* DISCONN was sent from L3 */
+}
+
+static void
+l4_active_dlrl(struct FsmInst *fi, int event, void *arg)
+{
+ struct Channel *chanp = fi->userdata;
+ isdn_ctrl ic;
+
+ chanp->data_open = 0;
+ FsmChangeState(fi, ST_NULL);
+ if (chanp->Flags & FLG_CONNECT_B) {
+ chanp->lc_b.l2_establish = 0; /* direct reset in lc_b.lcfi */
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
+ RESBIT(chanp->Flags, FLG_CONNECT_B);
+ }
+ if (chanp->Flags & FLG_LL_BCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_BHUP", 0);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ RESBIT(chanp->Flags, FLG_LL_BCONN);
+ }
+ if (chanp->Flags & FLG_START_B) {
+ release_ds(chanp);
+ RESBIT(chanp->Flags, FLG_START_B);
+ }
+ if (chanp->Flags & FLG_LL_DCONN) {
+ if (chanp->debug & 1)
+ link_debug(chanp, "STAT_DHUP", 0);
+ RESBIT(chanp->Flags, FLG_LL_DCONN);
+ if (chanp->sp->protocol == ISDN_PTYPE_EURO) {
+ chanp->para.cause = 0x2f;
+ chanp->para.loc = 0;
+ } else {
+ chanp->para.cause = 0x70;
+ chanp->para.loc = 0;
+ }
+ l4_deliver_cause(chanp);
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_DHUP;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+ }
+ chanp->Flags = 0;
+ chanp->is.l4.l4l3(&chanp->is, CC_DLRL, NULL);
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
+}
+/* *INDENT-OFF* */
+static struct FsmNode fnlist[] =
+{
+ {ST_NULL, EV_DIAL, l4_prep_dialout},
+ {ST_NULL, EV_SETUP_IND, l4_start_dchan},
+ {ST_NULL, EV_SHUTDOWN_D, l4_shutdown_d},
+ {ST_NULL, EV_DLRL, l4_go_null},
+ {ST_OUT_WAIT_D, EV_DLEST, l4_do_dialout},
+ {ST_OUT_WAIT_D, EV_DLRL, l4_no_dchan},
+ {ST_OUT_WAIT_D, EV_HANGUP, l4_no_dchan},
+ {ST_IN_WAIT_D, EV_DLEST, l4_deliver_call},
+ {ST_IN_WAIT_D, EV_DLRL, l4_no_dchan_in},
+ {ST_IN_WAIT_D, EV_HANGUP, l4_no_dchan_in},
+ {ST_OUT_DIAL, EV_SETUP_CNF, l4_init_bchan_out},
+ {ST_OUT_DIAL, EV_HANGUP, l4_cancel_call},
+ {ST_OUT_DIAL, EV_DISCONNECT_IND, l4_received_d_disc},
+ {ST_OUT_DIAL, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_OUT_DIAL, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_OUT_DIAL, EV_NOSETUP_RSP, l4_no_setup_rsp},
+ {ST_OUT_DIAL, EV_SETUP_ERR, l4_setup_err},
+ {ST_IN_WAIT_LL, EV_SETUP_CMPL_IND, l4_init_bchan_in},
+ {ST_IN_WAIT_LL, EV_ACCEPTD, l4_send_dconnect},
+ {ST_IN_WAIT_LL, EV_HANGUP, l4_reject_call},
+ {ST_IN_WAIT_LL, EV_DISCONNECT_IND, l4_received_d_disc},
+ {ST_IN_WAIT_LL, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_IN_WAIT_LL, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_IN_ALERT_SEND, EV_SETUP_CMPL_IND, l4_init_bchan_in},
+ {ST_IN_ALERT_SEND, EV_ACCEPTD, l4_send_dconnect},
+ {ST_IN_ALERT_SEND, EV_HANGUP, l4_send_d_disc},
+ {ST_IN_ALERT_SEND, EV_DISCONNECT_IND, l4_received_d_disc},
+ {ST_IN_ALERT_SEND, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_IN_ALERT_SEND, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, l4_init_bchan_in},
+ {ST_IN_WAIT_CONN_ACK, EV_HANGUP, l4_send_d_disc},
+ {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, l4_received_d_disc},
+ {ST_IN_WAIT_CONN_ACK, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_IN_WAIT_CONN_ACK, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, l4_connect_err},
+ {ST_WAIT_BCONN, EV_BC_EST, l4_go_active},
+ {ST_WAIT_BCONN, EV_BC_REL, l4_send_d_disc},
+ {ST_WAIT_BCONN, EV_HANGUP, l4_send_d_disc},
+ {ST_WAIT_BCONN, EV_DISCONNECT_IND, l4_received_d_disc},
+ {ST_WAIT_BCONN, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_WAIT_BCONN, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_ACTIVE, EV_CINF, l4_charge_info},
+ {ST_ACTIVE, EV_BC_REL, l4_released_bchan},
+ {ST_ACTIVE, EV_HANGUP, l4_disconn_bchan},
+ {ST_ACTIVE, EV_DISCONNECT_IND, l4_release_bchan},
+ {ST_ACTIVE, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_ACTIVE, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_ACTIVE, EV_DLRL, l4_active_dlrl},
+ {ST_WAIT_BRELEASE, EV_BC_REL, l4_send_d_disc},
+ {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, l4_received_d_disc},
+ {ST_WAIT_BRELEASE, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_WAIT_BRELEASE, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_WAIT_BREL_DISC, EV_BC_REL, l4_received_d_disc},
+ {ST_WAIT_BREL_DISC, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_WAIT_BREL_DISC, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_WAIT_DCOMMAND, EV_HANGUP, l4_send_d_disc},
+ {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, l4_received_d_disc},
+ {ST_WAIT_DCOMMAND, EV_RELEASE_CNF, l4_received_d_relcnf},
+ {ST_WAIT_DCOMMAND, EV_RELEASE_IND, l4_received_d_rel},
+ {ST_WAIT_DRELEASE, EV_RELEASE_IND, l4_timeout_d},
+ {ST_WAIT_DRELEASE, EV_RELEASE_CNF, l4_timeout_d},
+ {ST_WAIT_DRELEASE, EV_RELEASE_ERR, l4_timeout_d},
+ {ST_WAIT_DRELEASE, EV_DIAL, l4_no_dchan_ready},
+ {ST_WAIT_D_REL_CNF, EV_RELEASE_CNF, l4_timeout_d},
+ {ST_WAIT_D_REL_CNF, EV_RELEASE_ERR, l4_timeout_d},
+ {ST_WAIT_D_REL_CNF, EV_DIAL, l4_no_dchan_ready},
+ {ST_WAIT_DSHUTDOWN, EV_DLRL, l4_go_null},
+ {ST_WAIT_DSHUTDOWN, EV_DIAL, l4_prep_dialout},
+ {ST_WAIT_DSHUTDOWN, EV_SETUP_IND, l4_start_dchan},
+};
+/* *INDENT-ON* */
+
+
+
+
+#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
+
+static void
+lc_r1(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
+ FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
+ lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
+
+}
+
+static void
+lc_r6(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ FsmDelTimer(&lf->act_timer, 50);
+ FsmChangeState(fi, ST_LC_DELAY);
+ FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
+}
+
+static void
+lc_r2(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ if (lf->l2_establish) {
+ FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
+ if (lf->l2_start)
+ lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
+ } else {
+ FsmChangeState(fi, ST_LC_CONNECTED);
+ lf->lccall(lf, LC_ESTABLISH, NULL);
+ }
+}
+
+static void
+lc_r3(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ FsmChangeState(fi, ST_LC_CONNECTED);
+ lf->lccall(lf, LC_ESTABLISH, NULL);
+}
+
+static void
+lc_r7(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ FsmChangeState(fi, ST_LC_FLUSH_WAIT);
+ lf->st->ma.manl2(lf->st, DL_FLUSH, NULL);
+}
+
+static void
+lc_r4(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ if (lf->l2_establish) {
+ FsmChangeState(fi, ST_LC_RELEASE_WAIT);
+ lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
+ /* This timer is for releasing the channel even
+ * there is a hang in layer 2 ; 5 sec are a try
+ */
+ FsmAddTimer(&lf->act_timer, 5000, EV_LC_TIMER, NULL, 53);
+ } else {
+ FsmChangeState(fi, ST_LC_NULL);
+ lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
+ lf->lccall(lf, LC_RELEASE, NULL);
+ }
+}
+
+static void
+lc_r4_1(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ FsmChangeState(fi, ST_LC_FLUSH_DELAY);
+ FsmAddTimer(&lf->act_timer, 50, EV_LC_TIMER, NULL, 52);
+}
+
+static void
+lc_r5_1(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ FsmChangeState(fi, ST_LC_RELEASE_WAIT);
+ /* This delay is needed for send out the UA frame before
+ * PH_DEACTIVATE the interface
+ */
+ FsmAddTimer(&lf->act_timer, 10, EV_LC_TIMER, NULL, 54);
+}
+
+static void
+lc_r5(struct FsmInst *fi, int event, void *arg)
+{
+ struct LcFsm *lf = fi->userdata;
+
+ FsmDelTimer(&lf->act_timer, 54);
+ FsmChangeState(fi, ST_LC_NULL);
+ lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
+ lf->lccall(lf, LC_RELEASE, NULL);
+}
+/* *INDENT-OFF* */
+static struct FsmNode LcFnList[] =
+{
+ {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1},
+ {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6},
+ {ST_LC_DELAY, EV_LC_TIMER, lc_r2},
+ {ST_LC_DELAY, EV_LC_DL_ESTABLISH, lc_r3},
+ {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3},
+ {ST_LC_ESTABLISH_WAIT, EV_LC_RELEASE, lc_r5},
+ {ST_LC_CONNECTED, EV_LC_FLUSH, lc_r7},
+ {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4},
+ {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5_1},
+ {ST_LC_FLUSH_WAIT, EV_LC_DL_FLUSH, lc_r4_1},
+ {ST_LC_FLUSH_DELAY, EV_LC_TIMER, lc_r4},
+ {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5},
+ {ST_LC_RELEASE_WAIT, EV_LC_TIMER, lc_r5},
+ {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5},
+ {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5},
+};
+/* *INDENT-ON* */
+
+
+
+
+
+
+
+
+
+
+#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
+
+void
+CallcNew(void)
+{
+ callcfsm.state_count = STATE_COUNT;
+ callcfsm.event_count = EVENT_COUNT;
+ callcfsm.strEvent = strEvent;
+ callcfsm.strState = strState;
+ FsmNew(&callcfsm, fnlist, FNCOUNT);
+
+ lcfsm.state_count = LC_STATE_COUNT;
+ lcfsm.event_count = LC_EVENT_COUNT;
+ lcfsm.strEvent = strLcEvent;
+ lcfsm.strState = strLcState;
+ FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
+}
+
+void
+CallcFree(void)
+{
+ FsmFree(&lcfsm);
+ FsmFree(&callcfsm);
+}
+
+static void
+release_ds(struct Channel *chanp)
+{
+ struct PStack *st = &chanp->ds;
+ struct IsdnCardState *sp;
+ struct HscxState *hsp;
+
+ sp = st->l1.hardware;
+ hsp = sp->hs + chanp->hscx;
+
+ close_hscxstate(hsp);
+
+ switch (chanp->l2_active_protocol) {
+ case (ISDN_PROTO_L2_X75I):
+ releasestack_isdnl2(st);
+ break;
+ case (ISDN_PROTO_L2_HDLC):
+ case (ISDN_PROTO_L2_TRANS):
+ releasestack_transl2(st);
+ break;
+ }
+ /* Reset B-Channel Statemachine */
+ FsmDelTimer(&chanp->lc_b.act_timer, 79);
+ FsmChangeState(&chanp->lc_b.lcfi, ST_LC_NULL);
+}
+
+static void
+cc_l1man(struct PStack *st, int pr, void *arg)
+{
+ struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+ switch (pr) {
+ case (PH_ACTIVATE):
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
+ break;
+ case (PH_DEACTIVATE):
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+ break;
+ }
+}
+
+static void
+cc_l2man(struct PStack *st, int pr, void *arg)
+{
+ struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+ switch (pr) {
+ case (DL_ESTABLISH):
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
+ break;
+ case (DL_RELEASE):
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
+ break;
+ case (DL_FLUSH):
+ FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_FLUSH, NULL);
+ break;
+ }
+}
+
+static void
+dcc_l1man(struct PStack *st, int pr, void *arg)
+{
+ struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+ switch (pr) {
+ case (PH_ACTIVATE):
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
+ break;
+ case (PH_DEACTIVATE):
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
+ break;
+ }
+}
+
+static void
+dcc_l2man(struct PStack *st, int pr, void *arg)
+{
+ struct Channel *chanp = (struct Channel *) st->l4.userdata;
+
+ switch (pr) {
+ case (DL_ESTABLISH):
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
+ break;
+ case (DL_RELEASE):
+ FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
+ break;
+ }
+}
+
+static void
+l2tei_dummy(struct PStack *st, int pr, void *arg)
+{
+ struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ char tmp[64], tm[32];
+
+ jiftime(tm, jiffies);
+ sprintf(tmp, "%s Channel %d Warning! Dummy l2tei called pr=%d\n", tm, chanp->chan, pr);
+ HiSax_putstatus(chanp->sp, tmp);
+}
+
+static void
+ll_handler(struct PStack *st, int pr, void *arg)
+{
+ struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ char tmp[64], tm[32];
+
+ switch (pr) {
+ case (CC_DISCONNECT_IND):
+ FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
+ break;
+ case (CC_RELEASE_CNF):
+ FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
+ break;
+ case (CC_SETUP_IND):
+ FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+ break;
+ case (CC_RELEASE_IND):
+ FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
+ break;
+ case (CC_SETUP_COMPLETE_IND):
+ FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
+ break;
+ case (CC_SETUP_CNF):
+ FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
+ break;
+ case (CC_INFO_CHARGE):
+ FsmEvent(&chanp->fi, EV_CINF, NULL);
+ break;
+ case (CC_NOSETUP_RSP_ERR):
+ FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL);
+ break;
+ case (CC_SETUP_ERR):
+ FsmEvent(&chanp->fi, EV_SETUP_ERR, NULL);
+ break;
+ case (CC_CONNECT_ERR):
+ FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL);
+ break;
+ case (CC_RELEASE_ERR):
+ FsmEvent(&chanp->fi, EV_RELEASE_ERR, NULL);
+ break;
+ default:
+ if (chanp->debug & 2048) {
+ jiftime(tm, jiffies);
+ sprintf(tmp, "%s Channel %d L3->L4 unknown primitiv %d\n",
+ tm, chanp->chan, pr);
+ HiSax_putstatus(chanp->sp, tmp);
+ }
+ }
+}
+
+static void
+init_is(struct Channel *chanp, unsigned int ces)
+{
+ struct PStack *st = &chanp->is;
+ struct IsdnCardState *sp = chanp->sp;
+ char tmp[128];
+
+ setstack_HiSax(st, sp);
+ st->l2.sap = 0;
+ st->l2.tei = 255;
+ st->l2.ces = ces;
+ st->l2.extended = !0;
+ st->l2.laptype = LAPD;
+ st->l2.window = 1;
+ st->l2.orig = !0;
+ st->l2.t200 = 1000; /* 1000 milliseconds */
+ if (st->protocol == ISDN_PTYPE_1TR6) {
+ st->l2.n200 = 3; /* try 3 times */
+ st->l2.t203 = 10000; /* 10000 milliseconds */
+ } else {
+ st->l2.n200 = 4; /* try 4 times */
+ st->l2.t203 = 5000; /* 5000 milliseconds */
+ }
+ sprintf(tmp, "Channel %d q.921", chanp->chan);
+ setstack_isdnl2(st, tmp);
+ setstack_isdnl3(st, chanp);
+ st->l4.userdata = chanp;
+ st->l4.l2writewakeup = NULL;
+ st->l3.l3l4 = ll_handler;
+ st->l1.l1man = cc_l1man;
+ st->l2.l2man = cc_l2man;
+ st->pa = &chanp->para;
+ HiSax_addlist(sp, st);
+}
+
+static void
+callc_debug(struct FsmInst *fi, char *s)
+{
+ char str[80], tm[32];
+ struct Channel *chanp = fi->userdata;
+
+ jiftime(tm, jiffies);
+ sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
+ HiSax_putstatus(chanp->sp, str);
+}
+
+static void
+lc_debug(struct FsmInst *fi, char *s)
+{
+ char str[256], tm[32];
+ struct LcFsm *lf = fi->userdata;
+
+ jiftime(tm, jiffies);
+ sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
+ HiSax_putstatus(lf->ch->sp, str);
+}
+
+static void
+dlc_debug(struct FsmInst *fi, char *s)
+{
+ char str[256], tm[32];
+ struct LcFsm *lf = fi->userdata;
+
+ jiftime(tm, jiffies);
+ sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
+ HiSax_putstatus(lf->ch->sp, str);
+}
+
+static void
+lccall_d(struct LcFsm *lf, int pr, void *arg)
+{
+ struct Channel *chanp = lf->ch;
+
+ switch (pr) {
+ case (LC_ESTABLISH):
+ FsmEvent(&chanp->fi, EV_DLEST, NULL);
+ break;
+ case (LC_RELEASE):
+ FsmEvent(&chanp->fi, EV_DLRL, NULL);
+ break;
+ }
+}
+
+static void
+lccall_b(struct LcFsm *lf, int pr, void *arg)
+{
+ struct Channel *chanp = lf->ch;
+
+ switch (pr) {
+ case (LC_ESTABLISH):
+ FsmEvent(&chanp->fi, EV_BC_EST, NULL);
+ break;
+ case (LC_RELEASE):
+ FsmEvent(&chanp->fi, EV_BC_REL, NULL);
+ break;
+ }
+}
+
+static void
+init_chan(int chan, struct IsdnCardState *csta, int hscx,
+ unsigned int ces)
+{
+ struct Channel *chanp = csta->channel + chan;
+
+ chanp->sp = csta;
+ chanp->hscx = hscx;
+ chanp->chan = chan;
+ chanp->incoming = 0;
+ chanp->debug = 0;
+ chanp->Flags = 0;
+ chanp->leased = 0;
+ chanp->impair = 0;
+ init_is(chanp, ces);
+
+ chanp->fi.fsm = &callcfsm;
+ chanp->fi.state = ST_NULL;
+ chanp->fi.debug = 0;
+ chanp->fi.userdata = chanp;
+ chanp->fi.printdebug = callc_debug;
+ FsmInitTimer(&chanp->fi, &chanp->dial_timer);
+ FsmInitTimer(&chanp->fi, &chanp->drel_timer);
+
+ chanp->lc_d.lcfi.fsm = &lcfsm;
+ chanp->lc_d.lcfi.state = ST_LC_NULL;
+ chanp->lc_d.lcfi.debug = 0;
+ chanp->lc_d.lcfi.userdata = &chanp->lc_d;
+ chanp->lc_d.lcfi.printdebug = lc_debug;
+ chanp->lc_d.type = LC_D;
+ chanp->lc_d.ch = chanp;
+ chanp->lc_d.st = &chanp->is;
+ chanp->lc_d.l2_establish = !0;
+ chanp->lc_d.l2_start = !0;
+ chanp->lc_d.lccall = lccall_d;
+ FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
+
+ chanp->lc_b.lcfi.fsm = &lcfsm;
+ chanp->lc_b.lcfi.state = ST_LC_NULL;
+ chanp->lc_b.lcfi.debug = 0;
+ chanp->lc_b.lcfi.userdata = &chanp->lc_b;
+ chanp->lc_b.lcfi.printdebug = dlc_debug;
+ chanp->lc_b.type = LC_B;
+ chanp->lc_b.ch = chanp;
+ chanp->lc_b.st = &chanp->ds;
+ chanp->lc_b.l2_establish = !0;
+ chanp->lc_b.l2_start = !0;
+ chanp->lc_b.lccall = lccall_b;
+ FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
+ chanp->outcallref = 64;
+ chanp->data_open = 0;
+}
+
+int
+CallcNewChan(struct IsdnCardState *csta)
+{
+ int ces;
+
+ chancount += 2;
+ ces = randomces();
+ init_chan(0, csta, 1, ces++);
+ ces %= 0xffff;
+ init_chan(1, csta, 0, ces++);
+ printk(KERN_INFO "HiSax: 2 channels added\n");
+ return (2);
+}
+
+static void
+release_is(struct Channel *chanp)
+{
+ struct PStack *st = &chanp->is;
+
+ releasestack_isdnl2(st);
+ releasestack_isdnl3(st);
+ HiSax_rmlist(st->l1.hardware, st);
+}
+
+void
+CallcFreeChan(struct IsdnCardState *csta)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ FsmDelTimer(&csta->channel[i].drel_timer, 74);
+ FsmDelTimer(&csta->channel[i].dial_timer, 75);
+ FsmDelTimer(&csta->channel[i].lc_b.act_timer, 76);
+ FsmDelTimer(&csta->channel[i].lc_d.act_timer, 77);
+ if (csta->channel[i].Flags & FLG_START_B) {
+ release_ds(csta->channel + i);
+ }
+ release_is(csta->channel + i);
+ }
+}
+
+static void
+lldata_handler(struct PStack *st, int pr, void *arg)
+{
+ struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct sk_buff *skb = arg;
+
+ switch (pr) {
+ case (DL_DATA):
+ if (chanp->data_open)
+ chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb);
+ else {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ }
+ break;
+ default:
+ printk(KERN_WARNING "lldata_handler unknown primitive %d\n",
+ pr);
+ break;
+ }
+}
+
+static void
+lltrans_handler(struct PStack *st, int pr, void *arg)
+{
+ struct Channel *chanp = (struct Channel *) st->l4.userdata;
+ struct sk_buff *skb = arg;
+
+ switch (pr) {
+ case (PH_DATA):
+ if (chanp->data_open)
+ chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb);
+ else {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ }
+ break;
+ default:
+ printk(KERN_WARNING "lltrans_handler unknown primitive %d\n",
+ pr);
+ break;
+ }
+}
+
+static void
+ll_writewakeup(struct PStack *st)
+{
+ struct Channel *chanp = st->l4.userdata;
+ isdn_ctrl ic;
+
+ ic.driver = chanp->sp->myid;
+ ic.command = ISDN_STAT_BSENT;
+ ic.arg = chanp->chan;
+ chanp->sp->iif.statcallb(&ic);
+}
+
+static int
+init_ds(struct Channel *chanp, int incoming)
+{
+ struct PStack *st = &chanp->ds;
+ struct IsdnCardState *sp = chanp->sp;
+ struct HscxState *hsp = sp->hs + chanp->hscx;
+ char tmp[128];
+
+ st->l1.hardware = sp;
+
+ hsp->mode = 2;
+
+ if (setstack_hscx(st, hsp))
+ return (-1);
+
+ st->l2.extended = 0;
+ st->l2.laptype = LAPB;
+ st->l2.orig = !incoming;
+ st->l2.t200 = 1000; /* 1000 milliseconds */
+ st->l2.window = 7;
+ st->l2.n200 = 4; /* try 4 times */
+ st->l2.t203 = 5000; /* 5000 milliseconds */
+
+ st->l3.debug = 0;
+ switch (chanp->l2_active_protocol) {
+ case (ISDN_PROTO_L2_X75I):
+ sprintf(tmp, "Channel %d x.75", chanp->chan);
+ setstack_isdnl2(st, tmp);
+ st->l2.l2l3 = lldata_handler;
+ st->l1.l1man = dcc_l1man;
+ st->l2.l2man = dcc_l2man;
+ st->l2.l2tei = l2tei_dummy;
+ st->l4.userdata = chanp;
+ st->l4.l1writewakeup = NULL;
+ st->l4.l2writewakeup = ll_writewakeup;
+ st->l2.l2m.debug = chanp->debug & 16;
+ st->l2.debug = chanp->debug & 64;
+ st->ma.manl2(st, MDL_NOTEIPROC, NULL);
+ st->l1.hscxmode = 2; /* Packet-Mode ? */
+ st->l1.hscxchannel = chanp->para.bchannel - 1;
+ break;
+ case (ISDN_PROTO_L2_HDLC):
+ st->l1.l1l2 = lltrans_handler;
+ st->l1.l1man = dcc_l1man;
+ st->l4.userdata = chanp;
+ st->l4.l1writewakeup = ll_writewakeup;
+ st->l1.hscxmode = 2;
+ st->l1.hscxchannel = chanp->para.bchannel - 1;
+ break;
+ case (ISDN_PROTO_L2_TRANS):
+ st->l1.l1l2 = lltrans_handler;
+ st->l1.l1man = dcc_l1man;
+ st->l4.userdata = chanp;
+ st->l4.l1writewakeup = ll_writewakeup;
+ st->l1.hscxmode = 1;
+ st->l1.hscxchannel = chanp->para.bchannel - 1;
+ break;
+ }
+ return (0);
+}
+
+static void
+channel_report(struct Channel *chanp)
+{
+}
+
+static void
+distr_debug(struct IsdnCardState *csta, int debugflags)
+{
+ int i;
+ struct Channel *chanp = csta->channel;
+
+ for (i = 0; i < 2; i++) {
+ chanp[i].debug = debugflags;
+ chanp[i].fi.debug = debugflags & 2;
+ chanp[i].is.l2.l2m.debug = debugflags & 8;
+ chanp[i].ds.l2.l2m.debug = debugflags & 16;
+ chanp[i].is.l2.debug = debugflags & 32;
+ chanp[i].ds.l2.debug = debugflags & 64;
+ chanp[i].lc_d.lcfi.debug = debugflags & 128;
+ chanp[i].lc_b.lcfi.debug = debugflags & 256;
+ }
+ csta->dlogflag = debugflags & 4;
+ csta->teistack->l2.l2m.debug = debugflags & 512;
+}
+
+int
+HiSax_command(isdn_ctrl * ic)
+{
+ struct IsdnCardState *csta = hisax_findcard(ic->driver);
+ struct Channel *chanp;
+ char tmp[128];
+ int i;
+ unsigned int num;
+
+ if (!csta) {
+ printk(KERN_ERR
+ "HiSax: if_command %d called with invalid driverId %d!\n",
+ ic->command, ic->driver);
+ return -ENODEV;
+ }
+ switch (ic->command) {
+ case (ISDN_CMD_SETEAZ):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1)
+ link_debug(chanp, "SETEAZ", 1);
+ break;
+ case (ISDN_CMD_SETL2):
+ chanp = csta->channel + (ic->arg & 0xff);
+ if (chanp->debug & 1) {
+ sprintf(tmp, "SETL2 card %d %ld", csta->cardnr + 1,
+ ic->arg >> 8);
+ link_debug(chanp, tmp, 1);
+ }
+ chanp->l2_protocol = ic->arg >> 8;
+ break;
+ case (ISDN_CMD_DIAL):
+ chanp = csta->channel + (ic->arg & 0xff);
+ if (chanp->debug & 1) {
+ sprintf(tmp, "DIAL %s -> %s (%d,%d)",
+ ic->parm.setup.eazmsn, ic->parm.setup.phone,
+ ic->parm.setup.si1, ic->parm.setup.si2);
+ link_debug(chanp, tmp, 1);
+ }
+ chanp->para.setup = ic->parm.setup;
+ if (!strcmp(chanp->para.setup.eazmsn, "0"))
+ chanp->para.setup.eazmsn[0] = '\0';
+ /* this solution is dirty and may be change, if
+ * we make a callreference based callmanager */
+ if (chanp->fi.state == ST_NULL) {
+ FsmEvent(&chanp->fi, EV_DIAL, NULL);
+ } else {
+ FsmDelTimer(&chanp->dial_timer, 70);
+ FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, NULL, 71);
+ }
+ break;
+ case (ISDN_CMD_ACCEPTB):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1)
+ link_debug(chanp, "ACCEPTB", 1);
+ FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
+ break;
+ case (ISDN_CMD_ACCEPTD):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1)
+ link_debug(chanp, "ACCEPTD", 1);
+ FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
+ break;
+ case (ISDN_CMD_HANGUP):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1)
+ link_debug(chanp, "HANGUP", 1);
+ FsmEvent(&chanp->fi, EV_HANGUP, NULL);
+ break;
+ case (ISDN_CMD_SUSPEND):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1) {
+ sprintf(tmp, "SUSPEND %s", ic->parm.num);
+ link_debug(chanp, tmp, 1);
+ }
+ FsmEvent(&chanp->fi, EV_SUSPEND, ic);
+ break;
+ case (ISDN_CMD_RESUME):
+ chanp = csta->channel + ic->arg;
+ if (chanp->debug & 1) {
+ sprintf(tmp, "RESUME %s", ic->parm.num);
+ link_debug(chanp, tmp, 1);
+ }
+ FsmEvent(&chanp->fi, EV_RESUME, ic);
+ break;
+ case (ISDN_CMD_LOCK):
+ HiSax_mod_inc_use_count();
+#ifdef MODULE
+ if (csta->channel[0].debug & 1024) {
+ jiftime(tmp, jiffies);
+ i = strlen(tmp);
+ sprintf(tmp + i, " LOCK modcnt %lx\n", MOD_USE_COUNT);
+ HiSax_putstatus(csta, tmp);
+ }
+#endif /* MODULE */
+ break;
+ case (ISDN_CMD_UNLOCK):
+ HiSax_mod_dec_use_count();
+#ifdef MODULE
+ if (csta->channel[0].debug & 1024) {
+ jiftime(tmp, jiffies);
+ i = strlen(tmp);
+ sprintf(tmp + i, " UNLOCK modcnt %lx\n", MOD_USE_COUNT);
+ HiSax_putstatus(csta, tmp);
+ }
+#endif /* MODULE */
+ break;
+ case (ISDN_CMD_IOCTL):
+ switch (ic->arg) {
+ case (0):
+ HiSax_reportcard(csta->cardnr);
+ for (i = 0; i < 2; i++)
+ channel_report(&csta->channel[i]);
+ break;
+ case (1):
+ num = *(unsigned int *) ic->parm.num;
+ distr_debug(csta, num);
+ sprintf(tmp, "debugging flags card %d set to %x\n",
+ csta->cardnr + 1, num);
+ HiSax_putstatus(csta, tmp);
+ printk(KERN_DEBUG "HiSax: %s", tmp);
+ break;
+ case (2):
+ num = *(unsigned int *) ic->parm.num;
+ i = num >> 8;
+ if (i >= 2)
+ break;
+ chanp = csta->channel + i;
+ chanp->impair = num & 0xff;
+ if (chanp->debug & 1) {
+ sprintf(tmp, "IMPAIR %x", chanp->impair);
+ link_debug(chanp, tmp, 1);
+ }
+ break;
+ case (3):
+ for (i = 0; i < *(unsigned int *) ic->parm.num; i++)
+ HiSax_mod_dec_use_count();
+ break;
+ case (4):
+ for (i = 0; i < *(unsigned int *) ic->parm.num; i++)
+ HiSax_mod_inc_use_count();
+ break;
+ case (5): /* set card in leased mode */
+ csta->channel[0].leased = 1;
+ csta->channel[1].leased = 1;
+ sprintf(tmp, "card %d set into leased mode\n",
+ csta->cardnr + 1);
+ HiSax_putstatus(csta, tmp);
+ break;
+#ifdef MODULE
+ case (55):
+#if (LINUX_VERSION_CODE < 0x020111)
+ MOD_USE_COUNT = MOD_VISITED;
+#else
+ MOD_USE_COUNT = 0;
+#endif
+ HiSax_mod_inc_use_count();
+ break;
+#endif /* MODULE */
+ case (11):
+ csta->debug = *(unsigned int *) ic->parm.num;
+ sprintf(tmp, "l1 debugging flags card %d set to %x\n",
+ csta->cardnr + 1, csta->debug);
+ HiSax_putstatus(cards[0].sp, tmp);
+ printk(KERN_DEBUG "HiSax: %s", tmp);
+ break;
+ case (13):
+ csta->channel[0].is.l3.debug = *(unsigned int *) ic->parm.num;
+ csta->channel[1].is.l3.debug = *(unsigned int *) ic->parm.num;
+ sprintf(tmp, "l3 debugging flags card %d set to %x\n",
+ csta->cardnr + 1, *(unsigned int *) ic->parm.num);
+ HiSax_putstatus(cards[0].sp, tmp);
+ printk(KERN_DEBUG "HiSax: %s", tmp);
+ break;
+ default:
+ printk(KERN_DEBUG "HiSax: invalid ioclt %d\n",
+ (int) ic->arg);
+ return (-EINVAL);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb)
+{
+ struct IsdnCardState *csta = hisax_findcard(id);
+ struct Channel *chanp;
+ struct PStack *st;
+ int len = skb->len;
+ unsigned long flags;
+ struct sk_buff *nskb;
+ char tmp[64];
+
+ if (!csta) {
+ printk(KERN_ERR
+ "HiSax: if_sendbuf called with invalid driverId!\n");
+ return -ENODEV;
+ }
+ chanp = csta->channel + chan;
+ st = &chanp->ds;
+ if (!chanp->data_open) {
+ link_debug(chanp, "writebuf: channel not open", 1);
+ return -EIO;
+ }
+ if (len > MAX_DATA_SIZE) {
+ sprintf(tmp, "writebuf: packet too large (%d bytes)", len);
+ printk(KERN_WARNING "HiSax_%s !\n", tmp);
+ link_debug(chanp, tmp, 1);
+ return -EINVAL;
+ }
+ if (len) {
+ if ((len + csta->hs[chanp->hscx].tx_cnt) > MAX_DATA_MEM) {
+ /* Must return 0 here, since this is not an error
+ * but a temporary lack of resources.
+ */
+ if (chanp->debug & 2048) {
+ sprintf(tmp, "writebuf: no buffers for %d bytes", len);
+ link_debug(chanp, tmp, 1);
+ }
+ return 0;
+ }
+ save_flags(flags);
+ cli();
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (nskb) {
+ if (chanp->lc_b.l2_establish) {
+ csta->hs[chanp->hscx].tx_cnt += len + st->l2.ihsize;
+ chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, nskb);
+ } else {
+ csta->hs[chanp->hscx].tx_cnt += len;
+ chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, nskb);
+ }
+ dev_kfree_skb(skb, FREE_WRITE);
+ } else
+ len = 0;
+ restore_flags(flags);
+ }
+ return (len);
+}
--- /dev/null
+/* $Id: config.c,v 1.15 1997/04/06 22:57:24 keil Exp $
+
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * based on the teles driver from Jan den Ouden
+ *
+ *
+ * $Log: config.c,v $
+ * Revision 1.15 1997/04/06 22:57:24 keil
+ * Hisax version 2.1
+ *
+ * Revision 1.14 1997/03/25 23:11:22 keil
+ * US NI-1 protocol
+ *
+ * Revision 1.13 1997/03/23 21:45:49 keil
+ * Add support for ELSA PCMCIA
+ *
+ * Revision 1.12 1997/03/11 21:01:43 keil
+ * nzproto is only used with modules
+ *
+ * Revision 1.11 1997/02/14 12:23:12 fritz
+ * Added support for new insmod parameter handling.
+ *
+ * Revision 1.10 1997/02/14 09:22:09 keil
+ * Final 2.0 version
+ *
+ * Revision 1.9 1997/02/10 11:45:09 fritz
+ * More changes for Kernel 2.1.X compatibility.
+ *
+ * Revision 1.8 1997/02/09 00:28:05 keil
+ * new interface handling, one interface per card
+ * default protocol now works again
+ *
+ * Revision 1.7 1997/01/27 15:56:57 keil
+ * Teles PCMCIA ITK ix1 micro added
+ *
+ * Revision 1.6 1997/01/21 22:17:56 keil
+ * new module load syntax
+ *
+ * Revision 1.5 1997/01/09 18:28:20 keil
+ * cosmetic cleanups
+ *
+ * Revision 1.4 1996/11/05 19:35:17 keil
+ * using config.h; some spelling fixes
+ *
+ * Revision 1.3 1996/10/23 17:23:28 keil
+ * default config changes
+ *
+ * Revision 1.2 1996/10/23 11:58:48 fritz
+ * Changed default setup to reflect user's selection of supported
+ * cards/protocols.
+ *
+ * Revision 1.1 1996/10/13 20:04:51 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/config.h>
+#include "hisax.h"
+
+/*
+ * This structure array contains one entry per card. An entry looks
+ * like this:
+ *
+ * { type, protocol, p0, p1, p2, NULL }
+ *
+ * type
+ * 1 Teles 16.0 p0=irq p1=membase p2=iobase
+ * 2 Teles 8.0 p0=irq p1=membase
+ * 3 Teles 16.3 p0=irq p1=iobase
+ * 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX)
+ * 5 AVM A1 (Fritz) p0=irq p1=iobase
+ * 6 ELSA PC [p0=iobase] or nothing (autodetect)
+ * 7 ELSA Quickstep p0=irq p1=iobase
+ * ELSA PCMCIA p0=irq p1=iobase
+ * 8 Teles PCMCIA p0=irq p1=iobase
+ * 9 ITK ix1-micro p0=irq p1=iobase
+ *
+ *
+ * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
+ *
+ *
+ */
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+#define DEFAULT_CARD ISDN_CTYPE_ELSA
+#define DEFAULT_CFG {0,0,0}
+#endif
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+#define DEFAULT_CARD ISDN_CTYPE_ELSA_QS1000
+#define DEFAULT_CFG {3,0x2f8,0}
+#endif
+#ifdef CONFIG_HISAX_AVM_A1
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_A1
+#define DEFAULT_CFG {10,0x340,0}
+#endif
+#ifdef CONFIG_HISAX_16_3
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_16_3
+#define DEFAULT_CFG {15,0x180,0}
+#endif
+#ifdef CONFIG_HISAX_16_0
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_16_0
+#define DEFAULT_CFG {15,0xd0000,0xd80}
+#endif
+
+#ifdef CONFIG_HISAX_IX1MICROR2
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2
+#define DEFAULT_CFG {5,0x390,0}
+#endif
+
+#ifdef CONFIG_HISAX_1TR6
+#define DEFAULT_PROTO ISDN_PTYPE_1TR6
+#define DEFAULT_PROTO_NAME "1TR6"
+#endif
+#ifdef CONFIG_HISAX_EURO
+#undef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_EURO
+#undef DEFAULT_PROTO_NAME
+#define DEFAULT_PROTO_NAME "EURO"
+#endif
+#ifdef CONFIG_HISAX_NI1
+#undef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_NI1
+#undef DEFAULT_PROTO_NAME
+#define DEFAULT_PROTO_NAME "NI1"
+#endif
+#ifndef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN
+#define DEFAULT_PROTO_NAME "UNKNOWN"
+#endif
+#ifndef DEFAULT_CARD
+#error "HiSax: No cards configured"
+#endif
+
+#define FIRST_CARD { \
+ DEFAULT_CARD, \
+ DEFAULT_PROTO, \
+ DEFAULT_CFG, \
+ NULL, \
+}
+
+#define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0}, NULL}
+
+struct IsdnCard cards[] =
+{
+ FIRST_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+ EMPTY_CARD,
+};
+
+static char HiSaxID[96] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
+"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+char *HiSax_id = HiSaxID;
+#ifdef MODULE
+/* Variables for insmod */
+int type[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int protocol[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int io[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */
+int io0[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int io1[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#endif
+int irq[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+int mem[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+char *id = HiSaxID;
+
+#if (LINUX_VERSION_CODE > 0x020111)
+MODULE_AUTHOR("Karsten Keil");
+MODULE_PARM(type, "1-16i");
+MODULE_PARM(protocol, "1-16i");
+MODULE_PARM(io, "1-16i");
+MODULE_PARM(irq, "1-16i");
+MODULE_PARM(mem, "1-16i");
+MODULE_PARM(id, "s");
+#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */
+MODULE_PARM(io0, "1-16i");
+MODULE_PARM(io1, "1-16i");
+#endif
+#endif
+
+#endif
+
+extern char *l1_revision;
+extern char *l2_revision;
+extern char *l3_revision;
+extern char *l4_revision;
+extern char *tei_revision;
+
+char *
+HiSax_getrev(const char *revision)
+{
+ char *rev;
+ char *p;
+
+ if ((p = strchr(revision, ':'))) {
+ rev = p + 2;
+ p = strchr(rev, '$');
+ *--p = 0;
+ } else
+ rev = "???";
+ return rev;
+}
+
+int nrcards;
+
+void
+HiSax_mod_dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+void
+HiSax_mod_inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+#ifdef MODULE
+#define HiSax_init init_module
+#else
+void
+HiSax_setup(char *str, int *ints)
+{
+ int i, j, argc;
+
+ argc = ints[0];
+ i = 0;
+ j = 1;
+ while (argc && (i < 16)) {
+ if (argc) {
+ cards[i].typ = ints[j];
+ j++;
+ argc--;
+ }
+ if (argc) {
+ cards[i].protocol = ints[j];
+ j++;
+ argc--;
+ }
+ if (argc) {
+ cards[i].para[0] = ints[j];
+ j++;
+ argc--;
+ }
+ if (argc) {
+ cards[i].para[1] = ints[j];
+ j++;
+ argc--;
+ }
+ if (argc) {
+ cards[i].para[2] = ints[j];
+ j++;
+ argc--;
+ }
+ i++;
+ }
+ if (strlen(str)) {
+ strcpy(HiSaxID, str);
+ HiSax_id = HiSaxID;
+ } else {
+ strcpy(HiSaxID, "HiSax");
+ HiSax_id = HiSaxID;
+ }
+}
+#endif
+
+int
+HiSax_init(void)
+{
+ int i;
+ char tmp[64], rev[64];
+ char *r = rev;
+#ifdef MODULE
+ int nzproto = 0;
+#endif
+ nrcards = 0;
+ strcpy(tmp, l1_revision);
+ r += sprintf(r, "%s/", HiSax_getrev(tmp));
+ strcpy(tmp, l2_revision);
+ r += sprintf(r, "%s/", HiSax_getrev(tmp));
+ strcpy(tmp, l3_revision);
+ r += sprintf(r, "%s/", HiSax_getrev(tmp));
+ strcpy(tmp, l4_revision);
+ r += sprintf(r, "%s/", HiSax_getrev(tmp));
+ strcpy(tmp, tei_revision);
+ r += sprintf(r, "%s", HiSax_getrev(tmp));
+
+ printk(KERN_NOTICE "HiSax: Driver for Siemens chip set ISDN cards\n");
+ printk(KERN_NOTICE "HiSax: Version 2.1\n");
+ printk(KERN_NOTICE "HiSax: Revisions %s\n", rev);
+
+#ifdef MODULE
+ if (id) /* If id= string used */
+ HiSax_id = id;
+ for (i = 0; i < 16; i++) {
+ cards[i].typ = type[i];
+ if (protocol[i]) {
+ cards[i].protocol = protocol[i];
+ nzproto++;
+ }
+ switch (type[i]) {
+ case ISDN_CTYPE_16_0:
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = mem[i];
+ cards[i].para[2] = io[i];
+ break;
+
+ case ISDN_CTYPE_8_0:
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = mem[i];
+ break;
+
+ case ISDN_CTYPE_16_3:
+ case ISDN_CTYPE_TELESPCMCIA:
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = io[i];
+ break;
+
+#ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */
+ case ISDN_CTYPE_PNP:
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = io0[i];
+ cards[i].para[2] = io1[i];
+ break;
+#endif
+ case ISDN_CTYPE_A1:
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = io[i];
+ break;
+
+ case ISDN_CTYPE_ELSA:
+ cards[i].para[0] = io[i];
+ break;
+ case ISDN_CTYPE_ELSA_QS1000:
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = io[i];
+ break;
+
+ case ISDN_CTYPE_IX1MICROR2:
+ cards[i].para[0] = irq[i];
+ cards[i].para[1] = io[i];
+ break;
+
+ }
+ }
+ if (!nzproto) {
+ printk(KERN_WARNING "HiSax: Warning - no protocol specified\n");
+ printk(KERN_WARNING "HiSax: Note! module load syntax has changed.\n");
+ printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME);
+ }
+#endif
+ if (!HiSax_id)
+ HiSax_id = HiSaxID;
+ if (!HiSaxID[0])
+ strcpy(HiSaxID, "HiSax");
+ for (i = 0; i < 16; i++)
+ if (cards[i].typ > 0)
+ nrcards++;
+ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+ nrcards, (nrcards > 1) ? "s" : "");
+
+ CallcNew();
+ Isdnl2New();
+ if (HiSax_inithardware()) {
+ /* Install only, if at least one card found */
+ /* No symbols to export, hide all symbols */
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE < 0x020111)
+ register_symtab(NULL);
+#else
+ EXPORT_NO_SYMBOLS;
+#endif
+ printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
+ return (0);
+ } else {
+ Isdnl2Free();
+ CallcFree();
+ return -EIO;
+ }
+}
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+ HiSax_closehardware();
+ printk(KERN_NOTICE "HiSax module removed\n");
+}
+
+#endif
--- /dev/null
+/* $Id: elsa.c,v 1.14 1997/04/13 19:53:25 keil Exp $
+
+ * elsa.c low level stuff for Elsa isdn cards
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Elsa GmbH for documents and informations
+ *
+ *
+ * $Log: elsa.c,v $
+ * Revision 1.14 1997/04/13 19:53:25 keil
+ * Fixed QS1000 init, change in IRQ check delay for SMP
+ *
+ * Revision 1.13 1997/04/07 22:58:07 keil
+ * need include config.h
+ *
+ * Revision 1.12 1997/04/06 22:54:14 keil
+ * Using SKB's
+ *
+ * Revision 1.11 1997/03/23 21:45:46 keil
+ * Add support for ELSA PCMCIA
+ *
+ * Revision 1.10 1997/03/12 21:42:19 keil
+ * Bugfix: IRQ hangs with QS1000
+ *
+ * Revision 1.9 1997/03/04 15:57:39 keil
+ * bugfix IRQ reset Quickstep, ELSA PC changes, some stuff for new cards
+ *
+ * Revision 1.8 1997/01/27 15:51:48 keil
+ * SMP proof,cosmetics
+ *
+ * Revision 1.7 1997/01/21 22:20:48 keil
+ * Elsa Quickstep support
+ *
+ * Revision 1.6 1997/01/09 18:22:46 keil
+ * one more PCC-8 fix
+ *
+ * Revision 1.5 1996/12/08 19:46:14 keil
+ * PCC-8 correct IRQs; starting ARCOFI support
+ *
+ * Revision 1.4 1996/11/18 20:50:54 keil
+ * with PCF Pro release 16 Byte IO
+ *
+ * Revision 1.3 1996/11/18 15:33:04 keil
+ * PCC and PCFPro support
+ *
+ * Revision 1.2 1996/10/27 22:08:03 keil
+ * cosmetic changes
+ *
+ * Revision 1.1 1996/10/13 20:04:52 keil
+ * Initial revision
+ *
+ *
+ */
+
+#define ARCOFI_USE 0
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "siemens.h"
+#include "hisax.h"
+#include "elsa.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+
+const char *Elsa_revision = "$Revision: 1.14 $";
+const char *Elsa_Types[] =
+{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
+ "PCMCIA", "QS 1000", "QS 3000"};
+
+const char *ITACVer[] =
+{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
+ "B1", "A1"};
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline u_char
+readhscx(unsigned int adr, int hscx, u_char off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20));
+ ret = bytein(adr + CARD_HSCX);
+ restore_flags(flags);
+ return (ret);
+}
+
+static inline void
+read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+ /* fifo read without cli because it's allready done */
+
+ byteout(adr + CARD_ALE, (hscx ? 0x40 : 0));
+ insb(adr + CARD_HSCX, data, size);
+}
+
+
+static inline void
+writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(adr + CARD_ALE, off + (hscx ? 0x60 : 0x20));
+ byteout(adr + CARD_HSCX, data);
+ restore_flags(flags);
+}
+
+static inline void
+write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+ /* fifo write without cli because it's allready done */
+ byteout(adr + CARD_ALE, (hscx ? 0x40 : 0));
+ outsb(adr + CARD_HSCX, data, size);
+}
+
+static inline u_char
+readisac(unsigned int adr, u_char off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(adr + CARD_ALE, off + 0x20);
+ ret = bytein(adr + CARD_ISAC);
+ restore_flags(flags);
+ return (ret);
+}
+
+static inline void
+read_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+ /* fifo read without cli because it's allready done */
+
+ byteout(adr + CARD_ALE, 0);
+ insb(adr + CARD_ISAC, data, size);
+}
+
+
+static inline void
+writeisac(unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(adr + CARD_ALE, off + 0x20);
+ byteout(adr + CARD_ISAC, data);
+ restore_flags(flags);
+}
+
+static inline void
+write_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+ /* fifo write without cli because it's allready done */
+
+ byteout(adr + CARD_ALE, 0);
+ outsb(adr + CARD_ISAC, data, size);
+}
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+static inline u_char
+readitac(unsigned int adr, u_char off)
+{
+ register u_char ret;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(adr + CARD_ALE, off);
+ ret = bytein(adr + CARD_ITAC);
+ restore_flags(flags);
+ return (ret);
+}
+
+static inline void
+writeitac(unsigned int adr, u_char off, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ byteout(adr + CARD_ALE, off);
+ byteout(adr + CARD_ITAC, data);
+ restore_flags(flags);
+}
+
+static inline int
+TimerRun(struct IsdnCardState *sp)
+{
+ register u_char val;
+
+ val = bytein(sp->cfg_reg + CARD_CONFIG);
+ if (sp->subtyp == ELSA_QS1000)
+ return (0 == (val & TIMER_RUN));
+ else if (sp->subtyp == ELSA_PCC8)
+ return (val & TIMER_RUN_PCC8);
+ return (val & TIMER_RUN);
+}
+
+static inline void
+elsa_led_handler(struct IsdnCardState *sp)
+{
+
+ u_char outval = 0xf0;
+ int stat = 0, cval;
+
+
+ if ((sp->ph_state == 0) || (sp->ph_state == 15)) {
+ stat = 1;
+ } else {
+ if (sp->hs[0].mode != 0)
+ stat |= 2;
+ if (sp->hs[1].mode != 0)
+ stat |= 4;
+ }
+ cval = (sp->counter >> 6) & 3;
+ switch (cval) {
+ case 0:
+ if (!stat)
+ outval |= STAT_LED;
+ else if (stat == 1)
+ outval |= LINE_LED | STAT_LED;
+ else {
+ if (stat & 2)
+ outval |= STAT_LED;
+ if (stat & 4)
+ outval |= LINE_LED;
+ }
+ break;
+ case 1:
+ if (!stat)
+ outval |= LINE_LED;
+ else if (stat == 1)
+ outval |= LINE_LED | STAT_LED;
+ else {
+ if (stat & 2)
+ outval |= STAT_LED;
+ if (stat & 4)
+ outval |= LINE_LED;
+ }
+ break;
+ case 2:
+ if (!stat)
+ outval |= STAT_LED;
+ else if (stat == 1)
+ outval |= 0;
+ else {
+ if (stat & 2)
+ outval |= STAT_LED;
+ if (stat & 4)
+ outval |= LINE_LED;
+ }
+ break;
+ case 3:
+ if (!stat)
+ outval |= LINE_LED;
+ break;
+ }
+ byteout(sp->cfg_reg + CARD_CONTROL, outval);
+}
+#endif
+
+static inline void
+waitforCEC(int adr, int hscx)
+{
+ int to = 50;
+
+ while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "Elsa: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr, int hscx)
+{
+ int to = 50;
+
+ while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "Elsa: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, int hscx, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ waitforCEC(adr, hscx);
+ writehscx(adr, hscx, HSCX_CMDR, data);
+ restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+ printk(KERN_DEBUG "HSCX %d\n", hscx);
+ printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->cfg_reg, hscx, HSCX_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->cfg_reg, hscx, HSCX_EXIR));
+}
+
+void
+elsa_report(struct IsdnCardState *sp)
+{
+ printk(KERN_DEBUG "ISAC\n");
+ printk(KERN_DEBUG "ISTA %x\n", readisac(sp->cfg_reg, ISAC_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", readisac(sp->cfg_reg, ISAC_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", readisac(sp->cfg_reg, ISAC_EXIR));
+ hscxreport(sp, 0);
+ hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+ u_char *ptr;
+ struct IsdnCardState *sp = hsp->sp;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_empty_fifo");
+
+ if (hsp->rcvidx + count > HSCX_BUFMAX) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+ writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+ hsp->rcvidx = 0;
+ return;
+ }
+ ptr = hsp->rcvbuf + hsp->rcvidx;
+ hsp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ read_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
+ writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+ struct IsdnCardState *sp = hsp->sp;
+ int more, count;
+ u_char *ptr;
+ long flags;
+
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_fill_fifo");
+
+ if (!hsp->tx_skb)
+ return;
+ if (hsp->tx_skb->len <= 0)
+ return;
+
+ more = (hsp->mode == 1) ? 1 : 0;
+ if (hsp->tx_skb->len > 32) {
+ more = !0;
+ count = 32;
+ } else
+ count = hsp->tx_skb->len;
+
+ waitforXFW(sp->cfg_reg, hsp->hscx);
+ save_flags(flags);
+ cli();
+ ptr = hsp->tx_skb->data;
+ skb_pull(hsp->tx_skb, count);
+ hsp->tx_cnt -= count;
+ hsp->count += count;
+ write_fifo_hscx(sp->cfg_reg, hsp->hscx, ptr, count);
+ writehscxCMDR(sp->cfg_reg, hsp->hscx, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+ u_char r;
+ struct HscxState *hsp = sp->hs + hscx;
+ struct sk_buff *skb;
+ int count;
+ char tmp[32];
+
+ if (!hsp->init)
+ return;
+
+ if (val & 0x80) { /* RME */
+
+ r = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RSTA);
+ if ((r & 0xf0) != 0xa0) {
+ if (!r & 0x80)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX invalid frame");
+ if ((r & 0x40) && hsp->mode)
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX RDO mode=%d",
+ hsp->mode);
+ debugl1(sp, tmp);
+ }
+ if (!r & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX CRC error");
+ writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x80);
+ } else {
+ count = readhscx(sp->cfg_reg, hsp->hscx, HSCX_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ hscx_empty_fifo(hsp, count);
+ if ((count = hsp->rcvidx - 1) > 0) {
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ sprintf(tmp, "HX Frame %d", count);
+ debugl1(sp, tmp);
+ }
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "Elsa: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ }
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ hscx_empty_fifo(hsp, 32);
+ if (hsp->mode == 1) {
+ /* receive audio data */
+ if (!(skb = dev_alloc_skb(32)))
+ printk(KERN_WARNING "elsa: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ }
+ if (val & 0x10) { /* XPR */
+ if (hsp->tx_skb)
+ if (hsp->tx_skb->len) {
+ hscx_fill_fifo(hsp);
+ return;
+ } else {
+ dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+ hsp->count = 0;
+ if (hsp->st->l4.l1writewakeup)
+ hsp->st->l4.l1writewakeup(hsp->st);
+ hsp->tx_skb = NULL;
+ }
+ if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+ hsp->count = 0;
+ hscx_fill_fifo(hsp);
+ } else
+ hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+ }
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ debugl1(sp, "isac_empty_fifo");
+
+ if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+ if (sp->debug & L1_DEB_WARN) {
+ char tmp[40];
+ sprintf(tmp, "isac_empty_fifo overrun %d",
+ sp->rcvidx + count);
+ debugl1(sp, tmp);
+ }
+ writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+ sp->rcvidx = 0;
+ return;
+ }
+ ptr = sp->rcvbuf + sp->rcvidx;
+ sp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ read_fifo_isac(sp->cfg_reg, ptr, count);
+ writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_empty_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+ int count, more;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ debugl1(sp, "isac_fill_fifo");
+
+ if (!sp->tx_skb)
+ return;
+
+ count = sp->tx_skb->len;
+ if (count <= 0)
+ return;
+
+ more = 0;
+ if (count > 32) {
+ more = !0;
+ count = 32;
+ }
+ save_flags(flags);
+ cli();
+ ptr = sp->tx_skb->data;
+ skb_pull(sp->tx_skb, count);
+ sp->tx_cnt += count;
+ write_fifo_isac(sp->cfg_reg, ptr, count);
+ writeisac(sp->cfg_reg, ISAC_CMDR, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_fill_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+ if (sp->debug & L1_DEB_ISAC) {
+ char tmp[32];
+ sprintf(tmp, "ph_command %d", command);
+ debugl1(sp, tmp);
+ }
+ writeisac(sp->cfg_reg, ISAC_CIX0, (command << 2) | 3);
+}
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+ u_char exval, v1;
+ struct sk_buff *skb;
+ unsigned int count;
+ char tmp[32];
+#if ARCOFI_USE
+ struct BufHeader *ibh;
+ u_char *ptr;
+#endif
+
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "ISAC interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ if (val & 0x80) { /* RME */
+ exval = readisac(sp->cfg_reg, ISAC_RSTA);
+ if ((exval & 0x70) != 0x20) {
+ if (exval & 0x40)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RDO");
+ if (!exval & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC CRC error");
+ writeisac(sp->cfg_reg, ISAC_CMDR, 0x80);
+ } else {
+ count = readisac(sp->cfg_reg, ISAC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(sp, count);
+ if ((count = sp->rcvidx) > 0) {
+ sp->rcvidx = 0;
+ if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+ printk(KERN_WARNING "Elsa: D receive out of memory\n");
+ else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, count), sp->rcvbuf, count);
+ skb_queue_tail(&sp->rq, skb);
+ }
+ }
+ }
+ sp->rcvidx = 0;
+ isac_sched_event(sp, ISAC_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ isac_empty_fifo(sp, 32);
+ }
+ if (val & 0x20) { /* RSC */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RSC interrupt");
+ }
+ if (val & 0x10) { /* XPR */
+ if (sp->tx_skb)
+ if (sp->tx_skb->len) {
+ isac_fill_fifo(sp);
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+ sp->tx_cnt = 0;
+ sp->tx_skb = NULL;
+ }
+ if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+ sp->tx_cnt = 0;
+ isac_fill_fifo(sp);
+ } else
+ isac_sched_event(sp, ISAC_XMTBUFREADY);
+ }
+ afterXPR:
+ if (val & 0x04) { /* CISQ */
+ sp->ph_state = (readisac(sp->cfg_reg, ISAC_CIX0) >> 2)
+ & 0xf;
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "l1state %d", sp->ph_state);
+ debugl1(sp, tmp);
+ }
+ isac_new_ph(sp);
+ }
+ if (val & 0x02) { /* SIN */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC SIN interrupt");
+ }
+ if (val & 0x01) { /* EXI */
+ exval = readisac(sp->cfg_reg, ISAC_EXIR);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC EXIR %02x", exval);
+ debugl1(sp, tmp);
+ }
+ if (exval & 0x08) {
+ v1 = readisac(sp->cfg_reg, ISAC_MOSR);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC MOSR %02x", v1);
+ debugl1(sp, tmp);
+ }
+#if ARCOFI_USE
+ if (v1 & 0x08) {
+ if (!sp->mon_rx)
+ if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
+ GFP_ATOMIC, (void *) 1, 3)) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC MON RX out of buffers!");
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+ goto afterMONR0;
+ } else
+ sp->mon_rxp = 0;
+ ibh = sp->mon_rx;
+ ptr = DATAPTR(ibh);
+ ptr += sp->mon_rxp;
+ sp->mon_rxp++;
+ if (sp->mon_rxp >= 3072) {
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+ sp->mon_rxp = 0;
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC MON RX overflow!");
+ goto afterMONR0;
+ }
+ *ptr = readisac(sp->cfg_reg, ISAC_MOR0);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC MOR0 %02x", *ptr);
+ debugl1(sp, tmp);
+ }
+ }
+ afterMONR0:
+ if (v1 & 0x80) {
+ if (!sp->mon_rx)
+ if (BufPoolGet(&(sp->mon_rx), &(sp->rbufpool),
+ GFP_ATOMIC, (void *) 1, 3)) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC MON RX out of buffers!");
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+ goto afterMONR1;
+ } else
+ sp->mon_rxp = 0;
+ ibh = sp->mon_rx;
+ ptr = DATAPTR(ibh);
+ ptr += sp->mon_rxp;
+ sp->mon_rxp++;
+ if (sp->mon_rxp >= 3072) {
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+ sp->mon_rxp = 0;
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC MON RX overflow!");
+ goto afterMONR1;
+ }
+ *ptr = readisac(sp->cfg_reg, ISAC_MOR1);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC MOR1 %02x", *ptr);
+ debugl1(sp, tmp);
+ }
+ }
+ afterMONR1:
+ if (v1 & 0x04) {
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+ sp->mon_rx->datasize = sp->mon_rxp;
+ sp->mon_flg |= MON0_RX;
+ }
+ if (v1 & 0x40) {
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+ sp->mon_rx->datasize = sp->mon_rxp;
+ sp->mon_flg |= MON1_RX;
+ }
+ if (v1 == 0x02) {
+ ibh = sp->mon_tx;
+ if (!ibh) {
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0x0a);
+ goto AfterMOX0;
+ }
+ count = ibh->datasize - sp->mon_txp;
+ if (count <= 0) {
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0x0f);
+ BufPoolRelease(sp->mon_tx);
+ sp->mon_tx = NULL;
+ sp->mon_txp = 0;
+ sp->mon_flg |= MON0_TX;
+ goto AfterMOX0;
+ }
+ ptr = DATAPTR(ibh);
+ ptr += sp->mon_txp;
+ sp->mon_txp++;
+ writeisac(sp->cfg_reg, ISAC_MOX0, *ptr);
+ }
+ AfterMOX0:
+ if (v1 == 0x20) {
+ ibh = sp->mon_tx;
+ if (!ibh) {
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+ goto AfterMOX1;
+ }
+ count = ibh->datasize - sp->mon_txp;
+ if (count <= 0) {
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0xf0);
+ BufPoolRelease(sp->mon_tx);
+ sp->mon_tx = NULL;
+ sp->mon_txp = 0;
+ sp->mon_flg |= MON1_TX;
+ goto AfterMOX1;
+ }
+ ptr = DATAPTR(ibh);
+ ptr += sp->mon_txp;
+ sp->mon_txp++;
+ writeisac(sp->cfg_reg, ISAC_MOX1, *ptr);
+ }
+ AfterMOX1:
+#endif
+ }
+ }
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+ u_char exval;
+ struct HscxState *hsp;
+ char tmp[32];
+
+ if (val & 0x01) {
+ hsp = sp->hs + 1;
+ exval = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0xf8) {
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, val, 1);
+ }
+ if (val & 0x02) {
+ hsp = sp->hs;
+ exval = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->cfg_reg, hsp->hscx, 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0x04) {
+ exval = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A interrupt %x", exval);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, exval, 0);
+ }
+}
+
+static void
+elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *sp;
+ u_char val;
+
+ sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+ if (!sp) {
+ printk(KERN_WARNING "Elsa: Spurious interrupt!\n");
+ return;
+ }
+#ifdef CONFIG_HISAX_ELSA_PCC
+ INT_RESTART:
+ if (!TimerRun(sp)) {
+ /* Timer Restart */
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+ if (!(sp->counter++ & 0x3f)) {
+ /* Call LEDs all 64 tics */
+ elsa_led_handler(sp);
+ }
+ }
+#endif
+ val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+ Start_HSCX:
+ if (val) {
+ hscx_int_main(sp, val);
+ }
+ val = readisac(sp->cfg_reg, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(sp, val);
+ }
+#ifdef CONFIG_HISAX_ELSA_PCC
+ if (!TimerRun(sp))
+ goto INT_RESTART;
+#endif
+ val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+ if (val) {
+ if (sp->debug & L1_DEB_HSCX)
+ debugl1(sp, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = readisac(sp->cfg_reg, ISAC_ISTA);
+ if (val) {
+ if (sp->debug & L1_DEB_ISAC)
+ debugl1(sp, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
+ writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
+ writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
+#ifdef CONFIG_HISAX_ELSA_PCC
+ if (sp->subtyp == ELSA_QS1000) {
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+ byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+ }
+#endif
+ writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
+ writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
+ writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+ unsigned int adr = sp->cfg_reg;
+
+ /* Elsa IOM 2 Mode */
+ writeisac(adr, ISAC_MASK, 0xff);
+ writeisac(adr, ISAC_ADF2, 0x80);
+ writeisac(adr, ISAC_SQXR, 0x2f);
+ writeisac(adr, ISAC_SPCR, 0x00);
+ writeisac(adr, ISAC_STCR, 0x70);
+ writeisac(adr, ISAC_MODE, 0xc9);
+ writeisac(adr, ISAC_TIMR, 0x00);
+ writeisac(adr, ISAC_ADF1, 0x00);
+ writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
+ writeisac(adr, ISAC_MASK, 0xff);
+ writeisac(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+ struct IsdnCardState *sp = hs->sp;
+ int hscx = hs->hscx;
+
+ if (sp->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "hscx %c mode %d ichan %d",
+ 'A' + hscx, mode, ichan);
+ debugl1(sp, tmp);
+ }
+ hs->mode = mode;
+ writehscx(sp->cfg_reg, hscx, HSCX_CCR1, 0x85);
+ writehscx(sp->cfg_reg, hscx, HSCX_XAD1, 0xFF);
+ writehscx(sp->cfg_reg, hscx, HSCX_XAD2, 0xFF);
+ writehscx(sp->cfg_reg, hscx, HSCX_RAH2, 0xFF);
+ writehscx(sp->cfg_reg, hscx, HSCX_XBCH, 0x0);
+ writehscx(sp->cfg_reg, hscx, HSCX_RLCR, 0x0);
+ writehscx(sp->cfg_reg, hscx, HSCX_CCR2, 0x30);
+
+ switch (mode) {
+ case (0):
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0xff);
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0xff);
+ writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+ writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+ writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x84);
+ break;
+ case (1):
+ if (ichan == 0) {
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
+ } else {
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
+ }
+ writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+ writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+ writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0xe4);
+ writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
+ break;
+ case (2):
+ if (ichan == 0) {
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x2f);
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x2f);
+ } else {
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAX, 0x3);
+ writehscx(sp->cfg_reg, hscx, HSCX_TSAR, 0x3);
+ }
+ writehscx(sp->cfg_reg, hscx, HSCX_XCCR, 7);
+ writehscx(sp->cfg_reg, hscx, HSCX_RCCR, 7);
+ writehscx(sp->cfg_reg, hscx, HSCX_MODE, 0x8c);
+ writehscx(sp->cfg_reg, hscx, HSCX_CMDR, 0x41);
+ break;
+ }
+ writehscx(sp->cfg_reg, hscx, HSCX_ISTA, 0x00);
+}
+
+void
+release_io_elsa(struct IsdnCard *card)
+{
+ int bytecnt = 8;
+
+ if (card->sp->subtyp == ELSA_PCFPRO)
+ bytecnt = 16;
+ if (card->sp->cfg_reg)
+ release_region(card->sp->cfg_reg, bytecnt);
+}
+
+static void
+reset_elsa(struct IsdnCardState *sp)
+{
+#ifdef CONFIG_HISAX_ELSA_PCC
+ /* Wait 1 Timer */
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+ while (TimerRun(sp));
+ byteout(sp->cfg_reg + CARD_CONTROL, 0x00); /* Reset On */
+ /* Wait 1 Timer */
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+ while (TimerRun(sp));
+ byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET); /* Reset Off */
+ /* Wait 1 Timer */
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+ while (TimerRun(sp));
+ byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+#endif
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+ int val;
+ char tmp[64];
+
+ val = readhscx(sp->cfg_reg, 1, HSCX_ISTA);
+ sprintf(tmp, "HSCX B ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = readhscx(sp->cfg_reg, 1, HSCX_EXIR);
+ sprintf(tmp, "HSCX B EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x02) {
+ val = readhscx(sp->cfg_reg, 0, HSCX_EXIR);
+ sprintf(tmp, "HSCX A EXIR %x", val);
+ debugl1(sp, tmp);
+ }
+ val = readhscx(sp->cfg_reg, 0, HSCX_ISTA);
+ sprintf(tmp, "HSCX A ISTA %x", val);
+ debugl1(sp, tmp);
+ val = readhscx(sp->cfg_reg, 1, HSCX_STAR);
+ sprintf(tmp, "HSCX B STAR %x", val);
+ debugl1(sp, tmp);
+ val = readhscx(sp->cfg_reg, 0, HSCX_STAR);
+ sprintf(tmp, "HSCX A STAR %x", val);
+ debugl1(sp, tmp);
+ val = readisac(sp->cfg_reg, ISAC_STAR);
+ sprintf(tmp, "ISAC STAR %x", val);
+ debugl1(sp, tmp);
+ val = readisac(sp->cfg_reg, ISAC_MODE);
+ sprintf(tmp, "ISAC MODE %x", val);
+ debugl1(sp, tmp);
+ val = readisac(sp->cfg_reg, ISAC_ADF2);
+ sprintf(tmp, "ISAC ADF2 %x", val);
+ debugl1(sp, tmp);
+ val = readisac(sp->cfg_reg, ISAC_ISTA);
+ sprintf(tmp, "ISAC ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = readisac(sp->cfg_reg, ISAC_EXIR);
+ sprintf(tmp, "ISAC EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x04) {
+ val = readisac(sp->cfg_reg, ISAC_CIR0);
+ sprintf(tmp, "ISAC CIR0 %x", val);
+ debugl1(sp, tmp);
+ }
+#endif
+ writehscx(sp->cfg_reg, 0, HSCX_MASK, 0xFF);
+ writehscx(sp->cfg_reg, 1, HSCX_MASK, 0xFF);
+ writeisac(sp->cfg_reg, ISAC_MASK, 0xFF);
+#ifdef CONFIG_HISAX_ELSA_PCC
+ if (sp->subtyp == ELSA_QS1000) {
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+ byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+ }
+#endif
+ writehscx(sp->cfg_reg, 0, HSCX_MASK, 0x0);
+ writehscx(sp->cfg_reg, 1, HSCX_MASK, 0x0);
+ writeisac(sp->cfg_reg, ISAC_MASK, 0x0);
+ writeisac(sp->cfg_reg, ISAC_CMDR, 0x41);
+}
+
+static void
+check_arcofi(struct IsdnCardState *sp)
+{
+#if 0
+ u_char val;
+ char tmp[40];
+ char *t;
+ long flags;
+ u_char *p;
+
+ if (BufPoolGet(&(sp->mon_tx), &(sp->sbufpool),
+ GFP_ATOMIC, (void *) 1, 3)) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC MON TX out of buffers!");
+ return;
+ } else
+ sp->mon_txp = 0;
+ p = DATAPTR(sp->mon_tx);
+ *p++ = 0xa0;
+ *p++ = 0x0;
+ sp->mon_tx->datasize = 2;
+ sp->mon_txp = 1;
+ sp->mon_flg = 0;
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0xa0);
+ val = readisac(sp->cfg_reg, ISAC_MOSR);
+ writeisac(sp->cfg_reg, ISAC_MOX1, 0xa0);
+ writeisac(sp->cfg_reg, ISAC_MOCR, 0xb0);
+ save_flags(flags);
+ sti();
+ HZDELAY(3);
+ restore_flags(flags);
+ if (sp->mon_flg & MON1_TX) {
+ if (sp->mon_flg & MON1_RX) {
+ sprintf(tmp, "Arcofi response received %d bytes", sp->mon_rx->datasize);
+ debugl1(sp, tmp);
+ p = DATAPTR(sp->mon_rx);
+ t = tmp;
+ t += sprintf(tmp, "Arcofi data");
+ QuickHex(t, p, sp->mon_rx->datasize);
+ debugl1(sp, tmp);
+ BufPoolRelease(sp->mon_rx);
+ sp->mon_rx = NULL;
+ sp->mon_rxp = 0;
+ sp->mon_flg = 0;
+ }
+ } else if (sp->mon_tx) {
+ BufPoolRelease(sp->mon_tx);
+ sp->mon_tx = NULL;
+ sp->mon_txp = 0;
+ sprintf(tmp, "Arcofi not detected");
+ debugl1(sp, tmp);
+ }
+ sp->mon_flg = 0;
+#endif
+}
+
+int
+initelsa(struct IsdnCardState *sp)
+{
+ int ret, irq_cnt, cnt = 3;
+ long flags;
+
+ irq_cnt = kstat.interrupts[sp->irq];
+ printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, irq_cnt);
+ ret = get_irq(sp->cardnr, &elsa_interrupt);
+#ifdef CONFIG_HISAX_ELSA_PCC
+ byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+#endif
+ while (ret && cnt) {
+ sp->counter = 0;
+ clear_pending_ints(sp);
+ initisac(sp);
+ sp->modehscx(sp->hs, 0, 0);
+ sp->modehscx(sp->hs + 1, 0, 0);
+ save_flags(flags);
+ sp->counter = 0;
+ sti();
+#ifdef CONFIG_HISAX_ELSA_PCC
+ byteout(sp->cfg_reg + CARD_CONTROL, ISDN_RESET | ENABLE_TIM_INT);
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + (110 * HZ) / 1000; /* Timeout 110ms */
+ schedule();
+ restore_flags(flags);
+ printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
+ sp->counter);
+ if (abs(sp->counter - 13) < 3) {
+ printk(KERN_INFO "Elsa: timer and irq OK\n");
+ } else {
+ printk(KERN_WARNING
+ "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n",
+ sp->counter, sp->irq);
+ }
+#endif
+ printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq,
+ kstat.interrupts[sp->irq]);
+ if (kstat.interrupts[sp->irq] == irq_cnt) {
+ printk(KERN_WARNING
+ "Elsa: IRQ(%d) getting no interrupts during init %d\n",
+ sp->irq, 4 - cnt);
+ if (cnt == 1) {
+ irq2dev_map[sp->irq] = NULL;
+ free_irq(sp->irq, NULL);
+ return (0);
+ } else {
+ reset_elsa(sp);
+ cnt--;
+ }
+ } else {
+ check_arcofi(sp);
+ cnt = 0;
+ }
+ }
+ sp->counter = 0;
+ return (ret);
+}
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+static unsigned char
+probe_elsa_adr(unsigned int adr)
+{
+ int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0,
+ pc_2 = 0, pfp_1 = 0, pfp_2 = 0;
+ long flags;
+
+ if (check_region(adr, 8)) {
+ printk(KERN_WARNING
+ "Elsa: Probing Port 0x%x: already in use\n",
+ adr);
+ return (0);
+ }
+ save_flags(flags);
+ cli();
+ for (i = 0; i < 16; i++) {
+ in1 = inb(adr + CARD_CONFIG); /* 'toggelt' bei */
+ in2 = inb(adr + CARD_CONFIG); /* jedem Zugriff */
+ p16_1 += 0x04 & in1;
+ p16_2 += 0x04 & in2;
+ p8_1 += 0x02 & in1;
+ p8_2 += 0x02 & in2;
+ pc_1 += 0x01 & in1;
+ pc_2 += 0x01 & in2;
+ pfp_1 += 0x40 & in1;
+ pfp_2 += 0x40 & in2;
+ }
+ restore_flags(flags);
+ printk(KERN_INFO "Elsa: Probing IO 0x%x", adr);
+ if (65 == ++p16_1 * ++p16_2) {
+ printk(" PCC-16/PCF found\n");
+ return (ELSA_PCC16);
+ } else if (1025 == ++pfp_1 * ++pfp_2) {
+ printk(" PCF-Pro found\n");
+ return (ELSA_PCFPRO);
+ } else if (33 == ++p8_1 * ++p8_2) {
+ printk(" PCC8 found\n");
+ return (ELSA_PCC8);
+ } else if (17 == ++pc_1 * ++pc_2) {
+ printk(" PC found\n");
+ return (ELSA_PC);
+ } else {
+ printk(" failed\n");
+ return (0);
+ }
+}
+
+static unsigned int
+probe_elsa(struct IsdnCardState *sp)
+{
+ int i;
+ unsigned int CARD_portlist[] =
+ {0x160, 0x170, 0x260, 0x360, 0};
+
+ for (i = 0; CARD_portlist[i]; i++) {
+ if ((sp->subtyp = probe_elsa_adr(CARD_portlist[i])))
+ break;
+ }
+ return (CARD_portlist[i]);
+}
+#endif
+
+int
+setup_elsa(struct IsdnCard *card)
+{
+#ifdef CONFIG_HISAX_ELSA_PCC
+ long flags;
+#endif
+ int bytecnt;
+ u_char val, verA, verB;
+ struct IsdnCardState *sp = card->sp;
+ char tmp[64];
+
+ strcpy(tmp, Elsa_revision);
+ printk(KERN_NOTICE "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+#ifdef CONFIG_HISAX_ELSA_PCC
+ if (sp->typ == ISDN_CTYPE_ELSA) {
+ sp->cfg_reg = card->para[0];
+ printk(KERN_INFO "Elsa: Microlink IO probing\n");
+ if (sp->cfg_reg) {
+ if (!(sp->subtyp = probe_elsa_adr(sp->cfg_reg))) {
+ printk(KERN_WARNING
+ "Elsa: no Elsa Microlink at 0x%x\n",
+ sp->cfg_reg);
+ return (0);
+ }
+ } else
+ sp->cfg_reg = probe_elsa(sp);
+ if (sp->cfg_reg) {
+ val = bytein(sp->cfg_reg + CARD_CONFIG);
+ if (sp->subtyp == ELSA_PC) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PC) >> 2];
+ } else if (sp->subtyp == ELSA_PCC8) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ sp->irq = CARD_IrqTab[(val & IRQ_INDEX_PCC8) >> 4];
+ } else {
+ const u_char CARD_IrqTab[8] =
+ {15, 10, 15, 3, 11, 5, 11, 9};
+ sp->irq = CARD_IrqTab[(val & IRQ_INDEX) >> 3];
+ }
+ val = bytein(sp->cfg_reg + CARD_ALE) & 0x7;
+ if (val < 3)
+ val |= 8;
+ val += 'A' - 3;
+ if (val == 'B' || val == 'C')
+ val ^= 1;
+ if ((sp->subtyp == ELSA_PCFPRO) && (val = 'G'))
+ val = 'C';
+ printk(KERN_INFO
+ "Elsa: %s found at 0x%x Rev.:%c IRQ %d\n",
+ Elsa_Types[sp->subtyp],
+ sp->cfg_reg,
+ val, sp->irq);
+ val = bytein(sp->cfg_reg + CARD_ALE) & 0x08;
+ if (val)
+ printk(KERN_WARNING
+ "Elsa: Microlink S0 bus power bad\n");
+ } else {
+ printk(KERN_WARNING
+ "No Elsa Microlink found\n");
+ return (0);
+ }
+ } else if (sp->typ == ISDN_CTYPE_ELSA_QS1000) {
+ sp->cfg_reg = card->para[1];
+ sp->irq = card->para[0];
+ sp->subtyp = ELSA_QS1000;
+ printk(KERN_INFO
+ "Elsa: %s found at 0x%x IRQ %d\n",
+ Elsa_Types[sp->subtyp],
+ sp->cfg_reg,
+ sp->irq);
+ } else
+ return (0);
+#endif
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+ if (sp->typ == ISDN_CTYPE_ELSA_QS1000) {
+ sp->cfg_reg = card->para[1];
+ sp->irq = card->para[0];
+ sp->subtyp = ELSA_PCMCIA;
+ printk(KERN_INFO
+ "Elsa: %s found at 0x%x IRQ %d\n",
+ Elsa_Types[sp->subtyp],
+ sp->cfg_reg,
+ sp->irq);
+ } else
+ return (0);
+#endif
+
+ switch (sp->subtyp) {
+ case ELSA_PC:
+ bytecnt = 8;
+ break;
+ case ELSA_PCC8:
+ bytecnt = 8;
+ break;
+ case ELSA_PCFPRO:
+ bytecnt = 16;
+ break;
+ case ELSA_PCC16:
+ bytecnt = 8;
+ break;
+ case ELSA_PCF:
+ bytecnt = 16;
+ break;
+ case ELSA_QS1000:
+ bytecnt = 8;
+ break;
+ case ELSA_PCMCIA:
+ bytecnt = 8;
+ break;
+ default:
+ printk(KERN_WARNING
+ "Unknown ELSA subtype %d\n", sp->subtyp);
+ return (0);
+ }
+
+ if (check_region((sp->cfg_reg), bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ sp->cfg_reg,
+ sp->cfg_reg + bytecnt);
+ return (0);
+ } else {
+ request_region(sp->cfg_reg, bytecnt, "elsa isdn");
+ }
+
+ /* Teste Timer */
+#ifdef CONFIG_HISAX_ELSA_PCC
+ byteout(sp->cfg_reg + CARD_TRIG_IRQ, 0xff);
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0);
+ if (!TimerRun(sp)) {
+ byteout(sp->cfg_reg + CARD_START_TIMER, 0); /* 2. Versuch */
+ if (!TimerRun(sp)) {
+ printk(KERN_WARNING
+ "Elsa: timer do not start\n");
+ release_io_elsa(card);
+ return (0);
+ }
+ }
+ save_flags(flags);
+ sti();
+ HZDELAY(1); /* wait >=10 ms */
+ restore_flags(flags);
+ if (TimerRun(sp)) {
+ printk(KERN_WARNING "Elsa: timer do not run down\n");
+ release_io_elsa(card);
+ return (0);
+ }
+ printk(KERN_INFO "Elsa: timer OK; resetting card\n");
+ reset_elsa(sp);
+#endif
+ verA = readhscx(sp->cfg_reg, 0, HSCX_VSTR) & 0xf;
+ verB = readhscx(sp->cfg_reg, 1, HSCX_VSTR) & 0xf;
+ printk(KERN_INFO "Elsa: HSCX version A: %s B: %s\n",
+ HscxVersion(verA), HscxVersion(verB));
+ val = readisac(sp->cfg_reg, ISAC_RBCH);
+ printk(KERN_INFO "Elsa: ISAC %s\n",
+ ISACVersion(val));
+
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+ if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ printk(KERN_WARNING
+ "Elsa: wrong HSCX versions check IO address\n");
+ release_io_elsa(card);
+ return (0);
+ }
+#endif
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+ if (sp->subtyp == ELSA_PC) {
+ val = readitac(sp->cfg_reg, ITAC_SYS);
+ printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]);
+ writeitac(sp->cfg_reg, ITAC_ISEN, 0);
+ writeitac(sp->cfg_reg, ITAC_RFIE, 0);
+ writeitac(sp->cfg_reg, ITAC_XFIE, 0);
+ writeitac(sp->cfg_reg, ITAC_SCIE, 0);
+ writeitac(sp->cfg_reg, ITAC_STIE, 0);
+ }
+#endif
+ sp->modehscx = &modehscx;
+ sp->ph_command = &ph_command;
+ sp->hscx_fill_fifo = &hscx_fill_fifo;
+ sp->isac_fill_fifo = &isac_fill_fifo;
+
+ return (1);
+}
--- /dev/null
+/* $Id: elsa.h,v 1.6 1997/03/23 21:45:48 keil Exp $
+ *
+ * elsa.h Header for Elsa ISDN cards
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Elsa GmbH for documents and informations
+ *
+ *
+ * $Log: elsa.h,v $
+ * Revision 1.6 1997/03/23 21:45:48 keil
+ * Add support for ELSA PCMCIA
+ *
+ * Revision 1.5 1997/03/04 15:58:13 keil
+ * ELSA PC changes, some stuff for new cards
+ *
+ * Revision 1.4 1997/01/21 22:21:05 keil
+ * Elsa Quickstep support
+ *
+ * Revision 1.3 1996/12/08 19:47:38 keil
+ * ARCOFI support
+ *
+ * Revision 1.2 1996/11/18 15:33:35 keil
+ * PCC and PCFPro support
+ *
+ * Revision 1.1 1996/10/13 20:03:45 keil
+ * Initial revision
+ *
+ *
+*/
+#include <linux/config.h>
+
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+#define CARD_ISAC 1
+#define CARD_HSCX 2
+#define CARD_ALE 4
+#else
+#define CARD_ISAC 0
+#define CARD_ITAC 1
+#define CARD_HSCX 2
+#define CARD_ALE 3
+#define CARD_CONTROL 4
+#define CARD_CONFIG 5
+#define CARD_START_TIMER 6
+#define CARD_TRIG_IRQ 7
+#endif
+
+#define ELSA_PC 1
+#define ELSA_PCC8 2
+#define ELSA_PCC16 3
+#define ELSA_PCF 4
+#define ELSA_PCFPRO 5
+#define ELSA_PCMCIA 6
+#define ELSA_QS1000 7
+#define ELSA_QS3000 8
+
+/* ITAC Registeradressen (only Microlink PC) */
+#define ITAC_SYS 0x34
+#define ITAC_ISEN 0x48
+#define ITAC_RFIE 0x4A
+#define ITAC_XFIE 0x4C
+#define ITAC_SCIE 0x4E
+#define ITAC_STIE 0x46
+
+/*** ***
+ *** Makros als Befehle fuer die Kartenregister ***
+ *** (mehrere Befehle werden durch Bit-Oderung kombiniert) ***
+ *** ***/
+
+/* Config-Register (Read) */
+#define TIMER_RUN 0x02 /* Bit 1 des Config-Reg */
+#define TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */
+#define IRQ_INDEX 0x38 /* Bit 3,4,5 des Config-Reg */
+#define IRQ_INDEX_PCC8 0x30 /* Bit 4,5 des Config-Reg */
+#define IRQ_INDEX_PC 0x0c /* Bit 2,3 des Config-Reg */
+
+/* Control-Register (Write) */
+#define LINE_LED 0x02 /* Bit 1 Gelbe LED */
+#define STAT_LED 0x08 /* Bit 3 Gruene LED */
+#define ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */
+#define ENABLE_TIM_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */
+
+/* ALE-Register (Read) */
+#define HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */
+#define S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */
+
+extern void elsa_report(struct IsdnCardState *sp);
+extern void release_io_elsa(struct IsdnCard *card);
+extern int setup_elsa(struct IsdnCard *card);
+extern int initelsa(struct IsdnCardState *sp);
--- /dev/null
+/* $Id: fsm.c,v 1.4 1997/04/06 22:56:42 keil Exp $
+
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * based on the teles driver from Jan den Ouden
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ *
+ * $Log: fsm.c,v $
+ * Revision 1.4 1997/04/06 22:56:42 keil
+ * Some cosmetic changes
+ *
+ * Revision 1.3 1997/02/16 01:04:08 fritz
+ * Bugfix: Changed timer handling caused hang with 2.1.X
+ *
+ * Revision 1.2 1997/01/09 20:57:27 keil
+ * cleanup & FSM_TIMER_DEBUG
+ *
+ * Revision 1.1 1996/10/13 20:04:52 keil
+ * Initial revision
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+
+#define FSM_TIMER_DEBUG 0
+
+void
+FsmNew(struct Fsm *fsm,
+ struct FsmNode *fnlist, int fncount)
+{
+ int i;
+
+ fsm->jumpmatrix = (int *)
+ kmalloc(4L * fsm->state_count * fsm->event_count, GFP_KERNEL);
+ memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
+
+ for (i = 0; i < fncount; i++)
+ fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
+ fnlist[i].state] = (int) fnlist[i].routine;
+}
+
+void
+FsmFree(struct Fsm *fsm)
+{
+ kfree((void *) fsm->jumpmatrix);
+}
+
+int
+FsmEvent(struct FsmInst *fi, int event, void *arg)
+{
+ void (*r) (struct FsmInst *, int, void *);
+ char str[80];
+
+ r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
+ if (r) {
+ if (fi->debug) {
+ sprintf(str, "State %s Event %s",
+ fi->fsm->strState[fi->state],
+ fi->fsm->strEvent[event]);
+ fi->printdebug(fi, str);
+ }
+ r(fi, event, arg);
+ return (0);
+ } else {
+ if (fi->debug) {
+ sprintf(str, "State %s Event %s no routine",
+ fi->fsm->strState[fi->state],
+ fi->fsm->strEvent[event]);
+ fi->printdebug(fi, str);
+ }
+ return (!0);
+ }
+}
+
+void
+FsmChangeState(struct FsmInst *fi, int newstate)
+{
+ char str[80];
+
+ fi->state = newstate;
+ if (fi->debug) {
+ sprintf(str, "ChangeState %s",
+ fi->fsm->strState[newstate]);
+ fi->printdebug(fi, str);
+ }
+}
+
+static void
+FsmExpireTimer(struct FsmTimer *ft)
+{
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug) {
+ char str[40];
+ sprintf(str, "FsmExpireTimer %lx", (long) ft);
+ ft->fi->printdebug(ft->fi, str);
+ }
+#endif
+ FsmEvent(ft->fi, ft->event, ft->arg);
+}
+
+void
+FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
+{
+ ft->fi = fi;
+ ft->tl.function = (void *) FsmExpireTimer;
+ ft->tl.data = (long) ft;
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug) {
+ char str[40];
+ sprintf(str, "FsmInitTimer %lx", (long) ft);
+ ft->fi->printdebug(ft->fi, str);
+ }
+#endif
+ init_timer(&ft->tl);
+}
+
+void
+FsmDelTimer(struct FsmTimer *ft, int where)
+{
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug) {
+ char str[40];
+ sprintf(str, "FsmDelTimer %lx %d", (long) ft, where);
+ ft->fi->printdebug(ft->fi, str);
+ }
+#endif
+ del_timer(&ft->tl);
+}
+
+int
+FsmAddTimer(struct FsmTimer *ft,
+ int millisec, int event, void *arg, int where)
+{
+
+#if FSM_TIMER_DEBUG
+ if (ft->fi->debug) {
+ char str[40];
+ sprintf(str, "FsmAddTimer %lx %d %d", (long) ft, millisec, where);
+ ft->fi->printdebug(ft->fi, str);
+ }
+#endif
+
+ if (ft->tl.next || ft->tl.prev) {
+ printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
+ ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
+ return -1;
+ }
+ init_timer(&ft->tl);
+ ft->event = event;
+ ft->arg = arg;
+ ft->tl.expires = jiffies + (millisec * HZ) / 1000;
+ add_timer(&ft->tl);
+ return 0;
+}
+
+int
+FsmTimerRunning(struct FsmTimer *ft)
+{
+ return (ft->tl.next != NULL);
+}
+
+void
+jiftime(char *s, long mark)
+{
+ s += 8;
+
+ *s-- = '\0';
+ *s-- = mark % 10 + '0';
+ mark /= 10;
+ *s-- = mark % 10 + '0';
+ mark /= 10;
+ *s-- = '.';
+ *s-- = mark % 10 + '0';
+ mark /= 10;
+ *s-- = mark % 6 + '0';
+ mark /= 6;
+ *s-- = ':';
+ *s-- = mark % 10 + '0';
+ mark /= 10;
+ *s-- = mark % 10 + '0';
+}
--- /dev/null
+/* $Id: hisax.h,v 1.13 1997/04/06 22:54:12 keil Exp $
+
+ * Basic declarations, defines and prototypes
+ *
+ * $Log: hisax.h,v $
+ * Revision 1.13 1997/04/06 22:54:12 keil
+ * Using SKB's
+ *
+ * Revision 1.12 1997/03/23 21:45:45 keil
+ * Add support for ELSA PCMCIA
+ *
+ * Revision 1.11 1997/02/11 01:36:02 keil
+ * New Param structure
+ *
+ * Revision 1.10 1997/02/09 00:23:52 keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.9 1997/01/27 23:18:44 keil
+ * prototype for releasestack_isdnl3
+ *
+ * Revision 1.8 1997/01/27 16:02:37 keil
+ * new cards, callc timers, HZDELAY macro, HiSax_getrev prototype
+ *
+ * Revision 1.7 1997/01/21 22:22:14 keil
+ * changes for 2.0; Elsa Quickstep support
+ *
+ * Revision 1.6 1997/01/04 13:48:28 keil
+ * primitiv for MDL_REMOVE added
+ *
+ * Revision 1.5 1996/12/08 19:49:19 keil
+ * Monitor channel support
+ *
+ * Revision 1.4 1996/11/18 15:35:39 keil
+ * some changes for ELSA cards
+ *
+ * Revision 1.3 1996/11/05 19:37:23 keil
+ * using config.h
+ *
+ * Revision 1.2 1996/10/27 22:21:52 keil
+ * CallFlags for broadcast messages
+ *
+ * Revision 1.1 1996/10/13 20:03:46 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#include <linux/module.h>
+#include <linux/config.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/delay.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/isdnif.h>
+#include <linux/tty.h>
+
+#define PH_ACTIVATE 1
+#define PH_DATA 2
+#define PH_DEACTIVATE 3
+
+#define MDL_ASSIGN 4
+#define DL_UNIT_DATA 5
+#define SC_STARTUP 6
+#define CC_ESTABLISH 7
+#define DL_ESTABLISH 8
+#define DL_DATA 9
+#define CC_S_STATUS_ENQ 10
+
+#define CC_CONNECT 15
+#define CC_CONNECT_ACKNOWLEDGE 16
+#define CO_EOF 17
+#define SC_DISCONNECT 18
+#define CO_DTMF 19
+#define DL_RELEASE 20
+#define DL_FLUSH 21
+
+#define CO_ALARM 22
+#define CC_REJECT 23
+
+#define CC_SETUP_REQ 24
+#define CC_SETUP_CNF 25
+#define CC_SETUP_IND 26
+#define CC_SETUP_RSP 27
+#define CC_SETUP_COMPLETE_IND 28
+
+#define CC_DISCONNECT_REQ 29
+#define CC_DISCONNECT_IND 30
+
+#define CC_RELEASE_CNF 31
+#define CC_RELEASE_IND 32
+#define CC_RELEASE_REQ 33
+
+#define CC_REJECT_REQ 34
+
+#define CC_PROCEEDING_IND 35
+
+#define CC_DLRL 36
+#define CC_DLEST 37
+
+#define CC_ALERTING_REQ 38
+#define CC_ALERTING_IND 39
+
+#define DL_STOP 40
+#define DL_START 41
+
+#define MDL_NOTEIPROC 46
+
+#define LC_ESTABLISH 47
+#define LC_RELEASE 48
+
+#define PH_REQUEST_PULL 49
+#define PH_PULL_ACK 50
+#define PH_DATA_PULLED 51
+#define CC_INFO_CHARGE 52
+
+#define CC_MORE_INFO 53
+#define CC_IGNORE 54
+
+#define MDL_REMOVE 56
+#define MDL_VERIFY 57
+
+#define CC_T303 60
+#define CC_T304 61
+#define CC_T305 62
+#define CC_T308_1 64
+#define CC_T308_2 65
+#define CC_T310 66
+#define CC_T313 67
+#define CC_T318 68
+#define CC_T319 69
+
+#define CC_NOSETUP_RSP_ERR 70
+#define CC_SETUP_ERR 71
+#define CC_CONNECT_ERR 72
+#define CC_RELEASE_ERR 73
+
+/*
+ * Message-Types
+ */
+
+#define MT_ALERTING 0x01
+#define MT_CALL_PROCEEDING 0x02
+#define MT_CONNECT 0x07
+#define MT_CONNECT_ACKNOWLEDGE 0x0f
+#define MT_PROGRESS 0x03
+#define MT_SETUP 0x05
+#define MT_SETUP_ACKNOWLEDGE 0x0d
+#define MT_RESUME 0x26
+#define MT_RESUME_ACKNOWLEDGE 0x2e
+#define MT_RESUME_REJECT 0x22
+#define MT_SUSPEND 0x25
+#define MT_SUSPEND_ACKNOWLEDGE 0x2d
+#define MT_SUSPEND_REJECT 0x21
+#define MT_USER_INFORMATION 0x20
+#define MT_DISCONNECT 0x45
+#define MT_RELEASE 0x4d
+#define MT_RELEASE_COMPLETE 0x5a
+#define MT_RESTART 0x46
+#define MT_RESTART_ACKNOWLEDGE 0x4e
+#define MT_SEGMENT 0x60
+#define MT_CONGESTION_CONTROL 0x79
+#define MT_INFORMATION 0x7b
+#define MT_FACILITY 0x62
+#define MT_NOTIFY 0x6e
+#define MT_STATUS 0x7d
+#define MT_STATUS_ENQUIRY 0x75
+
+#define IE_CAUSE 0x08
+
+struct HscxIoctlArg {
+ int channel;
+ int mode;
+ int transbufsize;
+};
+
+#ifdef __KERNEL__
+
+#undef DEBUG_MAGIC
+
+#define MAX_DFRAME_LEN 3072
+#define HSCX_BUFMAX 4096
+#define MAX_DATA_SIZE (HSCX_BUFMAX - 4)
+#define MAX_DATA_MEM (HSCX_BUFMAX * 2)
+#define MAX_HEADER_LEN 4
+#define MAX_WINDOW 8
+
+/*
+ * Statemachine
+ */
+struct Fsm {
+ int *jumpmatrix;
+ int state_count, event_count;
+ char **strEvent, **strState;
+};
+
+struct FsmInst {
+ struct Fsm *fsm;
+ int state;
+ int debug;
+ void *userdata;
+ int userint;
+ void (*printdebug) (struct FsmInst *, char *);
+};
+
+struct FsmNode {
+ int state, event;
+ void (*routine) (struct FsmInst *, int, void *);
+};
+
+struct FsmTimer {
+ struct FsmInst *fi;
+ struct timer_list tl;
+ int event;
+ void *arg;
+};
+
+struct L3Timer {
+ struct PStack *st;
+ struct timer_list tl;
+ int event;
+};
+
+struct Layer1 {
+ void *hardware;
+ int hscx;
+ struct PStack **stlistp;
+ int act_state;
+ void (*l1l2) (struct PStack *, int, void *);
+ void (*l1man) (struct PStack *, int, void *);
+ int hscxmode, hscxchannel, requestpull;
+};
+
+struct Layer2 {
+ int sap, tei, ces;
+ int extended, laptype;
+ int uihsize, ihsize;
+ int vs, va, vr;
+ struct sk_buff_head i_queue;
+ int window, orig;
+ int rejexp;
+ int debug;
+ struct sk_buff *windowar[MAX_WINDOW];
+ int sow;
+ struct FsmInst l2m;
+ void (*l2l1) (struct PStack *, int, void *);
+ void (*l2l1discardq) (struct PStack *, int, void *, int);
+ void (*l2man) (struct PStack *, int, void *);
+ void (*l2l3) (struct PStack *, int, void *);
+ void (*l2tei) (struct PStack *, int, void *);
+ struct FsmTimer t200_timer, t203_timer;
+ int t200, n200, t203;
+ int rc, t200_running;
+ char debug_id[32];
+};
+
+struct Layer3 {
+ void (*l3l4) (struct PStack *, int, void *);
+ void (*l3l2) (struct PStack *, int, void *);
+ int state, callref;
+ struct L3Timer timer;
+ int t303, t304, t305, t308, t310, t313, t318, t319;
+ int n_t303;
+ int debug;
+ int channr;
+};
+
+struct Layer4 {
+ void (*l4l3) (struct PStack *, int, void *);
+ void *userdata;
+ void (*l1writewakeup) (struct PStack *);
+ void (*l2writewakeup) (struct PStack *);
+};
+
+struct Management {
+ void (*manl1) (struct PStack *, int, void *);
+ void (*manl2) (struct PStack *, int, void *);
+ void (*teil2) (struct PStack *, int, void *);
+};
+
+struct Param {
+ int cause;
+ int loc;
+ int bchannel;
+ int callref; /* Callreferenz Number */
+ setup_parm setup; /* from isdnif.h numbers and Serviceindicator */
+ int chargeinfo; /* Charge Info - only for 1tr6 in
+ * the moment
+ */
+ int spv; /* SPV Flag */
+};
+
+struct PStack {
+ struct PStack *next;
+ struct Layer1 l1;
+ struct Layer2 l2;
+ struct Layer3 l3;
+ struct Layer4 l4;
+ struct Management ma;
+ struct Param *pa;
+ int protocol; /* EDSS1 or 1TR6 */
+};
+
+struct HscxState {
+ int inuse, init, active;
+ struct IsdnCardState *sp;
+ int hscx, mode;
+ u_char *rcvbuf; /* B-Channel receive Buffer */
+ int rcvidx; /* B-Channel receive Buffer Index */
+ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
+ int tx_cnt; /* B-Channel transmit counter */
+ int count; /* Current skb sent count */
+ struct sk_buff_head rqueue; /* B-Channel receive Queue */
+ struct sk_buff_head squeue; /* B-Channel receive Queue */
+ struct PStack *st;
+ struct tq_struct tqueue;
+ int event;
+#ifdef DEBUG_MAGIC
+ int magic; /* 301270 */
+#endif
+};
+
+struct LcFsm {
+ struct FsmInst lcfi;
+ int type;
+ struct Channel *ch;
+ void (*lccall) (struct LcFsm *, int, void *);
+ struct PStack *st;
+ int l2_establish;
+ int l2_start;
+ struct FsmTimer act_timer;
+ char debug_id[32];
+};
+
+struct Channel {
+ struct PStack ds, is;
+ struct IsdnCardState *sp;
+ int hscx;
+ int chan;
+ int incoming;
+ struct FsmInst fi;
+ struct LcFsm lc_d, lc_b;
+ struct Param para;
+ struct FsmTimer drel_timer, dial_timer;
+ int debug;
+#ifdef DEBUG_MAGIC
+ int magic; /* 301272 */
+#endif
+ int l2_protocol, l2_active_protocol;
+ int l2_primitive, l2_headersize;
+ int data_open;
+ int outcallref;
+ int impair;
+ int Flags; /* for remembering action done in l4 */
+ int leased;
+};
+
+struct IsdnCardState {
+#ifdef DEBUG_MAGIC
+ int magic;
+#endif
+ unsigned char typ;
+ unsigned char subtyp;
+ int protocol;
+ unsigned int irq;
+ unsigned int cfg_reg;
+ unsigned int membase;
+ unsigned int isac;
+ unsigned int hscx[2];
+ unsigned int counter;
+ int myid;
+ isdn_if iif;
+ u_char *status_buf;
+ u_char *status_read;
+ u_char *status_write;
+ u_char *status_end;
+ void (*ph_command) (struct IsdnCardState *, unsigned int);
+ void (*modehscx) (struct HscxState *, int, int);
+ void (*hscx_fill_fifo) (struct HscxState *);
+ void (*isac_fill_fifo) (struct IsdnCardState *);
+ struct Channel channel[2];
+ struct PStack *stlist;
+ u_char *rcvbuf;
+ int rcvidx;
+ struct sk_buff *tx_skb;
+ int tx_cnt;
+ int event;
+ struct tq_struct tqueue;
+ int ph_active;
+ struct sk_buff_head rq, sq; /* D-channel queues */
+ int cardnr;
+ int ph_state;
+ struct PStack *teistack;
+ struct HscxState hs[2];
+ int dlogflag;
+ char *dlogspace;
+ int debug;
+ unsigned int CallFlags;
+};
+
+#define MON0_RX 1
+#define MON1_RX 2
+#define MON0_TX 4
+#define MON1_TX 8
+
+#define ISDN_CTYPE_16_0 1
+#define ISDN_CTYPE_8_0 2
+#define ISDN_CTYPE_16_3 3
+#define ISDN_CTYPE_PNP 4
+#define ISDN_CTYPE_A1 5
+#define ISDN_CTYPE_ELSA 6
+#define ISDN_CTYPE_ELSA_QS1000 7
+#define ISDN_CTYPE_TELESPCMCIA 8
+#define ISDN_CTYPE_IX1MICROR2 9
+
+#define ISDN_CTYPE_COUNT 9
+
+#ifdef CONFIG_HISAX_16_0
+#define CARD_TELES0 (1<< ISDN_CTYPE_16_0) | (1<< ISDN_CTYPE_8_0)
+#else
+#define CARD_TELES0 0
+#endif
+
+#ifdef CONFIG_HISAX_16_3
+#define CARD_TELES3 (1<< ISDN_CTYPE_16_3) | (1<< ISDN_CTYPE_PNP) | \
+ (1<< ISDN_CTYPE_TELESPCMCIA)
+#else
+#define CARD_TELES3 0
+#endif
+
+#ifdef CONFIG_HISAX_AVM_A1
+#define CARD_AVM_A1 (1<< ISDN_CTYPE_A1)
+#else
+#define CARD_AVM_A1 0
+#endif
+
+#ifdef CONFIG_HISAX_ELSA_PCC
+#define CARD_ELSA (1<< ISDN_CTYPE_ELSA) | (1<< ISDN_CTYPE_ELSA_QS1000)
+#else
+#define CARD_ELSA 0
+#endif
+
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+#if CARD_ELSA
+#error "You can't use a ELSA ISA card and a ELSA PCMCIA card with the same driver"
+#else
+#undef CARD_ELSA
+#define CARD_ELSA (1<< ISDN_CTYPE_ELSA_QS1000)
+#endif
+#endif
+
+#ifdef CONFIG_HISAX_IX1MICROR2
+#define CARD_IX1MICROR2 (1 << ISDN_CTYPE_IX1MICROR2)
+#else
+#define CARD_IX1MICROR2 0
+#endif
+
+#define SUPORTED_CARDS (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA \
+ | CARD_IX1MICROR2)
+
+struct IsdnCard {
+ int typ;
+ int protocol; /* EDSS1 or 1TR6 */
+ unsigned int para[3];
+ struct IsdnCardState *sp;
+};
+
+
+#define LAPD 0
+#define LAPB 1
+
+void l2down(struct PStack *st, u_char pr, struct sk_buff *skb);
+void l2up(struct PStack *st, u_char pr, struct sk_buff *skb);
+void acceptph(struct PStack *st, struct sk_buff *skb);
+void setstack_isdnl2(struct PStack *st, char *debug_id);
+int HiSax_inithardware(void);
+void HiSax_closehardware(void);
+
+void setstack_HiSax(struct PStack *st, struct IsdnCardState *sp);
+unsigned int randomces(void);
+void setstack_isdnl3(struct PStack *st, struct Channel *chanp);
+void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
+void releasestack_isdnl2(struct PStack *st);
+void releasestack_isdnl3(struct PStack *st);
+void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
+void newcallref(struct PStack *st);
+
+int setstack_hscx(struct PStack *st, struct HscxState *hs);
+u_char *findie(u_char * p, int size, u_char ie, int wanted_set);
+int getcallref(u_char * p);
+
+void FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
+void FsmFree(struct Fsm *fsm);
+int FsmEvent(struct FsmInst *fi, int event, void *arg);
+void FsmChangeState(struct FsmInst *fi, int newstate);
+void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
+int FsmAddTimer(struct FsmTimer *ft, int millisec,
+ int event, void *arg, int where);
+void FsmDelTimer(struct FsmTimer *ft, int where);
+int FsmTimerRunning(struct FsmTimer *ft);
+void jiftime(char *s, long mark);
+
+int HiSax_command(isdn_ctrl * ic);
+int HiSax_writebuf_skb(int id, int chan, struct sk_buff *skb);
+void HiSax_putstatus(struct IsdnCardState *csta, char *buf);
+void HiSax_reportcard(int cardnr);
+int QuickHex(char *txt, u_char * p, int cnt);
+void LogFrame(struct IsdnCardState *sp, u_char * p, int size);
+void dlogframe(struct IsdnCardState *sp, u_char * p, int size, char *comment);
+void iecpy(u_char * dest, u_char * iestart, int ieoffset);
+void setstack_transl2(struct PStack *st);
+void releasestack_transl2(struct PStack *st);
+void close_hscxstate(struct HscxState *);
+void setstack_tei(struct PStack *st);
+
+#endif /* __KERNEL__ */
+
+#define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
+
+int ll_run(struct IsdnCardState *csta);
+void ll_stop(struct IsdnCardState *csta);
+void CallcNew(void);
+void CallcFree(void);
+int CallcNewChan(struct IsdnCardState *csta);
+void CallcFreeChan(struct IsdnCardState *csta);
+void Isdnl2New(void);
+void Isdnl2Free(void);
+void init_tei(struct IsdnCardState *sp, int protocol);
+void release_tei(struct IsdnCardState *sp);
+char *HiSax_getrev(const char *revision);
--- /dev/null
+/* $Id: isdnl1.c,v 1.15 1997/05/27 15:17:55 fritz Exp $
+
+ * isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards
+ * based on the teles driver from Jan den Ouden
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ * Beat Doebeli
+ *
+ *
+ * $Log: isdnl1.c,v $
+ * Revision 1.15 1997/05/27 15:17:55 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.14 1997/04/07 23:00:08 keil
+ * GFP_KERNEL ---> GFP_ATOMIC
+ *
+ * Revision 1.13 1997/04/06 22:55:50 keil
+ * Using SKB's
+ *
+ * Revision 1.12 1997/03/26 13:43:57 keil
+ * small cosmetics
+ *
+ * Revision 1.11 1997/03/25 23:11:23 keil
+ * US NI-1 protocol
+ *
+ * Revision 1.10 1997/03/13 14:45:05 keil
+ * using IRQ proof queue_task
+ *
+ * Revision 1.9 1997/03/12 21:44:21 keil
+ * change Interrupt routine from atomic quick to normal
+ *
+ * Revision 1.8 1997/02/09 00:24:31 keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.7 1997/01/27 15:56:03 keil
+ * PCMCIA Teles card and ITK ix1 micro added
+ *
+ * Revision 1.6 1997/01/21 22:20:00 keil
+ * changes for D-channel log; Elsa Quickstep support
+ *
+ * Revision 1.5 1997/01/10 12:51:19 keil
+ * cleanup; set newversion
+ *
+ * Revision 1.4 1996/12/08 19:44:53 keil
+ * L2FRAME_DEBUG and other changes from Pekka Sarnila
+ *
+ * Revision 1.3 1996/11/18 15:34:47 keil
+ * fix HSCX version code
+ *
+ * Revision 1.2 1996/10/27 22:16:54 keil
+ * ISAC/HSCX version lookup
+ *
+ * Revision 1.1 1996/10/13 20:04:53 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+
+const char *l1_revision = "$Revision: 1.15 $";
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isdnl1.h"
+
+#if CARD_TELES0
+#include "teles0.h"
+#endif
+
+#if CARD_TELES3
+#include "teles3.h"
+#endif
+
+#if CARD_AVM_A1
+#include "avm_a1.h"
+#endif
+
+#if CARD_ELSA
+#include "elsa.h"
+#endif
+
+#if CARD_IX1MICROR2
+#include "ix1_micro.h"
+#endif
+
+/* #define I4L_IRQ_FLAG SA_INTERRUPT */
+#define I4L_IRQ_FLAG 0
+
+#define HISAX_STATUS_BUFSIZE 4096
+
+#define INCLUDE_INLINE_FUNCS
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+
+const char *CardType[] =
+{"No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3",
+ "Creatix/Teles PnP", "AVM A1", "Elsa ML",
+#ifdef CONFIG_HISAX_ELSA_PCMCIA
+ "Elsa PCMCIA",
+#else
+ "Elsa Quickstep",
+#endif
+ "Teles PCMCIA", "ITK ix1-micro Rev.2"};
+
+static char *HSCXVer[] =
+{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
+ "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+
+static char *ISACVer[] =
+{"2086/2186 V1.1", "2085 B1", "2085 B2",
+ "2085 V2.3"};
+
+extern struct IsdnCard cards[];
+extern int nrcards;
+extern char *HiSax_id;
+
+/*
+ * Find card with given driverId
+ */
+static inline struct IsdnCardState
+*
+hisax_findcard(int driverid)
+{
+ int i;
+
+ for (i = 0; i < nrcards; i++)
+ if (cards[i].sp)
+ if (cards[i].sp->myid == driverid)
+ return (cards[i].sp);
+ return (struct IsdnCardState *) 0;
+}
+
+int
+HiSax_readstatus(u_char * buf, int len, int user, int id, int channel)
+{
+ int count;
+ u_char *p;
+ struct IsdnCardState *csta = hisax_findcard(id);
+
+ if (csta) {
+ for (p = buf, count = 0; count < len; p++, count++) {
+ if (user)
+ put_user(*csta->status_read++, p);
+ else
+ *p++ = *csta->status_read++;
+ if (csta->status_read > csta->status_end)
+ csta->status_read = csta->status_buf;
+ }
+ return count;
+ } else {
+ printk(KERN_ERR
+ "HiSax: if_readstatus called with invalid driverId!\n");
+ return -ENODEV;
+ }
+}
+
+void
+HiSax_putstatus(struct IsdnCardState *csta, char *buf)
+{
+ long flags;
+ int len, count, i;
+ u_char *p;
+ isdn_ctrl ic;
+
+ save_flags(flags);
+ cli();
+ count = 0;
+ len = strlen(buf);
+
+ if (!csta) {
+ printk(KERN_WARNING "HiSax: No CardStatus for message %s", buf);
+ restore_flags(flags);
+ return;
+ }
+ for (p = buf, i = len; i > 0; i--, p++) {
+ *csta->status_write++ = *p;
+ if (csta->status_write > csta->status_end)
+ csta->status_write = csta->status_buf;
+ count++;
+ }
+ restore_flags(flags);
+ if (count) {
+ ic.command = ISDN_STAT_STAVAIL;
+ ic.driver = csta->myid;
+ ic.arg = count;
+ csta->iif.statcallb(&ic);
+ }
+}
+
+int
+ll_run(struct IsdnCardState *csta)
+{
+ long flags;
+ isdn_ctrl ic;
+
+ save_flags(flags);
+ cli();
+ ic.driver = csta->myid;
+ ic.command = ISDN_STAT_RUN;
+ csta->iif.statcallb(&ic);
+ restore_flags(flags);
+ return 0;
+}
+
+void
+ll_stop(struct IsdnCardState *csta)
+{
+ isdn_ctrl ic;
+
+ ic.command = ISDN_STAT_STOP;
+ ic.driver = csta->myid;
+ csta->iif.statcallb(&ic);
+ CallcFreeChan(csta);
+}
+
+static void
+ll_unload(struct IsdnCardState *csta)
+{
+ isdn_ctrl ic;
+
+ ic.command = ISDN_STAT_UNLOAD;
+ ic.driver = csta->myid;
+ csta->iif.statcallb(&ic);
+ if (csta->status_buf)
+ kfree(csta->status_buf);
+ csta->status_read = NULL;
+ csta->status_write = NULL;
+ csta->status_end = NULL;
+ kfree(csta->dlogspace);
+}
+
+void
+debugl1(struct IsdnCardState *sp, char *msg)
+{
+ char tmp[256], tm[32];
+
+ jiftime(tm, jiffies);
+ sprintf(tmp, "%s Card %d %s\n", tm, sp->cardnr + 1, msg);
+ HiSax_putstatus(sp, tmp);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+
+char *
+HscxVersion(u_char v)
+{
+ return (HSCXVer[v & 0xf]);
+}
+
+void
+hscx_sched_event(struct HscxState *hsp, int event)
+{
+ hsp->event |= 1 << event;
+ queue_task(&hsp->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+char *
+ISACVersion(u_char v)
+{
+ return (ISACVer[(v >> 5) & 3]);
+}
+
+void
+isac_sched_event(struct IsdnCardState *sp, int event)
+{
+ sp->event |= 1 << event;
+ queue_task(&sp->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+int
+act_wanted(struct IsdnCardState *sp)
+{
+ struct PStack *st;
+
+ st = sp->stlist;
+ while (st)
+ if (st->l1.act_state)
+ return (!0);
+ else
+ st = st->next;
+ return (0);
+}
+
+void
+isac_new_ph(struct IsdnCardState *sp)
+{
+ int enq;
+
+ enq = act_wanted(sp);
+
+ switch (sp->ph_state) {
+ case (6):
+ sp->ph_active = 0;
+ sp->ph_command(sp, 15);
+ break;
+ case (15):
+ sp->ph_active = 0;
+ if (enq)
+ sp->ph_command(sp, 0);
+ break;
+ case (0):
+ sp->ph_active = 0;
+ if (enq)
+ sp->ph_command(sp, 0);
+#if 0
+ else
+ sp->ph_command(sp, 15);
+#endif
+ break;
+ case (7):
+ sp->ph_active = 0;
+ if (enq)
+ sp->ph_command(sp, 9);
+ break;
+ case (12):
+ sp->ph_command(sp, 8);
+ sp->ph_active = 5;
+ isac_sched_event(sp, ISAC_PHCHANGE);
+ if (!sp->tx_skb)
+ sp->tx_skb = skb_dequeue(&sp->sq);
+ if (sp->tx_skb) {
+ sp->tx_cnt = 0;
+ sp->isac_fill_fifo(sp);
+ }
+ break;
+ case (13):
+ sp->ph_command(sp, 9);
+ sp->ph_active = 5;
+ isac_sched_event(sp, ISAC_PHCHANGE);
+ if (!sp->tx_skb)
+ sp->tx_skb = skb_dequeue(&sp->sq);
+ if (sp->tx_skb) {
+ sp->tx_cnt = 0;
+ sp->isac_fill_fifo(sp);
+ }
+ break;
+ case (4):
+ case (8):
+ sp->ph_active = 0;
+ break;
+ default:
+ sp->ph_active = 0;
+ break;
+ }
+}
+
+static void
+restart_ph(struct IsdnCardState *sp)
+{
+ if (!sp->ph_active) {
+ if ((sp->ph_state == 6) || (sp->ph_state == 0)) {
+ sp->ph_command(sp, 0);
+ sp->ph_active = 2;
+ } else {
+ sp->ph_command(sp, 1);
+ sp->ph_active = 1;
+ }
+ } else if (sp->ph_active == 2) {
+ sp->ph_command(sp, 1);
+ sp->ph_active = 1;
+ }
+}
+
+
+static void
+act_ivated(struct IsdnCardState *sp)
+{
+ struct PStack *st;
+
+ st = sp->stlist;
+ while (st) {
+ if (st->l1.act_state == 1) {
+ st->l1.act_state = 2;
+ st->l1.l1man(st, PH_ACTIVATE, NULL);
+ }
+ st = st->next;
+ }
+}
+
+static void
+process_new_ph(struct IsdnCardState *sp)
+{
+ if (sp->ph_active == 5)
+ act_ivated(sp);
+}
+
+static void
+process_xmt(struct IsdnCardState *sp)
+{
+ struct PStack *stptr;
+
+ if (sp->tx_skb)
+ return;
+
+ stptr = sp->stlist;
+ while (stptr != NULL)
+ if (stptr->l1.requestpull) {
+ stptr->l1.requestpull = 0;
+ stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
+ break;
+ } else
+ stptr = stptr->next;
+}
+
+static void
+process_rcv(struct IsdnCardState *sp)
+{
+ struct sk_buff *skb, *nskb;
+ struct PStack *stptr;
+ int found, broadc;
+ char tmp[64];
+
+ while ((skb = skb_dequeue(&sp->rq))) {
+#ifdef L2FRAME_DEBUG /* psa */
+ if (sp->debug & L1_DEB_LAPD)
+ Logl2Frame(sp, skb, "PH_DATA", 1);
+#endif
+ stptr = sp->stlist;
+ broadc = (skb->data[1] >> 1) == 127;
+
+ if (broadc) {
+ if (!(skb->data[0] >> 2)) { /* sapi 0 */
+ sp->CallFlags = 3;
+ if (sp->dlogflag) {
+ LogFrame(sp, skb->data, skb->len);
+ dlogframe(sp, skb->data + 3, skb->len - 3,
+ "Q.931 frame network->user broadcast");
+ }
+ }
+ while (stptr != NULL) {
+ if ((skb->data[0] >> 2) == stptr->l2.sap)
+ if ((nskb = skb_clone(skb, GFP_ATOMIC)))
+ stptr->l1.l1l2(stptr, PH_DATA, nskb);
+ else
+ printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
+ stptr = stptr->next;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ } else {
+ found = 0;
+ while (stptr != NULL)
+ if (((skb->data[0] >> 2) == stptr->l2.sap) &&
+ ((skb->data[1] >> 1) == stptr->l2.tei)) {
+ stptr->l1.l1l2(stptr, PH_DATA, skb);
+ found = !0;
+ break;
+ } else
+ stptr = stptr->next;
+ if (!found) {
+ /* BD 10.10.95
+ * Print out D-Channel msg not processed
+ * by isdn4linux
+ */
+
+ if ((!(skb->data[0] >> 2)) && (!(skb->data[2] & 0x01))) {
+ sprintf(tmp,
+ "Q.931 frame network->user with tei %d (not for us)",
+ skb->data[1] >> 1);
+ LogFrame(sp, skb->data, skb->len);
+ dlogframe(sp, skb->data + 4, skb->len - 4, tmp);
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ }
+ }
+
+ }
+
+}
+
+static void
+isac_bh(struct IsdnCardState *sp)
+{
+ if (!sp)
+ return;
+
+ if (test_and_clear_bit(ISAC_PHCHANGE, &sp->event))
+ process_new_ph(sp);
+ if (test_and_clear_bit(ISAC_RCVBUFREADY, &sp->event))
+ process_rcv(sp);
+ if (test_and_clear_bit(ISAC_XMTBUFREADY, &sp->event))
+ process_xmt(sp);
+}
+
+static void
+l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb = arg;
+ char str[64];
+
+ switch (pr) {
+ case (PH_DATA):
+ if (sp->tx_skb) {
+ skb_queue_tail(&sp->sq, skb);
+#ifdef L2FRAME_DEBUG /* psa */
+ if (sp->debug & L1_DEB_LAPD)
+ Logl2Frame(sp, skb, "PH_DATA Queued", 0);
+#endif
+ } else {
+ if ((sp->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
+ LogFrame(sp, skb->data, skb->len);
+ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+ dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize,
+ str);
+ }
+ sp->tx_skb = skb;
+ sp->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG /* psa */
+ if (sp->debug & L1_DEB_LAPD)
+ Logl2Frame(sp, skb, "PH_DATA", 0);
+#endif
+ sp->isac_fill_fifo(sp);
+ }
+ break;
+ case (PH_DATA_PULLED):
+ if (sp->tx_skb) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, " l2l1 tx_skb exist this shouldn't happen");
+ break;
+ }
+ if ((sp->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
+ LogFrame(sp, skb->data, skb->len);
+ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
+ dlogframe(sp, skb->data + st->l2.ihsize, skb->len - st->l2.ihsize,
+ str);
+ }
+ sp->tx_skb = skb;
+ sp->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG /* psa */
+ if (sp->debug & L1_DEB_LAPD)
+ Logl2Frame(sp, skb, "PH_DATA_PULLED", 0);
+#endif
+ sp->isac_fill_fifo(sp);
+ break;
+ case (PH_REQUEST_PULL):
+#ifdef L2FRAME_DEBUG /* psa */
+ if (sp->debug & L1_DEB_LAPD)
+ debugl1(sp, "-> PH_REQUEST_PULL");
+#endif
+ if (!sp->tx_skb) {
+ st->l1.requestpull = 0;
+ st->l1.l1l2(st, PH_PULL_ACK, NULL);
+ } else
+ st->l1.requestpull = !0;
+ break;
+ }
+}
+
+
+static void
+hscx_process_xmt(struct HscxState *hsp)
+{
+ struct PStack *st = hsp->st;
+
+ if (hsp->tx_skb)
+ return;
+
+ if (st->l1.requestpull) {
+ st->l1.requestpull = 0;
+ st->l1.l1l2(st, PH_PULL_ACK, NULL);
+ }
+ if (!hsp->active)
+ if ((!hsp->tx_skb) && (!skb_queue_len(&hsp->squeue)))
+ hsp->sp->modehscx(hsp, 0, 0);
+}
+
+static void
+hscx_process_rcv(struct HscxState *hsp)
+{
+ struct sk_buff *skb;
+
+#ifdef DEBUG_MAGIC
+ if (hsp->magic != 301270) {
+ printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
+ return;
+ }
+#endif
+ while ((skb = skb_dequeue(&hsp->rqueue))) {
+ hsp->st->l1.l1l2(hsp->st, PH_DATA, skb);
+ }
+}
+
+static void
+hscx_bh(struct HscxState *hsp)
+{
+
+ if (!hsp)
+ return;
+
+ if (test_and_clear_bit(HSCX_RCVBUFREADY, &hsp->event))
+ hscx_process_rcv(hsp);
+ if (test_and_clear_bit(HSCX_XMTBUFREADY, &hsp->event))
+ hscx_process_xmt(hsp);
+
+}
+
+/*
+ * interrupt stuff ends here
+ */
+
+void
+HiSax_addlist(struct IsdnCardState *sp,
+ struct PStack *st)
+{
+ st->next = sp->stlist;
+ sp->stlist = st;
+}
+
+void
+HiSax_rmlist(struct IsdnCardState *sp,
+ struct PStack *st)
+{
+ struct PStack *p;
+
+ if (sp->stlist == st)
+ sp->stlist = st->next;
+ else {
+ p = sp->stlist;
+ while (p)
+ if (p->next == st) {
+ p->next = st->next;
+ return;
+ } else
+ p = p->next;
+ }
+}
+
+static void
+check_ph_act(struct IsdnCardState *sp)
+{
+ struct PStack *st = sp->stlist;
+
+ while (st) {
+ if (st->l1.act_state)
+ return;
+ st = st->next;
+ }
+ if (sp->ph_active == 5)
+ sp->ph_active = 4;
+}
+
+static void
+HiSax_manl1(struct PStack *st, int pr,
+ void *arg)
+{
+ struct IsdnCardState *sp = (struct IsdnCardState *)
+ st->l1.hardware;
+ long flags;
+ char tmp[32];
+
+ switch (pr) {
+ case (PH_ACTIVATE):
+ if (sp->debug) {
+ sprintf(tmp, "PH_ACT ph_active %d", sp->ph_active);
+ debugl1(sp, tmp);
+ }
+ save_flags(flags);
+ cli();
+ if (sp->ph_active & 4) {
+ sp->ph_active = 5;
+ st->l1.act_state = 2;
+ restore_flags(flags);
+ st->l1.l1man(st, PH_ACTIVATE, NULL);
+ } else {
+ st->l1.act_state = 1;
+ if (sp->ph_active == 0)
+ restart_ph(sp);
+ restore_flags(flags);
+ }
+ break;
+ case (PH_DEACTIVATE):
+ st->l1.act_state = 0;
+ if (sp->debug) {
+ sprintf(tmp, "PH_DEACT ph_active %d", sp->ph_active);
+ debugl1(sp, tmp);
+ }
+ check_ph_act(sp);
+ break;
+ }
+}
+
+static void
+HiSax_l2l1discardq(struct PStack *st, int pr,
+ void *heldby, int releasetoo)
+{
+ struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+ struct sk_buff *skb;
+
+#ifdef DEBUG_MAGIC
+ if (sp->magic != 301271) {
+ printk(KERN_DEBUG "isac_discardq magic not 301271\n");
+ return;
+ }
+#endif
+
+ while ((skb = skb_dequeue(&sp->sq)))
+ dev_kfree_skb(skb, FREE_WRITE);
+}
+
+void
+setstack_HiSax(struct PStack *st, struct IsdnCardState *sp)
+{
+ st->l1.hardware = sp;
+ st->protocol = sp->protocol;
+
+ setstack_tei(st);
+
+ st->l1.stlistp = &(sp->stlist);
+ st->l1.act_state = 0;
+ st->l2.l2l1 = l2l1;
+ st->l2.l2l1discardq = HiSax_l2l1discardq;
+ st->ma.manl1 = HiSax_manl1;
+ st->l1.requestpull = 0;
+}
+
+void
+init_hscxstate(struct IsdnCardState *sp,
+ int hscx)
+{
+ struct HscxState *hsp = sp->hs + hscx;
+
+ hsp->sp = sp;
+ hsp->hscx = hscx;
+
+ hsp->tqueue.next = 0;
+ hsp->tqueue.sync = 0;
+ hsp->tqueue.routine = (void *) (void *) hscx_bh;
+ hsp->tqueue.data = hsp;
+
+ hsp->inuse = 0;
+ hsp->init = 0;
+ hsp->active = 0;
+
+#ifdef DEBUG_MAGIC
+ hsp->magic = 301270;
+#endif
+}
+
+int
+get_irq(int cardnr, void *routine)
+{
+ struct IsdnCard *card = cards + cardnr;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ if (request_irq(card->sp->irq, routine,
+ I4L_IRQ_FLAG, "HiSax", NULL)) {
+ printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
+ card->sp->irq);
+ restore_flags(flags);
+ return (0);
+ }
+ irq2dev_map[card->sp->irq] = (void *) card->sp;
+ restore_flags(flags);
+ return (1);
+}
+
+static void
+release_irq(int cardnr)
+{
+ struct IsdnCard *card = cards + cardnr;
+
+ irq2dev_map[card->sp->irq] = NULL;
+ free_irq(card->sp->irq, NULL);
+}
+
+void
+close_hscxstate(struct HscxState *hs)
+{
+ struct sk_buff *skb;
+
+ hs->sp->modehscx(hs, 0, 0);
+ hs->inuse = 0;
+ if (hs->init) {
+ if (hs->rcvbuf) {
+ kfree(hs->rcvbuf);
+ hs->rcvbuf = NULL;
+ }
+ while ((skb = skb_dequeue(&hs->rqueue))) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ }
+ while ((skb = skb_dequeue(&hs->squeue)))
+ dev_kfree_skb(skb, FREE_WRITE);
+ if (hs->tx_skb) {
+ dev_kfree_skb(hs->tx_skb, FREE_WRITE);
+ hs->tx_skb = NULL;
+ }
+ }
+ hs->init = 0;
+}
+
+static void
+closecard(int cardnr)
+{
+ struct IsdnCardState *csta = cards[cardnr].sp;
+ struct sk_buff *skb;
+
+ close_hscxstate(csta->hs + 1);
+ close_hscxstate(csta->hs);
+
+ if (csta->rcvbuf) {
+ kfree(csta->rcvbuf);
+ csta->rcvbuf = NULL;
+ }
+ while ((skb = skb_dequeue(&csta->rq))) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ }
+ while ((skb = skb_dequeue(&csta->sq)))
+ dev_kfree_skb(skb, FREE_WRITE);
+ if (csta->tx_skb) {
+ dev_kfree_skb(csta->tx_skb, FREE_WRITE);
+ csta->tx_skb = NULL;
+ }
+ switch (csta->typ) {
+#if CARD_TELES0
+ case ISDN_CTYPE_16_0:
+ case ISDN_CTYPE_8_0:
+ release_io_teles0(cards + cardnr);
+ break;
+#endif
+#if CARD_TELES3
+ case ISDN_CTYPE_PNP:
+ case ISDN_CTYPE_16_3:
+ case ISDN_CTYPE_TELESPCMCIA:
+ release_io_teles3(cards + cardnr);
+ break;
+#endif
+#if CARD_AVM_A1
+ case ISDN_CTYPE_A1:
+ release_io_avm_a1(cards + cardnr);
+ break;
+#endif
+#if CARD_ELSA
+ case ISDN_CTYPE_ELSA:
+ case ISDN_CTYPE_ELSA_QS1000:
+ release_io_elsa(cards + cardnr);
+ break;
+#endif
+#if CARD_IX1MICROR2
+ case ISDN_CTYPE_IX1MICROR2:
+ release_io_ix1micro(cards + cardnr);
+ break;
+#endif
+ default:
+ break;
+ }
+ ll_unload(csta);
+}
+
+static int
+checkcard(int cardnr, char *id)
+{
+ long flags;
+ int ret = 0;
+ struct IsdnCard *card = cards + cardnr;
+ struct IsdnCardState *sp;
+
+ save_flags(flags);
+ cli();
+ if (!(sp = (struct IsdnCardState *)
+ kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for IsdnCardState(card %d)\n",
+ cardnr + 1);
+ restore_flags(flags);
+ return (0);
+ }
+ card->sp = sp;
+ sp->cardnr = cardnr;
+ sp->cfg_reg = 0;
+ sp->protocol = card->protocol;
+
+ if ((card->typ > 0) && (card->typ < 31)) {
+ if (!((1 << card->typ) & SUPORTED_CARDS)) {
+ printk(KERN_WARNING
+ "HiSax: Support for %s Card not selected\n",
+ CardType[card->typ]);
+ restore_flags(flags);
+ return (0);
+ }
+ } else {
+ printk(KERN_WARNING
+ "HiSax: Card Type %d out of range\n",
+ card->typ);
+ restore_flags(flags);
+ return (0);
+ }
+ if (!(sp->dlogspace = kmalloc(4096, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for dlogspace(card %d)\n",
+ cardnr + 1);
+ restore_flags(flags);
+ return (0);
+ }
+ if (!(sp->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for status_buf(card %d)\n",
+ cardnr + 1);
+ kfree(sp->dlogspace);
+ restore_flags(flags);
+ return (0);
+ }
+ sp->status_read = sp->status_buf;
+ sp->status_write = sp->status_buf;
+ sp->status_end = sp->status_buf + HISAX_STATUS_BUFSIZE - 1;
+ sp->typ = card->typ;
+ sp->CallFlags = 0;
+ strcpy(sp->iif.id, id);
+ sp->iif.channels = 2;
+ sp->iif.maxbufsize = MAX_DATA_SIZE;
+ sp->iif.hl_hdrlen = MAX_HEADER_LEN;
+ sp->iif.features =
+ ISDN_FEATURE_L2_X75I |
+ ISDN_FEATURE_L2_HDLC |
+ ISDN_FEATURE_L2_TRANS |
+ ISDN_FEATURE_L3_TRANS |
+#ifdef CONFIG_HISAX_1TR6
+ ISDN_FEATURE_P_1TR6 |
+#endif
+#ifdef CONFIG_HISAX_EURO
+ ISDN_FEATURE_P_EURO |
+#endif
+#ifdef CONFIG_HISAX_NI1
+ ISDN_FEATURE_P_NI1 |
+#endif
+ 0;
+
+ sp->iif.command = HiSax_command;
+ sp->iif.writebuf = NULL;
+ sp->iif.writecmd = NULL;
+ sp->iif.writebuf_skb = HiSax_writebuf_skb;
+ sp->iif.readstat = HiSax_readstatus;
+ register_isdn(&sp->iif);
+ sp->myid = sp->iif.channels;
+ restore_flags(flags);
+ printk(KERN_NOTICE
+ "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+ (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+ (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+ (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+ (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+ "NONE", sp->iif.id, sp->myid);
+ switch (card->typ) {
+#if CARD_TELES0
+ case ISDN_CTYPE_16_0:
+ case ISDN_CTYPE_8_0:
+ ret = setup_teles0(card);
+ break;
+#endif
+#if CARD_TELES3
+ case ISDN_CTYPE_16_3:
+ case ISDN_CTYPE_PNP:
+ case ISDN_CTYPE_TELESPCMCIA:
+ ret = setup_teles3(card);
+ break;
+#endif
+#if CARD_AVM_A1
+ case ISDN_CTYPE_A1:
+ ret = setup_avm_a1(card);
+ break;
+#endif
+#if CARD_ELSA
+ case ISDN_CTYPE_ELSA:
+ case ISDN_CTYPE_ELSA_QS1000:
+ ret = setup_elsa(card);
+ break;
+#endif
+#if CARD_IX1MICROR2
+ case ISDN_CTYPE_IX1MICROR2:
+ ret = setup_ix1micro(card);
+ break;
+#endif
+ default:
+ printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n",
+ card->typ);
+ ll_unload(sp);
+ return (0);
+ }
+ if (!ret) {
+ ll_unload(sp);
+ return (0);
+ }
+ if (!(sp->rcvbuf = kmalloc(MAX_DFRAME_LEN, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for isac rcvbuf\n");
+ return (1);
+ }
+ sp->rcvidx = 0;
+ sp->tx_skb = NULL;
+ sp->tx_cnt = 0;
+ sp->event = 0;
+ sp->tqueue.next = 0;
+ sp->tqueue.sync = 0;
+ sp->tqueue.routine = (void *) (void *) isac_bh;
+ sp->tqueue.data = sp;
+
+ skb_queue_head_init(&sp->rq);
+ skb_queue_head_init(&sp->sq);
+
+ sp->stlist = NULL;
+ sp->ph_active = 0;
+ sp->dlogflag = 0;
+ sp->debug = L1_DEB_WARN;
+#ifdef DEBUG_MAGIC
+ sp->magic = 301271;
+#endif
+
+ init_hscxstate(sp, 0);
+ init_hscxstate(sp, 1);
+
+ switch (card->typ) {
+#if CARD_TELES0
+ case ISDN_CTYPE_16_0:
+ case ISDN_CTYPE_8_0:
+ ret = initteles0(sp);
+ break;
+#endif
+#if CARD_TELES3
+ case ISDN_CTYPE_16_3:
+ case ISDN_CTYPE_PNP:
+ case ISDN_CTYPE_TELESPCMCIA:
+ ret = initteles3(sp);
+ break;
+#endif
+#if CARD_AVM_A1
+ case ISDN_CTYPE_A1:
+ ret = initavm_a1(sp);
+ break;
+#endif
+#if CARD_ELSA
+ case ISDN_CTYPE_ELSA:
+ case ISDN_CTYPE_ELSA_QS1000:
+ ret = initelsa(sp);
+ break;
+#endif
+#if CARD_IX1MICROR2
+ case ISDN_CTYPE_IX1MICROR2:
+ ret = initix1micro(sp);
+ break;
+#endif
+ default:
+ ret = 0;
+ break;
+ }
+ if (!ret) {
+ closecard(cardnr);
+ return (0);
+ }
+ init_tei(sp, sp->protocol);
+ CallcNewChan(sp);
+ ll_run(sp);
+ return (1);
+}
+
+void
+HiSax_shiftcards(int idx)
+{
+ int i;
+
+ for (i = idx; i < 15; i++)
+ memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
+}
+
+int
+HiSax_inithardware(void)
+{
+ int foundcards = 0;
+ int i = 0;
+ int t = ',';
+ int flg = 0;
+ char *id;
+ char *next_id = HiSax_id;
+ char ids[20];
+
+ if (strchr(HiSax_id, ','))
+ t = ',';
+ else if (strchr(HiSax_id, '%'))
+ t = '%';
+
+ while (i < nrcards) {
+ if (cards[i].typ < 1)
+ break;
+ id = next_id;
+ if ((next_id = strchr(id, t))) {
+ *next_id++ = 0;
+ strcpy(ids, id);
+ flg = i + 1;
+ } else {
+ next_id = id;
+ if (flg >= i)
+ strcpy(ids, id);
+ else
+ sprintf(ids, "%s%d", id, i);
+ }
+ if (checkcard(i, ids)) {
+ foundcards++;
+ i++;
+ } else {
+ printk(KERN_WARNING "HiSax: Card %s not installed !\n",
+ CardType[cards[i].typ]);
+ if (cards[i].sp)
+ kfree((void *) cards[i].sp);
+ cards[i].sp = NULL;
+ HiSax_shiftcards(i);
+ }
+ }
+ return foundcards;
+}
+
+void
+HiSax_closehardware(void)
+{
+ int i;
+ long flags;
+
+ save_flags(flags);
+ cli();
+ for (i = 0; i < nrcards; i++)
+ if (cards[i].sp) {
+ ll_stop(cards[i].sp);
+ CallcFreeChan(cards[i].sp);
+ release_tei(cards[i].sp);
+ release_irq(i);
+ closecard(i);
+ kfree((void *) cards[i].sp);
+ cards[i].sp = NULL;
+ }
+ Isdnl2Free();
+ CallcFree();
+ restore_flags(flags);
+}
+
+static void
+hscx_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+ struct HscxState *hsp = sp->hs + st->l1.hscx;
+ long flags;
+
+ switch (pr) {
+ case (PH_DATA):
+ save_flags(flags);
+ cli();
+ if (hsp->tx_skb) {
+ skb_queue_tail(&hsp->squeue, skb);
+ restore_flags(flags);
+ } else {
+ restore_flags(flags);
+ hsp->tx_skb = skb;
+ hsp->count = 0;
+ sp->hscx_fill_fifo(hsp);
+ }
+ break;
+ case (PH_DATA_PULLED):
+ if (hsp->tx_skb) {
+ printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
+ break;
+ }
+ hsp->tx_skb = skb;
+ hsp->count = 0;
+ sp->hscx_fill_fifo(hsp);
+ break;
+ case (PH_REQUEST_PULL):
+ if (!hsp->tx_skb) {
+ st->l1.requestpull = 0;
+ st->l1.l1l2(st, PH_PULL_ACK, NULL);
+ } else
+ st->l1.requestpull = !0;
+ break;
+ }
+
+}
+extern struct IsdnBuffers *tracebuf;
+
+static void
+hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
+ int releasetoo)
+{
+ struct IsdnCardState *sp = (struct IsdnCardState *)
+ st->l1.hardware;
+ struct HscxState *hsp = sp->hs + st->l1.hscx;
+ struct sk_buff *skb;
+
+#ifdef DEBUG_MAGIC
+ if (hsp->magic != 301270) {
+ printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
+ return;
+ }
+#endif
+
+ while ((skb = skb_dequeue(&hsp->squeue)))
+ dev_kfree_skb(skb, FREE_WRITE);
+}
+
+static int
+open_hscxstate(struct IsdnCardState *sp,
+ int hscx)
+{
+ struct HscxState *hsp = sp->hs + hscx;
+
+ if (!hsp->init) {
+ if (!(hsp->rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for hscx_rcvbuf\n");
+ return (1);
+ }
+ skb_queue_head_init(&hsp->rqueue);
+ skb_queue_head_init(&hsp->squeue);
+ }
+ hsp->init = !0;
+
+ hsp->tx_skb = NULL;
+ hsp->event = 0;
+ hsp->rcvidx = 0;
+ hsp->tx_cnt = 0;
+ return (0);
+}
+
+static void
+hscx_manl1(struct PStack *st, int pr,
+ void *arg)
+{
+ struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
+ struct HscxState *hsp = sp->hs + st->l1.hscx;
+
+ switch (pr) {
+ case (PH_ACTIVATE):
+ hsp->active = !0;
+ sp->modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
+ st->l1.l1man(st, PH_ACTIVATE, NULL);
+ break;
+ case (PH_DEACTIVATE):
+ if (!hsp->tx_skb)
+ sp->modehscx(hsp, 0, 0);
+
+ hsp->active = 0;
+ break;
+ }
+}
+
+int
+setstack_hscx(struct PStack *st, struct HscxState *hs)
+{
+ if (open_hscxstate(st->l1.hardware, hs->hscx))
+ return (-1);
+
+ st->l1.hscx = hs->hscx;
+ st->l2.l2l1 = hscx_l2l1;
+ st->ma.manl1 = hscx_manl1;
+ st->l2.l2l1discardq = hscx_l2l1discardq;
+
+ st->l1.act_state = 0;
+ st->l1.requestpull = 0;
+
+ hs->st = st;
+ return (0);
+}
+
+void
+HiSax_reportcard(int cardnr)
+{
+ struct IsdnCardState *sp = cards[cardnr].sp;
+
+ printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1);
+ printk(KERN_DEBUG "HiSax: Type %s\n", CardType[sp->typ]);
+ printk(KERN_DEBUG "HiSax: debuglevel %x\n", sp->debug);
+ printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
+ (ulong) & HiSax_reportcard);
+}
+
+#ifdef L2FRAME_DEBUG /* psa */
+
+char *
+l2cmd(u_char cmd)
+{
+ switch (cmd & ~0x10) {
+ case 1:
+ return "RR";
+ case 5:
+ return "RNR";
+ case 9:
+ return "REJ";
+ case 0x6f:
+ return "SABME";
+ case 0x0f:
+ return "DM";
+ case 3:
+ return "UI";
+ case 0x43:
+ return "DISC";
+ case 0x63:
+ return "UA";
+ case 0x87:
+ return "FRMR";
+ case 0xaf:
+ return "XID";
+ default:
+ if (!(cmd & 1))
+ return "I";
+ else
+ return "invalid command";
+ }
+}
+
+static char tmp[20];
+
+char *
+l2frames(u_char * ptr)
+{
+ switch (ptr[2] & ~0x10) {
+ case 1:
+ case 5:
+ case 9:
+ sprintf(tmp, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1);
+ break;
+ case 0x6f:
+ case 0x0f:
+ case 3:
+ case 0x43:
+ case 0x63:
+ case 0x87:
+ case 0xaf:
+ sprintf(tmp, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4);
+ break;
+ default:
+ if (!(ptr[2] & 1)) {
+ sprintf(tmp, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1);
+ break;
+ } else
+ return "invalid command";
+ }
+
+
+ return tmp;
+}
+
+void
+Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir)
+{
+ char tmp[132];
+ u_char *ptr;
+
+ ptr = skb->data;
+
+ if (ptr[0] & 1 || !(ptr[1] & 1))
+ debugl1(sp, "Addres not LAPD");
+ else {
+ sprintf(tmp, "%s %s: %s%c (sapi %d, tei %d)",
+ (dir ? "<-" : "->"), buf, l2frames(ptr),
+ ((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1);
+ debugl1(sp, tmp);
+ }
+}
+
+#endif
--- /dev/null
+/* $Id: isdnl1.h,v 1.4 1997/04/06 22:55:52 keil Exp $
+ *
+ * $Log: isdnl1.h,v $
+ * Revision 1.4 1997/04/06 22:55:52 keil
+ * Using SKB's
+ *
+ * Revision 1.3 1996/12/08 19:41:55 keil
+ * L2FRAME_DEBUG
+ *
+ * Revision 1.2 1996/10/27 22:26:27 keil
+ * ISAC/HSCX version functions
+ *
+ * Revision 1.1 1996/10/13 20:03:47 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+
+
+#define L2FRAME_DEBUG
+
+/* DEBUG Level */
+
+#define L1_DEB_WARN 0x01
+#define L1_DEB_INTSTAT 0x02
+#define L1_DEB_ISAC 0x04
+#define L1_DEB_ISAC_FIFO 0x08
+#define L1_DEB_HSCX 0x10
+#define L1_DEB_HSCX_FIFO 0x20
+#define L1_DEB_LAPD 0x40
+
+
+#define ISAC_RCVBUFREADY 0
+#define ISAC_XMTBUFREADY 1
+#define ISAC_PHCHANGE 2
+
+#define HSCX_RCVBUFREADY 0
+#define HSCX_XMTBUFREADY 1
+
+extern void debugl1(struct IsdnCardState *sp, char *msg);
+extern char *HscxVersion(u_char v);
+extern char *ISACVersion(u_char v);
+extern void hscx_sched_event(struct HscxState *hsp, int event);
+extern void isac_sched_event(struct IsdnCardState *sp, int event);
+extern void isac_new_ph(struct IsdnCardState *sp);
+extern get_irq(int cardnr, void *routine);
+
+#ifdef L2FRAME_DEBUG
+extern void Logl2Frame(struct IsdnCardState *sp, struct sk_buff *skb, char *buf, int dir);
+#endif
--- /dev/null
+/* $Id: isdnl2.c,v 1.10 1997/05/06 09:38:13 keil Exp $
+
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * based on the teles driver from Jan den Ouden
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ *
+ * $Log: isdnl2.c,v $
+ * Revision 1.10 1997/05/06 09:38:13 keil
+ * Bugfixes: - clear ack queue entries after resend
+ * - acknowlege each frame to linklevel
+ * - UA for SABM is Response, not command
+ * - only RR was send as supervisor frame (X.75 hangs after a
+ * sequence error)
+ *
+ * Revision 1.9 1997/04/07 23:02:11 keil
+ * missing braces
+ *
+ * Revision 1.8 1997/04/06 22:59:59 keil
+ * Using SKB's; changing function names; some minor changes
+ *
+ * Revision 1.7 1997/02/09 00:25:44 keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.6 1997/01/21 22:23:42 keil
+ * D-channel log changed
+ *
+ * Revision 1.5 1997/01/04 13:47:06 keil
+ * handling of MDL_REMOVE added (Thanks to Sim Yskes)
+ *
+ * Revision 1.4 1996/12/08 19:51:51 keil
+ * many fixes from Pekka Sarnila
+ *
+ * Revision 1.3 1996/11/05 19:39:12 keil
+ * X.75 bugfixes Thank to Martin Maurer
+ *
+ * Revision 1.2 1996/10/30 10:20:58 keil
+ * X.75 answer of SABMX fixed to response address (AVM X.75 problem)
+ *
+ * Revision 1.1 1996/10/13 20:04:54 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl2.h"
+
+const char *l2_revision = "$Revision: 1.10 $";
+
+static void l2m_debug(struct FsmInst *fi, char *s);
+
+struct Fsm l2fsm =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+ ST_L2_1,
+ ST_L2_3,
+ ST_L2_4,
+ ST_L2_5,
+ ST_L2_6,
+ ST_L2_7,
+ ST_L2_8,
+};
+
+#define L2_STATE_COUNT (ST_L2_8+1)
+
+static char *strL2State[] =
+{
+ "ST_L2_1",
+ "ST_L2_3",
+ "ST_L2_4",
+ "ST_L2_5",
+ "ST_L2_6",
+ "ST_L2_7",
+ "ST_L2_8",
+};
+
+enum {
+ EV_L2_UI,
+ EV_L2_SABMX,
+ EV_L2_UA,
+ EV_L2_DISC,
+ EV_L2_I,
+ EV_L2_RR,
+ EV_L2_REJ,
+ EV_L2_FRMR,
+ EV_L2_DL_DATA,
+ EV_L2_DL_ESTABLISH,
+ EV_L2_MDL_ASSIGN,
+ EV_L2_MDL_REMOVE,
+ EV_L2_DL_UNIT_DATA,
+ EV_L2_DL_RELEASE,
+ EV_L2_MDL_NOTEIPROC,
+ EV_L2_T200,
+ EV_L2_ACK_PULL,
+ EV_L2_T203,
+ EV_L2_RNR,
+};
+
+#define L2_EVENT_COUNT (EV_L2_RNR+1)
+
+static char *strL2Event[] =
+{
+ "EV_L2_UI",
+ "EV_L2_SABMX",
+ "EV_L2_UA",
+ "EV_L2_DISC",
+ "EV_L2_I",
+ "EV_L2_RR",
+ "EV_L2_REJ",
+ "EV_L2_FRMR",
+ "EV_L2_DL_DATA",
+ "EV_L2_DL_ESTABLISH",
+ "EV_L2_MDL_ASSIGN",
+ "EV_L2_MDL_REMOVE",
+ "EV_L2_DL_UNIT_DATA",
+ "EV_L2_DL_RELEASE",
+ "EV_L2_MDL_NOTEIPROC",
+ "EV_L2_T200",
+ "EV_L2_ACK_PULL",
+ "EV_L2_T203",
+ "EV_L2_RNR",
+};
+
+int errcount = 0;
+
+static int l2addrsize(struct Layer2 *tsp);
+
+static void
+InitWin(struct Layer2 *l2)
+{
+ int i;
+
+ for (i = 0; i < MAX_WINDOW; i++)
+ l2->windowar[i] = NULL;
+}
+
+static void
+ReleaseWin(struct Layer2 *l2)
+{
+ int i, cnt = 0;
+
+
+ for (i = 0; i < MAX_WINDOW; i++) {
+ if (l2->windowar[i]) {
+ cnt++;
+ dev_kfree_skb(l2->windowar[i], FREE_WRITE);
+ l2->windowar[i] = NULL;
+ }
+ }
+ if (cnt)
+ printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
+}
+
+static int
+cansend(struct PStack *st)
+{
+ int p1;
+
+ p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
+ return (st->l2.vs != p1);
+}
+
+static void
+discard_i_queue(struct PStack *st)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&st->l2.i_queue))) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ }
+}
+
+int
+l2headersize(struct Layer2 *tsp, int ui)
+{
+ return ((tsp->extended && (!ui) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
+}
+
+int
+l2addrsize(struct Layer2 *tsp)
+{
+ return (tsp->laptype == LAPD ? 2 : 1);
+}
+
+static int
+sethdraddr(struct Layer2 *tsp,
+ u_char * header, int rsp)
+{
+ u_char *ptr = header;
+ int crbit;
+
+ if (tsp->laptype == LAPD) {
+ crbit = rsp;
+ if (!tsp->orig)
+ crbit = !crbit;
+ *ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
+ *ptr++ = (tsp->tei << 1) | 1;
+ return (2);
+ } else {
+ crbit = rsp;
+ if (tsp->orig)
+ crbit = !crbit;
+ if (crbit)
+ *ptr++ = 1;
+ else
+ *ptr++ = 3;
+ return (1);
+ }
+}
+
+static void
+enqueue_ui(struct PStack *st,
+ struct sk_buff *skb)
+{
+ st->l2.l2l1(st, PH_DATA, skb);
+}
+
+static void
+enqueue_super(struct PStack *st,
+ struct sk_buff *skb)
+{
+ st->l2.l2l1(st, PH_DATA, skb);
+}
+
+static int
+legalnr(struct PStack *st, int nr)
+{
+ struct Layer2 *l2 = &st->l2;
+ int lnr, lvs;
+
+ lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
+ lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
+ return (lnr <= lvs);
+}
+
+static void
+setva(struct PStack *st, int nr)
+{
+ struct Layer2 *l2 = &st->l2;
+
+ if (l2->va != nr) {
+ while (l2->va != nr) {
+ l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
+ dev_kfree_skb(l2->windowar[l2->sow], FREE_WRITE);
+ l2->windowar[l2->sow] = NULL;
+ l2->sow = (l2->sow + 1) % l2->window;
+ if (st->l4.l2writewakeup)
+ st->l4.l2writewakeup(st);
+ }
+ }
+}
+
+static void
+l2s1(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ st->l2.l2tei(st, MDL_ASSIGN, (void *) st->l2.ces);
+ FsmChangeState(fi, ST_L2_3);
+}
+
+static void
+l2_send_ui(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ u_char header[MAX_HEADER_LEN];
+ int i;
+
+ i = sethdraddr(&(st->l2), header, CMD);
+ header[i++] = UI;
+ memcpy(skb_push(skb, i), header, i);
+ enqueue_ui(st, skb);
+}
+
+static void
+l2_receive_ui(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ skb_pull(skb, l2headersize(&st->l2, 1));
+ st->l2.l2l3(st, DL_UNIT_DATA, skb);
+}
+
+inline void
+send_uframe(struct PStack *st, u_char cmd, u_char cr)
+{
+ struct sk_buff *skb;
+ u_char tmp[MAX_HEADER_LEN];
+ int i;
+
+ i = sethdraddr(&st->l2, tmp, cr);
+ tmp[i++] = cmd;
+ if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
+ printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n");
+ return;
+ }
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, i), tmp, i);
+ enqueue_super(st, skb);
+}
+
+static void
+establishlink(struct FsmInst *fi)
+{
+ struct PStack *st = fi->userdata;
+ u_char cmd;
+
+ FsmChangeState(fi, ST_L2_5);
+ st->l2.rc = 0;
+
+ if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 1");
+
+
+ cmd = (st->l2.extended ? SABME : SABM) | 0x10;
+ send_uframe(st, cmd, CMD);
+}
+
+static void
+l2_establish(struct FsmInst *fi, int event, void *arg)
+{
+ establishlink(fi);
+}
+
+static void
+l2_send_disconn(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct Channel *chanp = st->l4.userdata;
+
+ FsmChangeState(fi, ST_L2_6);
+
+ FsmDelTimer(&st->l2.t203_timer, 1);
+ if (st->l2.t200_running) {
+ FsmDelTimer(&st->l2.t200_timer, 2);
+ st->l2.t200_running = 0;
+ }
+ st->l2.rc = 0;
+ if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 2");
+
+
+ if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
+ send_uframe(st, DISC | 0x10, CMD);
+
+ discard_i_queue(st);
+}
+
+static void
+l2_got_SABMX(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int est = 1, state;
+ u_char PollFlag;
+
+ state = fi->state;
+
+ skb_pull(skb, l2addrsize(&(st->l2)));
+ PollFlag = *skb->data & 0x10;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ if (ST_L2_4 != state)
+ if (st->l2.vs != st->l2.va) {
+ discard_i_queue(st);
+ est = 1;
+ } else
+ est = 0;
+
+ st->l2.vs = 0;
+ st->l2.va = 0;
+ st->l2.vr = 0;
+ st->l2.sow = 0;
+ if (ST_L2_7 != state)
+ FsmChangeState(fi, ST_L2_7);
+
+ send_uframe(st, UA | PollFlag, RSP);
+
+ if (st->l2.t200_running) {
+ FsmDelTimer(&st->l2.t200_timer, 15);
+ st->l2.t200_running = 0;
+ }
+ if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 3");
+
+ if (est)
+ st->l2.l2man(st, DL_ESTABLISH, NULL);
+
+ if (ST_L2_8 == state)
+ if (skb_queue_len(&st->l2.i_queue) && cansend(st))
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static void
+l2_got_disconn(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ struct Channel *chanp = st->l4.userdata;
+ u_char PollFlag;
+
+ skb_pull(skb, l2addrsize(&(st->l2)));
+ PollFlag = *skb->data & 0x10;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ FsmChangeState(fi, ST_L2_4);
+
+ FsmDelTimer(&st->l2.t203_timer, 3);
+ if (st->l2.t200_running) {
+ FsmDelTimer(&st->l2.t200_timer, 4);
+ st->l2.t200_running = 0;
+ }
+ if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
+ send_uframe(st, UA | PollFlag, RSP);
+
+ st->l2.l2man(st, DL_RELEASE, NULL);
+}
+
+static void
+l2_got_st4_disc(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ struct Channel *chanp = st->l4.userdata;
+ u_char PollFlag;
+
+ skb_pull(skb, l2addrsize(&(st->l2)));
+ PollFlag = *skb->data & 0x10;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ if (!((chanp->impair == 1) && (st->l2.laptype == LAPB)))
+ send_uframe(st, DM | (PollFlag ? 0x10 : 0x0), RSP);
+
+}
+
+static void
+l2_got_ua_establish(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ u_char f;
+
+ skb_pull(skb, l2addrsize(&(st->l2)));
+ f = *skb->data & 0x10;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ if (f) {
+ st->l2.vs = 0;
+ st->l2.va = 0;
+ st->l2.vr = 0;
+ st->l2.sow = 0;
+ FsmChangeState(fi, ST_L2_7);
+
+ FsmDelTimer(&st->l2.t200_timer, 5);
+ if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 4");
+
+ st->l2.l2man(st, DL_ESTABLISH, NULL);
+ }
+}
+
+static void
+l2_got_ua_disconn(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ u_char f;
+
+ skb_pull(skb, l2addrsize(&(st->l2)));
+ f = *skb->data & 0x10;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ if (f) {
+ FsmDelTimer(&st->l2.t200_timer, 6);
+ FsmChangeState(fi, ST_L2_4);
+ st->l2.l2man(st, DL_RELEASE, NULL);
+ }
+}
+
+inline void
+enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
+{
+ struct sk_buff *skb;
+ struct Layer2 *l2;
+ u_char tmp[MAX_HEADER_LEN];
+ int i;
+
+ l2 = &st->l2;
+ i = sethdraddr(l2, tmp, cr);
+ if (l2->extended) {
+ tmp[i++] = typ;
+ tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0);
+ } else
+ tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0);
+ if (!(skb = alloc_skb(i, GFP_ATOMIC))) {
+ printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n");
+ return;
+ }
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, i), tmp, i);
+ enqueue_super(st, skb);
+}
+
+inline void
+enquiry_response(struct PStack *st, u_char typ, u_char final)
+{
+ enquiry_cr(st, typ, RSP, final);
+}
+
+inline void
+enquiry_command(struct PStack *st, u_char typ, u_char poll)
+{
+ enquiry_cr(st, typ, CMD, poll);
+}
+
+static void
+nrerrorrecovery(struct FsmInst *fi)
+{
+ /* should log error here */
+ establishlink(fi);
+}
+
+static void
+l2_got_st7_RR(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct Channel *chanp = st->l4.userdata;
+ struct sk_buff *skb = arg;
+ int PollFlag, seq, rsp;
+ struct Layer2 *l2;
+
+ l2 = &st->l2;
+ if (l2->laptype == LAPD)
+ rsp = *skb->data & 0x2;
+ else
+ rsp = *skb->data == 0x3;
+ if (l2->orig)
+ rsp = !rsp;
+
+ skb_pull(skb, l2addrsize(l2));
+ if (l2->extended) {
+ PollFlag = (skb->data[1] & 0x1) == 0x1;
+ seq = skb->data[1] >> 1;
+ } else {
+ PollFlag = (skb->data[0] & 0x10);
+ seq = (skb->data[0] >> 5) & 0x7;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ if (!((chanp->impair == 4) && (st->l2.laptype == LAPB)))
+ if ((!rsp) && PollFlag)
+ enquiry_response(st, RR, PollFlag);
+
+ if (legalnr(st, seq)) {
+ if (seq == l2->vs) {
+ setva(st, seq);
+ FsmDelTimer(&l2->t200_timer, 7);
+ l2->t200_running = 0;
+ FsmDelTimer(&l2->t203_timer, 8);
+ if (FsmAddTimer(&l2->t203_timer, l2->t203, EV_L2_T203, NULL, 5))
+ if (l2->l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 5");
+
+ if (skb_queue_len(&st->l2.i_queue))
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ } else if (l2->va != seq) {
+ setva(st, seq);
+ FsmDelTimer(&st->l2.t200_timer, 9);
+ if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 6");
+ if (skb_queue_len(&st->l2.i_queue))
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ }
+ } else
+ nrerrorrecovery(fi);
+
+ if ((fi->userint & LC_FLUSH_WAIT) && rsp && !(skb_queue_len(&st->l2.i_queue))) {
+ fi->userint &= ~LC_FLUSH_WAIT;
+ st->l2.l2man(st, DL_FLUSH, NULL);
+ }
+}
+
+static void
+l2_feed_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ skb_queue_tail(&st->l2.i_queue, skb);
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static int
+icommandreceived(struct FsmInst *fi, int event, void *arg, int *nr)
+{
+ struct PStack *st = fi->userdata;
+ struct Channel *chanp = st->l4.userdata;
+ struct sk_buff *skb = arg;
+ struct IsdnCardState *sp = st->l1.hardware;
+ struct Layer2 *l2 = &(st->l2);
+ int i, p, seq, wasok;
+ char str[64];
+
+ i = l2addrsize(l2);
+ if (l2->extended) {
+ p = (skb->data[i + 1] & 0x1) == 0x1;
+ seq = skb->data[i] >> 1;
+ *nr = (skb->data[i + 1] >> 1) & 0x7f;
+ } else {
+ p = (skb->data[i] & 0x10);
+ seq = (skb->data[i] >> 1) & 0x7;
+ *nr = (skb->data[i] >> 5) & 0x7;
+ }
+
+ if (l2->vr == seq) {
+ wasok = !0;
+
+ l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
+ l2->rejexp = 0;
+
+ if (st->l2.laptype == LAPD)
+ if (sp->dlogflag) {
+ LogFrame(st->l1.hardware, skb->data, skb->len);
+ sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
+ dlogframe(st->l1.hardware, skb->data + l2->ihsize,
+ skb->len - l2->ihsize, str);
+ }
+ if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
+ if (p || (!skb_queue_len(&st->l2.i_queue)))
+ enquiry_response(st, RR, p);
+ skb_pull(skb, l2headersize(l2, 0));
+ } else {
+ /* n(s)!=v(r) */
+ wasok = 0;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ if (st->l2.rejexp) {
+ if (p)
+ if (!((chanp->impair == 3) && (st->l2.laptype == LAPB)))
+ enquiry_response(st, RR, p);
+ } else {
+ st->l2.rejexp = !0;
+ enquiry_command(st, REJ, 1);
+ }
+ }
+ return wasok;
+}
+
+static void
+l2_got_st7_data(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int nr, wasok;
+
+ wasok = icommandreceived(fi, event, arg, &nr);
+
+ if (legalnr(st, nr)) {
+ if (nr == st->l2.vs) {
+ setva(st, nr);
+ FsmDelTimer(&st->l2.t200_timer, 10);
+ st->l2.t200_running = 0;
+ FsmDelTimer(&st->l2.t203_timer, 11);
+ if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 5");
+
+ if (skb_queue_len(&st->l2.i_queue))
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ } else if (nr != st->l2.va) {
+ setva(st, nr);
+ FsmDelTimer(&st->l2.t200_timer, 12);
+ if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 6");
+
+ if (skb_queue_len(&st->l2.i_queue))
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ }
+ } else
+ nrerrorrecovery(fi);
+
+ if (wasok)
+ st->l2.l2l3(st, DL_DATA, skb);
+}
+
+static void
+l2_got_st8_data(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int nr, wasok;
+
+ wasok = icommandreceived(fi, event, arg, &nr);
+
+ if (legalnr(st, nr)) {
+ setva(st, nr);
+ if (skb_queue_len(&st->l2.i_queue))
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ } else
+ nrerrorrecovery(fi);
+
+ if (wasok)
+ st->l2.l2l3(st, DL_DATA, skb);
+}
+
+static void
+l2_got_tei(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ st->l2.tei = (int) arg;
+ establishlink(fi);
+}
+
+static void
+invoke_retransmission(struct PStack *st, int nr)
+{
+ struct Layer2 *l2 = &st->l2;
+ int p1;
+
+ if (l2->vs != nr) {
+ while (l2->vs != nr) {
+
+ l2->vs = l2->vs - 1;
+ if (l2->vs < 0)
+ l2->vs += l2->extended ? 128 : 8;
+
+ p1 = l2->vs - l2->va;
+ if (p1 < 0)
+ p1 += l2->extended ? 128 : 8;
+ p1 = (p1 + l2->sow) % l2->window;
+
+ skb_queue_head(&l2->i_queue, l2->windowar[p1]);
+ l2->windowar[p1] = NULL;
+ }
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ }
+}
+
+static void
+l2_got_st7_rej(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int PollFlag, seq, rsp;
+ struct Layer2 *l2;
+
+ l2 = &st->l2;
+ if (l2->laptype == LAPD)
+ rsp = *skb->data & 0x2;
+ else
+ rsp = *skb->data == 0x3;
+ if (l2->orig)
+ rsp = !rsp;
+
+ skb_pull(skb, l2addrsize(l2));
+ if (l2->extended) {
+ PollFlag = (skb->data[1] & 0x1) == 0x1;
+ seq = skb->data[1] >> 1;
+ } else {
+ PollFlag = (skb->data[0] & 0x10);
+ seq = (skb->data[0] >> 5) & 0x7;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ if ((!rsp) && PollFlag)
+ enquiry_response(st, RR, PollFlag);
+
+ if (!legalnr(st, seq))
+ return;
+
+ setva(st, seq);
+ invoke_retransmission(st, seq);
+}
+
+static void
+l2_no_tei(struct FsmInst *fi, int event, void *arg)
+{
+ FsmChangeState(fi, ST_L2_4);
+}
+
+static void
+l2_st5_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ u_char cmd;
+
+ if (st->l2.rc == st->l2.n200) {
+ FsmChangeState(fi, ST_L2_4);
+ st->l2.l2tei(st, MDL_VERIFY, (void *) st->l2.tei);
+ st->l2.l2man(st, DL_RELEASE, NULL);
+ } else {
+ st->l2.rc++;
+
+ if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 7");
+
+ cmd = (st->l2.extended ? SABME : SABM) | 0x10;
+ send_uframe(st, cmd, CMD);
+ }
+}
+
+static void
+l2_st6_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct Channel *chanp = st->l4.userdata;
+
+ if (st->l2.rc == st->l2.n200) {
+ FsmChangeState(fi, ST_L2_4);
+ st->l2.l2man(st, DL_RELEASE, NULL);
+ } else {
+ st->l2.rc++;
+
+ if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 8");
+
+
+ if (!((chanp->impair == 2) && (st->l2.laptype == LAPB)))
+ send_uframe(st, DISC | 0x10, CMD);
+
+ }
+}
+
+static void
+l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb;
+ struct Layer2 *l2 = &st->l2;
+ u_char header[MAX_HEADER_LEN];
+ int p1, i;
+
+ if (!cansend(st))
+ return;
+
+ skb = skb_dequeue(&l2->i_queue);
+ if (!skb)
+ return;
+
+ p1 = l2->vs - l2->va;
+ if (p1 < 0)
+ p1 += l2->extended ? 128 : 8;
+ p1 = (p1 + l2->sow) % l2->window;
+ if (l2->windowar[p1]) {
+ printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n",
+ p1);
+ dev_kfree_skb(l2->windowar[p1], FREE_WRITE);
+ }
+ l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC);
+
+ i = sethdraddr(&st->l2, header, CMD);
+
+ if (l2->extended) {
+ header[i++] = l2->vs << 1;
+ header[i++] = l2->vr << 1;
+ l2->vs = (l2->vs + 1) % 128;
+ } else {
+ header[i++] = (l2->vr << 5) | (l2->vs << 1);
+ l2->vs = (l2->vs + 1) % 8;
+ }
+
+ memcpy(skb_push(skb, i), header, i);
+ st->l2.l2l1(st, PH_DATA_PULLED, skb);
+ if (!st->l2.t200_running) {
+ FsmDelTimer(&st->l2.t203_timer, 13);
+ if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 9");
+
+ st->l2.t200_running = !0;
+ }
+ if (skb_queue_len(&l2->i_queue) && cansend(st))
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+}
+
+static void
+transmit_enquiry(struct PStack *st)
+{
+
+ enquiry_command(st, RR, 1);
+ if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 10");
+
+ st->l2.t200_running = !0;
+}
+
+static void
+l2_st7_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ st->l2.t200_running = 0;
+
+ st->l2.rc = 1;
+ FsmChangeState(fi, ST_L2_8);
+ transmit_enquiry(st);
+}
+
+static void
+l2_got_st8_rr_rej(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ int PollFlag, seq, rsp;
+ struct Layer2 *l2;
+
+ l2 = &st->l2;
+ if (l2->laptype == LAPD)
+ rsp = *skb->data & 0x2;
+ else
+ rsp = *skb->data == 0x3;
+ if (l2->orig)
+ rsp = !rsp;
+
+ skb_pull(skb, l2addrsize(l2));
+ if (l2->extended) {
+ PollFlag = (skb->data[1] & 0x1) == 0x1;
+ seq = skb->data[1] >> 1;
+ } else {
+ PollFlag = (skb->data[0] & 0x10);
+ seq = (skb->data[0] >> 5) & 0x7;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ if (rsp && PollFlag) {
+ if (legalnr(st, seq)) {
+ FsmChangeState(fi, ST_L2_7);
+ setva(st, seq);
+ if (st->l2.t200_running) {
+ FsmDelTimer(&st->l2.t200_timer, 14);
+ st->l2.t200_running = 0;
+ }
+ if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
+ if (st->l2.l2m.debug)
+ l2m_debug(&st->l2.l2m, "FAT 11");
+
+ invoke_retransmission(st, seq);
+
+ if (skb_queue_len(&l2->i_queue) && cansend(st))
+ st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
+ else if (fi->userint & LC_FLUSH_WAIT) {
+ fi->userint &= ~LC_FLUSH_WAIT;
+ st->l2.l2man(st, DL_FLUSH, NULL);
+ }
+ }
+ } else {
+ if (!rsp && PollFlag)
+ enquiry_response(st, RR, PollFlag);
+ if (legalnr(st, seq)) {
+ setva(st, seq);
+ }
+ }
+}
+
+static void
+l2_st7_tout_203(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ st->l2.rc = 0;
+ FsmChangeState(fi, ST_L2_8);
+ transmit_enquiry(st);
+}
+
+static void
+l2_st8_tout_200(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+ if (st->l2.rc == st->l2.n200) {
+ establishlink(fi);
+ } else {
+ st->l2.rc++;
+ transmit_enquiry(st);
+ }
+}
+
+static void
+l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+ struct sk_buff *skb = arg;
+ char tmp[64];
+
+ skb_pull(skb, l2addrsize(&st->l2));
+ if (st->l2.l2m.debug) {
+ if (st->l2.extended)
+ sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
+ skb->data[0], skb->data[1], skb->data[2],
+ skb->data[3], skb->data[4]);
+ else
+ sprintf(tmp, "FRMR information %2x %2x %2x",
+ skb->data[0], skb->data[1], skb->data[2]);
+
+ l2m_debug(&st->l2.l2m, tmp);
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+}
+
+static void
+l2_tei_remove(struct FsmInst *fi, int event, void *arg)
+{
+ struct PStack *st = fi->userdata;
+
+/*TODO
+ if( DL_RELEASE.req outstanding ) {
+ ... issue DL_RELEASE.confirm
+ } else {
+ if( fi->state != ST_L2_4 ) {
+ ... issue DL_RELEASE.indication
+ }
+ }
+ TODO */
+ discard_i_queue(st); /* There is no UI queue in layer 2 */
+ st->l2.tei = 255;
+ if (st->l2.t200_running) {
+ FsmDelTimer(&st->l2.t200_timer, 18);
+ st->l2.t200_running = 0;
+ }
+ FsmDelTimer(&st->l2.t203_timer, 19);
+ st->l2.l2man(st, DL_RELEASE, NULL); /* TEMP */
+ FsmChangeState(fi, ST_L2_1);
+}
+
+inline int
+IsUI(u_char * data, int ext)
+{
+ return ((data[0] & 0xef) == UI);
+}
+
+inline int
+IsUA(u_char * data, int ext)
+{
+ return ((data[0] & 0xef) == UA);
+}
+
+inline int
+IsDISC(u_char * data, int ext)
+{
+ return ((data[0] & 0xef) == DISC);
+}
+
+inline int
+IsRR(u_char * data, int ext)
+{
+ if (ext)
+ return (data[0] == RR);
+ else
+ return ((data[0] & 0xf) == 1);
+}
+
+inline int
+IsI(u_char * data, int ext)
+{
+ return ((data[0] & 0x1) == 0x0);
+}
+
+inline int
+IsSABMX(u_char * data, int ext)
+{
+ u_char d = data[0] & ~0x10;
+
+ return (ext ? d == SABME : d == SABM);
+}
+
+inline int
+IsREJ(u_char * data, int ext)
+{
+ return (ext ? data[0] == REJ : (data[0] & 0xf) == 0x9);
+}
+
+inline int
+IsFRMR(u_char * data, int ext)
+{
+ return ((data[0] & 0xef) == FRMR);
+}
+
+inline int
+IsRNR(u_char * data, int ext)
+{
+ if (ext)
+ return (data[0] == RNR);
+ else
+ return ((data[0] & 0xf) == 5);
+}
+
+static struct FsmNode L2FnList[] =
+{
+ {ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
+ {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2_no_tei},
+ {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei},
+ {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui},
+ {ST_L2_4, EV_L2_DL_ESTABLISH, l2_establish},
+ {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui},
+ {ST_L2_7, EV_L2_DL_DATA, l2_feed_iqueue},
+ {ST_L2_7, EV_L2_DL_RELEASE, l2_send_disconn},
+ {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue},
+ {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue},
+ {ST_L2_8, EV_L2_DL_RELEASE, l2_send_disconn},
+
+ {ST_L2_1, EV_L2_UI, l2_receive_ui},
+ {ST_L2_4, EV_L2_UI, l2_receive_ui},
+ {ST_L2_4, EV_L2_SABMX, l2_got_SABMX},
+ {ST_L2_4, EV_L2_DISC, l2_got_st4_disc},
+ {ST_L2_5, EV_L2_UA, l2_got_ua_establish},
+ {ST_L2_6, EV_L2_UA, l2_got_ua_disconn},
+ {ST_L2_7, EV_L2_UI, l2_receive_ui},
+ {ST_L2_7, EV_L2_DISC, l2_got_disconn},
+ {ST_L2_7, EV_L2_I, l2_got_st7_data},
+ {ST_L2_7, EV_L2_RR, l2_got_st7_RR},
+ {ST_L2_7, EV_L2_REJ, l2_got_st7_rej},
+ {ST_L2_7, EV_L2_SABMX, l2_got_SABMX},
+ {ST_L2_7, EV_L2_FRMR, l2_got_FRMR},
+ {ST_L2_8, EV_L2_RR, l2_got_st8_rr_rej},
+ {ST_L2_8, EV_L2_REJ, l2_got_st8_rr_rej},
+ {ST_L2_8, EV_L2_SABMX, l2_got_SABMX},
+ {ST_L2_8, EV_L2_DISC, l2_got_disconn},
+ {ST_L2_8, EV_L2_FRMR, l2_got_FRMR},
+ {ST_L2_8, EV_L2_I, l2_got_st8_data},
+
+ {ST_L2_5, EV_L2_T200, l2_st5_tout_200},
+ {ST_L2_6, EV_L2_T200, l2_st6_tout_200},
+ {ST_L2_7, EV_L2_T200, l2_st7_tout_200},
+ {ST_L2_7, EV_L2_T203, l2_st7_tout_203},
+ {ST_L2_8, EV_L2_T200, l2_st8_tout_200},
+
+ {ST_L2_1, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_3, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_4, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_5, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_6, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove},
+ {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove},
+};
+
+#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
+
+static void
+isdnl2_l1l2(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ u_char *datap;
+ int ret = !0;
+
+ switch (pr) {
+ case (PH_DATA):
+ datap = skb->data;
+ datap += l2addrsize(&st->l2);
+
+ if (IsI(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb);
+ else if (IsRR(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_RR, skb);
+ else if (IsUI(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb);
+ else if (IsSABMX(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, skb);
+ else if (IsUA(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb);
+ else if (IsDISC(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb);
+ else if (IsREJ(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, skb);
+ else if (IsFRMR(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
+ else if (IsRNR(datap, st->l2.extended))
+ ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, skb);
+
+ if (ret) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ }
+ break;
+ case (PH_PULL_ACK):
+ FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
+ break;
+ }
+}
+
+static void
+isdnl2_l3l2(struct PStack *st, int pr, void *arg)
+{
+ switch (pr) {
+ case (DL_DATA):
+ if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) {
+ dev_kfree_skb((struct sk_buff *) arg, FREE_READ);
+ }
+ break;
+ case (DL_UNIT_DATA):
+ if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) {
+ dev_kfree_skb((struct sk_buff *) arg, FREE_READ);
+ }
+ break;
+ }
+}
+
+static void
+isdnl2_manl2(struct PStack *st, int pr, void *arg)
+{
+ switch (pr) {
+ case (DL_ESTABLISH):
+ FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
+ break;
+ case (DL_RELEASE):
+ FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
+ break;
+ case (MDL_NOTEIPROC):
+ FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
+ break;
+ case (DL_FLUSH):
+ (&st->l2.l2m)->userint |= LC_FLUSH_WAIT;
+ break;
+ }
+}
+
+static void
+isdnl2_teil2(struct PStack *st, int pr, void *arg)
+{
+ switch (pr) {
+ case (MDL_ASSIGN):
+ FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
+ break;
+ case (MDL_REMOVE):
+ FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg);
+ break;
+ }
+}
+
+void
+releasestack_isdnl2(struct PStack *st)
+{
+ FsmDelTimer(&st->l2.t200_timer, 15);
+ FsmDelTimer(&st->l2.t203_timer, 16);
+ discard_i_queue(st);
+ ReleaseWin(&st->l2);
+}
+
+static void
+l2m_debug(struct FsmInst *fi, char *s)
+{
+ struct PStack *st = fi->userdata;
+ char tm[32], str[256];
+
+ jiftime(tm, jiffies);
+ sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
+ HiSax_putstatus(st->l1.hardware, str);
+}
+
+void
+setstack_isdnl2(struct PStack *st, char *debug_id)
+{
+ st->l1.l1l2 = isdnl2_l1l2;
+ st->l3.l3l2 = isdnl2_l3l2;
+ st->ma.manl2 = isdnl2_manl2;
+ st->ma.teil2 = isdnl2_teil2;
+
+ st->l2.uihsize = l2headersize(&st->l2, !0);
+ st->l2.ihsize = l2headersize(&st->l2, 0);
+ skb_queue_head_init(&st->l2.i_queue);
+ InitWin(&st->l2);
+ st->l2.rejexp = 0;
+ st->l2.debug = 0;
+
+ st->l2.l2m.fsm = &l2fsm;
+ st->l2.l2m.state = ST_L2_1;
+ st->l2.l2m.debug = 0;
+ st->l2.l2m.userdata = st;
+ st->l2.l2m.userint = 0;
+ st->l2.l2m.printdebug = l2m_debug;
+ strcpy(st->l2.debug_id, debug_id);
+
+ FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
+ FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
+ st->l2.t200_running = 0;
+}
+
+void
+setstack_transl2(struct PStack *st)
+{
+}
+
+void
+releasestack_transl2(struct PStack *st)
+{
+}
+
+void
+Isdnl2New(void)
+{
+ l2fsm.state_count = L2_STATE_COUNT;
+ l2fsm.event_count = L2_EVENT_COUNT;
+ l2fsm.strEvent = strL2Event;
+ l2fsm.strState = strL2State;
+ FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
+}
+
+void
+Isdnl2Free(void)
+{
+ FsmFree(&l2fsm);
+}
--- /dev/null
+/* isdnl2.h */
+
+#define RR 0x01
+#define RNR 0x05
+#define REJ 0x09
+#define SABME 0x6f
+#define SABM 0x2f
+#define DM 0x0f
+#define UI 0x03
+#define DISC 0x43
+#define UA 0x63
+#define FRMR 0x87
+#define XID 0xaf
+
+#define CMD 0
+#define RSP 1
+
+#define LC_FLUSH_WAIT 1
--- /dev/null
+/* $Id: isdnl3.c,v 1.10 1997/04/06 22:54:16 keil Exp $
+
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * based on the teles driver from Jan den Ouden
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ *
+ * $Log: isdnl3.c,v $
+ * Revision 1.10 1997/04/06 22:54:16 keil
+ * Using SKB's
+ *
+ * Revision 1.9 1997/03/25 23:11:25 keil
+ * US NI-1 protocol
+ *
+ * Revision 1.8 1997/03/21 18:53:44 keil
+ * Report no protocol error to syslog too
+ *
+ * Revision 1.7 1997/03/17 18:34:38 keil
+ * fixed oops if no protocol selected during config
+ *
+ * Revision 1.6 1997/02/16 01:04:08 fritz
+ * Bugfix: Changed timer handling caused hang with 2.1.X
+ *
+ * Revision 1.5 1997/02/09 00:26:27 keil
+ * new interface handling, one interface per card
+ * leased line changes
+ *
+ * Revision 1.4 1997/01/27 23:17:44 keil
+ * delete timers while unloading
+ *
+ * Revision 1.3 1997/01/21 22:31:12 keil
+ * new statemachine; L3 timers
+ *
+ * Revision 1.2 1996/11/05 19:42:04 keil
+ * using config.h
+ *
+ * Revision 1.1 1996/10/13 20:04:54 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl3.h"
+#include <linux/config.h>
+
+const char *l3_revision = "$Revision: 1.10 $";
+
+void
+l3_debug(struct PStack *st, char *s)
+{
+ char str[256], tm[32];
+
+ jiftime(tm, jiffies);
+ sprintf(str, "%s Channel %d l3 %s\n", tm, st->l3.channr, s);
+ HiSax_putstatus(st->l1.hardware, str);
+}
+
+
+
+void
+newl3state(struct PStack *st, int state)
+{
+ char tmp[80];
+
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "newstate %d --> %d", st->l3.state, state);
+ l3_debug(st, tmp);
+ }
+ st->l3.state = state;
+}
+
+static void
+L3ExpireTimer(struct L3Timer *t)
+{
+ t->st->l4.l4l3(t->st, t->event, NULL);
+}
+
+void
+L3InitTimer(struct PStack *st, struct L3Timer *t)
+{
+ t->st = st;
+ t->tl.function = (void *) L3ExpireTimer;
+ t->tl.data = (long) t;
+ init_timer(&t->tl);
+}
+
+void
+L3DelTimer(struct L3Timer *t)
+{
+ del_timer(&t->tl);
+}
+
+int
+L3AddTimer(struct L3Timer *t,
+ int millisec, int event)
+{
+ if (t->tl.next || t->tl.prev) {
+ printk(KERN_WARNING "L3AddTimer: timer already active!\n");
+ return -1;
+ }
+ init_timer(&t->tl);
+ t->event = event;
+ t->tl.expires = jiffies + (millisec * HZ) / 1000;
+ add_timer(&t->tl);
+ return 0;
+}
+
+void
+StopAllL3Timer(struct PStack *st)
+{
+ L3DelTimer(&st->l3.timer);
+}
+
+struct sk_buff *
+l3_alloc_skb(int len)
+{
+ struct sk_buff *skb;
+
+ if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) {
+ printk(KERN_WARNING "HiSax: No skb for D-channel\n");
+ return (NULL);
+ }
+ SET_SKB_FREE(skb);
+ skb_reserve(skb, MAX_HEADER_LEN);
+ return (skb);
+}
+
+static void
+no_l3_proto(struct PStack *st, int pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ l3_debug(st, "no protocol");
+ if (skb)
+ dev_kfree_skb(skb, FREE_READ);
+}
+
+#ifdef CONFIG_HISAX_EURO
+extern void setstack_dss1(struct PStack *st);
+#endif
+
+#ifdef CONFIG_HISAX_NI1
+extern void setstack_ni1(struct PStack *st);
+#endif
+
+#ifdef CONFIG_HISAX_1TR6
+extern void setstack_1tr6(struct PStack *st);
+#endif
+
+void
+setstack_isdnl3(struct PStack *st, struct Channel *chanp)
+{
+ char tmp[64];
+
+ st->l3.debug = L3_DEB_WARN;
+ st->l3.channr = chanp->chan;
+ L3InitTimer(st, &st->l3.timer);
+
+#ifdef CONFIG_HISAX_EURO
+ if (st->protocol == ISDN_PTYPE_EURO) {
+ setstack_dss1(st);
+ } else
+#endif
+#ifdef CONFIG_HISAX_NI1
+ if (st->protocol == ISDN_PTYPE_NI1) {
+ setstack_ni1(st);
+ } else
+#endif
+#ifdef CONFIG_HISAX_1TR6
+ if (st->protocol == ISDN_PTYPE_1TR6) {
+ setstack_1tr6(st);
+ } else
+#endif
+ if (st->protocol == ISDN_PTYPE_LEASED) {
+ st->l4.l4l3 = no_l3_proto;
+ st->l2.l2l3 = no_l3_proto;
+ printk(KERN_NOTICE "HiSax: Leased line mode\n");
+ } else {
+ st->l4.l4l3 = no_l3_proto;
+ st->l2.l2l3 = no_l3_proto;
+ sprintf(tmp, "protocol %s not supported",
+ (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" :
+ (st->protocol == ISDN_PTYPE_EURO) ? "euro" :
+ (st->protocol == ISDN_PTYPE_NI1) ? "ni1" :
+ "unknown");
+ printk(KERN_WARNING "HiSax: %s\n", tmp);
+ l3_debug(st, tmp);
+ st->protocol = -1;
+ }
+ st->l3.state = 0;
+ st->l3.callref = 0;
+}
+
+void
+releasestack_isdnl3(struct PStack *st)
+{
+ StopAllL3Timer(st);
+}
--- /dev/null
+/* $Id: isdnl3.h,v 1.3 1997/04/06 22:54:17 keil Exp $
+ *
+ * $Log: isdnl3.h,v $
+ * Revision 1.3 1997/04/06 22:54:17 keil
+ * Using SKB's
+ *
+ * Revision 1.2 1997/01/21 22:31:28 keil
+ * new statemachine; L3 timers
+ *
+ * Revision 1.1 1996/10/13 20:03:47 keil
+ * Initial revision
+ *
+ *
+ */
+
+#define SBIT(state) (1<<state)
+#define ALL_STATES 0x00ffffff
+
+#define PROTO_DIS_EURO 0x08
+
+#define L3_DEB_WARN 0x01
+#define L3_DEB_PROTERR 0x02
+#define L3_DEB_STATE 0x04
+#define L3_DEB_CHARGE 0x08
+
+struct stateentry {
+ int state;
+ u_char primitive;
+ void (*rout) (struct PStack *, u_char, void *);
+};
+
+extern void l3_debug(struct PStack *st, char *s);
+extern void newl3state(struct PStack *st, int state);
+extern void L3InitTimer(struct PStack *st, struct L3Timer *t);
+extern void L3DelTimer(struct L3Timer *t);
+extern int L3AddTimer(struct L3Timer *t, int millisec, int event);
+extern void StopAllL3Timer(struct PStack *st);
+extern struct sk_buff *l3_alloc_skb(int len);
--- /dev/null
+/* $Id: ix1_micro.c,v 1.3 1997/04/13 19:54:02 keil Exp $
+
+ * ix1_micro.c low level stuff for ITK ix1-micro Rev.2 isdn cards
+ * derived from the original file teles3.c from Karsten Keil
+ *
+ * Copyright (C) 1997 Klaus-Peter Nischke (ITK AG) (for the modifications to
+ * the original file teles.c)
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ * Beat Doebeli
+ *
+ * $Log: ix1_micro.c,v $
+ * Revision 1.3 1997/04/13 19:54:02 keil
+ * Change in IRQ check delay for SMP
+ *
+ * Revision 1.2 1997/04/06 22:54:21 keil
+ * Using SKB's
+ *
+ * Revision 1.1 1997/01/27 15:43:10 keil
+ * first version
+ *
+ *
+ */
+
+/*
+ For the modification done by the author the following terms and conditions
+ apply (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.
+
+
+ You may contact Klaus-Peter Nischke by email: klaus@nischke.do.eunet.de
+ or by conventional mail:
+
+ Klaus-Peter Nischke
+ Deusener Str. 287
+ 44369 Dortmund
+ Germany
+ */
+
+
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "teles3.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+const char *ix1_revision = "$Revision: 1.3 $";
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+#define SPECIAL_PORT_OFFSET 3
+
+#define ISAC_COMMAND_OFFSET 2
+#define ISAC_DATA_OFFSET 0
+#define HSCX_COMMAND_OFFSET 2
+#define HSCX_DATA_OFFSET 1
+
+#define ISAC_FIFOSIZE 16
+#define HSCX_FIFOSIZE 16
+
+#define TIMEOUT 50
+
+static inline u_char
+IsacReadReg(unsigned int adr, u_char off)
+{
+ byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20);
+ return bytein(adr + ISAC_DATA_OFFSET);
+}
+
+static inline void
+IsacWriteReg(unsigned int adr, u_char off, u_char data)
+{
+ byteout(adr + ISAC_COMMAND_OFFSET, off + 0x20);
+ byteout(adr + ISAC_DATA_OFFSET, data);
+}
+
+#define HSCX_OFFSET(WhichHscx,offset) \
+( (WhichHscx) ? (offset+0x60) : (offset+0x20) )
+
+static inline u_char
+HscxReadReg(unsigned int adr, int WhichHscx, u_char off)
+{
+ byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off));
+ return bytein(adr + HSCX_DATA_OFFSET);
+}
+
+static inline void
+HscxWriteReg(unsigned int adr, int WhichHscx, u_char off, u_char data)
+{
+ byteout(adr + HSCX_COMMAND_OFFSET, HSCX_OFFSET(WhichHscx, off));
+ byteout(adr + HSCX_DATA_OFFSET, data);
+}
+
+
+static inline void
+IsacReadFifo(unsigned int adr, u_char * data, int size)
+{
+ byteout(adr + ISAC_COMMAND_OFFSET, 0);
+ while (size--)
+ *data++ = bytein(adr + ISAC_DATA_OFFSET);
+}
+
+static void
+IsacWriteFifo(unsigned int adr, u_char * data, int size)
+{
+ byteout(adr + ISAC_COMMAND_OFFSET, 0);
+ while (size--) {
+ byteout(adr + ISAC_DATA_OFFSET, *data);
+ data++;
+ }
+}
+
+static inline void
+HscxReadFifo(unsigned int adr, int WhichHscx, u_char * data, int size)
+{
+ byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00);
+ while (size--)
+ *data++ = bytein(adr + HSCX_DATA_OFFSET);
+}
+
+static void
+HscxWriteFifo(unsigned int adr, int WhichHscx, u_char * data, int size)
+{
+ byteout(adr + HSCX_COMMAND_OFFSET, (WhichHscx) ? 0x40 : 0x00);
+ while (size--) {
+ byteout(adr + HSCX_DATA_OFFSET, *data);
+ data++;
+ }
+}
+
+static inline void
+waitforCEC(int adr, int WhichHscx)
+{
+ int to = TIMEOUT;
+
+ while ((HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x04) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "ix1-Micro: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr, int WhichHscx)
+{
+ int to = TIMEOUT;
+
+ while ((!(HscxReadReg(adr, WhichHscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "ix1-Micro: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, int WhichHscx, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ waitforCEC(adr, WhichHscx);
+ HscxWriteReg(adr, WhichHscx, HSCX_CMDR, data);
+ restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+ printk(KERN_DEBUG "HSCX %d\n", hscx);
+ printk(KERN_DEBUG "ISTA %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", HscxReadReg(sp->hscx[hscx], hscx, HSCX_EXIR));
+}
+
+void
+ix1micro_report(struct IsdnCardState *sp)
+{
+ printk(KERN_DEBUG "ISAC\n");
+ printk(KERN_DEBUG "ISTA %x\n", IsacReadReg(sp->isac, ISAC_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", IsacReadReg(sp->isac, ISAC_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", IsacReadReg(sp->isac, ISAC_EXIR));
+ hscxreport(sp, 0);
+ hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+ u_char *ptr;
+ struct IsdnCardState *sp = hsp->sp;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_empty_fifo");
+
+ if (hsp->rcvidx + count > HSCX_BUFMAX) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+ writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
+ hsp->rcvidx = 0;
+ return;
+ }
+ ptr = hsp->rcvbuf + hsp->rcvidx;
+ hsp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ HscxReadFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count);
+ writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+ struct IsdnCardState *sp = hsp->sp;
+ int more, count;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_fill_fifo");
+
+ if (!hsp->tx_skb)
+ return;
+ if (hsp->tx_skb->len <= 0)
+ return;
+
+ more = (hsp->mode == 1) ? 1 : 0;
+ if (hsp->tx_skb->len > 32) {
+ more = !0;
+ count = 32;
+ } else
+ count = hsp->tx_skb->len;
+
+ waitforXFW(sp->hscx[hsp->hscx], hsp->hscx);
+ save_flags(flags);
+ cli();
+ ptr = hsp->tx_skb->data;
+ skb_pull(hsp->tx_skb, count);
+ hsp->tx_cnt -= count;
+ hsp->count += count;
+ HscxWriteFifo(sp->hscx[hsp->hscx], hsp->hscx, ptr, count);
+ writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+ u_char r;
+ struct HscxState *hsp = sp->hs + hscx;
+ struct sk_buff *skb;
+ int count;
+ char tmp[32];
+
+ if (!hsp->init)
+ return;
+
+ if (val & 0x80) { /* RME */
+
+ r = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RSTA);
+ if ((r & 0xf0) != 0xa0) {
+ if (!r & 0x80)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX invalid frame");
+ if ((r & 0x40) && hsp->mode)
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX RDO mode=%d",
+ hsp->mode);
+ debugl1(sp, tmp);
+ }
+ if (!r & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX CRC error");
+ writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80);
+ } else {
+ count = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ hscx_empty_fifo(hsp, count);
+ if ((count = hsp->rcvidx - 1) > 0) {
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ sprintf(tmp, "HX Frame %d", count);
+ debugl1(sp, tmp);
+ }
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "IX1: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ }
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ hscx_empty_fifo(hsp, 32);
+ if (hsp->mode == 1) {
+ /* receive audio data */
+ if (!(skb = dev_alloc_skb(32)))
+ printk(KERN_WARNING "IX1: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ }
+ if (val & 0x10) { /* XPR */
+ if (hsp->tx_skb)
+ if (hsp->tx_skb->len) {
+ hscx_fill_fifo(hsp);
+ return;
+ } else {
+ dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+ hsp->count = 0;
+ if (hsp->st->l4.l1writewakeup)
+ hsp->st->l4.l1writewakeup(hsp->st);
+ hsp->tx_skb = NULL;
+ }
+ if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+ hsp->count = 0;
+ hscx_fill_fifo(hsp);
+ } else
+ hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+ }
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ if (sp->debug & L1_DEB_ISAC)
+ debugl1(sp, "isac_empty_fifo");
+
+ if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+ if (sp->debug & L1_DEB_WARN) {
+ char tmp[40];
+ sprintf(tmp, "isac_empty_fifo overrun %d",
+ sp->rcvidx + count);
+ debugl1(sp, tmp);
+ }
+ IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
+ sp->rcvidx = 0;
+ return;
+ }
+ ptr = sp->rcvbuf + sp->rcvidx;
+ sp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ IsacReadFifo(sp->isac, ptr, count);
+ IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_empty_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+ int count, more;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ debugl1(sp, "isac_fill_fifo");
+
+ if (!sp->tx_skb)
+ return;
+
+ count = sp->tx_skb->len;
+ if (count <= 0)
+ return;
+
+ more = 0;
+ if (count > 32) {
+ more = !0;
+ count = 32;
+ }
+ save_flags(flags);
+ cli();
+ ptr = sp->tx_skb->data;
+ skb_pull(sp->tx_skb, count);
+ sp->tx_cnt += count;
+ IsacWriteFifo(sp->isac, ptr, count);
+ IsacWriteReg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_fill_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+ if (sp->debug & L1_DEB_ISAC) {
+ char tmp[32];
+ sprintf(tmp, "ph_command %d", command);
+ debugl1(sp, tmp);
+ }
+ IsacWriteReg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+ u_char exval;
+ struct sk_buff *skb;
+ unsigned int count;
+ char tmp[32];
+
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "ISAC interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ if (val & 0x80) { /* RME */
+ exval = IsacReadReg(sp->isac, ISAC_RSTA);
+ if ((exval & 0x70) != 0x20) {
+ if (exval & 0x40)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RDO");
+ if (!exval & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC CRC error");
+ IsacWriteReg(sp->isac, ISAC_CMDR, 0x80);
+ } else {
+ count = IsacReadReg(sp->isac, ISAC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(sp, count);
+ if ((count = sp->rcvidx) > 0) {
+ sp->rcvidx = 0;
+ if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+ printk(KERN_WARNING "IX1: D receive out of memory\n");
+ else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, count), sp->rcvbuf, count);
+ skb_queue_tail(&sp->rq, skb);
+ }
+ }
+ }
+ sp->rcvidx = 0;
+ isac_sched_event(sp, ISAC_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ isac_empty_fifo(sp, 32);
+ }
+ if (val & 0x20) { /* RSC */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RSC interrupt");
+ }
+ if (val & 0x10) { /* XPR */
+ if (sp->tx_skb)
+ if (sp->tx_skb->len) {
+ isac_fill_fifo(sp);
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+ sp->tx_cnt = 0;
+ sp->tx_skb = NULL;
+ }
+ if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+ sp->tx_cnt = 0;
+ isac_fill_fifo(sp);
+ } else
+ isac_sched_event(sp, ISAC_XMTBUFREADY);
+ }
+ afterXPR:
+ if (val & 0x04) { /* CISQ */
+ sp->ph_state = (IsacReadReg(sp->isac, ISAC_CIX0) >> 2)
+ & 0xf;
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "l1state %d", sp->ph_state);
+ debugl1(sp, tmp);
+ }
+ isac_new_ph(sp);
+ }
+ if (val & 0x02) { /* SIN */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC SIN interrupt");
+ }
+ if (val & 0x01) { /* EXI */
+ exval = IsacReadReg(sp->isac, ISAC_EXIR);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC EXIR %02x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+ u_char exval;
+ struct HscxState *hsp;
+ char tmp[32];
+
+
+ if (val & 0x01) {
+ hsp = sp->hs + 1;
+ exval = HscxReadReg(sp->hscx[1], 1, HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0xf8) {
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, val, 1);
+ }
+ if (val & 0x02) {
+ hsp = sp->hs;
+ exval = HscxReadReg(sp->hscx[0], 0, HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0x04) {
+ exval = HscxReadReg(sp->hscx[0], 0, HSCX_ISTA);
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A interrupt %x", exval);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, exval, 0);
+ }
+}
+
+static void
+ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *sp;
+ u_char val, stat = 0;
+
+ sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+ if (!sp) {
+ printk(KERN_WARNING "Teles: Spurious interrupt!\n");
+ return;
+ }
+ val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+ Start_HSCX:
+ if (val) {
+ hscx_int_main(sp, val);
+ stat |= 1;
+ }
+ val = IsacReadReg(sp->isac, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(sp, val);
+ stat |= 2;
+ }
+ val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+ if (val) {
+ if (sp->debug & L1_DEB_HSCX)
+ debugl1(sp, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = IsacReadReg(sp->isac, ISAC_ISTA);
+ if (val) {
+ if (sp->debug & L1_DEB_ISAC)
+ debugl1(sp, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (stat & 1) {
+ HscxWriteReg(sp->hscx[0], 0, HSCX_MASK, 0xFF);
+ HscxWriteReg(sp->hscx[1], 1, HSCX_MASK, 0xFF);
+ HscxWriteReg(sp->hscx[0], 0, HSCX_MASK, 0x0);
+ HscxWriteReg(sp->hscx[1], 1, HSCX_MASK, 0x0);
+ }
+ if (stat & 2) {
+ IsacWriteReg(sp->isac, ISAC_MASK, 0xFF);
+ IsacWriteReg(sp->isac, ISAC_MASK, 0x0);
+ }
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+ unsigned int adr = sp->isac;
+
+ /* 16.3 IOM 2 Mode */
+ IsacWriteReg(adr, ISAC_MASK, 0xff);
+ IsacWriteReg(adr, ISAC_ADF2, 0x80);
+ IsacWriteReg(adr, ISAC_SQXR, 0x2f);
+ IsacWriteReg(adr, ISAC_SPCR, 0x0);
+ IsacWriteReg(adr, ISAC_ADF1, 0x2);
+ IsacWriteReg(adr, ISAC_STCR, 0x70);
+ IsacWriteReg(adr, ISAC_MODE, 0xc9);
+ IsacWriteReg(adr, ISAC_TIMR, 0x0);
+ IsacWriteReg(adr, ISAC_ADF1, 0x0);
+ IsacWriteReg(adr, ISAC_CMDR, 0x41);
+ IsacWriteReg(adr, ISAC_CIX0, (1 << 2) | 3);
+ IsacWriteReg(adr, ISAC_MASK, 0xff);
+ IsacWriteReg(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+ struct IsdnCardState *sp = hs->sp;
+ int hscx = hs->hscx;
+
+ if (sp->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "hscx %c mode %d ichan %d",
+ 'A' + hscx, mode, ichan);
+ debugl1(sp, tmp);
+ }
+ hs->mode = mode;
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR1, 0x85);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XAD1, 0xFF);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XAD2, 0xFF);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RAH2, 0xFF);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XBCH, 0x0);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RLCR, 0x0);
+
+ switch (mode) {
+ case 0:
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0xff);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0xff);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0x84);
+ break;
+ case 1:
+ if (ichan == 0) {
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x2f);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x2f);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+ } else {
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x3);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x3);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+ }
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0xe4);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41);
+ break;
+ case 2:
+ if (ichan == 0) {
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x2f);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x2f);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+ } else {
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CCR2, 0x30);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAX, 0x3);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_TSAR, 0x3);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_XCCR, 7);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_RCCR, 7);
+ }
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_MODE, 0x8c);
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_CMDR, 0x41);
+ break;
+ }
+ HscxWriteReg(sp->hscx[hscx], hscx, HSCX_ISTA, 0x00);
+}
+
+void
+release_io_ix1micro(struct IsdnCard *card)
+{
+ if (card->sp->cfg_reg)
+ release_region(card->sp->cfg_reg, 4);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+ int val;
+ char tmp[64];
+
+ val = HscxReadReg(sp->hscx[1], 1, HSCX_ISTA);
+ sprintf(tmp, "HSCX B ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = HscxReadReg(sp->hscx[1], 1, HSCX_EXIR);
+ sprintf(tmp, "HSCX B EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x02) {
+ val = HscxReadReg(sp->hscx[0], 0, HSCX_EXIR);
+ sprintf(tmp, "HSCX A EXIR %x", val);
+ debugl1(sp, tmp);
+ }
+ val = HscxReadReg(sp->hscx[0], 0, HSCX_ISTA);
+ sprintf(tmp, "HSCX A ISTA %x", val);
+ debugl1(sp, tmp);
+ val = HscxReadReg(sp->hscx[1], 1, HSCX_STAR);
+ sprintf(tmp, "HSCX B STAR %x", val);
+ debugl1(sp, tmp);
+ val = HscxReadReg(sp->hscx[0], 0, HSCX_STAR);
+ sprintf(tmp, "HSCX A STAR %x", val);
+ debugl1(sp, tmp);
+ val = IsacReadReg(sp->isac, ISAC_STAR);
+ sprintf(tmp, "ISAC STAR %x", val);
+ debugl1(sp, tmp);
+ val = IsacReadReg(sp->isac, ISAC_MODE);
+ sprintf(tmp, "ISAC MODE %x", val);
+ debugl1(sp, tmp);
+ val = IsacReadReg(sp->isac, ISAC_ADF2);
+ sprintf(tmp, "ISAC ADF2 %x", val);
+ debugl1(sp, tmp);
+ val = IsacReadReg(sp->isac, ISAC_ISTA);
+ sprintf(tmp, "ISAC ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = IsacReadReg(sp->isac, ISAC_EXIR);
+ sprintf(tmp, "ISAC EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x04) {
+ val = IsacReadReg(sp->isac, ISAC_CIR0);
+ sprintf(tmp, "ISAC CIR0 %x", val);
+ debugl1(sp, tmp);
+ }
+ IsacWriteReg(sp->isac, ISAC_MASK, 0);
+ IsacWriteReg(sp->isac, ISAC_CMDR, 0x41);
+}
+
+int
+initix1micro(struct IsdnCardState *sp)
+{
+ int ret;
+ int loop = 0;
+ char tmp[40];
+
+ sp->counter = kstat.interrupts[sp->irq];
+ sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+ debugl1(sp, tmp);
+ clear_pending_ints(sp);
+ ret = get_irq(sp->cardnr, &ix1micro_interrupt);
+ if (ret) {
+ initisac(sp);
+ sp->modehscx(sp->hs, 0, 0);
+ sp->modehscx(sp->hs + 1, 0, 0);
+ while (loop++ < 10) {
+ /* At least 1-3 irqs must happen
+ * (one from HSCX A, one from HSCX B, 3rd from ISAC)
+ */
+ if (kstat.interrupts[sp->irq] > sp->counter)
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ }
+ sprintf(tmp, "IRQ %d count %d", sp->irq,
+ kstat.interrupts[sp->irq]);
+ debugl1(sp, tmp);
+ if (kstat.interrupts[sp->irq] == sp->counter) {
+ printk(KERN_WARNING
+ "ix1-Micro: IRQ(%d) getting no interrupts during init\n",
+ sp->irq);
+ irq2dev_map[sp->irq] = NULL;
+ free_irq(sp->irq, NULL);
+ return (0);
+ }
+ }
+ return (ret);
+}
+
+int
+setup_ix1micro(struct IsdnCard *card)
+{
+ u_char val, verA, verB;
+ struct IsdnCardState *sp = card->sp;
+ long flags;
+ char tmp[64];
+
+ strcpy(tmp, ix1_revision);
+ printk(KERN_NOTICE "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
+ if (sp->typ != ISDN_CTYPE_IX1MICROR2)
+ return (0);
+
+ /* IO-Ports */
+ sp->isac = sp->hscx[0] = sp->hscx[1] = sp->cfg_reg = card->para[1];
+ sp->irq = card->para[0];
+ if (sp->cfg_reg) {
+ if (check_region((sp->cfg_reg), 4)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ sp->cfg_reg,
+ sp->cfg_reg + 4);
+ return (0);
+ } else
+ request_region(sp->cfg_reg, 4, "ix1micro cfg");
+ }
+ /* reset isac */
+ save_flags(flags);
+ val = 3 * (HZ / 10) + 1;
+ sti();
+ while (val--) {
+ byteout(sp->cfg_reg + SPECIAL_PORT_OFFSET, 1);
+ HZDELAY(1); /* wait >=10 ms */
+ }
+ byteout(sp->cfg_reg + SPECIAL_PORT_OFFSET, 0);
+ restore_flags(flags);
+
+ printk(KERN_NOTICE
+ "HiSax: %s config irq:%d io:0x%x\n",
+ CardType[sp->typ], sp->irq,
+ sp->cfg_reg);
+ verA = HscxReadReg(sp->hscx[0], 0, HSCX_VSTR) & 0xf;
+ verB = HscxReadReg(sp->hscx[1], 1, HSCX_VSTR) & 0xf;
+ printk(KERN_INFO "ix1-Micro: HSCX version A: %s B: %s\n",
+ HscxVersion(verA), HscxVersion(verB));
+ val = IsacReadReg(sp->isac, ISAC_RBCH);
+ printk(KERN_INFO "ix1-Micro: ISAC %s\n",
+ ISACVersion(val));
+ if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ printk(KERN_WARNING
+ "ix1-Micro: wrong HSCX versions check IO address\n");
+ release_io_ix1micro(card);
+ return (0);
+ }
+ sp->modehscx = &modehscx;
+ sp->ph_command = &ph_command;
+ sp->hscx_fill_fifo = &hscx_fill_fifo;
+ sp->isac_fill_fifo = &isac_fill_fifo;
+ return (1);
+}
--- /dev/null
+/* $Id: ix1_micro.h,v 1.1 1997/01/27 15:42:48 keil Exp $
+
+ * ix1_micro.h low level stuff for ITK ix1-micro Rev.2 isdn cards
+ *
+ * derived from teles3.h from Karsten Keil
+ *
+ * Copyright (C) 1997 Klaus-Peter Nischke (ITK AG) (for the modifications
+ to the original file teles.c)
+ *
+ * $Log: ix1_micro.h,v $
+ * Revision 1.1 1997/01/27 15:42:48 keil
+ * first version
+ *
+ *
+ */
+
+/*
+ For the modification done by the author the following terms and conditions
+ apply (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.
+
+
+ You may contact Klaus-Peter Nischke by email: klaus@nischke.do.eunet.de
+ or by conventional mail:
+
+ Klaus-Peter Nischke
+ Deusener Str. 287
+ 44369 Dortmund
+ Germany
+ */
+
+
+extern void ix1micro_report(struct IsdnCardState *sp);
+extern void release_io_ix1micro(struct IsdnCard *card);
+extern int setup_ix1micro(struct IsdnCard *card);
+extern int initix1micro(struct IsdnCardState *sp);
--- /dev/null
+/* $Id: l3_1tr6.c,v 1.11 1997/04/06 22:54:18 keil Exp $
+
+ * German 1TR6 D-channel protocol
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: l3_1tr6.c,v $
+ * Revision 1.11 1997/04/06 22:54:18 keil
+ * Using SKB's
+ *
+ * Revision 1.10 1997/03/13 20:37:58 keil
+ * channel request added
+ *
+ * Revision 1.9 1997/02/11 01:37:40 keil
+ * Changed setup-interface (incoming and outgoing)
+ *
+ * Revision 1.8 1997/01/27 23:20:21 keil
+ * report revision only ones
+ *
+ * Revision 1.7 1997/01/21 22:30:07 keil
+ * new statemachine; L3 timers
+ *
+ * Revision 1.6 1996/12/14 21:07:20 keil
+ * additional states for CC_REJECT
+ *
+ * Revision 1.5 1996/12/08 19:55:17 keil
+ * change CC_REJECT_REQ routine
+ *
+ * Revision 1.4 1996/10/30 10:18:01 keil
+ * bugfixes in debugging output
+ *
+ * Revision 1.3 1996/10/27 22:15:37 keil
+ * bugfix reject handling
+ *
+ * Revision 1.2 1996/10/13 23:08:56 keil
+ * added missing state for callback reject
+ *
+ * Revision 1.1 1996/10/13 20:04:55 keil
+ * Initial revision
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "l3_1tr6.h"
+#include "isdnl3.h"
+#include <linux/ctype.h>
+
+extern char *HiSax_getrev(const char *revision);
+const char *l3_1tr6_revision = "$Revision: 1.11 $";
+
+#define MsgHead(ptr, cref, mty, dis) \
+ *ptr++ = dis; \
+ *ptr++ = 0x1; \
+ *ptr++ = cref; \
+ *ptr++ = mty
+
+static void
+l3_1TR6_message(struct PStack *st, u_char mt, u_char pd)
+{
+ struct sk_buff *skb;
+ u_char *p;
+
+ if (!(skb = l3_alloc_skb(4)))
+ return;
+ p = skb_put(skb, 4);
+ MsgHead(p, st->l3.callref, mt, pd);
+ st->l3.l3l2(st, DL_DATA, skb);
+}
+
+static void
+l3_1tr6_setup_req(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[128];
+ u_char *p = tmp;
+ u_char *teln;
+ u_char *eaz;
+ u_char channel = 0;
+ int l;
+
+
+ st->l3.callref = st->pa->callref;
+ MsgHead(p, st->l3.callref, MT_N1_SETUP, PROTO_DIS_N1);
+
+ teln = st->pa->setup.phone;
+ st->pa->spv = 0;
+ if (!isdigit(*teln)) {
+ switch (0x5f & *teln) {
+ case 'S':
+ st->pa->spv = 1;
+ break;
+ case 'C':
+ channel = 0x08;
+ case 'P':
+ channel |= 0x80;
+ teln++;
+ if (*teln == '1')
+ channel |= 0x01;
+ else
+ channel |= 0x02;
+ break;
+ default:
+ if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "Wrong MSN Code");
+ break;
+ }
+ teln++;
+ }
+ if (channel) {
+ *p++ = 0x18; /* channel indicator */
+ *p++ = 1;
+ *p++ = channel;
+ }
+ if (st->pa->spv) { /* SPV ? */
+ /* NSF SPV */
+ *p++ = WE0_netSpecFac;
+ *p++ = 4; /* Laenge */
+ *p++ = 0;
+ *p++ = FAC_SPV; /* SPV */
+ *p++ = st->pa->setup.si1; /* 0 for all Services */
+ *p++ = st->pa->setup.si2; /* 0 for all Services */
+ *p++ = WE0_netSpecFac;
+ *p++ = 4; /* Laenge */
+ *p++ = 0;
+ *p++ = FAC_Activate; /* aktiviere SPV (default) */
+ *p++ = st->pa->setup.si1; /* 0 for all Services */
+ *p++ = st->pa->setup.si2; /* 0 for all Services */
+ }
+ eaz = st->pa->setup.eazmsn;
+ if (*eaz) {
+ *p++ = WE0_origAddr;
+ *p++ = strlen(eaz) + 1;
+ /* Classify as AnyPref. */
+ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+ while (*eaz)
+ *p++ = *eaz++ & 0x7f;
+ }
+ *p++ = WE0_destAddr;
+ *p++ = strlen(teln) + 1;
+ /* Classify as AnyPref. */
+ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+ while (*teln)
+ *p++ = *teln++ & 0x7f;
+
+ *p++ = WE_Shift_F6;
+ /* Codesatz 6 fuer Service */
+ *p++ = WE6_serviceInd;
+ *p++ = 2; /* len=2 info,info2 */
+ *p++ = st->pa->setup.si1;
+ *p++ = st->pa->setup.si2;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ L3DelTimer(&st->l3.timer);
+ L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303);
+ newl3state(st, 1);
+ st->l3.l3l2(st, DL_DATA, skb);
+
+}
+
+static void
+l3_1tr6_setup(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ int bcfound = 0;
+ char tmp[80];
+ struct sk_buff *skb = arg;
+
+ p = skb->data;
+ st->pa->callref = getcallref(p);
+ st->l3.callref = 0x80 + st->pa->callref;
+
+ /* Channel Identification */
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+ st->pa->bchannel = p[2] & 0x3;
+ bcfound++;
+ } else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup without bchannel");
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE6_serviceInd, 6))) {
+ st->pa->setup.si1 = p[2];
+ st->pa->setup.si2 = p[3];
+ } else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup without service indicator");
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE0_destAddr, 0)))
+ iecpy(st->pa->setup.eazmsn, p, 1);
+ else
+ st->pa->setup.eazmsn[0] = 0;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE0_origAddr, 0))) {
+ iecpy(st->pa->setup.phone, p, 1);
+ } else
+ st->pa->setup.phone[0] = 0;
+
+ p = skb->data;
+ st->pa->spv = 0;
+ if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) {
+ if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
+ st->pa->spv = 1;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ /* Signal all services, linklevel takes care of Service-Indicator */
+ if (bcfound) {
+ if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+ sprintf(tmp, "non-digital call: %s -> %s",
+ st->pa->setup.phone,
+ st->pa->setup.eazmsn);
+ l3_debug(st, tmp);
+ }
+ newl3state(st, 6);
+ st->l3.l3l4(st, CC_SETUP_IND, NULL);
+ }
+}
+
+static void
+l3_1tr6_setup_ack(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+
+ L3DelTimer(&st->l3.timer);
+ p = skb->data;
+ newl3state(st, 2);
+ if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+ st->pa->bchannel = p[2] & 0x3;
+ } else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup answer without bchannel");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304);
+ st->l3.l3l4(st, CC_MORE_INFO, NULL);
+}
+
+static void
+l3_1tr6_call_sent(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+
+ L3DelTimer(&st->l3.timer);
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE0_chanID, 0))) {
+ st->pa->bchannel = p[2] & 0x3;
+ } else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup answer without bchannel");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310);
+ newl3state(st, 3);
+ st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+}
+
+static void
+l3_1tr6_alert(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ L3DelTimer(&st->l3.timer); /* T304 */
+ newl3state(st, 4);
+ st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+}
+
+static void
+l3_1tr6_info(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ int i, tmpcharge = 0;
+ char a_charge[8], tmp[32];
+ struct sk_buff *skb = arg;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
+ iecpy(a_charge, p, 1);
+ for (i = 0; i < strlen(a_charge); i++) {
+ tmpcharge *= 10;
+ tmpcharge += a_charge[i] & 0xf;
+ }
+ if (tmpcharge > st->pa->chargeinfo) {
+ st->pa->chargeinfo = tmpcharge;
+ st->l3.l3l4(st, CC_INFO_CHARGE, NULL);
+ }
+ if (st->l3.debug & L3_DEB_CHARGE) {
+ sprintf(tmp, "charging info %d", st->pa->chargeinfo);
+ l3_debug(st, tmp);
+ }
+ } else if (st->l3.debug & L3_DEB_CHARGE)
+ l3_debug(st, "charging info not found");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+}
+
+static void
+l3_1tr6_info_s2(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+}
+
+static void
+l3_1tr6_connect(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ L3DelTimer(&st->l3.timer); /* T310 */
+ newl3state(st, 10);
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ st->pa->chargeinfo = 0;
+ st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+}
+
+static void
+l3_1tr6_rel(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ u_char *p;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE0_cause, 0))) {
+ if (p[1] > 0) {
+ st->pa->cause = p[2];
+ if (p[1] > 1)
+ st->pa->loc = p[3];
+ else
+ st->pa->loc = 0;
+ } else {
+ st->pa->cause = 0;
+ st->pa->loc = 0;
+ }
+ } else
+ st->pa->cause = -1;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ StopAllL3Timer(st);
+ newl3state(st, 0);
+ l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
+ st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+}
+
+static void
+l3_1tr6_rel_ack(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ StopAllL3Timer(st);
+ newl3state(st, 0);
+ st->pa->cause = -1;
+ st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+}
+
+static void
+l3_1tr6_disc(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+ u_char *p;
+ int i, tmpcharge = 0;
+ char a_charge[8], tmp[32];
+
+ StopAllL3Timer(st);
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) {
+ iecpy(a_charge, p, 1);
+ for (i = 0; i < strlen(a_charge); i++) {
+ tmpcharge *= 10;
+ tmpcharge += a_charge[i] & 0xf;
+ }
+ if (tmpcharge > st->pa->chargeinfo) {
+ st->pa->chargeinfo = tmpcharge;
+ st->l3.l3l4(st, CC_INFO_CHARGE, NULL);
+ }
+ if (st->l3.debug & L3_DEB_CHARGE) {
+ sprintf(tmp, "charging info %d", st->pa->chargeinfo);
+ l3_debug(st, tmp);
+ }
+ } else if (st->l3.debug & L3_DEB_CHARGE)
+ l3_debug(st, "charging info not found");
+
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, WE0_cause, 0))) {
+ if (p[1] > 0) {
+ st->pa->cause = p[2];
+ if (p[1] > 1)
+ st->pa->loc = p[3];
+ else
+ st->pa->loc = 0;
+ } else {
+ st->pa->cause = 0;
+ st->pa->loc = 0;
+ }
+ } else {
+ if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "cause not found");
+ st->pa->cause = -1;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ newl3state(st, 12);
+ st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+}
+
+
+static void
+l3_1tr6_connect_ack(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ newl3state(st, 10);
+ st->pa->chargeinfo = 0;
+ L3DelTimer(&st->l3.timer);
+ st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+}
+
+static void
+l3_1tr6_alert_req(struct PStack *st, u_char pr, void *arg)
+{
+ newl3state(st, 7);
+ l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
+}
+
+static void
+l3_1tr6_setup_rsp(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[24];
+ u_char *p = tmp;
+ int l;
+
+ MsgHead(p, st->l3.callref, MT_N1_CONN, PROTO_DIS_N1);
+ if (st->pa->spv) { /* SPV ? */
+ /* NSF SPV */
+ *p++ = WE0_netSpecFac;
+ *p++ = 4; /* Laenge */
+ *p++ = 0;
+ *p++ = FAC_SPV; /* SPV */
+ *p++ = st->pa->setup.si1;
+ *p++ = st->pa->setup.si2;
+ *p++ = WE0_netSpecFac;
+ *p++ = 4; /* Laenge */
+ *p++ = 0;
+ *p++ = FAC_Activate; /* aktiviere SPV */
+ *p++ = st->pa->setup.si1;
+ *p++ = st->pa->setup.si2;
+ }
+ newl3state(st, 8);
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ st->l3.l3l2(st, DL_DATA, skb);
+ L3DelTimer(&st->l3.timer);
+ L3AddTimer(&st->l3.timer, st->l3.t313, CC_T313);
+}
+
+static void
+l3_1tr6_reset(struct PStack *st, u_char pr, void *arg)
+{
+ newl3state(st, 0);
+}
+
+static void
+l3_1tr6_disconnect_req(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ u_char cause = 0x10;
+ u_char clen = 1;
+
+ if (st->pa->cause > 0)
+ cause = st->pa->cause;
+ /* Map DSS1 causes */
+ switch (cause & 0x7f) {
+ case 0x10:
+ clen = 0;
+ break;
+ case 0x15:
+ cause = CAUSE_CallRejected;
+ break;
+ }
+ StopAllL3Timer(st);
+ MsgHead(p, st->l3.callref, MT_N1_DISC, PROTO_DIS_N1);
+ *p++ = WE0_cause;
+ *p++ = clen; /* Laenge */
+ if (clen)
+ *p++ = cause | 0x80;
+ newl3state(st, 11);
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ st->l3.l3l2(st, DL_DATA, skb);
+ L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305);
+}
+
+static void
+l3_1tr6_release_req(struct PStack *st, u_char pr, void *arg)
+{
+ StopAllL3Timer(st);
+ newl3state(st, 19);
+ l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
+ L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+}
+
+static void
+l3_1tr6_t303(struct PStack *st, u_char pr, void *arg)
+{
+ if (st->l3.n_t303 > 0) {
+ st->l3.n_t303--;
+ L3DelTimer(&st->l3.timer);
+ l3_1tr6_setup_req(st, pr, arg);
+ } else {
+ L3DelTimer(&st->l3.timer);
+ st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
+ st->l3.n_t303 = 1;
+ newl3state(st, 0);
+ }
+}
+
+static void
+l3_1tr6_t304(struct PStack *st, u_char pr, void *arg)
+{
+ L3DelTimer(&st->l3.timer);
+ st->pa->cause = 0xE6;
+ l3_1tr6_disconnect_req(st, pr, NULL);
+ st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+
+}
+
+static void
+l3_1tr6_t305(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ u_char cause = 0x90;
+ u_char clen = 1;
+
+ L3DelTimer(&st->l3.timer);
+ if (st->pa->cause > 0)
+ cause = st->pa->cause;
+ /* Map DSS1 causes */
+ switch (cause & 0x7f) {
+ case 0x10:
+ clen = 0;
+ break;
+ case 0x15:
+ cause = CAUSE_CallRejected;
+ break;
+ }
+ MsgHead(p, st->l3.callref, MT_N1_REL, PROTO_DIS_N1);
+ *p++ = WE0_cause;
+ *p++ = clen; /* Laenge */
+ if (clen)
+ *p++ = cause;
+ newl3state(st, 19);
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ st->l3.l3l2(st, DL_DATA, skb);
+ L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+}
+
+static void
+l3_1tr6_t310(struct PStack *st, u_char pr, void *arg)
+{
+ L3DelTimer(&st->l3.timer);
+ st->pa->cause = 0xE6;
+ l3_1tr6_disconnect_req(st, pr, NULL);
+ st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+}
+
+static void
+l3_1tr6_t313(struct PStack *st, u_char pr, void *arg)
+{
+ L3DelTimer(&st->l3.timer);
+ st->pa->cause = 0xE6;
+ l3_1tr6_disconnect_req(st, pr, NULL);
+ st->l3.l3l4(st, CC_CONNECT_ERR, NULL);
+}
+
+static void
+l3_1tr6_t308_1(struct PStack *st, u_char pr, void *arg)
+{
+ L3DelTimer(&st->l3.timer);
+ l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
+ L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_2);
+ newl3state(st, 19);
+}
+
+static void
+l3_1tr6_t308_2(struct PStack *st, u_char pr, void *arg)
+{
+ L3DelTimer(&st->l3.timer);
+ st->l3.l3l4(st, CC_RELEASE_ERR, NULL);
+ newl3state(st, 0);
+}
+/* *INDENT-OFF* */
+static struct stateentry downstl[] =
+{
+ {SBIT(0),
+ CC_SETUP_REQ, l3_1tr6_setup_req},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) |
+ SBIT(10),
+ CC_DISCONNECT_REQ, l3_1tr6_disconnect_req},
+ {SBIT(12),
+ CC_RELEASE_REQ, l3_1tr6_release_req},
+ {ALL_STATES,
+ CC_DLRL, l3_1tr6_reset},
+ {SBIT(6),
+ CC_IGNORE, l3_1tr6_reset},
+ {SBIT(6),
+ CC_REJECT_REQ, l3_1tr6_disconnect_req},
+ {SBIT(6),
+ CC_ALERTING_REQ, l3_1tr6_alert_req},
+ {SBIT(6) | SBIT(7),
+ CC_SETUP_RSP, l3_1tr6_setup_rsp},
+ {SBIT(1),
+ CC_T303, l3_1tr6_t303},
+ {SBIT(2),
+ CC_T304, l3_1tr6_t304},
+ {SBIT(3),
+ CC_T310, l3_1tr6_t310},
+ {SBIT(8),
+ CC_T313, l3_1tr6_t313},
+ {SBIT(11),
+ CC_T305, l3_1tr6_t305},
+ {SBIT(19),
+ CC_T308_1, l3_1tr6_t308_1},
+ {SBIT(19),
+ CC_T308_2, l3_1tr6_t308_2},
+};
+
+static int downstl_len = sizeof(downstl) /
+sizeof(struct stateentry);
+
+static struct stateentry datastln1[] =
+{
+ {SBIT(0),
+ MT_N1_SETUP, l3_1tr6_setup},
+ {SBIT(1),
+ MT_N1_SETUP_ACK, l3_1tr6_setup_ack},
+ {SBIT(1) | SBIT(2),
+ MT_N1_CALL_SENT, l3_1tr6_call_sent},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
+ MT_N1_DISC, l3_1tr6_disc},
+ {SBIT(2) | SBIT(3) | SBIT(4),
+ MT_N1_ALERT, l3_1tr6_alert},
+ {SBIT(2) | SBIT(3) | SBIT(4),
+ MT_N1_CONN, l3_1tr6_connect},
+ {SBIT(2),
+ MT_N1_INFO, l3_1tr6_info_s2},
+ {SBIT(8),
+ MT_N1_CONN_ACK, l3_1tr6_connect_ack},
+ {SBIT(10),
+ MT_N1_INFO, l3_1tr6_info},
+ {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
+ SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+ MT_N1_REL, l3_1tr6_rel},
+ {SBIT(19),
+ MT_N1_REL_ACK, l3_1tr6_rel_ack}
+};
+/* *INDENT-ON* */
+
+
+
+static int datastln1_len = sizeof(datastln1) /
+sizeof(struct stateentry);
+
+static void
+up1tr6(struct PStack *st, int pr, void *arg)
+{
+ int i, mt;
+ struct sk_buff *skb = arg;
+ char tmp[80];
+
+ if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
+ if (st->l3.debug & L3_DEB_PROTERR) {
+ sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %ld state %d",
+ (pr == DL_DATA) ? " " : "(broadcast) ",
+ skb->data[0], skb->len, st->l3.state);
+ l3_debug(st, tmp);
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ return;
+ }
+ mt = skb->data[skb->data[1] + 2];
+ if (skb->data[0] == PROTO_DIS_N0) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "up1tr6%s N0 state %d mt %x unhandled",
+ (pr == DL_DATA) ? " " : "(broadcast) ",
+ st->l3.state, mt);
+ l3_debug(st, tmp);
+ }
+ } else if (skb->data[0] == PROTO_DIS_N1) {
+ for (i = 0; i < datastln1_len; i++)
+ if ((mt == datastln1[i].primitive) &&
+ ((1 << st->l3.state) & datastln1[i].state))
+ break;
+ if (i == datastln1_len) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
+ (pr == DL_DATA) ? " " : "(broadcast) ",
+ st->l3.state, mt);
+ l3_debug(st, tmp);
+ }
+ return;
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "up1tr6%sstate %d mt %x",
+ (pr == DL_DATA) ? " " : "(broadcast) ",
+ st->l3.state, mt);
+ l3_debug(st, tmp);
+ }
+ datastln1[i].rout(st, pr, skb);
+ }
+ }
+}
+
+static void
+down1tr6(struct PStack *st, int pr, void *arg)
+{
+ int i;
+ char tmp[80];
+
+ for (i = 0; i < downstl_len; i++)
+ if ((pr == downstl[i].primitive) &&
+ ((1 << st->l3.state) & downstl[i].state))
+ break;
+ if (i == downstl_len) {
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "down1tr6 state %d prim %d unhandled",
+ st->l3.state, pr);
+ l3_debug(st, tmp);
+ }
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "down1tr6 state %d prim %d",
+ st->l3.state, pr);
+ l3_debug(st, tmp);
+ }
+ downstl[i].rout(st, pr, arg);
+ }
+}
+
+void
+setstack_1tr6(struct PStack *st)
+{
+ char tmp[64];
+
+ st->l4.l4l3 = down1tr6;
+ st->l2.l2l3 = up1tr6;
+ st->l3.t303 = 4000;
+ st->l3.t304 = 20000;
+ st->l3.t305 = 4000;
+ st->l3.t308 = 4000;
+ st->l3.t310 = 120000;
+ st->l3.t313 = 4000;
+ st->l3.t318 = 4000;
+ st->l3.t319 = 4000;
+ st->l3.n_t303 = 0;
+
+ if (st->l3.channr & 1) {
+ strcpy(tmp, l3_1tr6_revision);
+ printk(KERN_NOTICE "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
+ }
+}
--- /dev/null
+/* $Id: l3_1tr6.h,v 1.1 1996/10/13 20:03:48 keil Exp $
+ *
+ * German 1TR6 D-channel protocol defines
+ *
+ * $Log: l3_1tr6.h,v $
+ * Revision 1.1 1996/10/13 20:03:48 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#ifndef l3_1tr6
+#define l3_1tr6
+
+#define PROTO_DIS_N0 0x40
+#define PROTO_DIS_N1 0x41
+
+/*
+ * MsgType N0
+ */
+#define MT_N0_REG_IND 0x61
+#define MT_N0_CANC_IND 0x62
+#define MT_N0_FAC_STA 0x63
+#define MT_N0_STA_ACK 0x64
+#define MT_N0_STA_REJ 0x65
+#define MT_N0_FAC_INF 0x66
+#define MT_N0_INF_ACK 0x67
+#define MT_N0_INF_REJ 0x68
+#define MT_N0_CLOSE 0x75
+#define MT_N0_CLO_ACK 0x77
+
+
+/*
+ * MsgType N1
+ */
+
+#define MT_N1_ESC 0x00
+#define MT_N1_ALERT 0x01
+#define MT_N1_CALL_SENT 0x02
+#define MT_N1_CONN 0x07
+#define MT_N1_CONN_ACK 0x0F
+#define MT_N1_SETUP 0x05
+#define MT_N1_SETUP_ACK 0x0D
+#define MT_N1_RES 0x26
+#define MT_N1_RES_ACK 0x2E
+#define MT_N1_RES_REJ 0x22
+#define MT_N1_SUSP 0x25
+#define MT_N1_SUSP_ACK 0x2D
+#define MT_N1_SUSP_REJ 0x21
+#define MT_N1_USER_INFO 0x20
+#define MT_N1_DET 0x40
+#define MT_N1_DISC 0x45
+#define MT_N1_REL 0x4D
+#define MT_N1_REL_ACK 0x5A
+#define MT_N1_CANC_ACK 0x6E
+#define MT_N1_CANC_REJ 0x67
+#define MT_N1_CON_CON 0x69
+#define MT_N1_FAC 0x60
+#define MT_N1_FAC_ACK 0x68
+#define MT_N1_FAC_CAN 0x66
+#define MT_N1_FAC_REG 0x64
+#define MT_N1_FAC_REJ 0x65
+#define MT_N1_INFO 0x6D
+#define MT_N1_REG_ACK 0x6C
+#define MT_N1_REG_REJ 0x6F
+#define MT_N1_STAT 0x63
+
+
+
+/*
+ * W Elemente
+ */
+
+#define WE_Shift_F0 0x90
+#define WE_Shift_F6 0x96
+#define WE_Shift_OF0 0x98
+#define WE_Shift_OF6 0x9E
+
+#define WE0_cause 0x08
+#define WE0_connAddr 0x0C
+#define WE0_callID 0x10
+#define WE0_chanID 0x18
+#define WE0_netSpecFac 0x20
+#define WE0_display 0x28
+#define WE0_keypad 0x2C
+#define WE0_origAddr 0x6C
+#define WE0_destAddr 0x70
+#define WE0_userInfo 0x7E
+
+#define WE0_moreData 0xA0
+#define WE0_congestLevel 0xB0
+
+#define WE6_serviceInd 0x01
+#define WE6_chargingInfo 0x02
+#define WE6_date 0x03
+#define WE6_facSelect 0x05
+#define WE6_facStatus 0x06
+#define WE6_statusCalled 0x07
+#define WE6_addTransAttr 0x08
+
+/*
+ * FacCodes
+ */
+#define FAC_Sperre 0x01
+#define FAC_Sperre_All 0x02
+#define FAC_Sperre_Fern 0x03
+#define FAC_Sperre_Intl 0x04
+#define FAC_Sperre_Interk 0x05
+
+#define FAC_Forward1 0x02
+#define FAC_Forward2 0x03
+#define FAC_Konferenz 0x06
+#define FAC_GrabBchan 0x0F
+#define FAC_Reactivate 0x10
+#define FAC_Konferenz3 0x11
+#define FAC_Dienstwechsel1 0x12
+#define FAC_Dienstwechsel2 0x13
+#define FAC_NummernIdent 0x14
+#define FAC_GBG 0x15
+#define FAC_DisplayUebergeben 0x17
+#define FAC_DisplayUmgeleitet 0x1A
+#define FAC_Unterdruecke 0x1B
+#define FAC_Deactivate 0x1E
+#define FAC_Activate 0x1D
+#define FAC_SPV 0x1F
+#define FAC_Rueckwechsel 0x23
+#define FAC_Umleitung 0x24
+
+/*
+ * Cause codes
+ */
+#define CAUSE_InvCRef 0x01
+#define CAUSE_BearerNotImpl 0x03
+#define CAUSE_CIDunknown 0x07
+#define CAUSE_CIDinUse 0x08
+#define CAUSE_NoChans 0x0A
+#define CAUSE_FacNotImpl 0x10
+#define CAUSE_FacNotSubscr 0x11
+#define CAUSE_OutgoingBarred 0x20
+#define CAUSE_UserAccessBusy 0x21
+#define CAUSE_NegativeGBG 0x22
+#define CAUSE_UnknownGBG 0x23
+#define CAUSE_NoSPVknown 0x25
+#define CAUSE_DestNotObtain 0x35
+#define CAUSE_NumberChanged 0x38
+#define CAUSE_OutOfOrder 0x39
+#define CAUSE_NoUserResponse 0x3A
+#define CAUSE_UserBusy 0x3B
+#define CAUSE_IncomingBarred 0x3D
+#define CAUSE_CallRejected 0x3E
+#define CAUSE_NetworkCongestion 0x59
+#define CAUSE_RemoteUser 0x5A
+#define CAUSE_LocalProcErr 0x70
+#define CAUSE_RemoteProcErr 0x71
+#define CAUSE_RemoteUserSuspend 0x72
+#define CAUSE_RemoteUserResumed 0x73
+#define CAUSE_UserInfoDiscarded 0x7F
+
+
+#endif
--- /dev/null
+/* $Id: l3dss1.c,v 1.16 1997/06/03 20:43:46 keil Exp $
+
+ * EURO/DSS1 D-channel protocol
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * based on the teles driver from Jan den Ouden
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ *
+ * $Log: l3dss1.c,v $
+ * Revision 1.16 1997/06/03 20:43:46 keil
+ * Display numbers as default
+ *
+ * Revision 1.15 1997/04/17 11:50:48 keil
+ * pa->loc was undefined, if it was not send by the exchange
+ *
+ * Revision 1.14 1997/04/06 22:54:20 keil
+ * Using SKB's
+ *
+ * Revision 1.13 1997/03/13 20:37:28 keil
+ * CLIR and channel request added
+ *
+ * Revision 1.12 1997/02/17 00:34:26 keil
+ * Bugfix: Wrong cause delivered
+ *
+ * Revision 1.11 1997/02/16 12:12:47 fritz
+ * Bugfix: SI2 was nont initialized on incoming calls.
+ *
+ * Revision 1.10 1997/02/11 01:37:24 keil
+ * Changed setup-interface (incoming and outgoing)
+ *
+ * Revision 1.9 1997/01/27 23:20:52 keil
+ * report revision only ones
+ *
+ * Revision 1.8 1997/01/21 22:29:41 keil
+ * new statemachine; L3 timers
+ *
+ * Revision 1.7 1996/12/14 21:06:59 keil
+ * additional states for CC_REJECT
+ *
+ * Revision 1.6 1996/12/08 22:59:16 keil
+ * fixed calling party number without octet 3a
+ *
+ * Revision 1.5 1996/12/08 19:53:31 keil
+ * fixes from Pekka Sarnila
+ *
+ * Revision 1.4 1996/11/05 19:44:36 keil
+ * some fixes from Henner Eisen
+ *
+ * Revision 1.3 1996/10/30 10:18:01 keil
+ * bugfixes in debugging output
+ *
+ * Revision 1.2 1996/10/27 22:15:16 keil
+ * bugfix reject handling
+ *
+ * Revision 1.1 1996/10/13 20:04:55 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl3.h"
+#include <linux/ctype.h>
+
+extern char *HiSax_getrev(const char *revision);
+const char *dss1_revision = "$Revision: 1.16 $";
+
+#define MsgHead(ptr, cref, mty) \
+ *ptr++ = 0x8; \
+ *ptr++ = 0x1; \
+ *ptr++ = cref; \
+ *ptr++ = mty
+
+static void
+l3dss1_message(struct PStack *st, u_char mt)
+{
+ struct sk_buff *skb;
+ u_char *p;
+
+ if (!(skb = l3_alloc_skb(4)))
+ return;
+ p = skb_put(skb, 4);
+ MsgHead(p, st->l3.callref, mt);
+ st->l3.l3l2(st, DL_DATA, skb);
+}
+
+static void
+l3dss1_release_req(struct PStack *st, u_char pr, void *arg)
+{
+ StopAllL3Timer(st);
+ newl3state(st, 19);
+ l3dss1_message(st, MT_RELEASE);
+ L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+}
+
+static void
+l3dss1_release_cmpl(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+ int cause = -1;
+
+ p = skb->data;
+ st->pa->loc = 0;
+ if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+ p++;
+ if (*p++ == 2)
+ st->pa->loc = *p++;
+ cause = *p & 0x7f;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ StopAllL3Timer(st);
+ st->pa->cause = cause;
+ newl3state(st, 0);
+ st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
+}
+
+static void
+l3dss1_setup_req(struct PStack *st, u_char pr,
+ void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[128];
+ u_char *p = tmp;
+ u_char channel = 0;
+ u_char screen = 0x80;
+ u_char *teln;
+ u_char *msn;
+ int l;
+
+ st->l3.callref = st->pa->callref;
+ MsgHead(p, st->l3.callref, MT_SETUP);
+
+ /*
+ * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
+ */
+ *p++ = 0xa1; /* complete indicator */
+ switch (st->pa->setup.si1) {
+ case 1: /* Telephony */
+ *p++ = 0x4; /* BC-IE-code */
+ *p++ = 0x3; /* Length */
+ *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ *p++ = 0xa3; /* A-Law Audio */
+ break;
+ case 5: /* Datatransmission 64k, BTX */
+ case 7: /* Datatransmission 64k */
+ default:
+ *p++ = 0x4; /* BC-IE-code */
+ *p++ = 0x2; /* Length */
+ *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
+ *p++ = 0x90; /* Circuit-Mode 64kbps */
+ break;
+ }
+ /*
+ * What about info2? Mapping to High-Layer-Compatibility?
+ */
+ teln = st->pa->setup.phone;
+ if (*teln) {
+ /* parse number for special things */
+ if (!isdigit(*teln)) {
+ switch (0x5f & *teln) {
+ case 'C':
+ channel = 0x08;
+ case 'P':
+ channel |= 0x80;
+ teln++;
+ if (*teln == '1')
+ channel |= 0x01;
+ else
+ channel |= 0x02;
+ break;
+ case 'R':
+ screen = 0xA0;
+ break;
+ case 'D':
+ screen = 0x80;
+ break;
+ default:
+ if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "Wrong MSN Code");
+ break;
+ }
+ teln++;
+ }
+ }
+ if (channel) {
+ *p++ = 0x18; /* channel indicator */
+ *p++ = 1;
+ *p++ = channel;
+ }
+ msn = st->pa->setup.eazmsn;
+ if (*msn) {
+ *p++ = 0x6c;
+ *p++ = strlen(msn) + (screen ? 2 : 1);
+ /* Classify as AnyPref. */
+ if (screen) {
+ *p++ = 0x01; /* Ext = '0'B, Type = '000'B, Plan = '0001'B. */
+ *p++ = screen;
+ } else
+ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+ while (*msn)
+ *p++ = *msn++ & 0x7f;
+ }
+ *p++ = 0x70;
+ *p++ = strlen(teln) + 1;
+ /* Classify as AnyPref. */
+ *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+
+ while (*teln)
+ *p++ = *teln++ & 0x7f;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ L3DelTimer(&st->l3.timer);
+ L3AddTimer(&st->l3.timer, st->l3.t303, CC_T303);
+ newl3state(st, 1);
+ st->l3.l3l2(st, DL_DATA, skb);
+
+}
+
+static void
+l3dss1_call_proc(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+
+ L3DelTimer(&st->l3.timer);
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x18, 0))) {
+ st->pa->bchannel = p[2] & 0x3;
+ if ((!st->pa->bchannel) && (st->l3.debug & L3_DEB_WARN))
+ l3_debug(st, "setup answer without bchannel");
+ } else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup answer without bchannel");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ newl3state(st, 3);
+ L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310);
+ st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
+}
+
+static void
+l3dss1_setup_ack(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+
+ L3DelTimer(&st->l3.timer);
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x18, 0))) {
+ st->pa->bchannel = p[2] & 0x3;
+ if ((!st->pa->bchannel) && (st->l3.debug & L3_DEB_WARN))
+ l3_debug(st, "setup answer without bchannel");
+ } else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup answer without bchannel");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ newl3state(st, 2);
+ L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304);
+ st->l3.l3l4(st, CC_MORE_INFO, NULL);
+}
+
+static void
+l3dss1_disconnect(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+ int cause = -1;
+
+ StopAllL3Timer(st);
+ p = skb->data;
+ st->pa->loc = 0;
+ if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+ p++;
+ if (*p++ == 2)
+ st->pa->loc = *p++;
+ cause = *p & 0x7f;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ newl3state(st, 12);
+ st->pa->cause = cause;
+ st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
+}
+
+static void
+l3dss1_connect(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ L3DelTimer(&st->l3.timer); /* T310 */
+ newl3state(st, 10);
+ st->l3.l3l4(st, CC_SETUP_CNF, NULL);
+}
+
+static void
+l3dss1_alerting(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ L3DelTimer(&st->l3.timer); /* T304 */
+ newl3state(st, 4);
+ st->l3.l3l4(st, CC_ALERTING_IND, NULL);
+}
+
+static void
+l3dss1_setup(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ int bcfound = 0;
+ char tmp[80];
+ struct sk_buff *skb = arg;
+
+ p = skb->data;
+ st->pa->callref = getcallref(p);
+ st->l3.callref = 0x80 + st->pa->callref;
+
+ /*
+ * Channel Identification
+ */
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x18, 0))) {
+ st->pa->bchannel = p[2] & 0x3;
+ if (st->pa->bchannel)
+ bcfound++;
+ else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup without bchannel");
+ } else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup without bchannel");
+
+ /*
+ * Bearer Capabilities
+ */
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x04, 0))) {
+ st->pa->setup.si2 = 0;
+ switch (p[2] & 0x1f) {
+ case 0x00:
+ /* Speech */
+ case 0x10:
+ /* 3.1 Khz audio */
+ st->pa->setup.si1 = 1;
+ break;
+ case 0x08:
+ /* Unrestricted digital information */
+ st->pa->setup.si1 = 7;
+ break;
+ case 0x09:
+ /* Restricted digital information */
+ st->pa->setup.si1 = 2;
+ break;
+ case 0x11:
+ /* Unrestr. digital information with tones/announcements */
+ st->pa->setup.si1 = 3;
+ break;
+ case 0x18:
+ /* Video */
+ st->pa->setup.si1 = 4;
+ break;
+ default:
+ st->pa->setup.si1 = 0;
+ }
+ } else if (st->l3.debug & L3_DEB_WARN)
+ l3_debug(st, "setup without bearer capabilities");
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x70, 0)))
+ iecpy(st->pa->setup.eazmsn, p, 1);
+ else
+ st->pa->setup.eazmsn[0] = 0;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, 0x6c, 0))) {
+ st->pa->setup.plan = p[2];
+ if (p[2] & 0x80) {
+ iecpy(st->pa->setup.phone, p, 1);
+ st->pa->setup.screen = 0;
+ } else {
+ iecpy(st->pa->setup.phone, p, 2);
+ st->pa->setup.screen = p[3];
+ }
+ } else {
+ st->pa->setup.phone[0] = 0;
+ st->pa->setup.plan = 0;
+ st->pa->setup.screen = 0;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ if (bcfound) {
+ if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) {
+ sprintf(tmp, "non-digital call: %s -> %s",
+ st->pa->setup.phone,
+ st->pa->setup.eazmsn);
+ l3_debug(st, tmp);
+ }
+ newl3state(st, 6);
+ st->l3.l3l4(st, CC_SETUP_IND, NULL);
+ }
+}
+
+static void
+l3dss1_reset(struct PStack *st, u_char pr, void *arg)
+{
+ StopAllL3Timer(st);
+ newl3state(st, 0);
+}
+
+static void
+l3dss1_setup_rsp(struct PStack *st, u_char pr,
+ void *arg)
+{
+ newl3state(st, 8);
+ l3dss1_message(st, MT_CONNECT);
+ L3DelTimer(&st->l3.timer);
+ L3AddTimer(&st->l3.timer, st->l3.t313, CC_T313);
+}
+
+static void
+l3dss1_connect_ack(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb = arg;
+
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ newl3state(st, 10);
+ L3DelTimer(&st->l3.timer);
+ st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
+}
+
+static void
+l3dss1_disconnect_req(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ u_char cause = 0x10;
+
+ if (st->pa->cause > 0)
+ cause = st->pa->cause;
+
+ StopAllL3Timer(st);
+
+ MsgHead(p, st->l3.callref, MT_DISCONNECT);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = cause | 0x80;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ newl3state(st, 11);
+ st->l3.l3l2(st, DL_DATA, skb);
+ L3AddTimer(&st->l3.timer, st->l3.t305, CC_T305);
+}
+
+static void
+l3dss1_reject_req(struct PStack *st, u_char pr, void *arg)
+{
+ struct sk_buff *skb;
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ u_char cause = 0x95;
+
+ if (st->pa->cause > 0)
+ cause = st->pa->cause;
+
+ MsgHead(p, st->l3.callref, MT_RELEASE_COMPLETE);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = cause;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ newl3state(st, 0);
+ st->l3.l3l2(st, DL_DATA, skb);
+ st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+}
+
+static void
+l3dss1_release(struct PStack *st, u_char pr, void *arg)
+{
+ u_char *p;
+ struct sk_buff *skb = arg;
+ int cause = -1;
+
+ p = skb->data;
+ if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+ p++;
+ if (*p++ == 2)
+ st->pa->loc = *p++;
+ cause = *p & 0x7f;
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ StopAllL3Timer(st);
+ st->pa->cause = cause;
+ newl3state(st, 0);
+ l3dss1_message(st, MT_RELEASE_COMPLETE);
+ st->l3.l3l4(st, CC_RELEASE_IND, NULL);
+}
+
+static void
+l3dss1_alert_req(struct PStack *st, u_char pr,
+ void *arg)
+{
+ newl3state(st, 7);
+ l3dss1_message(st, MT_ALERTING);
+}
+
+static void
+l3dss1_status_enq(struct PStack *st, u_char pr, void *arg)
+{
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ struct sk_buff *skb = arg;
+
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+
+ MsgHead(p, st->l3.callref, MT_STATUS);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = 0x9E; /* answer status enquire */
+
+ *p++ = 0x14; /* CallState */
+ *p++ = 0x1;
+ *p++ = st->l3.state & 0x3f;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ st->l3.l3l2(st, DL_DATA, skb);
+}
+
+static void
+l3dss1_t303(struct PStack *st, u_char pr, void *arg)
+{
+ if (st->l3.n_t303 > 0) {
+ st->l3.n_t303--;
+ L3DelTimer(&st->l3.timer);
+ l3dss1_setup_req(st, pr, arg);
+ } else {
+ newl3state(st, 0);
+ L3DelTimer(&st->l3.timer);
+ st->l3.l3l4(st, CC_NOSETUP_RSP_ERR, NULL);
+ st->l3.n_t303 = 1;
+ }
+}
+
+static void
+l3dss1_t304(struct PStack *st, u_char pr, void *arg)
+{
+ L3DelTimer(&st->l3.timer);
+ st->pa->cause = 0xE6;
+ l3dss1_disconnect_req(st, pr, NULL);
+ st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+
+}
+
+static void
+l3dss1_t305(struct PStack *st, u_char pr, void *arg)
+{
+ u_char tmp[16];
+ u_char *p = tmp;
+ int l;
+ struct sk_buff *skb;
+ u_char cause = 0x90;
+
+ L3DelTimer(&st->l3.timer);
+ if (st->pa->cause > 0)
+ cause = st->pa->cause;
+
+ MsgHead(p, st->l3.callref, MT_RELEASE);
+
+ *p++ = IE_CAUSE;
+ *p++ = 0x2;
+ *p++ = 0x80;
+ *p++ = cause;
+
+ l = p - tmp;
+ if (!(skb = l3_alloc_skb(l)))
+ return;
+ memcpy(skb_put(skb, l), tmp, l);
+ newl3state(st, 19);
+ st->l3.l3l2(st, DL_DATA, skb);
+ L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_1);
+}
+
+static void
+l3dss1_t310(struct PStack *st, u_char pr, void *arg)
+{
+ L3DelTimer(&st->l3.timer);
+ st->pa->cause = 0xE6;
+ l3dss1_disconnect_req(st, pr, NULL);
+ st->l3.l3l4(st, CC_SETUP_ERR, NULL);
+}
+
+static void
+l3dss1_t313(struct PStack *st, u_char pr, void *arg)
+{
+ L3DelTimer(&st->l3.timer);
+ st->pa->cause = 0xE6;
+ l3dss1_disconnect_req(st, pr, NULL);
+ st->l3.l3l4(st, CC_CONNECT_ERR, NULL);
+}
+
+static void
+l3dss1_t308_1(struct PStack *st, u_char pr, void *arg)
+{
+ newl3state(st, 19);
+ L3DelTimer(&st->l3.timer);
+ l3dss1_message(st, MT_RELEASE);
+ L3AddTimer(&st->l3.timer, st->l3.t308, CC_T308_2);
+}
+
+static void
+l3dss1_t308_2(struct PStack *st, u_char pr, void *arg)
+{
+ newl3state(st, 0);
+ L3DelTimer(&st->l3.timer);
+ st->l3.l3l4(st, CC_RELEASE_ERR, NULL);
+}
+/* *INDENT-OFF* */
+static struct stateentry downstatelist[] =
+{
+ {SBIT(0),
+ CC_SETUP_REQ, l3dss1_setup_req},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(10),
+ CC_DISCONNECT_REQ, l3dss1_disconnect_req},
+ {SBIT(12),
+ CC_RELEASE_REQ, l3dss1_release_req},
+ {ALL_STATES,
+ CC_DLRL, l3dss1_reset},
+ {SBIT(6),
+ CC_IGNORE, l3dss1_reset},
+ {SBIT(6),
+ CC_REJECT_REQ, l3dss1_reject_req},
+ {SBIT(6),
+ CC_ALERTING_REQ, l3dss1_alert_req},
+ {SBIT(6) | SBIT(7),
+ CC_SETUP_RSP, l3dss1_setup_rsp},
+ {SBIT(1),
+ CC_T303, l3dss1_t303},
+ {SBIT(2),
+ CC_T304, l3dss1_t304},
+ {SBIT(3),
+ CC_T310, l3dss1_t310},
+ {SBIT(8),
+ CC_T313, l3dss1_t313},
+ {SBIT(11),
+ CC_T305, l3dss1_t305},
+ {SBIT(19),
+ CC_T308_1, l3dss1_t308_1},
+ {SBIT(19),
+ CC_T308_2, l3dss1_t308_2},
+};
+
+static int downsllen = sizeof(downstatelist) /
+sizeof(struct stateentry);
+
+static struct stateentry datastatelist[] =
+{
+ {ALL_STATES,
+ MT_STATUS_ENQUIRY, l3dss1_status_enq},
+ {SBIT(0) | SBIT(6),
+ MT_SETUP, l3dss1_setup},
+ {SBIT(1) | SBIT(2),
+ MT_CALL_PROCEEDING, l3dss1_call_proc},
+ {SBIT(1),
+ MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack},
+ {SBIT(1) | SBIT(2) | SBIT(3),
+ MT_ALERTING, l3dss1_alerting},
+ {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
+ SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+ MT_RELEASE_COMPLETE, l3dss1_release_cmpl},
+ {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
+ SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19),
+ MT_RELEASE, l3dss1_release},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10),
+ MT_DISCONNECT, l3dss1_disconnect},
+ {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
+ MT_CONNECT, l3dss1_connect},
+ {SBIT(8),
+ MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack},
+};
+/* *INDENT-ON* */
+
+
+static int datasllen = sizeof(datastatelist) /
+sizeof(struct stateentry);
+
+static void
+dss1up(struct PStack *st, int pr, void *arg)
+{
+ int i, mt;
+ struct sk_buff *skb = arg;
+ char tmp[80];
+
+ if (skb->data[0] != PROTO_DIS_EURO) {
+ if (st->l3.debug & L3_DEB_PROTERR) {
+ sprintf(tmp, "dss1up%sunexpected discriminator %x message len %ld state %d",
+ (pr == DL_DATA) ? " " : "(broadcast) ",
+ skb->data[0], skb->len, st->l3.state);
+ l3_debug(st, tmp);
+ }
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ return;
+ }
+ mt = skb->data[skb->data[1] + 2];
+ for (i = 0; i < datasllen; i++)
+ if ((mt == datastatelist[i].primitive) &&
+ ((1 << st->l3.state) & datastatelist[i].state))
+ break;
+ if (i == datasllen) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_READ);
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "dss1up%sstate %d mt %x unhandled",
+ (pr == DL_DATA) ? " " : "(broadcast) ",
+ st->l3.state, mt);
+ l3_debug(st, tmp);
+ }
+ return;
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "dss1up%sstate %d mt %x",
+ (pr == DL_DATA) ? " " : "(broadcast) ",
+ st->l3.state, mt);
+ l3_debug(st, tmp);
+ }
+ datastatelist[i].rout(st, pr, skb);
+ }
+}
+
+static void
+dss1down(struct PStack *st, int pr, void *arg)
+{
+ int i;
+ char tmp[80];
+
+ for (i = 0; i < downsllen; i++)
+ if ((pr == downstatelist[i].primitive) &&
+ ((1 << st->l3.state) & downstatelist[i].state))
+ break;
+ if (i == downsllen) {
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "dss1down state %d prim %d unhandled",
+ st->l3.state, pr);
+ l3_debug(st, tmp);
+ }
+ } else {
+ if (st->l3.debug & L3_DEB_STATE) {
+ sprintf(tmp, "dss1down state %d prim %d",
+ st->l3.state, pr);
+ l3_debug(st, tmp);
+ }
+ downstatelist[i].rout(st, pr, arg);
+ }
+}
+
+void
+setstack_dss1(struct PStack *st)
+{
+ char tmp[64];
+
+ st->l4.l4l3 = dss1down;
+ st->l2.l2l3 = dss1up;
+ st->l3.t303 = 4000;
+ st->l3.t304 = 30000;
+ st->l3.t305 = 30000;
+ st->l3.t308 = 4000;
+ st->l3.t310 = 30000;
+ st->l3.t313 = 4000;
+ st->l3.t318 = 4000;
+ st->l3.t319 = 4000;
+ st->l3.n_t303 = 1;
+
+ if (st->l3.channr & 1) {
+ strcpy(tmp, dss1_revision);
+ printk(KERN_NOTICE "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));
+ }
+}
--- /dev/null
+/* $Id: q931.c,v 1.5 1997/04/06 22:56:43 keil Exp $
+
+ * q931.c code to decode ITU Q.931 call control messages
+ *
+ * Author Jan den Ouden
+ *
+ * Changelog
+ *
+ * Pauline Middelink general improvements
+ *
+ * Beat Doebeli cause texts, display information element
+ *
+ * Karsten Keil cause texts, display information element for 1TR6
+ *
+ *
+ * $Log: q931.c,v $
+ * Revision 1.5 1997/04/06 22:56:43 keil
+ * Some cosmetic changes
+ *
+ * Revision 1.4 1997/02/09 00:29:11 keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.3 1997/01/21 22:24:59 keil
+ * cleanups
+ *
+ * Revision 1.2 1996/10/27 22:12:45 keil
+ * reporting unknown level 3 protocol ids
+ *
+ * Revision 1.1 1996/10/13 20:04:56 keil
+ * Initial revision
+ *
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "l3_1tr6.h"
+
+u_char *
+findie(u_char * p, int size, u_char ie, int wanted_set)
+{
+ int l, codeset, maincodeset;
+ u_char *pend = p + size;
+
+ /* skip protocol discriminator, callref and message type */
+ p++;
+ l = (*p++) & 0xf;
+ p += l;
+ p++;
+ codeset = 0;
+ maincodeset = 0;
+ /* while there are bytes left... */
+ while (p < pend) {
+ if ((*p & 0xf0) == 0x90) {
+ codeset = *p & 0x07;
+ if (!(*p & 0x08))
+ maincodeset = codeset;
+ }
+ if (*p & 0x80)
+ p++;
+ else {
+ if (codeset == wanted_set) {
+ if (*p == ie)
+ return (p);
+ if (*p > ie)
+ return (NULL);
+ }
+ p++;
+ l = *p++;
+ p += l;
+ codeset = maincodeset;
+ }
+ }
+ return (NULL);
+}
+
+void
+iecpy(u_char * dest, u_char * iestart, int ieoffset)
+{
+ u_char *p;
+ int l;
+
+ p = iestart + ieoffset + 2;
+ l = iestart[1] - ieoffset;
+ while (l--)
+ *dest++ = *p++;
+ *dest++ = '\0';
+}
+
+int
+getcallref(u_char * p)
+{
+ p++; /* prot discr */
+ p++; /* callref length */
+ return (*p); /* assuming one-byte callref */
+}
+
+/*
+ * According to Table 4-2/Q.931
+ */
+static
+struct MessageType {
+ u_char nr;
+ char *descr;
+} mtlist[] = {
+
+ {
+ 0x1, "ALERTING"
+ },
+ {
+ 0x2, "CALL PROCEEDING"
+ },
+ {
+ 0x7, "CONNECT"
+ },
+ {
+ 0xf, "CONNECT ACKNOWLEDGE"
+ },
+ {
+ 0x3, "PROGRESS"
+ },
+ {
+ 0x5, "SETUP"
+ },
+ {
+ 0xd, "SETUP ACKNOWLEDGE"
+ },
+ {
+ 0x26, "RESUME"
+ },
+ {
+ 0x2e, "RESUME ACKNOWLEDGE"
+ },
+ {
+ 0x22, "RESUME REJECT"
+ },
+ {
+ 0x25, "SUSPEND"
+ },
+ {
+ 0x2d, "SUSPEND ACKNOWLEDGE"
+ },
+ {
+ 0x21, "SUSPEND REJECT"
+ },
+ {
+ 0x20, "USER INFORMATION"
+ },
+ {
+ 0x45, "DISCONNECT"
+ },
+ {
+ 0x4d, "RELEASE"
+ },
+ {
+ 0x5a, "RELEASE COMPLETE"
+ },
+ {
+ 0x46, "RESTART"
+ },
+ {
+ 0x4e, "RESTART ACKNOWLEDGE"
+ },
+ {
+ 0x60, "SEGMENT"
+ },
+ {
+ 0x79, "CONGESTION CONTROL"
+ },
+ {
+ 0x7b, "INFORMATION"
+ },
+ {
+ 0x62, "FACILITY"
+ },
+ {
+ 0x6e, "NOTIFY"
+ },
+ {
+ 0x7d, "STATUS"
+ },
+ {
+ 0x75, "STATUS ENQUIRY"
+ }
+};
+
+#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
+
+static
+struct MessageType mt_n0[] =
+{
+ {MT_N0_REG_IND, "REGister INDication"},
+ {MT_N0_CANC_IND, "CANCel INDication"},
+ {MT_N0_FAC_STA, "FACility STAtus"},
+ {MT_N0_STA_ACK, "STAtus ACKnowledge"},
+ {MT_N0_STA_REJ, "STAtus REJect"},
+ {MT_N0_FAC_INF, "FACility INFormation"},
+ {MT_N0_INF_ACK, "INFormation ACKnowledge"},
+ {MT_N0_INF_REJ, "INFormation REJect"},
+ {MT_N0_CLOSE, "CLOSE"},
+ {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
+};
+
+int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
+
+static
+struct MessageType mt_n1[] =
+{
+ {MT_N1_ESC, "ESCape"},
+ {MT_N1_ALERT, "ALERT"},
+ {MT_N1_CALL_SENT, "CALL SENT"},
+ {MT_N1_CONN, "CONNect"},
+ {MT_N1_CONN_ACK, "CONNect ACKnowledge"},
+ {MT_N1_SETUP, "SETUP"},
+ {MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
+ {MT_N1_RES, "RESume"},
+ {MT_N1_RES_ACK, "RESume ACKnowledge"},
+ {MT_N1_RES_REJ, "RESume REJect"},
+ {MT_N1_SUSP, "SUSPend"},
+ {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
+ {MT_N1_SUSP_REJ, "SUSPend REJect"},
+ {MT_N1_USER_INFO, "USER INFO"},
+ {MT_N1_DET, "DETach"},
+ {MT_N1_DISC, "DISConnect"},
+ {MT_N1_REL, "RELease"},
+ {MT_N1_REL_ACK, "RELease ACKnowledge"},
+ {MT_N1_CANC_ACK, "CANCel ACKnowledge"},
+ {MT_N1_CANC_REJ, "CANCel REJect"},
+ {MT_N1_CON_CON, "CONgestion CONtrol"},
+ {MT_N1_FAC, "FACility"},
+ {MT_N1_FAC_ACK, "FACility ACKnowledge"},
+ {MT_N1_FAC_CAN, "FACility CANcel"},
+ {MT_N1_FAC_REG, "FACility REGister"},
+ {MT_N1_FAC_REJ, "FACility REJect"},
+ {MT_N1_INFO, "INFOrmation"},
+ {MT_N1_REG_ACK, "REGister ACKnowledge"},
+ {MT_N1_REG_REJ, "REGister REJect"},
+ {MT_N1_STAT, "STATus"}
+};
+
+int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
+
+static struct MessageType fac_1tr6[] =
+{
+ {FAC_Sperre, "Sperre"},
+ {FAC_Forward1, "Forward 1"},
+ {FAC_Forward2, "Forward 2"},
+ {FAC_Konferenz, "Konferenz"},
+ {FAC_GrabBchan, "Grab Bchannel"},
+ {FAC_Reactivate, "Reactivate"},
+ {FAC_Konferenz3, "Dreier Konferenz"},
+ {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
+ {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
+ {FAC_NummernIdent, "Rufnummer-Identifizierung"},
+ {FAC_GBG, "GBG"},
+ {FAC_DisplayUebergeben, "Display Uebergeben"},
+ {FAC_DisplayUmgeleitet, "Display Umgeleitet"},
+ {FAC_Unterdruecke, "Unterdruecke Rufnummer"},
+ {FAC_Deactivate, "Deactivate"},
+ {FAC_Activate, "Activate"},
+ {FAC_SPV, "SPV"},
+ {FAC_Rueckwechsel, "Rueckwechsel"},
+ {FAC_Umleitung, "Umleitung"}
+};
+int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
+
+
+
+static int
+prbits(char *dest, u_char b, int start, int len)
+{
+ char *dp = dest;
+
+ b = b << (8 - start);
+ while (len--) {
+ if (b & 0x80)
+ *dp++ = '1';
+ else
+ *dp++ = '0';
+ b = b << 1;
+ }
+ return (dp - dest);
+}
+
+static
+u_char *
+skipext(u_char * p)
+{
+ while (!(*p++ & 0x80));
+ return (p);
+}
+
+/*
+ * Cause Values According to Q.850
+ * edescr: English description
+ * ddescr: German description used by Swissnet II (Swiss Telecom
+ * not yet written...
+ */
+
+static
+struct CauseValue {
+ u_char nr;
+ char *edescr;
+ char *ddescr;
+} cvlist[] = {
+
+ {
+ 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
+ },
+ {
+ 0x02, "No route to specified transit network", ""
+ },
+ {
+ 0x03, "No route to destination", ""
+ },
+ {
+ 0x04, "Send special information tone", ""
+ },
+ {
+ 0x05, "Misdialled trunk prefix", ""
+ },
+ {
+ 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
+ },
+ {
+ 0x07, "Channel awarded and being delivered in an established channel", ""
+ },
+ {
+ 0x08, "Preemption", ""
+ },
+ {
+ 0x09, "Preemption - circuit reserved for reuse", ""
+ },
+ {
+ 0x10, "Normal call clearing", "Normale Ausloesung"
+ },
+ {
+ 0x11, "User busy", "TNB besetzt"
+ },
+ {
+ 0x12, "No user responding", ""
+ },
+ {
+ 0x13, "No answer from user (user alerted)", ""
+ },
+ {
+ 0x14, "Subscriber absent", ""
+ },
+ {
+ 0x15, "Call rejected", ""
+ },
+ {
+ 0x16, "Number changed", ""
+ },
+ {
+ 0x1a, "non-selected user clearing", ""
+ },
+ {
+ 0x1b, "Destination out of order", ""
+ },
+ {
+ 0x1c, "Invalid number format (address incomplete)", ""
+ },
+ {
+ 0x1d, "Facility rejected", ""
+ },
+ {
+ 0x1e, "Response to Status enquiry", ""
+ },
+ {
+ 0x1f, "Normal, unspecified", ""
+ },
+ {
+ 0x22, "No circuit/channel available", ""
+ },
+ {
+ 0x26, "Network out of order", ""
+ },
+ {
+ 0x27, "Permanent frame mode connection out-of-service", ""
+ },
+ {
+ 0x28, "Permanent frame mode connection operational", ""
+ },
+ {
+ 0x29, "Temporary failure", ""
+ },
+ {
+ 0x2a, "Switching equipment congestion", ""
+ },
+ {
+ 0x2b, "Access information discarded", ""
+ },
+ {
+ 0x2c, "Requested circuit/channel not available", ""
+ },
+ {
+ 0x2e, "Precedence call blocked", ""
+ },
+ {
+ 0x2f, "Resource unavailable, unspecified", ""
+ },
+ {
+ 0x31, "Quality of service unavailable", ""
+ },
+ {
+ 0x32, "Requested facility not subscribed", ""
+ },
+ {
+ 0x35, "Outgoing calls barred within CUG", ""
+ },
+ {
+ 0x37, "Incoming calls barred within CUG", ""
+ },
+ {
+ 0x39, "Bearer capability not authorized", ""
+ },
+ {
+ 0x3a, "Bearer capability not presently available", ""
+ },
+ {
+ 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
+ },
+ {
+ 0x3f, "Service or option not available, unspecified", ""
+ },
+ {
+ 0x41, "Bearer capability not implemented", ""
+ },
+ {
+ 0x42, "Channel type not implemented", ""
+ },
+ {
+ 0x43, "Requested facility not implemented", ""
+ },
+ {
+ 0x44, "Only restricted digital information bearer capability is available", ""
+ },
+ {
+ 0x4f, "Service or option not implemented", ""
+ },
+ {
+ 0x51, "Invalid call reference value", ""
+ },
+ {
+ 0x52, "Identified channel does not exist", ""
+ },
+ {
+ 0x53, "A suspended call exists, but this call identity does not", ""
+ },
+ {
+ 0x54, "Call identity in use", ""
+ },
+ {
+ 0x55, "No call suspended", ""
+ },
+ {
+ 0x56, "Call having the requested call identity has been cleared", ""
+ },
+ {
+ 0x57, "User not member of CUG", ""
+ },
+ {
+ 0x58, "Incompatible destination", ""
+ },
+ {
+ 0x5a, "Non-existent CUG", ""
+ },
+ {
+ 0x5b, "Invalid transit network selection", ""
+ },
+ {
+ 0x5f, "Invalid message, unspecified", ""
+ },
+ {
+ 0x60, "Mandatory information element is missing", ""
+ },
+ {
+ 0x61, "Message type non-existent or not implemented", ""
+ },
+ {
+ 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
+ },
+ {
+ 0x63, "Information element/parameter non-existent or not implemented", ""
+ },
+ {
+ 0x64, "Invalid information element contents", ""
+ },
+ {
+ 0x65, "Message not compatible with call state", ""
+ },
+ {
+ 0x66, "Recovery on timer expiry", ""
+ },
+ {
+ 0x67, "Parameter non-existent or not implemented - passed on", ""
+ },
+ {
+ 0x6e, "Message with unrecognized parameter discarded", ""
+ },
+ {
+ 0x6f, "Protocol error, unspecified", ""
+ },
+ {
+ 0x7f, "Interworking, unspecified", ""
+ },
+};
+
+#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
+
+static
+int
+prcause(char *dest, u_char * p)
+{
+ u_char *end;
+ char *dp = dest;
+ int i, cause;
+
+ end = p + p[1] + 1;
+ p += 2;
+ dp += sprintf(dp, " coding ");
+ dp += prbits(dp, *p, 7, 2);
+ dp += sprintf(dp, " location ");
+ dp += prbits(dp, *p, 4, 4);
+ *dp++ = '\n';
+ p = skipext(p);
+
+ cause = 0x7f & *p++;
+
+ /* locate cause value */
+ for (i = 0; i < CVSIZE; i++)
+ if (cvlist[i].nr == cause)
+ break;
+
+ /* display cause value if it exists */
+ if (i == CVSIZE)
+ dp += sprintf(dp, "Unknown cause type %x!\n", cause);
+ else
+ dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr);
+
+ while (!0) {
+ if (p > end)
+ break;
+ dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f);
+ dp += sprintf(dp, " rej %d ", *p & 0x7f);
+ if (*p & 0x80) {
+ *dp++ = '\n';
+ break;
+ } else
+ dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
+ }
+ return (dp - dest);
+
+}
+
+static
+struct MessageType cause_1tr6[] =
+{
+ {CAUSE_InvCRef, "Invalid Call Reference"},
+ {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
+ {CAUSE_CIDunknown, "Caller Identity unknown"},
+ {CAUSE_CIDinUse, "Caller Identity in Use"},
+ {CAUSE_NoChans, "No Channels available"},
+ {CAUSE_FacNotImpl, "Facility Not Implemented"},
+ {CAUSE_FacNotSubscr, "Facility Not Subscribed"},
+ {CAUSE_OutgoingBarred, "Outgoing calls barred"},
+ {CAUSE_UserAccessBusy, "User Access Busy"},
+ {CAUSE_NegativeGBG, "Negative GBG"},
+ {CAUSE_UnknownGBG, "Unknown GBG"},
+ {CAUSE_NoSPVknown, "No SPV known"},
+ {CAUSE_DestNotObtain, "Destination not obtainable"},
+ {CAUSE_NumberChanged, "Number changed"},
+ {CAUSE_OutOfOrder, "Out Of Order"},
+ {CAUSE_NoUserResponse, "No User Response"},
+ {CAUSE_UserBusy, "User Busy"},
+ {CAUSE_IncomingBarred, "Incoming Barred"},
+ {CAUSE_CallRejected, "Call Rejected"},
+ {CAUSE_NetworkCongestion, "Network Congestion"},
+ {CAUSE_RemoteUser, "Remote User initiated"},
+ {CAUSE_LocalProcErr, "Local Procedure Error"},
+ {CAUSE_RemoteProcErr, "Remote Procedure Error"},
+ {CAUSE_RemoteUserSuspend, "Remote User Suspend"},
+ {CAUSE_RemoteUserResumed, "Remote User Resumed"},
+ {CAUSE_UserInfoDiscarded, "User Info Discarded"}
+};
+
+int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
+
+static int
+prcause_1tr6(char *dest, u_char * p)
+{
+ char *dp = dest;
+ int i, cause;
+
+ p++;
+ if (0 == *p) {
+ dp += sprintf(dp, " OK (cause length=0)\n");
+ return (dp - dest);
+ } else if (*p > 1) {
+ dp += sprintf(dp, " coding ");
+ dp += prbits(dp, p[2], 7, 2);
+ dp += sprintf(dp, " location ");
+ dp += prbits(dp, p[2], 4, 4);
+ *dp++ = '\n';
+ }
+ p++;
+ cause = 0x7f & *p;
+
+ /* locate cause value */
+ for (i = 0; i < cause_1tr6_len; i++)
+ if (cause_1tr6[i].nr == cause)
+ break;
+
+ /* display cause value if it exists */
+ if (i == cause_1tr6_len)
+ dp += sprintf(dp, "Unknown cause type %x!\n", cause);
+ else
+ dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr);
+
+ return (dp - dest);
+
+}
+
+static int
+prchident(char *dest, u_char * p)
+{
+ char *dp = dest;
+
+ p += 2;
+ dp += sprintf(dp, " octet 3 ");
+ dp += prbits(dp, *p, 8, 8);
+ *dp++ = '\n';
+ return (dp - dest);
+}
+
+static int
+prcalled(char *dest, u_char * p)
+{
+ int l;
+ char *dp = dest;
+
+ p++;
+ l = *p++ - 1;
+ dp += sprintf(dp, " octet 3 ");
+ dp += prbits(dp, *p++, 8, 8);
+ *dp++ = '\n';
+ dp += sprintf(dp, " number digits ");
+ while (l--)
+ *dp++ = *p++;
+ *dp++ = '\n';
+ return (dp - dest);
+}
+static int
+prcalling(char *dest, u_char * p)
+{
+ int l;
+ char *dp = dest;
+
+ p++;
+ l = *p++ - 1;
+ dp += sprintf(dp, " octet 3 ");
+ dp += prbits(dp, *p, 8, 8);
+ *dp++ = '\n';
+ if (!(*p & 0x80)) {
+ dp += sprintf(dp, " octet 3a ");
+ dp += prbits(dp, *++p, 8, 8);
+ *dp++ = '\n';
+ l--;
+ };
+ p++;
+
+ dp += sprintf(dp, " number digits ");
+ while (l--)
+ *dp++ = *p++;
+ *dp++ = '\n';
+ return (dp - dest);
+}
+
+static
+int
+prbearer(char *dest, u_char * p)
+{
+ char *dp = dest, ch;
+
+ p += 2;
+ dp += sprintf(dp, " octet 3 ");
+ dp += prbits(dp, *p++, 8, 8);
+ *dp++ = '\n';
+ dp += sprintf(dp, " octet 4 ");
+ dp += prbits(dp, *p, 8, 8);
+ *dp++ = '\n';
+ if ((*p++ & 0x1f) == 0x18) {
+ dp += sprintf(dp, " octet 4.1 ");
+ dp += prbits(dp, *p++, 8, 8);
+ *dp++ = '\n';
+ }
+ /* check for user information layer 1 */
+ if ((*p & 0x60) == 0x20) {
+ ch = ' ';
+ do {
+ dp += sprintf(dp, " octet 5%c ", ch);
+ dp += prbits(dp, *p, 8, 8);
+ *dp++ = '\n';
+ if (ch == ' ')
+ ch = 'a';
+ else
+ ch++;
+ }
+ while (!(*p++ & 0x80));
+ }
+ /* check for user information layer 2 */
+ if ((*p & 0x60) == 0x40) {
+ dp += sprintf(dp, " octet 6 ");
+ dp += prbits(dp, *p++, 8, 8);
+ *dp++ = '\n';
+ }
+ /* check for user information layer 3 */
+ if ((*p & 0x60) == 0x60) {
+ dp += sprintf(dp, " octet 7 ");
+ dp += prbits(dp, *p++, 8, 8);
+ *dp++ = '\n';
+ }
+ return (dp - dest);
+}
+
+static int
+general(char *dest, u_char * p)
+{
+ char *dp = dest;
+ char ch = ' ';
+ int l, octet = 3;
+
+ p++;
+ l = *p++;
+ /* Iterate over all octets in the information element */
+ while (l--) {
+ dp += sprintf(dp, " octet %d%c ", octet, ch);
+ dp += prbits(dp, *p++, 8, 8);
+ *dp++ = '\n';
+
+ /* last octet in group? */
+ if (*p & 0x80) {
+ octet++;
+ ch = ' ';
+ } else if (ch == ' ')
+ ch = 'a';
+ else
+ ch++;
+ }
+ return (dp - dest);
+}
+
+static int
+prcharge(char *dest, u_char * p)
+{
+ char *dp = dest;
+ int l;
+
+ p++;
+ l = *p++ - 1;
+ dp += sprintf(dp, " GEA ");
+ dp += prbits(dp, *p++, 8, 8);
+ dp += sprintf(dp, " Anzahl: ");
+ /* Iterate over all octets in the * information element */
+ while (l--)
+ *dp++ = *p++;
+ *dp++ = '\n';
+ return (dp - dest);
+}
+static int
+prtext(char *dest, u_char * p)
+{
+ char *dp = dest;
+ int l;
+
+ p++;
+ l = *p++;
+ dp += sprintf(dp, " ");
+ /* Iterate over all octets in the * information element */
+ while (l--)
+ *dp++ = *p++;
+ *dp++ = '\n';
+ return (dp - dest);
+}
+static int
+display(char *dest, u_char * p)
+{
+ char *dp = dest;
+ char ch = ' ';
+ int l, octet = 3;
+
+ p++;
+ l = *p++;
+ /* Iterate over all octets in the * display-information element */
+ dp += sprintf(dp, " \"");
+ while (l--) {
+ dp += sprintf(dp, "%c", *p++);
+
+ /* last octet in group? */
+ if (*p & 0x80) {
+ octet++;
+ ch = ' ';
+ } else if (ch == ' ')
+ ch = 'a';
+
+ else
+ ch++;
+ }
+ *dp++ = '\"';
+ *dp++ = '\n';
+ return (dp - dest);
+}
+
+int
+prfacility(char *dest, u_char * p)
+{
+ char *dp = dest;
+ int l, l2;
+
+ p++;
+ l = *p++;
+ dp += sprintf(dp, " octet 3 ");
+ dp += prbits(dp, *p++, 8, 8);
+ dp += sprintf(dp, "\n");
+ l -= 1;
+
+ while (l > 0) {
+ dp += sprintf(dp, " octet 4 ");
+ dp += prbits(dp, *p++, 8, 8);
+ dp += sprintf(dp, "\n");
+ dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f);
+ l -= 2;
+ dp += sprintf(dp, " contents ");
+ while (l2--) {
+ dp += sprintf(dp, "%2x ", *p++);
+ l--;
+ }
+ dp += sprintf(dp, "\n");
+ }
+
+ return (dp - dest);
+}
+
+static
+struct InformationElement {
+ u_char nr;
+ char *descr;
+ int (*f) (char *, u_char *);
+} ielist[] = {
+
+ {
+ 0x00, "Segmented message", general
+ },
+ {
+ 0x04, "Bearer capability", prbearer
+ },
+ {
+ 0x08, "Cause", prcause
+ },
+ {
+ 0x10, "Call identity", general
+ },
+ {
+ 0x14, "Call state", general
+ },
+ {
+ 0x18, "Channel identification", prchident
+ },
+ {
+ 0x1c, "Facility", prfacility
+ },
+ {
+ 0x1e, "Progress indicator", general
+ },
+ {
+ 0x20, "Network-specific facilities", general
+ },
+ {
+ 0x27, "Notification indicator", general
+ },
+ {
+ 0x28, "Display", display
+ },
+ {
+ 0x29, "Date/Time", general
+ },
+ {
+ 0x2c, "Keypad facility", general
+ },
+ {
+ 0x34, "Signal", general
+ },
+ {
+ 0x40, "Information rate", general
+ },
+ {
+ 0x42, "End-to-end delay", general
+ },
+ {
+ 0x43, "Transit delay selection and indication", general
+ },
+ {
+ 0x44, "Packet layer binary parameters", general
+ },
+ {
+ 0x45, "Packet layer window size", general
+ },
+ {
+ 0x46, "Packet size", general
+ },
+ {
+ 0x47, "Closed user group", general
+ },
+ {
+ 0x4a, "Reverse charge indication", general
+ },
+ {
+ 0x6c, "Calling party number", prcalling
+ },
+ {
+ 0x6d, "Calling party subaddress", general
+ },
+ {
+ 0x70, "Called party number", prcalled
+ },
+ {
+ 0x71, "Called party subaddress", general
+ },
+ {
+ 0x74, "Redirecting number", general
+ },
+ {
+ 0x78, "Transit network selection", general
+ },
+ {
+ 0x79, "Restart indicator", general
+ },
+ {
+ 0x7c, "Low layer compatibility", general
+ },
+ {
+ 0x7d, "High layer compatibility", general
+ },
+ {
+ 0x7e, "User-user", general
+ },
+ {
+ 0x7f, "Escape for extension", general
+ },
+};
+
+
+#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
+
+static struct InformationElement we_0[] =
+{
+ {WE0_cause, "Cause", prcause_1tr6},
+ {WE0_connAddr, "Connecting Address", prcalled},
+ {WE0_callID, "Call IDentity", general},
+ {WE0_chanID, "Channel IDentity", general},
+ {WE0_netSpecFac, "Network Specific Facility", general},
+ {WE0_display, "Display", general},
+ {WE0_keypad, "Keypad", general},
+ {WE0_origAddr, "Origination Address", prcalled},
+ {WE0_destAddr, "Destination Address", prcalled},
+ {WE0_userInfo, "User Info", general}
+};
+
+static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
+
+static struct InformationElement we_6[] =
+{
+ {WE6_serviceInd, "Service Indicator", general},
+ {WE6_chargingInfo, "Charging Information", prcharge},
+ {WE6_date, "Date", prtext},
+ {WE6_facSelect, "Facility Select", general},
+ {WE6_facStatus, "Facility Status", general},
+ {WE6_statusCalled, "Status Called", general},
+ {WE6_addTransAttr, "Additional Transmission Attributes", general}
+};
+static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
+
+int
+QuickHex(char *txt, u_char * p, int cnt)
+{
+ register int i;
+ register char *t = txt;
+ register u_char w;
+
+ for (i = 0; i < cnt; i++) {
+ *t++ = ' ';
+ w = (p[i] >> 4) & 0x0f;
+ if (w < 10)
+ *t++ = '0' + w;
+ else
+ *t++ = 'A' - 10 + w;
+ w = p[i] & 0x0f;
+ if (w < 10)
+ *t++ = '0' + w;
+ else
+ *t++ = 'A' - 10 + w;
+ }
+ *t++ = 0;
+ return (t - txt);
+}
+
+void
+LogFrame(struct IsdnCardState *sp, u_char * buf, int size)
+{
+ char *dp;
+
+ if (size < 1)
+ return;
+ dp = sp->dlogspace;
+ if (size < 4096 / 3 - 10) {
+ dp += sprintf(dp, "HEX:");
+ dp += QuickHex(dp, buf, size);
+ dp--;
+ *dp++ = '\n';
+ *dp = 0;
+ } else
+ sprintf(dp, "LogFrame: warning Frame too big (%d)\n",
+ size);
+ HiSax_putstatus(sp, sp->dlogspace);
+}
+
+void
+dlogframe(struct IsdnCardState *sp, u_char * buf, int size, char *comment)
+{
+ u_char *bend = buf + size;
+ char *dp;
+ unsigned char pd, cr_l, cr, mt;
+ int i, cs = 0, cs_old = 0, cs_fest = 0;
+
+ if (size < 1)
+ return;
+ /* display header */
+ dp = sp->dlogspace;
+ dp += sprintf(dp, "%s\n", comment);
+
+ if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */
+ /* locate message type */
+ pd = *buf++;
+ cr_l = *buf++;
+ if (cr_l)
+ cr = *buf++;
+ else
+ cr = 0;
+ mt = *buf++;
+ if (pd == PROTO_DIS_N0) { /* N0 */
+ for (i = 0; i < mt_n0_len; i++)
+ if (mt_n0[i].nr == mt)
+ break;
+ /* display message type if it exists */
+ if (i == mt_n0_len)
+ dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n",
+ cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+ size, mt);
+ else
+ dp += sprintf(dp, "callref %d %s size %d message type %s\n",
+ cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+ size, mt_n0[i].descr);
+ } else { /* N1 */
+ for (i = 0; i < mt_n1_len; i++)
+ if (mt_n1[i].nr == mt)
+ break;
+ /* display message type if it exists */
+ if (i == mt_n1_len)
+ dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n",
+ cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+ size, mt);
+ else
+ dp += sprintf(dp, "callref %d %s size %d message type %s\n",
+ cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+ size, mt_n1[i].descr);
+ }
+
+ /* display each information element */
+ while (buf < bend) {
+ /* Is it a single octet information element? */
+ if (*buf & 0x80) {
+ switch ((*buf >> 4) & 7) {
+ case 1:
+ dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
+ cs_old = cs;
+ cs = *buf & 7;
+ cs_fest = *buf & 8;
+ break;
+ case 3:
+ dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
+ break;
+ case 2:
+ if (*buf == 0xa0) {
+ dp += sprintf(dp, " More data\n");
+ break;
+ }
+ if (*buf == 0xa1) {
+ dp += sprintf(dp, " Sending complete\n");
+ }
+ break;
+ /* fall through */
+ default:
+ dp += sprintf(dp, " Reserved %x\n", *buf);
+ break;
+ }
+ buf++;
+ continue;
+ }
+ /* No, locate it in the table */
+ if (cs == 0) {
+ for (i = 0; i < we_0_len; i++)
+ if (*buf == we_0[i].nr)
+ break;
+
+ /* When found, give appropriate msg */
+ if (i != we_0_len) {
+ dp += sprintf(dp, " %s\n", we_0[i].descr);
+ dp += we_0[i].f(dp, buf);
+ } else
+ dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+ } else if (cs == 6) {
+ for (i = 0; i < we_6_len; i++)
+ if (*buf == we_6[i].nr)
+ break;
+
+ /* When found, give appropriate msg */
+ if (i != we_6_len) {
+ dp += sprintf(dp, " %s\n", we_6[i].descr);
+ dp += we_6[i].f(dp, buf);
+ } else
+ dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+ } else
+ dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
+ /* Skip to next element */
+ if (cs_fest == 8) {
+ cs = cs_old;
+ cs_old = 0;
+ cs_fest = 0;
+ }
+ buf += buf[1] + 2;
+ }
+ } else if (buf[0] == 8) { /* EURO */
+ /* locate message type */
+ buf++;
+ cr_l = *buf++;
+ if (cr_l)
+ cr = *buf++;
+ else
+ cr = 0;
+ mt = *buf++;
+ for (i = 0; i < MTSIZE; i++)
+ if (mtlist[i].nr == mt)
+ break;
+
+ /* display message type if it exists */
+ if (i == MTSIZE)
+ dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
+ cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+ size, mt);
+ else
+ dp += sprintf(dp, "callref %d %s size %d message type %s\n",
+ cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+ size, mtlist[i].descr);
+
+ /* display each information element */
+ while (buf < bend) {
+ /* Is it a single octet information element? */
+ if (*buf & 0x80) {
+ switch ((*buf >> 4) & 7) {
+ case 1:
+ dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
+ break;
+ case 3:
+ dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
+ break;
+ case 5:
+ dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf);
+ break;
+ case 2:
+ if (*buf == 0xa0) {
+ dp += sprintf(dp, " More data\n");
+ break;
+ }
+ if (*buf == 0xa1) {
+ dp += sprintf(dp, " Sending complete\n");
+ }
+ break;
+ /* fall through */
+ default:
+ dp += sprintf(dp, " Reserved %x\n", *buf);
+ break;
+ }
+ buf++;
+ continue;
+ }
+ /* No, locate it in the table */
+ for (i = 0; i < IESIZE; i++)
+ if (*buf == ielist[i].nr)
+ break;
+
+ /* When not found, give appropriate msg */
+ if (i != IESIZE) {
+ dp += sprintf(dp, " %s\n", ielist[i].descr);
+ dp += ielist[i].f(dp, buf);
+ } else
+ dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
+
+ /* Skip to next element */
+ buf += buf[1] + 2;
+ }
+ } else {
+ dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
+ }
+ dp += sprintf(dp, "\n");
+ HiSax_putstatus(sp, sp->dlogspace);
+}
--- /dev/null
+/* $Id: siemens.h,v 1.4 1997/01/21 22:24:33 keil Exp $
+ *
+ * siemens.h ISAC and HSCX spezific Macros
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: siemens.h,v $
+ * Revision 1.4 1997/01/21 22:24:33 keil
+ * cleanups
+ *
+ * Revision 1.3 1996/12/08 19:48:34 keil
+ * adding Monitor channel registers
+ *
+ * Revision 1.2 1996/10/27 22:24:00 keil
+ * HSCX version code removed
+ *
+ * Revision 1.1 1996/10/12 21:39:39 keil
+ * Initial revision
+ *
+ *
+*/
+
+
+/* All Registers without FIFOs (original Siemens Spec - 20 hex) */
+
+#define ISAC_MASK 0x0
+#define ISAC_ISTA 0x0
+#define ISAC_STAR 0x1
+#define ISAC_CMDR 0x1
+#define ISAC_EXIR 0x4
+#define ISAC_RBCH 0xa
+#define ISAC_ADF2 0x19
+#define ISAC_SPCR 0x10
+#define ISAC_ADF1 0x18
+#define ISAC_CIR0 0x11
+#define ISAC_CIX0 0x11
+#define ISAC_STCR 0x17
+#define ISAC_MODE 0x2
+#define ISAC_RSTA 0x7
+#define ISAC_RBCL 0x5
+#define ISAC_TIMR 0x3
+#define ISAC_SQXR 0x1b
+#define ISAC_MOSR 0x1a
+#define ISAC_MOCR 0x1a
+#define ISAC_MOR0 0x12
+#define ISAC_MOX0 0x12
+#define ISAC_MOR1 0x14
+#define ISAC_MOX1 0x14
+
+#define HSCX_ISTA 0x0
+#define HSCX_CCR1 0xf
+#define HSCX_CCR2 0xc
+#define HSCX_TSAR 0x11
+#define HSCX_TSAX 0x10
+#define HSCX_XCCR 0x12
+#define HSCX_RCCR 0x13
+#define HSCX_MODE 0x2
+#define HSCX_CMDR 0x1
+#define HSCX_EXIR 0x4
+#define HSCX_XAD1 0x4
+#define HSCX_XAD2 0x5
+#define HSCX_RAH2 0x7
+#define HSCX_RSTA 0x7
+#define HSCX_TIMR 0x3
+#define HSCX_STAR 0x1
+#define HSCX_RBCL 0x5
+#define HSCX_XBCH 0xd
+#define HSCX_VSTR 0xe
+#define HSCX_RLCR 0xe
+#define HSCX_MASK 0x0
--- /dev/null
+/* $Id: tei.c,v 1.8 1997/04/07 22:59:08 keil Exp $
+
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ * based on the teles driver from Jan den Ouden
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ *
+ * $Log: tei.c,v $
+ * Revision 1.8 1997/04/07 22:59:08 keil
+ * GFP_KERNEL --> GFP_ATOMIC
+ *
+ * Revision 1.7 1997/04/06 22:54:03 keil
+ * Using SKB's
+ *
+ * Revision 1.6 1997/02/09 00:25:12 keil
+ * new interface handling, one interface per card
+ *
+ * Revision 1.5 1997/01/27 15:57:51 keil
+ * cosmetics
+ *
+ * Revision 1.4 1997/01/21 22:32:44 keil
+ * Tei verify request
+ *
+ * Revision 1.3 1997/01/04 13:45:02 keil
+ * cleanup,adding remove tei request (thanks to Sim Yskes)
+ *
+ * Revision 1.2 1996/12/08 19:52:39 keil
+ * minor debug fix
+ *
+ * Revision 1.1 1996/10/13 20:04:57 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "hisax.h"
+
+extern struct IsdnCard cards[];
+extern int nrcards;
+
+const char *tei_revision = "$Revision: 1.8 $";
+
+static struct PStack *
+findces(struct PStack *st, int ces)
+{
+ struct PStack *ptr = *(st->l1.stlistp);
+
+ while (ptr)
+ if (ptr->l2.ces == ces)
+ return (ptr);
+ else
+ ptr = ptr->next;
+ return (NULL);
+}
+
+static struct PStack *
+findtei(struct PStack *st, int tei)
+{
+ struct PStack *ptr = *(st->l1.stlistp);
+
+ if (tei == 127)
+ return (NULL);
+
+ while (ptr)
+ if (ptr->l2.tei == tei)
+ return (ptr);
+ else
+ ptr = ptr->next;
+ return (NULL);
+}
+
+static void
+mdl_unit_data_res(struct PStack *st, unsigned int ri, u_char mt, u_char ai)
+{
+ struct sk_buff *skb;
+ u_char *bp;
+
+ if (!(skb = alloc_skb(6 + MAX_HEADER_LEN, GFP_ATOMIC))) {
+ printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
+ return;
+ }
+ SET_SKB_FREE(skb);
+ skb_reserve(skb, MAX_HEADER_LEN);
+ bp = skb_put(skb, 5);
+ bp[0] = 0xf;
+ bp[1] = ri >> 8;
+ bp[2] = ri & 0xff;
+ bp[3] = mt;
+ bp[4] = (ai << 1) | 1;
+ st->l3.l3l2(st, DL_UNIT_DATA, skb);
+}
+
+static void
+mdl_unit_data_ind(struct PStack *st, unsigned int ri, u_char mt, u_char ai)
+{
+ unsigned int tces;
+ struct PStack *otsp, *ptr;
+ char tmp[64];
+
+ switch (mt) {
+ case (2):
+ tces = ri;
+ if (st->l3.debug) {
+ sprintf(tmp, "identity assign ces %d ai %d", tces, ai);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ if ((otsp = findces(st, tces))) {
+ if (st->l3.debug) {
+ sprintf(tmp, "ces %d --> tei %d", tces, ai);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ otsp->ma.teil2(otsp, MDL_ASSIGN, (void *) (int) ai);
+ }
+ break;
+ case (3):
+ tces = ri;
+ if (st->l3.debug) {
+ sprintf(tmp, "identity denied for ces %d ai %d", tces, ai);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ if ((otsp = findces(st, tces))) {
+ if (st->l3.debug) {
+ sprintf(tmp, "ces %d denied tei %d", tces, ai);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ otsp->l2.tei = 255;
+ otsp->l2.ces = randomces();
+ otsp->ma.teil2(otsp, MDL_REMOVE, 0);
+ }
+ break;
+ case (4):
+ if (st->l3.debug) {
+ sprintf(tmp, "checking identity for %d", ai);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ if (ai == 0x7f) {
+ ptr = *(st->l1.stlistp);
+ while (ptr) {
+ if ((ptr->l2.tei & 0x7f) != 0x7f) {
+ if (st->l3.debug) {
+ sprintf(tmp, "check response for ces %d with tei %d",
+ ptr->l2.ces, ptr->l2.tei);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ /* send identity check response (user->network) */
+ mdl_unit_data_res(st, ptr->l2.ces, 5, ptr->l2.tei);
+ }
+ ptr = ptr->next;
+ }
+ } else {
+ otsp = findtei(st, ai);
+ if (!otsp)
+ break;
+ if (st->l3.debug) {
+ sprintf(tmp, "check response for ces %d with tei %d",
+ otsp->l2.ces, otsp->l2.tei);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ /* send identity check response (user->network) */
+ mdl_unit_data_res(st, otsp->l2.ces, 5, otsp->l2.tei);
+ }
+ break;
+ case (6):
+ if (st->l3.debug) {
+ sprintf(tmp, "removal for %d", ai);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ if (ai == 0x7f) {
+ ptr = *(st->l1.stlistp);
+ while (ptr) {
+ if ((ptr->l2.tei & 0x7f) != 0x7f) {
+ if (st->l3.debug) {
+ sprintf(tmp, "rem ces %d with tei %d",
+ ptr->l2.ces, ptr->l2.tei);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ ptr->ma.teil2(ptr, MDL_REMOVE, 0);
+ }
+ ptr = ptr->next;
+ }
+ } else {
+ otsp = findtei(st, ai);
+ if (!otsp)
+ break;
+ if (st->l3.debug) {
+ sprintf(tmp, "rem ces %d with tei %d",
+ otsp->l2.ces, otsp->l2.tei);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ otsp->ma.teil2(otsp, MDL_REMOVE, 0);
+ }
+ break;
+ default:
+ if (st->l3.debug) {
+ sprintf(tmp, "message unknown %d ai %d", mt, ai);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ }
+}
+
+void
+tei_handler(struct PStack *st,
+ u_char pr, struct sk_buff *skb)
+{
+ u_char *bp;
+ unsigned int data;
+ char tmp[32];
+
+ switch (pr) {
+ case (MDL_ASSIGN):
+ data = (unsigned int) skb;
+ if (st->l3.debug) {
+ sprintf(tmp, "ces %d assign request", data);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ mdl_unit_data_res(st, data, 1, 127);
+ break;
+ case (MDL_VERIFY):
+ data = (unsigned int) skb;
+ if (st->l3.debug) {
+ sprintf(tmp, "%d id verify request", data);
+ st->l2.l2m.printdebug(&st->l2.l2m, tmp);
+ }
+ mdl_unit_data_res(st, 0, 7, data);
+ break;
+ case (DL_UNIT_DATA):
+ bp = skb->data;
+ if (bp[0] != 0xf) {
+ /* wrong management entity identifier, ignore */
+ /* shouldn't ibh be released??? */
+ printk(KERN_WARNING "tei handler wrong entity id %x\n", bp[0]);
+ } else
+ mdl_unit_data_ind(st, (bp[1] << 8) | bp[2], bp[3], bp[4] >> 1);
+ dev_kfree_skb(skb, FREE_READ);
+ break;
+ default:
+ break;
+ }
+}
+
+unsigned int
+randomces(void)
+{
+ int x = jiffies & 0xffff;
+
+ return (x);
+}
+
+static void
+tei_man(struct PStack *sp, int i, void *v)
+{
+
+ printk(KERN_DEBUG "tei_man\n");
+}
+
+static void
+tei_l2tei(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *sp = st->l1.hardware;
+
+ tei_handler(sp->teistack, pr, arg);
+}
+
+void
+setstack_tei(struct PStack *st)
+{
+ st->l2.l2tei = tei_l2tei;
+}
+
+void
+init_tei(struct IsdnCardState *sp, int protocol)
+{
+ struct PStack *st;
+ char tmp[128];
+
+ st = (struct PStack *) kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+ setstack_HiSax(st, sp);
+ st->l2.extended = !0;
+ st->l2.laptype = LAPD;
+ st->l2.window = 1;
+ st->l2.orig = !0;
+ st->protocol = protocol;
+/*
+ * the following is not necessary for tei mng. (broadcast only)
+ */
+ st->l2.t200 = 500; /* 500 milliseconds */
+ st->l2.n200 = 4; /* try 4 times */
+
+ st->l2.sap = 63;
+ st->l2.tei = 127;
+
+ sprintf(tmp, "Card %d tei", sp->cardnr + 1);
+ setstack_isdnl2(st, tmp);
+ st->l2.debug = 0;
+ st->l3.debug = 0;
+
+ st->ma.manl2(st, MDL_NOTEIPROC, NULL);
+
+ st->l2.l2l3 = (void *) tei_handler;
+ st->l1.l1man = tei_man;
+ st->l2.l2man = tei_man;
+ st->l4.l2writewakeup = NULL;
+
+ HiSax_addlist(sp, st);
+ sp->teistack = st;
+}
+
+void
+release_tei(struct IsdnCardState *sp)
+{
+ struct PStack *st = sp->teistack;
+
+ HiSax_rmlist(sp, st);
+ kfree((void *) st);
+}
--- /dev/null
+/* $Id: teles0.c,v 1.8 1997/04/13 19:54:04 keil Exp $
+
+ * teles0.c low level stuff for Teles Memory IO isdn cards
+ * based on the teles driver from Jan den Ouden
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ * Beat Doebeli
+ *
+ * $Log: teles0.c,v $
+ * Revision 1.8 1997/04/13 19:54:04 keil
+ * Change in IRQ check delay for SMP
+ *
+ * Revision 1.7 1997/04/06 22:54:04 keil
+ * Using SKB's
+ *
+ * Revision 1.6 1997/01/27 15:52:18 keil
+ * SMP proof,cosmetics
+ *
+ * Revision 1.5 1997/01/21 22:25:59 keil
+ * cleanups
+ *
+ * Revision 1.4 1996/11/05 19:41:27 keil
+ * more changes for 2.1
+ *
+ * Revision 1.3 1996/10/30 10:22:58 keil
+ * Changes for 2.1 kernels
+ *
+ * Revision 1.2 1996/10/27 22:08:34 keil
+ * cosmetic changes
+ *
+ * Revision 1.1 1996/10/13 20:04:58 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "teles0.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+
+const char *teles0_revision = "$Revision: 1.8 $";
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline u_char
+readisac(unsigned int adr, u_char off)
+{
+ return readb(adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+writeisac(unsigned int adr, u_char off, u_char data)
+{
+ writeb(data, adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
+}
+
+
+static inline u_char
+readhscx(unsigned int adr, int hscx, u_char off)
+{
+ return readb(adr + (hscx ? 0x1e0 : 0x1a0) +
+ ((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+writehscx(unsigned int adr, int hscx, u_char off, u_char data)
+{
+ writeb(data, adr + (hscx ? 0x1e0 : 0x1a0) +
+ ((off & 1) ? 0x1ff : 0) + off);
+}
+
+static inline void
+read_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+ register int i;
+ register u_char *ad = (u_char *) (adr + 0x100);
+ for (i = 0; i < size; i++)
+ data[i] = readb(ad);
+}
+
+static void
+write_fifo_isac(unsigned int adr, u_char * data, int size)
+{
+ register int i;
+ register u_char *ad = (u_char *) (adr + 0x100);
+ for (i = 0; i < size; i++)
+ writeb(data[i], ad);
+}
+
+static inline void
+read_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+ register int i;
+ register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
+ for (i = 0; i < size; i++)
+ data[i] = readb(ad);
+}
+
+static inline void
+write_fifo_hscx(unsigned int adr, int hscx, u_char * data, int size)
+{
+ int i;
+ register u_char *ad = (u_char *) (adr + (hscx ? 0x1c0 : 0x180));
+ for (i = 0; i < size; i++)
+ writeb(data[i], ad);
+}
+static inline void
+waitforCEC(int adr, int hscx)
+{
+ int to = 50;
+
+ while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "Teles0: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr, int hscx)
+{
+ int to = 50;
+
+ while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44) == 0x40) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "Teles0: waitforXFW timeout\n");
+}
+
+static inline void
+writehscxCMDR(int adr, int hscx, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ waitforCEC(adr, hscx);
+ writehscx(adr, hscx, HSCX_CMDR, data);
+ restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+ printk(KERN_DEBUG "HSCX %d\n", hscx);
+ printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->membase, hscx, HSCX_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", readhscx(sp->membase, hscx, HSCX_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->membase, hscx, HSCX_EXIR));
+}
+
+void
+teles0_report(struct IsdnCardState *sp)
+{
+ printk(KERN_DEBUG "ISAC\n");
+ printk(KERN_DEBUG "ISTA %x\n", readisac(sp->membase, ISAC_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", readisac(sp->membase, ISAC_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", readisac(sp->membase, ISAC_EXIR));
+ hscxreport(sp, 0);
+ hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+ u_char *ptr;
+ struct IsdnCardState *sp = hsp->sp;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_empty_fifo");
+
+ if (hsp->rcvidx + count > HSCX_BUFMAX) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+ writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+ hsp->rcvidx = 0;
+ return;
+ }
+ ptr = hsp->rcvbuf + hsp->rcvidx;
+ hsp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ read_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
+ writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+ struct IsdnCardState *sp = hsp->sp;
+ int more, count;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_fill_fifo");
+
+ if (!hsp->tx_skb)
+ return;
+ if (hsp->tx_skb->len <= 0)
+ return;
+
+ more = (hsp->mode == 1) ? 1 : 0;
+ if (hsp->tx_skb->len > 32) {
+ more = !0;
+ count = 32;
+ } else
+ count = hsp->tx_skb->len;
+
+ waitforXFW(sp->membase, hsp->hscx);
+ save_flags(flags);
+ cli();
+ ptr = hsp->tx_skb->data;
+ skb_pull(hsp->tx_skb, count);
+ hsp->tx_cnt -= count;
+ hsp->count += count;
+ write_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
+ writehscxCMDR(sp->membase, hsp->hscx, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+ u_char r;
+ struct HscxState *hsp = sp->hs + hscx;
+ struct sk_buff *skb;
+ int count;
+ char tmp[32];
+
+ if (!hsp->init)
+ return;
+
+ if (val & 0x80) { /* RME */
+
+ r = readhscx(sp->membase, hsp->hscx, HSCX_RSTA);
+ if ((r & 0xf0) != 0xa0) {
+ if (!r & 0x80)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX invalid frame");
+ if ((r & 0x40) && hsp->mode)
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX RDO mode=%d",
+ hsp->mode);
+ debugl1(sp, tmp);
+ }
+ if (!r & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX CRC error");
+ writehscxCMDR(sp->membase, hsp->hscx, 0x80);
+ } else {
+ count = readhscx(sp->membase, hsp->hscx, HSCX_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ hscx_empty_fifo(hsp, count);
+ if ((count = hsp->rcvidx - 1) > 0) {
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "teles0: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ }
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ hscx_empty_fifo(hsp, 32);
+ if (hsp->mode == 1) {
+ /* receive audio data */
+ if (!(skb = dev_alloc_skb(32)))
+ printk(KERN_WARNING "teles0: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ }
+ if (val & 0x10) { /* XPR */
+ if (hsp->tx_skb)
+ if (hsp->tx_skb->len) {
+ hscx_fill_fifo(hsp);
+ return;
+ } else {
+ dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+ hsp->count = 0;
+ if (hsp->st->l4.l1writewakeup)
+ hsp->st->l4.l1writewakeup(hsp->st);
+ hsp->tx_skb = NULL;
+ }
+ if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+ hsp->count = 0;
+ hscx_fill_fifo(hsp);
+ } else
+ hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+ }
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ debugl1(sp, "isac_empty_fifo");
+
+ if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+ if (sp->debug & L1_DEB_WARN) {
+ char tmp[40];
+ sprintf(tmp, "isac_empty_fifo overrun %d",
+ sp->rcvidx + count);
+ debugl1(sp, tmp);
+ }
+ writeisac(sp->membase, ISAC_CMDR, 0x80);
+ sp->rcvidx = 0;
+ return;
+ }
+ ptr = sp->rcvbuf + sp->rcvidx;
+ sp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ read_fifo_isac(sp->membase, ptr, count);
+ writeisac(sp->membase, ISAC_CMDR, 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_empty_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+ int count, more;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ debugl1(sp, "isac_fill_fifo");
+
+ if (!sp->tx_skb)
+ return;
+
+ count = sp->tx_skb->len;
+ if (count <= 0)
+ return;
+
+ more = 0;
+ if (count > 32) {
+ more = !0;
+ count = 32;
+ }
+ save_flags(flags);
+ cli();
+ ptr = sp->tx_skb->data;
+ skb_pull(sp->tx_skb, count);
+ sp->tx_cnt += count;
+ write_fifo_isac(sp->membase, ptr, count);
+ writeisac(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_fill_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+ if (sp->debug & L1_DEB_ISAC) {
+ char tmp[32];
+ sprintf(tmp, "ph_command %d", command);
+ debugl1(sp, tmp);
+ }
+ writeisac(sp->membase, ISAC_CIX0, (command << 2) | 3);
+}
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+ u_char exval;
+ struct sk_buff *skb;
+ unsigned int count;
+ char tmp[32];
+
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "ISAC interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ if (val & 0x80) { /* RME */
+ exval = readisac(sp->membase, ISAC_RSTA);
+ if ((exval & 0x70) != 0x20) {
+ if (exval & 0x40)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RDO");
+ if (!exval & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC CRC error");
+ writeisac(sp->membase, ISAC_CMDR, 0x80);
+ } else {
+ count = readisac(sp->membase, ISAC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(sp, count);
+ if ((count = sp->rcvidx) > 0) {
+ if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+ printk(KERN_WARNING "teles0: D receive out of memory\n");
+ else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, count), sp->rcvbuf, count);
+ skb_queue_tail(&sp->rq, skb);
+ }
+ }
+ }
+ sp->rcvidx = 0;
+ isac_sched_event(sp, ISAC_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ isac_empty_fifo(sp, 32);
+ }
+ if (val & 0x20) { /* RSC */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RSC interrupt");
+ }
+ if (val & 0x10) { /* XPR */
+ if (sp->tx_skb)
+ if (sp->tx_skb->len) {
+ isac_fill_fifo(sp);
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+ sp->tx_cnt = 0;
+ sp->tx_skb = NULL;
+ }
+ if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+ sp->tx_cnt = 0;
+ isac_fill_fifo(sp);
+ } else
+ isac_sched_event(sp, ISAC_XMTBUFREADY);
+ }
+ afterXPR:
+ if (val & 0x04) { /* CISQ */
+ sp->ph_state = (readisac(sp->membase, ISAC_CIX0) >> 2)
+ & 0xf;
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "l1state %d", sp->ph_state);
+ debugl1(sp, tmp);
+ }
+ isac_new_ph(sp);
+ }
+ if (val & 0x02) { /* SIN */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC SIN interrupt");
+ }
+ if (val & 0x01) { /* EXI */
+ exval = readisac(sp->membase, ISAC_EXIR);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC EXIR %02x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+ u_char exval;
+ struct HscxState *hsp;
+ char tmp[32];
+
+
+ if (val & 0x01) {
+ hsp = sp->hs + 1;
+ exval = readhscx(sp->membase, 1, HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->membase, hsp->hscx, 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0xf8) {
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, val, 1);
+ }
+ if (val & 0x02) {
+ hsp = sp->hs;
+ exval = readhscx(sp->membase, 0, HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->membase, hsp->hscx, 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0x04) {
+ exval = readhscx(sp->membase, 0, HSCX_ISTA);
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A interrupt %x", exval);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, exval, 0);
+ }
+}
+
+static void
+telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+ struct IsdnCardState *sp;
+ u_char val, stat = 0;
+
+ sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+ if (!sp) {
+ printk(KERN_WARNING "Teles0: Spurious interrupt!\n");
+ return;
+ }
+ val = readhscx(sp->membase, 1, HSCX_ISTA);
+ Start_HSCX:
+ if (val) {
+ hscx_int_main(sp, val);
+ stat |= 1;
+ }
+ val = readisac(sp->membase, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(sp, val);
+ stat |= 2;
+ }
+ val = readhscx(sp->membase, 1, HSCX_ISTA);
+ if (val) {
+ if (sp->debug & L1_DEB_HSCX)
+ debugl1(sp, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = readisac(sp->membase, ISAC_ISTA);
+ if (val) {
+ if (sp->debug & L1_DEB_ISAC)
+ debugl1(sp, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (stat & 1) {
+ writehscx(sp->membase, 0, HSCX_MASK, 0xFF);
+ writehscx(sp->membase, 1, HSCX_MASK, 0xFF);
+ writehscx(sp->membase, 0, HSCX_MASK, 0x0);
+ writehscx(sp->membase, 1, HSCX_MASK, 0x0);
+ }
+ if (stat & 2) {
+ writeisac(sp->membase, ISAC_MASK, 0xFF);
+ writeisac(sp->membase, ISAC_MASK, 0x0);
+ }
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+ unsigned int adr = sp->membase;
+
+ /* 16.0 IOM 1 Mode */
+ writeisac(adr, ISAC_MASK, 0xff);
+ writeisac(adr, ISAC_ADF2, 0x0);
+ writeisac(adr, ISAC_SPCR, 0xa);
+ writeisac(adr, ISAC_ADF1, 0x2);
+ writeisac(adr, ISAC_STCR, 0x70);
+ writeisac(adr, ISAC_MODE, 0xc9);
+ writeisac(adr, ISAC_CMDR, 0x41);
+ writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
+ writeisac(adr, ISAC_MASK, 0xff);
+ writeisac(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+ struct IsdnCardState *sp = hs->sp;
+ int hscx = hs->hscx;
+
+ if (sp->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "hscx %c mode %d ichan %d",
+ 'A' + hscx, mode, ichan);
+ debugl1(sp, tmp);
+ }
+ hs->mode = mode;
+ writehscx(sp->membase, hscx, HSCX_CCR1, 0x85);
+ writehscx(sp->membase, hscx, HSCX_XAD1, 0xFF);
+ writehscx(sp->membase, hscx, HSCX_XAD2, 0xFF);
+ writehscx(sp->membase, hscx, HSCX_RAH2, 0xFF);
+ writehscx(sp->membase, hscx, HSCX_XBCH, 0x0);
+
+ /* Switch IOM 1 SSI */
+ if (hscx == 0)
+ ichan = 1 - ichan;
+
+ switch (mode) {
+ case (0):
+ writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+ writehscx(sp->membase, hscx, HSCX_TSAX, 0xff);
+ writehscx(sp->membase, hscx, HSCX_TSAR, 0xff);
+ writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+ writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+ writehscx(sp->membase, hscx, HSCX_MODE, 0x84);
+ break;
+ case (1):
+ if (ichan == 0) {
+ writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+ writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
+ writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
+ writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+ writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+ } else {
+ writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+ writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
+ writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
+ writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+ writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+ }
+ writehscx(sp->membase, hscx, HSCX_MODE, 0xe4);
+ writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
+ break;
+ case (2):
+ if (ichan == 0) {
+ writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+ writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
+ writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
+ writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+ writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+ } else {
+ writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
+ writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
+ writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
+ writehscx(sp->membase, hscx, HSCX_XCCR, 7);
+ writehscx(sp->membase, hscx, HSCX_RCCR, 7);
+ }
+ writehscx(sp->membase, hscx, HSCX_MODE, 0x8c);
+ writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
+ break;
+ }
+ writehscx(sp->membase, hscx, HSCX_ISTA, 0x00);
+}
+
+void
+release_io_teles0(struct IsdnCard *card)
+{
+ if (card->sp->cfg_reg)
+ release_region(card->sp->cfg_reg, 8);
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+ int val;
+ char tmp[64];
+
+ val = readhscx(sp->membase, 1, HSCX_ISTA);
+ sprintf(tmp, "HSCX B ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = readhscx(sp->membase, 1, HSCX_EXIR);
+ sprintf(tmp, "HSCX B EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x02) {
+ val = readhscx(sp->membase, 0, HSCX_EXIR);
+ sprintf(tmp, "HSCX A EXIR %x", val);
+ debugl1(sp, tmp);
+ }
+ val = readhscx(sp->membase, 0, HSCX_ISTA);
+ sprintf(tmp, "HSCX A ISTA %x", val);
+ debugl1(sp, tmp);
+ val = readhscx(sp->membase, 1, HSCX_STAR);
+ sprintf(tmp, "HSCX B STAR %x", val);
+ debugl1(sp, tmp);
+ val = readhscx(sp->membase, 0, HSCX_STAR);
+ sprintf(tmp, "HSCX A STAR %x", val);
+ debugl1(sp, tmp);
+ val = readisac(sp->membase, ISAC_STAR);
+ sprintf(tmp, "ISAC STAR %x", val);
+ debugl1(sp, tmp);
+ val = readisac(sp->membase, ISAC_MODE);
+ sprintf(tmp, "ISAC MODE %x", val);
+ debugl1(sp, tmp);
+ val = readisac(sp->membase, ISAC_ADF2);
+ sprintf(tmp, "ISAC ADF2 %x", val);
+ debugl1(sp, tmp);
+ val = readisac(sp->membase, ISAC_ISTA);
+ sprintf(tmp, "ISAC ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = readisac(sp->membase, ISAC_EXIR);
+ sprintf(tmp, "ISAC EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x04) {
+ val = readisac(sp->membase, ISAC_CIR0);
+ sprintf(tmp, "ISAC CIR0 %x", val);
+ debugl1(sp, tmp);
+ }
+ writeisac(sp->membase, ISAC_MASK, 0);
+ writeisac(sp->membase, ISAC_CMDR, 0x41);
+}
+
+int
+initteles0(struct IsdnCardState *sp)
+{
+ int ret;
+ int loop = 0;
+ char tmp[40];
+
+ sp->counter = kstat.interrupts[sp->irq];
+ sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+ debugl1(sp, tmp);
+ clear_pending_ints(sp);
+ ret = get_irq(sp->cardnr, &telesS0_interrupt);
+ if (ret) {
+ initisac(sp);
+ sp->modehscx(sp->hs, 0, 0);
+ sp->modehscx(sp->hs + 1, 0, 0);
+ while (loop++ < 10) {
+ /* At least 1-3 irqs must happen
+ * (one from HSCX A, one from HSCX B, 3rd from ISAC)
+ */
+ if (kstat.interrupts[sp->irq] > sp->counter)
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ }
+ sprintf(tmp, "IRQ %d count %d", sp->irq,
+ kstat.interrupts[sp->irq]);
+ debugl1(sp, tmp);
+ if (kstat.interrupts[sp->irq] == sp->counter) {
+ printk(KERN_WARNING
+ "Teles0: IRQ(%d) getting no interrupts during init\n",
+ sp->irq);
+ irq2dev_map[sp->irq] = NULL;
+ free_irq(sp->irq, NULL);
+ return (0);
+ }
+ }
+ return (ret);
+}
+
+int
+setup_teles0(struct IsdnCard *card)
+{
+ u_char cfval, val, verA, verB;
+ struct IsdnCardState *sp = card->sp;
+ long flags;
+ char tmp[64];
+
+ strcpy(tmp, teles0_revision);
+ printk(KERN_NOTICE "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
+ if ((sp->typ != ISDN_CTYPE_16_0) && (sp->typ != ISDN_CTYPE_8_0))
+ return (0);
+
+ if (sp->typ == ISDN_CTYPE_16_0)
+ sp->cfg_reg = card->para[2];
+ else /* 8.0 */
+ sp->cfg_reg = 0;
+
+ if (card->para[1] < 0x10000) {
+ card->para[1] <<= 4;
+ printk(KERN_INFO
+ "Teles0: membase configured DOSish, assuming 0x%lx\n",
+ (unsigned long) card->para[1]);
+ }
+ sp->membase = card->para[1];
+ sp->irq = card->para[0];
+ if (sp->cfg_reg) {
+ if (check_region((sp->cfg_reg), 8)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ sp->cfg_reg,
+ sp->cfg_reg + 8);
+ return (0);
+ } else {
+ request_region(sp->cfg_reg, 8, "teles cfg");
+ }
+ }
+ switch (sp->irq) {
+ case 2:
+ cfval = 0x00;
+ break;
+ case 3:
+ cfval = 0x02;
+ break;
+ case 4:
+ cfval = 0x04;
+ break;
+ case 5:
+ cfval = 0x06;
+ break;
+ case 10:
+ cfval = 0x08;
+ break;
+ case 11:
+ cfval = 0x0A;
+ break;
+ case 12:
+ cfval = 0x0C;
+ break;
+ case 15:
+ cfval = 0x0E;
+ break;
+ default:
+ cfval = 0x00;
+ break;
+ }
+ cfval |= ((card->para[1] >> 9) & 0xF0);
+ if (sp->cfg_reg) {
+ if ((val = bytein(sp->cfg_reg + 0)) != 0x51) {
+ printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+ sp->cfg_reg + 0, val);
+ release_region(sp->cfg_reg, 8);
+ return (0);
+ }
+ if ((val = bytein(sp->cfg_reg + 1)) != 0x93) {
+ printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+ sp->cfg_reg + 1, val);
+ release_region(sp->cfg_reg, 8);
+ return (0);
+ }
+ val = bytein(sp->cfg_reg + 2); /* 0x1e=without AB
+ * 0x1f=with AB
+ * 0x1c 16.3 ???
+ */
+ if (val != 0x1e && val != 0x1f) {
+ printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
+ sp->cfg_reg + 2, val);
+ release_region(sp->cfg_reg, 8);
+ return (0);
+ }
+ save_flags(flags);
+ byteout(sp->cfg_reg + 4, cfval);
+ sti();
+ HZDELAY(HZ / 10 + 1);
+ byteout(sp->cfg_reg + 4, cfval | 1);
+ HZDELAY(HZ / 10 + 1);
+ restore_flags(flags);
+ }
+ printk(KERN_NOTICE
+ "HiSax: %s config irq:%d mem:%x cfg:%x\n",
+ CardType[sp->typ], sp->irq,
+ sp->membase, sp->cfg_reg);
+ verA = readhscx(sp->membase, 0, HSCX_VSTR) & 0xf;
+ verB = readhscx(sp->membase, 1, HSCX_VSTR) & 0xf;
+ printk(KERN_INFO "Teles0: HSCX version A: %s B: %s\n",
+ HscxVersion(verA), HscxVersion(verB));
+ val = readisac(sp->membase, ISAC_RBCH);
+ printk(KERN_INFO "Teles0: ISAC %s\n",
+ ISACVersion(val));
+
+ if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ printk(KERN_WARNING
+ "Teles0: wrong HSCX versions check IO/MEM addresses\n");
+ release_io_teles0(card);
+ return (0);
+ }
+ save_flags(flags);
+ writeb(0, sp->membase + 0x80);
+ sti();
+ HZDELAY(HZ / 5 + 1);
+ writeb(1, sp->membase + 0x80);
+ HZDELAY(HZ / 5 + 1);
+ restore_flags(flags);
+
+ sp->modehscx = &modehscx;
+ sp->ph_command = &ph_command;
+ sp->hscx_fill_fifo = &hscx_fill_fifo;
+ sp->isac_fill_fifo = &isac_fill_fifo;
+ return (1);
+}
--- /dev/null
+/* $Id: teles0.h,v 1.2 1997/01/21 22:26:52 keil Exp $
+ *
+ * teles0.h Header for Teles 16.0 8.0 & compatible
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: teles0.h,v $
+ * Revision 1.2 1997/01/21 22:26:52 keil
+ * cleanups
+ *
+ * Revision 1.1 1996/10/13 20:03:48 keil
+ * Initial revision
+ *
+ *
+*/
+
+extern void teles0_report(struct IsdnCardState *sp);
+extern void release_io_teles0(struct IsdnCard *card);
+extern int setup_teles0(struct IsdnCard *card);
+extern int initteles0(struct IsdnCardState *sp);
--- /dev/null
+/* $Id: teles3.c,v 1.11 1997/04/13 19:54:05 keil Exp $
+
+ * teles3.c low level stuff for Teles 16.3 & PNP isdn cards
+ *
+ * based on the teles driver from Jan den Ouden
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ * Thanks to Jan den Ouden
+ * Fritz Elfert
+ * Beat Doebeli
+ *
+ * $Log: teles3.c,v $
+ * Revision 1.11 1997/04/13 19:54:05 keil
+ * Change in IRQ check delay for SMP
+ *
+ * Revision 1.10 1997/04/06 22:54:05 keil
+ * Using SKB's
+ *
+ * Revision 1.9 1997/03/22 02:01:07 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.8 1997/02/23 18:43:55 fritz
+ * Added support for Teles-Vision.
+ *
+ * Revision 1.7 1997/01/28 22:48:33 keil
+ * fixes for Teles PCMCIA (Christof Petig)
+ *
+ * Revision 1.6 1997/01/27 15:52:55 keil
+ * SMP proof,cosmetics, PCMCIA added
+ *
+ * Revision 1.5 1997/01/21 22:28:32 keil
+ * cleanups
+ *
+ * Revision 1.4 1996/12/14 21:05:41 keil
+ * Reset for 16.3 PnP
+ *
+ * Revision 1.3 1996/11/05 19:56:54 keil
+ * debug output fixed
+ *
+ * Revision 1.2 1996/10/27 22:09:15 keil
+ * cosmetic changes
+ *
+ * Revision 1.1 1996/10/13 20:04:59 keil
+ * Initial revision
+ *
+ *
+ *
+ */
+#define __NO_VERSION__
+#include "siemens.h"
+#include "hisax.h"
+#include "teles3.h"
+#include "isdnl1.h"
+#include <linux/kernel_stat.h>
+
+extern const char *CardType[];
+const char *teles3_revision = "$Revision: 1.11 $";
+
+#define byteout(addr,val) outb_p(val,addr)
+#define bytein(addr) inb_p(addr)
+
+static inline u_char
+readreg(unsigned int adr, u_char off)
+{
+ return (bytein(adr + off));
+}
+
+static inline void
+writereg(unsigned int adr, u_char off, u_char data)
+{
+ byteout(adr + off, data);
+}
+
+
+static inline void
+read_fifo(unsigned int adr, u_char * data, int size)
+{
+ insb(adr + 0x1e, data, size);
+}
+
+static void
+write_fifo(unsigned int adr, u_char * data, int size)
+{
+ outsb(adr + 0x1e, data, size);
+}
+
+static inline void
+waitforCEC(int adr)
+{
+ int to = 50;
+
+ while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "Teles3: waitforCEC timeout\n");
+}
+
+
+static inline void
+waitforXFW(int adr)
+{
+ int to = 50;
+
+ while ((!(readreg(adr, HSCX_STAR) & 0x44) == 0x40) && to) {
+ udelay(1);
+ to--;
+ }
+ if (!to)
+ printk(KERN_WARNING "Teles3: waitforXFW timeout\n");
+}
+static inline void
+writehscxCMDR(int adr, u_char data)
+{
+ long flags;
+
+ save_flags(flags);
+ cli();
+ waitforCEC(adr);
+ writereg(adr, HSCX_CMDR, data);
+ restore_flags(flags);
+}
+
+/*
+ * fast interrupt here
+ */
+
+static void
+hscxreport(struct IsdnCardState *sp, int hscx)
+{
+ printk(KERN_DEBUG "HSCX %d\n", hscx);
+ printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
+}
+
+void
+teles3_report(struct IsdnCardState *sp)
+{
+ printk(KERN_DEBUG "ISAC\n");
+ printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
+ printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
+ printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
+ hscxreport(sp, 0);
+ hscxreport(sp, 1);
+}
+
+/*
+ * HSCX stuff goes here
+ */
+
+static void
+hscx_empty_fifo(struct HscxState *hsp, int count)
+{
+ u_char *ptr;
+ struct IsdnCardState *sp = hsp->sp;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_empty_fifo");
+
+ if (hsp->rcvidx + count > HSCX_BUFMAX) {
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "hscx_empty_fifo: incoming packet too large");
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+ hsp->rcvidx = 0;
+ return;
+ }
+ ptr = hsp->rcvbuf + hsp->rcvidx;
+ hsp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ read_fifo(sp->hscx[hsp->hscx], ptr, count);
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_empty_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+hscx_fill_fifo(struct HscxState *hsp)
+{
+ struct IsdnCardState *sp = hsp->sp;
+ int more, count;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
+ debugl1(sp, "hscx_fill_fifo");
+
+ if (!hsp->tx_skb)
+ return;
+ if (hsp->tx_skb->len <= 0)
+ return;
+
+ more = (hsp->mode == 1) ? 1 : 0;
+ if (hsp->tx_skb->len > 32) {
+ more = !0;
+ count = 32;
+ } else
+ count = hsp->tx_skb->len;
+
+ waitforXFW(sp->hscx[hsp->hscx]);
+ save_flags(flags);
+ cli();
+ ptr = hsp->tx_skb->data;
+ skb_pull(hsp->tx_skb, count);
+ hsp->tx_cnt -= count;
+ hsp->count += count;
+ write_fifo(sp->hscx[hsp->hscx], ptr, count);
+ writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_HSCX_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "hscx_fill_fifo %c cnt %d",
+ hsp->hscx ? 'B' : 'A', count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static inline void
+hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx)
+{
+ u_char r;
+ struct HscxState *hsp = sp->hs + hscx;
+ struct sk_buff *skb;
+ int count;
+ char tmp[32];
+
+ if (!hsp->init)
+ return;
+
+ if (val & 0x80) { /* RME */
+
+ r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
+ if ((r & 0xf0) != 0xa0) {
+ if (!r & 0x80)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX invalid frame");
+ if ((r & 0x40) && hsp->mode)
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX RDO mode=%d",
+ hsp->mode);
+ debugl1(sp, tmp);
+ }
+ if (!r & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "HSCX CRC error");
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
+ } else {
+ count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ hscx_empty_fifo(hsp, count);
+ if ((count = hsp->rcvidx - 1) > 0) {
+ if (!(skb = dev_alloc_skb(count)))
+ printk(KERN_WARNING "teles3: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, count), hsp->rcvbuf, count);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ }
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ hscx_empty_fifo(hsp, 32);
+ if (hsp->mode == 1) {
+ /* receive audio data */
+ if (!(skb = dev_alloc_skb(32)))
+ printk(KERN_WARNING "teles3: receive out of memory\n");
+ else {
+ memcpy(skb_put(skb, 32), hsp->rcvbuf, 32);
+ skb_queue_tail(&hsp->rqueue, skb);
+ }
+ hsp->rcvidx = 0;
+ hscx_sched_event(hsp, HSCX_RCVBUFREADY);
+ }
+ }
+ if (val & 0x10) { /* XPR */
+ if (hsp->tx_skb)
+ if (hsp->tx_skb->len) {
+ hscx_fill_fifo(hsp);
+ return;
+ } else {
+ dev_kfree_skb(hsp->tx_skb, FREE_WRITE);
+ hsp->count = 0;
+ if (hsp->st->l4.l1writewakeup)
+ hsp->st->l4.l1writewakeup(hsp->st);
+ hsp->tx_skb = NULL;
+ }
+ if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) {
+ hsp->count = 0;
+ hscx_fill_fifo(hsp);
+ } else
+ hscx_sched_event(hsp, HSCX_XMTBUFREADY);
+ }
+}
+
+/*
+ * ISAC stuff goes here
+ */
+
+static void
+isac_empty_fifo(struct IsdnCardState *sp, int count)
+{
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ if (sp->debug & L1_DEB_ISAC)
+ debugl1(sp, "isac_empty_fifo");
+
+ if ((sp->rcvidx + count) >= MAX_DFRAME_LEN) {
+ if (sp->debug & L1_DEB_WARN) {
+ char tmp[40];
+ sprintf(tmp, "isac_empty_fifo overrun %d",
+ sp->rcvidx + count);
+ debugl1(sp, tmp);
+ }
+ writereg(sp->isac, ISAC_CMDR, 0x80);
+ sp->rcvidx = 0;
+ return;
+ }
+ ptr = sp->rcvbuf + sp->rcvidx;
+ sp->rcvidx += count;
+ save_flags(flags);
+ cli();
+ read_fifo(sp->isac, ptr, count);
+ writereg(sp->isac, ISAC_CMDR, 0x80);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_empty_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+isac_fill_fifo(struct IsdnCardState *sp)
+{
+ int count, more;
+ u_char *ptr;
+ long flags;
+
+ if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
+ debugl1(sp, "isac_fill_fifo");
+
+ if (!sp->tx_skb)
+ return;
+
+ count = sp->tx_skb->len;
+ if (count <= 0)
+ return;
+
+ more = 0;
+ if (count > 32) {
+ more = !0;
+ count = 32;
+ }
+ save_flags(flags);
+ cli();
+ ptr = sp->tx_skb->data;
+ skb_pull(sp->tx_skb, count);
+ sp->tx_cnt += count;
+ write_fifo(sp->isac, ptr, count);
+ writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
+ restore_flags(flags);
+ if (sp->debug & L1_DEB_ISAC_FIFO) {
+ char tmp[128];
+ char *t = tmp;
+
+ t += sprintf(t, "isac_fill_fifo cnt %d", count);
+ QuickHex(t, ptr, count);
+ debugl1(sp, tmp);
+ }
+}
+
+static void
+ph_command(struct IsdnCardState *sp, unsigned int command)
+{
+ if (sp->debug & L1_DEB_ISAC) {
+ char tmp[32];
+ sprintf(tmp, "ph_command %d", command);
+ debugl1(sp, tmp);
+ }
+ writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+
+static inline void
+isac_interrupt(struct IsdnCardState *sp, u_char val)
+{
+ u_char exval;
+ struct sk_buff *skb;
+ unsigned int count;
+ char tmp[32];
+
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "ISAC interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ if (val & 0x80) { /* RME */
+ exval = readreg(sp->isac, ISAC_RSTA);
+ if ((exval & 0x70) != 0x20) {
+ if (exval & 0x40)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RDO");
+ if (!exval & 0x20)
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC CRC error");
+ writereg(sp->isac, ISAC_CMDR, 0x80);
+ } else {
+ count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(sp, count);
+ if ((count = sp->rcvidx) > 0) {
+ if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+ printk(KERN_WARNING "AVM: D receive out of memory\n");
+ else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, count), sp->rcvbuf, count);
+ skb_queue_tail(&sp->rq, skb);
+ }
+ }
+ }
+ sp->rcvidx = 0;
+ isac_sched_event(sp, ISAC_RCVBUFREADY);
+ }
+ if (val & 0x40) { /* RPF */
+ isac_empty_fifo(sp, 32);
+ }
+ if (val & 0x20) { /* RSC */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC RSC interrupt");
+ }
+ if (val & 0x10) { /* XPR */
+ if (sp->tx_skb)
+ if (sp->tx_skb->len) {
+ isac_fill_fifo(sp);
+ goto afterXPR;
+ } else {
+ dev_kfree_skb(sp->tx_skb, FREE_WRITE);
+ sp->tx_cnt = 0;
+ sp->tx_skb = NULL;
+ }
+ if ((sp->tx_skb = skb_dequeue(&sp->sq))) {
+ sp->tx_cnt = 0;
+ isac_fill_fifo(sp);
+ } else
+ isac_sched_event(sp, ISAC_XMTBUFREADY);
+ }
+ afterXPR:
+ if (val & 0x04) { /* CISQ */
+ sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
+ & 0xf;
+ if (sp->debug & L1_DEB_ISAC) {
+ sprintf(tmp, "l1state %d", sp->ph_state);
+ debugl1(sp, tmp);
+ }
+ isac_new_ph(sp);
+ }
+ if (val & 0x02) { /* SIN */
+ /* never */
+ if (sp->debug & L1_DEB_WARN)
+ debugl1(sp, "ISAC SIN interrupt");
+ }
+ if (val & 0x01) { /* EXI */
+ exval = readreg(sp->isac, ISAC_EXIR);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "ISAC EXIR %02x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+}
+
+static inline void
+hscx_int_main(struct IsdnCardState *sp, u_char val)
+{
+
+ u_char exval;
+ struct HscxState *hsp;
+ char tmp[32];
+
+
+ if (val & 0x01) {
+ hsp = sp->hs + 1;
+ exval = readreg(sp->hscx[1], HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0xf8) {
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX B interrupt %x", val);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, val, 1);
+ }
+ if (val & 0x02) {
+ hsp = sp->hs;
+ exval = readreg(sp->hscx[0], HSCX_EXIR);
+ if (exval == 0x40) {
+ if (hsp->mode == 1)
+ hscx_fill_fifo(hsp);
+ else {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame.
+ */
+ if (hsp->tx_skb) {
+ skb_push(hsp->tx_skb, hsp->count);
+ hsp->tx_cnt += hsp->count;
+ hsp->count = 0;
+ }
+ writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
+ if (sp->debug & L1_DEB_WARN) {
+ sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ } else if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A EXIR %x", exval);
+ debugl1(sp, tmp);
+ }
+ }
+ if (val & 0x04) {
+ exval = readreg(sp->hscx[0], HSCX_ISTA);
+ if (sp->debug & L1_DEB_HSCX) {
+ sprintf(tmp, "HSCX A interrupt %x", exval);
+ debugl1(sp, tmp);
+ }
+ hscx_interrupt(sp, exval, 0);
+ }
+}
+
+static void
+teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+#define MAXCOUNT 20
+ struct IsdnCardState *sp;
+ u_char val, stat = 0;
+ int count = 0;
+
+ sp = (struct IsdnCardState *) irq2dev_map[intno];
+
+ if (!sp) {
+ printk(KERN_WARNING "Teles: Spurious interrupt!\n");
+ return;
+ }
+ val = readreg(sp->hscx[1], HSCX_ISTA);
+ Start_HSCX:
+ if (val) {
+ hscx_int_main(sp, val);
+ stat |= 1;
+ }
+ val = readreg(sp->isac, ISAC_ISTA);
+ Start_ISAC:
+ if (val) {
+ isac_interrupt(sp, val);
+ stat |= 2;
+ }
+ count++;
+ val = readreg(sp->hscx[1], HSCX_ISTA);
+ if (val && count < MAXCOUNT) {
+ if (sp->debug & L1_DEB_HSCX)
+ debugl1(sp, "HSCX IntStat after IntRoutine");
+ goto Start_HSCX;
+ }
+ val = readreg(sp->isac, ISAC_ISTA);
+ if (val && count < MAXCOUNT) {
+ if (sp->debug & L1_DEB_ISAC)
+ debugl1(sp, "ISAC IntStat after IntRoutine");
+ goto Start_ISAC;
+ }
+ if (count >= MAXCOUNT)
+ printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
+ if (stat & 1) {
+ writereg(sp->hscx[0], HSCX_MASK, 0xFF);
+ writereg(sp->hscx[1], HSCX_MASK, 0xFF);
+ writereg(sp->hscx[0], HSCX_MASK, 0x0);
+ writereg(sp->hscx[1], HSCX_MASK, 0x0);
+ }
+ if (stat & 2) {
+ writereg(sp->isac, ISAC_MASK, 0xFF);
+ writereg(sp->isac, ISAC_MASK, 0x0);
+ }
+}
+
+
+static void
+initisac(struct IsdnCardState *sp)
+{
+ unsigned int adr = sp->isac;
+
+ /* 16.3 IOM 2 Mode */
+ writereg(adr, ISAC_MASK, 0xff);
+ writereg(adr, ISAC_ADF2, 0x80);
+ writereg(adr, ISAC_SQXR, 0x2f);
+ writereg(adr, ISAC_SPCR, 0x0);
+ writereg(adr, ISAC_ADF1, 0x2);
+ writereg(adr, ISAC_STCR, 0x70);
+ writereg(adr, ISAC_MODE, 0xc9);
+ writereg(adr, ISAC_TIMR, 0x0);
+ writereg(adr, ISAC_ADF1, 0x0);
+ writereg(adr, ISAC_CMDR, 0x41);
+ writereg(adr, ISAC_CIX0, (1 << 2) | 3);
+ writereg(adr, ISAC_MASK, 0xff);
+ writereg(adr, ISAC_MASK, 0x0);
+}
+
+static void
+modehscx(struct HscxState *hs, int mode, int ichan)
+{
+ struct IsdnCardState *sp = hs->sp;
+ int hscx = hs->hscx;
+
+ if (sp->debug & L1_DEB_HSCX) {
+ char tmp[40];
+ sprintf(tmp, "hscx %c mode %d ichan %d",
+ 'A' + hscx, mode, ichan);
+ debugl1(sp, tmp);
+ }
+ hs->mode = mode;
+ writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
+ writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
+ writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
+ writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
+ writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
+ writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
+
+ switch (mode) {
+ case (0):
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
+ break;
+ case (1):
+ if (ichan == 0) {
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ } else {
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ }
+ writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
+ writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+ break;
+ case (2):
+ if (ichan == 0) {
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ } else {
+ writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
+ writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
+ writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
+ writereg(sp->hscx[hscx], HSCX_XCCR, 7);
+ writereg(sp->hscx[hscx], HSCX_RCCR, 7);
+ }
+ writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
+ writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
+ break;
+ }
+ writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
+}
+
+inline static void
+release_ioregs(struct IsdnCard *card, int mask)
+{
+ if (mask & 1)
+ release_region(card->sp->isac, 32);
+ if (mask & 2)
+ release_region(card->sp->hscx[0], 32);
+ if (mask & 4)
+ release_region(card->sp->hscx[1], 32);
+}
+
+void
+release_io_teles3(struct IsdnCard *card)
+{
+ if (card->sp->typ == ISDN_CTYPE_TELESPCMCIA)
+ release_region(card->sp->hscx[0], 97);
+ else {
+ if (card->sp->cfg_reg)
+ release_region(card->sp->cfg_reg, 8);
+ release_ioregs(card, 0x7);
+ }
+}
+
+static void
+clear_pending_ints(struct IsdnCardState *sp)
+{
+ int val;
+ char tmp[64];
+
+ val = readreg(sp->hscx[1], HSCX_ISTA);
+ sprintf(tmp, "HSCX B ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = readreg(sp->hscx[1], HSCX_EXIR);
+ sprintf(tmp, "HSCX B EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x02) {
+ val = readreg(sp->hscx[0], HSCX_EXIR);
+ sprintf(tmp, "HSCX A EXIR %x", val);
+ debugl1(sp, tmp);
+ }
+ val = readreg(sp->hscx[0], HSCX_ISTA);
+ sprintf(tmp, "HSCX A ISTA %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->hscx[1], HSCX_STAR);
+ sprintf(tmp, "HSCX B STAR %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->hscx[0], HSCX_STAR);
+ sprintf(tmp, "HSCX A STAR %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->isac, ISAC_STAR);
+ sprintf(tmp, "ISAC STAR %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->isac, ISAC_MODE);
+ sprintf(tmp, "ISAC MODE %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->isac, ISAC_ADF2);
+ sprintf(tmp, "ISAC ADF2 %x", val);
+ debugl1(sp, tmp);
+ val = readreg(sp->isac, ISAC_ISTA);
+ sprintf(tmp, "ISAC ISTA %x", val);
+ debugl1(sp, tmp);
+ if (val & 0x01) {
+ val = readreg(sp->isac, ISAC_EXIR);
+ sprintf(tmp, "ISAC EXIR %x", val);
+ debugl1(sp, tmp);
+ } else if (val & 0x04) {
+ val = readreg(sp->isac, ISAC_CIR0);
+ sprintf(tmp, "ISAC CIR0 %x", val);
+ debugl1(sp, tmp);
+ }
+ writereg(sp->isac, ISAC_MASK, 0);
+ writereg(sp->isac, ISAC_CMDR, 0x41);
+}
+
+int
+initteles3(struct IsdnCardState *sp)
+{
+ int ret;
+ int loop = 0;
+ char tmp[40];
+
+ sp->counter = kstat.interrupts[sp->irq];
+ sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
+ debugl1(sp, tmp);
+ clear_pending_ints(sp);
+ ret = get_irq(sp->cardnr, &teles3_interrupt);
+ if (ret) {
+ initisac(sp);
+ sp->modehscx(sp->hs, 0, 0);
+ writereg(sp->hscx[sp->hs->hscx], HSCX_CMDR, 0x01);
+ sp->modehscx(sp->hs + 1, 0, 0);
+ writereg(sp->hscx[(sp->hs + 1)->hscx], HSCX_CMDR, 0x01);
+ while (loop++ < 10) {
+ /* At least 1-3 irqs must happen
+ * (one from HSCX A, one from HSCX B, 3rd from ISAC)
+ */
+ if (kstat.interrupts[sp->irq] > sp->counter)
+ break;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ }
+ sprintf(tmp, "IRQ %d count %d loop %d", sp->irq,
+ kstat.interrupts[sp->irq], loop);
+ debugl1(sp, tmp);
+ if (kstat.interrupts[sp->irq] <= sp->counter) {
+ printk(KERN_WARNING
+ "Teles3: IRQ(%d) getting no interrupts during init\n",
+ sp->irq);
+ irq2dev_map[sp->irq] = NULL;
+ free_irq(sp->irq, NULL);
+ return (0);
+ }
+ }
+ return (ret);
+}
+
+int
+setup_teles3(struct IsdnCard *card)
+{
+ u_char cfval = 0, val, verA, verB;
+ struct IsdnCardState *sp = card->sp;
+ long flags;
+ char tmp[64];
+
+ strcpy(tmp, teles3_revision);
+ printk(KERN_NOTICE "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
+ if ((sp->typ != ISDN_CTYPE_16_3) && (sp->typ != ISDN_CTYPE_PNP)
+ && (sp->typ != ISDN_CTYPE_TELESPCMCIA))
+ return (0);
+
+ if (sp->typ == ISDN_CTYPE_16_3) {
+ sp->cfg_reg = card->para[1];
+ switch (sp->cfg_reg) {
+ case 0x180:
+ case 0x280:
+ case 0x380:
+ sp->cfg_reg |= 0xc00;
+ break;
+ }
+ sp->isac = sp->cfg_reg - 0x400;
+ sp->hscx[0] = sp->cfg_reg - 0xc00;
+ sp->hscx[1] = sp->cfg_reg - 0x800;
+ } else if (sp->typ == ISDN_CTYPE_TELESPCMCIA) {
+ sp->cfg_reg = 0;
+ sp->hscx[0] = card->para[1];
+ sp->hscx[1] = card->para[1] + 0x20;
+ sp->isac = card->para[1] + 0x40;
+ } else { /* PNP */
+ sp->cfg_reg = 0;
+ sp->isac = card->para[1];
+ sp->hscx[0] = card->para[2];
+ sp->hscx[1] = card->para[2] + 0x20;
+ }
+ sp->irq = card->para[0];
+ if (sp->typ == ISDN_CTYPE_TELESPCMCIA) {
+ if (check_region((sp->hscx[0]), 97)) {
+ printk(KERN_WARNING
+ "HiSax: %s ports %x-%x already in use\n",
+ CardType[sp->typ],
+ sp->hscx[0],
+ sp->hscx[0] + 96);
+ return (0);
+ } else
+ request_region(sp->hscx[0], 97, "HiSax Teles PCMCIA");
+ } else {
+ if (sp->cfg_reg) {
+ if (check_region((sp->cfg_reg), 8)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %x-%x already in use\n",
+ CardType[card->typ],
+ sp->cfg_reg,
+ sp->cfg_reg + 8);
+ return (0);
+ } else {
+ request_region(sp->cfg_reg, 8, "teles3 cfg");
+ }
+ }
+ if (check_region((sp->isac), 32)) {
+ printk(KERN_WARNING
+ "HiSax: %s isac ports %x-%x already in use\n",
+ CardType[sp->typ],
+ sp->isac,
+ sp->isac + 32);
+ if (sp->cfg_reg) {
+ release_region(sp->cfg_reg, 8);
+ }
+ return (0);
+ } else {
+ request_region(sp->isac, 32, "HiSax isac");
+ }
+ if (check_region((sp->hscx[0]), 32)) {
+ printk(KERN_WARNING
+ "HiSax: %s hscx A ports %x-%x already in use\n",
+ CardType[sp->typ],
+ sp->hscx[0],
+ sp->hscx[0] + 32);
+ if (sp->cfg_reg) {
+ release_region(sp->cfg_reg, 8);
+ }
+ release_ioregs(card, 1);
+ return (0);
+ } else {
+ request_region(sp->hscx[0], 32, "HiSax hscx A");
+ }
+ if (check_region((sp->hscx[1]), 32)) {
+ printk(KERN_WARNING
+ "HiSax: %s hscx B ports %x-%x already in use\n",
+ CardType[sp->typ],
+ sp->hscx[1],
+ sp->hscx[1] + 32);
+ if (sp->cfg_reg) {
+ release_region(sp->cfg_reg, 8);
+ }
+ release_ioregs(card, 3);
+ return (0);
+ } else {
+ request_region(sp->hscx[1], 32, "HiSax hscx B");
+ }
+ switch (sp->irq) {
+ case 2:
+ cfval = 0x00;
+ break;
+ case 3:
+ cfval = 0x02;
+ break;
+ case 4:
+ cfval = 0x04;
+ break;
+ case 5:
+ cfval = 0x06;
+ break;
+ case 10:
+ cfval = 0x08;
+ break;
+ case 11:
+ cfval = 0x0A;
+ break;
+ case 12:
+ cfval = 0x0C;
+ break;
+ case 15:
+ cfval = 0x0E;
+ break;
+ default:
+ cfval = 0x00;
+ break;
+ }
+ }
+ if (sp->cfg_reg) {
+ if ((val = bytein(sp->cfg_reg + 0)) != 0x51) {
+ printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+ sp->cfg_reg + 0, val);
+ release_io_teles3(card);
+ return (0);
+ }
+ if ((val = bytein(sp->cfg_reg + 1)) != 0x93) {
+ printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+ sp->cfg_reg + 1, val);
+ release_io_teles3(card);
+ return (0);
+ }
+ val = bytein(sp->cfg_reg + 2); /* 0x1e=without AB
+ * 0x1f=with AB
+ * 0x1c 16.3 ???
+ * 0x46 16.3 with AB + Video (Teles-Vision)
+ */
+ if (val != 0x46 && val != 0x1c && val != 0x1e && val != 0x1f) {
+ printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
+ sp->cfg_reg + 2, val);
+ release_io_teles3(card);
+ return (0);
+ }
+ save_flags(flags);
+ byteout(sp->cfg_reg + 4, cfval);
+ sti();
+ HZDELAY(HZ / 10 + 1);
+ byteout(sp->cfg_reg + 4, cfval | 1);
+ HZDELAY(HZ / 10 + 1);
+ restore_flags(flags);
+ } else {
+ /* Reset off for 16.3 PnP , thanks to Georg Acher */
+ save_flags(flags);
+ byteout(sp->isac + 0x1c, 1);
+ HZDELAY(2);
+ restore_flags(flags);
+ }
+ printk(KERN_NOTICE
+ "HiSax: %s config irq:%d isac:%x cfg:%x\n",
+ CardType[sp->typ], sp->irq,
+ sp->isac, sp->cfg_reg);
+ printk(KERN_NOTICE
+ "HiSax: hscx A:%x hscx B:%x\n",
+ sp->hscx[0], sp->hscx[1]);
+ verA = readreg(sp->hscx[0], HSCX_VSTR) & 0xf;
+ verB = readreg(sp->hscx[1], HSCX_VSTR) & 0xf;
+ printk(KERN_INFO "Teles3: HSCX version A: %s B: %s\n",
+ HscxVersion(verA), HscxVersion(verB));
+ val = readreg(sp->isac, ISAC_RBCH);
+ printk(KERN_INFO "Teles3: ISAC %s\n",
+ ISACVersion(val));
+ if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) {
+ printk(KERN_WARNING
+ "Teles3: wrong HSCX versions check IO address\n");
+ release_io_teles3(card);
+ return (0);
+ }
+ sp->modehscx = &modehscx;
+ sp->ph_command = &ph_command;
+ sp->hscx_fill_fifo = &hscx_fill_fifo;
+ sp->isac_fill_fifo = &isac_fill_fifo;
+ return (1);
+}
--- /dev/null
+/* $Id: teles3.h,v 1.2 1997/01/21 22:27:14 keil Exp $
+ *
+ * teles3.h Header for Teles 16.3 PNP & compatible
+ *
+ * Author Karsten Keil (keil@temic-ech.spacenet.de)
+ *
+ *
+ * $Log: teles3.h,v $
+ * Revision 1.2 1997/01/21 22:27:14 keil
+ * cleanups
+ *
+ * Revision 1.1 1996/10/13 20:03:49 keil
+ * Initial revision
+ *
+ *
+*/
+
+extern void teles3_report(struct IsdnCardState *sp);
+extern void release_io_teles3(struct IsdnCard *card);
+extern int setup_teles3(struct IsdnCard *card);
+extern int initteles3(struct IsdnCardState *sp);
-/* $Id: icn.c,v 1.31 1996/11/13 02:36:25 fritz Exp $
- *
+/* $Id: icn.c,v 1.45 1997/06/21 10:42:06 fritz Exp $
+
* ISDN low-level module for the ICN active ISDN-Card.
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: icn.c,v $
+ * Revision 1.45 1997/06/21 10:42:06 fritz
+ * Added availability to select leased mode on only one channel.
+ *
+ * Revision 1.44 1997/03/30 16:51:26 calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.43 1997/03/21 18:27:04 fritz
+ * Corrected parsing of incoming setup.
+ *
+ * Revision 1.42 1997/03/05 21:13:18 fritz
+ * Bugfix: sndcount was not reset on hangup.
+ *
+ * Revision 1.41 1997/02/24 23:34:29 fritz
+ * Bugfix in Layer1 error-recovery.
+ *
+ * Revision 1.40 1997/02/23 23:34:45 fritz
+ * Minor bugfixes in debugging code.
+ *
+ * Revision 1.39 1997/02/23 16:21:56 fritz
+ * Bugfix: Check for NULL pointer in icn_parse_status().
+ *
+ * Revision 1.38 1997/02/11 18:29:31 fritz
+ * Bugfix in D64S initialization.
+ *
+ * Revision 1.37 1997/02/10 22:43:20 fritz
+ * Added plan and screen elements on ISDN_STAT_ICALL
+ *
+ * Revision 1.36 1997/02/10 21:31:20 fritz
+ * Changed setup-interface (incoming and outgoing).
+ *
+ * Revision 1.35 1997/02/10 10:10:28 fritz
+ * Changes for Kernel 2.1.X compatibility.
+ * Enhanced initialization, can recover from
+ * misconfiguration by other autoprobing drivers.
+ *
+ * Revision 1.34 1997/01/29 22:34:44 fritz
+ * Cleanup, Corrected D64S setup of 2nd channel.
+ *
+ * Revision 1.33 1996/12/05 20:31:48 tsbogend
+ * added handling of L2: DATA LINK LOST messages
+ *
+ * Revision 1.32 1996/11/14 23:49:18 fritz
+ * Bugfix: copy_to_user/copy_from_user mismatch in debugging-ioctl.
+ *
* Revision 1.31 1996/11/13 02:36:25 fritz
* Fixed a race condition in writecmd.
* Some optimizations and cleanup.
#undef MAP_DEBUG
static char
-*revision = "$Revision: 1.31 $";
+*revision = "$Revision: 1.45 $";
static int icn_addcard(int, char *, char *);
/*
- * Free queue completely.
+ * Free send-queue completely.
* Parameter:
- * queue = pointer to queue-head
+ * card = pointer to card struct
+ * channel = channel number
*/
-static void icn_free_queue(struct sk_buff_head *queue)
+static void
+icn_free_queue(icn_card * card, int channel)
{
- struct sk_buff *skb;
+ struct sk_buff_head *queue = &card->spqueue[channel];
+ struct sk_buff *skb;
- while ((skb = skb_dequeue(queue)))
- dev_kfree_skb(skb, FREE_WRITE);
+ while ((skb = skb_dequeue(queue)))
+ dev_kfree_skb(skb, FREE_WRITE);
+ card->sndcount[channel] = 0;
}
/* Put a value into a shift-register, highest bit first.
* firstbit = Bit-Number of highest bit
* bitcount = Number of bits to output
*/
-static inline void icn_shiftout(unsigned short port,
- unsigned long val,
- int firstbit,
- int bitcount)
+static inline void
+icn_shiftout(unsigned short port,
+ unsigned long val,
+ int firstbit,
+ int bitcount)
{
- register u_char s;
- register u_char c;
+ register u_char s;
+ register u_char c;
- for (s = firstbit, c = bitcount; c > 0; s--, c--)
- OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
+ for (s = firstbit, c = bitcount; c > 0; s--, c--)
+ OUTB_P((u_char) ((val >> s) & 1) ? 0xff : 0, port);
}
/*
* disable a cards shared memory
*/
-static inline void icn_disable_ram(icn_card *card)
+static inline void
+icn_disable_ram(icn_card * card)
{
- OUTB_P(0, ICN_MAPRAM);
+ OUTB_P(0, ICN_MAPRAM);
}
/*
* enable a cards shared memory
*/
-static inline void icn_enable_ram(icn_card *card)
+static inline void
+icn_enable_ram(icn_card * card)
{
- OUTB_P(0xff, ICN_MAPRAM);
+ OUTB_P(0xff, ICN_MAPRAM);
}
/*
* Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
*/
-static inline void icn_map_channel(icn_card *card, int channel)
+static inline void
+icn_map_channel(icn_card * card, int channel)
{
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_map_channel %d %d\n", dev->channel, channel);
+ printk(KERN_DEBUG "icn_map_channel %d %d\n", dev.channel, channel);
#endif
- if ((channel == dev.channel) && (card == dev.mcard))
- return;
- if (dev.mcard)
- icn_disable_ram(dev.mcard);
- icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */
- icn_enable_ram(card);
- dev.mcard = card;
- dev.channel = channel;
+ if ((channel == dev.channel) && (card == dev.mcard))
+ return;
+ if (dev.mcard)
+ icn_disable_ram(dev.mcard);
+ icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */
+ icn_enable_ram(card);
+ dev.mcard = card;
+ dev.channel = channel;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_map_channel done\n");
+ printk(KERN_DEBUG "icn_map_channel done\n");
#endif
}
* Return 0 if requested card/channel is unmapped (failure).
* Return 1 on success.
*/
-static inline int icn_lock_channel(icn_card *card, int channel)
+static inline int
+icn_lock_channel(icn_card * card, int channel)
{
- register int retval;
- ulong flags;
+ register int retval;
+ ulong flags;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
+ printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
#endif
- save_flags(flags);
- cli();
- if ((dev.channel == channel) && (card == dev.mcard)) {
- dev.chanlock++;
- retval = 1;
+ save_flags(flags);
+ cli();
+ if ((dev.channel == channel) && (card == dev.mcard)) {
+ dev.chanlock++;
+ retval = 1;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
+ printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
#endif
- } else {
- retval = 0;
+ } else {
+ retval = 0;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, device->channel);
+ printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev.channel);
#endif
- }
- restore_flags(flags);
- return retval;
+ }
+ restore_flags(flags);
+ return retval;
}
/*
* Release current card/channel lock
*/
-static inline void icn_release_channel(void)
+static inline void
+icn_release_channel(void)
{
- ulong flags;
+ ulong flags;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_release_channel l=%d\n", device->chanlock);
+ printk(KERN_DEBUG "icn_release_channel l=%d\n", dev.chanlock);
#endif
- save_flags(flags);
- cli();
- if (dev.chanlock > 0)
- dev.chanlock--;
- restore_flags(flags);
+ save_flags(flags);
+ cli();
+ if (dev.chanlock > 0)
+ dev.chanlock--;
+ restore_flags(flags);
}
/*
* Try to map and lock a cards channel.
* Return 1 on success, 0 on failure.
*/
-static inline int icn_trymaplock_channel(icn_card *card, int channel)
+static inline int
+icn_trymaplock_channel(icn_card * card, int channel)
{
- ulong flags;
+ ulong flags;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
- dev.chanlock);
+ printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
+ dev.chanlock);
#endif
- save_flags(flags);
- cli();
- if ((!dev.chanlock) ||
- ((dev.channel == channel) && (dev.mcard == card))) {
- dev.chanlock++;
- icn_map_channel(card,channel);
- restore_flags(flags);
+ save_flags(flags);
+ cli();
+ if ((!dev.chanlock) ||
+ ((dev.channel == channel) && (dev.mcard == card))) {
+ dev.chanlock++;
+ icn_map_channel(card, channel);
+ restore_flags(flags);
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock %d OK\n", channel);
+ printk(KERN_DEBUG "trymaplock %d OK\n", channel);
#endif
- return 1;
- }
- restore_flags(flags);
+ return 1;
+ }
+ restore_flags(flags);
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
+ printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
#endif
- return 0;
+ return 0;
}
/*
* Release current card/channel lock,
* then map same or other channel without locking.
*/
-static inline void icn_maprelease_channel(icn_card *card, int channel)
+static inline void
+icn_maprelease_channel(icn_card * card, int channel)
{
- ulong flags;
+ ulong flags;
#ifdef MAP_DEBUG
- printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
+ printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
#endif
- save_flags(flags);
- cli();
- if (dev.chanlock > 0)
- dev.chanlock--;
- if (!dev.chanlock)
- icn_map_channel(card,channel);
- restore_flags(flags);
+ save_flags(flags);
+ cli();
+ if (dev.chanlock > 0)
+ dev.chanlock--;
+ if (!dev.chanlock)
+ icn_map_channel(card, channel);
+ restore_flags(flags);
}
/* Get Data from the B-Channel, assemble fragmented packets and put them
* This routine is called via timer-callback from icn_pollbchan().
*/
-static void icn_pollbchan_receive(int channel, icn_card *card)
+static void
+icn_pollbchan_receive(int channel, icn_card * card)
{
- int mch = channel + ((card->secondhalf) ? 2 : 0);
- int eflag;
- int cnt;
+ int mch = channel + ((card->secondhalf) ? 2 : 0);
+ int eflag;
+ int cnt;
struct sk_buff *skb;
- if (icn_trymaplock_channel(card,mch)) {
- while (rbavl) {
- cnt = readb(&rbuf_l);
- if ((card->rcvidx[channel] + cnt) > 4000) {
- printk(KERN_WARNING
- "icn: (%s) bogus packet on ch%d, dropping.\n",
- CID,
- channel + 1);
- card->rcvidx[channel] = 0;
- eflag = 0;
- } else {
- memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
- &rbuf_d, cnt);
- card->rcvidx[channel] += cnt;
- eflag = readb(&rbuf_f);
- }
- rbnext;
- icn_maprelease_channel(card, mch & 2);
- if (!eflag) {
- if ((cnt = card->rcvidx[channel])) {
- if (!(skb = dev_alloc_skb(cnt))) {
- printk(KERN_WARNING "ïcn: receive out of memory\n");
- break;
- }
- memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
- card->rcvidx[channel] = 0;
- card->interface.rcvcallb_skb(card->myid, channel, skb);
- }
- }
- if (!icn_trymaplock_channel(card, mch))
- break;
- }
- icn_maprelease_channel(card, mch & 2);
- }
+ if (icn_trymaplock_channel(card, mch)) {
+ while (rbavl) {
+ cnt = readb(&rbuf_l);
+ if ((card->rcvidx[channel] + cnt) > 4000) {
+ printk(KERN_WARNING
+ "icn: (%s) bogus packet on ch%d, dropping.\n",
+ CID,
+ channel + 1);
+ card->rcvidx[channel] = 0;
+ eflag = 0;
+ } else {
+ memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
+ &rbuf_d, cnt);
+ card->rcvidx[channel] += cnt;
+ eflag = readb(&rbuf_f);
+ }
+ rbnext;
+ icn_maprelease_channel(card, mch & 2);
+ if (!eflag) {
+ if ((cnt = card->rcvidx[channel])) {
+ if (!(skb = dev_alloc_skb(cnt))) {
+ printk(KERN_WARNING "ïcn: receive out of memory\n");
+ break;
+ }
+ memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
+ card->rcvidx[channel] = 0;
+ card->interface.rcvcallb_skb(card->myid, channel, skb);
+ }
+ }
+ if (!icn_trymaplock_channel(card, mch))
+ break;
+ }
+ icn_maprelease_channel(card, mch & 2);
+ }
}
/* Send data-packet to B-Channel, split it up into fragments of
* directly from icn_sendbuf().
*/
-static void icn_pollbchan_send(int channel, icn_card *card)
+static void
+icn_pollbchan_send(int channel, icn_card * card)
{
- int mch = channel + ((card->secondhalf) ? 2 : 0);
- int cnt;
+ int mch = channel + ((card->secondhalf) ? 2 : 0);
+ int cnt;
unsigned long flags;
- struct sk_buff *skb;
- isdn_ctrl cmd;
-
- if (!(card->sndcount[channel] ||
- skb_queue_len(&card->spqueue[channel])))
- return;
- if (icn_trymaplock_channel(card,mch)) {
- while (sbfree && (card->sndcount[channel] ||
- skb_queue_len(&card->spqueue[channel]))) {
- save_flags(flags);
- cli();
- if (card->xmit_lock[channel]) {
- restore_flags(flags);
- break;
- }
- card->xmit_lock[channel]++;
- restore_flags(flags);
- skb = skb_dequeue(&card->spqueue[channel]);
- if (!skb)
- break;
- if (skb->len > ICN_FRAGSIZE) {
- writeb (0xff, &sbuf_f);
- cnt = ICN_FRAGSIZE;
+ struct sk_buff *skb;
+ isdn_ctrl cmd;
+
+ if (!(card->sndcount[channel] ||
+ skb_queue_len(&card->spqueue[channel])))
+ return;
+ if (icn_trymaplock_channel(card, mch)) {
+ while (sbfree && (card->sndcount[channel] ||
+ skb_queue_len(&card->spqueue[channel]))) {
+ save_flags(flags);
+ cli();
+ if (card->xmit_lock[channel]) {
+ restore_flags(flags);
+ break;
+ }
+ card->xmit_lock[channel]++;
+ restore_flags(flags);
+ skb = skb_dequeue(&card->spqueue[channel]);
+ if (!skb)
+ break;
+ if (skb->len > ICN_FRAGSIZE) {
+ writeb(0xff, &sbuf_f);
+ cnt = ICN_FRAGSIZE;
} else {
- writeb (0x0, &sbuf_f);
- cnt = skb->len;
+ writeb(0x0, &sbuf_f);
+ cnt = skb->len;
}
- writeb (cnt, &sbuf_l);
- memcpy_toio(&sbuf_d, skb->data, cnt);
- skb_pull(skb, cnt);
- card->sndcount[channel] -= cnt;
- sbnext; /* switch to next buffer */
- icn_maprelease_channel(card, mch & 2);
- if (!skb->len) {
- dev_kfree_skb(skb, FREE_WRITE);
- cmd.command = ISDN_STAT_BSENT;
- cmd.driver = card->myid;
- cmd.arg = channel;
- card->interface.statcallb(&cmd);
- } else
- skb_queue_head(&card->spqueue[channel], skb);
- card->xmit_lock[channel] = 0;
- if (!icn_trymaplock_channel(card, mch))
- break;
- }
- icn_maprelease_channel(card, mch & 2);
- }
+ writeb(cnt, &sbuf_l);
+ memcpy_toio(&sbuf_d, skb->data, cnt);
+ skb_pull(skb, cnt);
+ card->sndcount[channel] -= cnt;
+ sbnext; /* switch to next buffer */
+ icn_maprelease_channel(card, mch & 2);
+ if (!skb->len) {
+ dev_kfree_skb(skb, FREE_WRITE);
+ cmd.command = ISDN_STAT_BSENT;
+ cmd.driver = card->myid;
+ cmd.arg = channel;
+ card->interface.statcallb(&cmd);
+ } else
+ skb_queue_head(&card->spqueue[channel], skb);
+ card->xmit_lock[channel] = 0;
+ if (!icn_trymaplock_channel(card, mch))
+ break;
+ }
+ icn_maprelease_channel(card, mch & 2);
+ }
}
/* Send/Receive Data to/from the B-Channel.
* It schedules itself while any B-Channel is open.
*/
-static void icn_pollbchan(unsigned long data)
+static void
+icn_pollbchan(unsigned long data)
{
- icn_card *card = (icn_card *)data;
- unsigned long flags;
-
- if (card->flags & ICN_FLAGS_B1ACTIVE) {
- icn_pollbchan_receive(0, card);
- icn_pollbchan_send(0, card);
- }
- if (card->flags & ICN_FLAGS_B2ACTIVE) {
- icn_pollbchan_receive(1, card);
- icn_pollbchan_send(1, card);
- }
- if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
- /* schedule b-channel polling again */
- save_flags(flags);
- cli();
- del_timer(&card->rb_timer);
- card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- card->flags |= ICN_FLAGS_RBTIMER;
- restore_flags(flags);
- } else
- card->flags &= ~ICN_FLAGS_RBTIMER;
+ icn_card *card = (icn_card *) data;
+ unsigned long flags;
+
+ if (card->flags & ICN_FLAGS_B1ACTIVE) {
+ icn_pollbchan_receive(0, card);
+ icn_pollbchan_send(0, card);
+ }
+ if (card->flags & ICN_FLAGS_B2ACTIVE) {
+ icn_pollbchan_receive(1, card);
+ icn_pollbchan_send(1, card);
+ }
+ if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
+ /* schedule b-channel polling again */
+ save_flags(flags);
+ cli();
+ del_timer(&card->rb_timer);
+ card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+ add_timer(&card->rb_timer);
+ card->flags |= ICN_FLAGS_RBTIMER;
+ restore_flags(flags);
+ } else
+ card->flags &= ~ICN_FLAGS_RBTIMER;
}
typedef struct icn_stat {
- char *statstr;
- int command;
- int action;
+ char *statstr;
+ int command;
+ int action;
} icn_stat;
-
-static icn_stat icn_stat_table[] = {
- {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
- {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
- {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
- {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */
- {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
- {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
- {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
- {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
- {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
- {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
- {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
- {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */
- {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {NULL, 0 , -1}
+/* *INDENT-OFF* */
+static icn_stat icn_stat_table[] =
+{
+ {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
+ {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
+ {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
+ {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */
+ {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
+ {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
+ {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
+ {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
+ {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
+ {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
+ {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
+ {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */
+ {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
+ {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
+ {"E_L1: ACTIVATION FAILED",
+ ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
+ {NULL, 0, -1}
};
+/* *INDENT-ON* */
+
/*
* Check Statusqueue-Pointer from isdn-cards.
* This routine is called periodically via timer.
*/
-static int icn_parse_status(u_char *status, int channel, icn_card *card)
+static int
+icn_parse_status(u_char * status, int channel, icn_card * card)
{
- icn_stat *s = icn_stat_table;
- int action = -1;
- int dflag = 0;
- unsigned long flags;
- isdn_ctrl cmd;
-
- while (s->statstr) {
- if (!strncmp(status,s->statstr,strlen(s->statstr))) {
- cmd.command = s->command;
- action = s->action;
- break;
- }
- s++;
- }
- if (action==-1)
- return 0;
- cmd.driver = card->myid;
- cmd.arg = channel;
- switch (action) {
- case 1:
- card->flags |= (channel)?
- ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE;
- break;
- case 2:
- card->flags &= ~((channel)?
- ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE);
- icn_free_queue(&card->spqueue[channel]);
- save_flags(flags);
- cli();
- card->rcvidx[channel] = 0;
- restore_flags(flags);
- dflag |= (channel+1);
- break;
- case 3:
- strncpy(cmd.num, status + 6, sizeof(cmd.num) - 1);
- break;
- case 4:
- sprintf(cmd.num,"LEASED%d,07,00,%d",
- card->myid,channel+1);
- break;
- case 5:
- strncpy(cmd.num, status + 3, sizeof(cmd.num) - 1);
- break;
- case 6:
- sprintf(cmd.num,"%d",
- (int)simple_strtoul(status + 7,NULL,16));
- break;
- case 7:
- status += 3;
- if (strlen(status)==4)
- sprintf(cmd.num,"%s%c%c",
- status+2,*status,*(status+1));
- else
- strncpy(cmd.num, status+1, sizeof(cmd.num) - 1);
- break;
- case 8:
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_BHUP;
- cmd.arg = 1;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 1;
- cmd.driver = card->myid;
- break;
- }
- card->interface.statcallb(&cmd);
- return dflag;
+ icn_stat *s = icn_stat_table;
+ int action = -1;
+ int dflag = 0;
+ unsigned long flags;
+ isdn_ctrl cmd;
+
+ while (s->statstr) {
+ if (!strncmp(status, s->statstr, strlen(s->statstr))) {
+ cmd.command = s->command;
+ action = s->action;
+ break;
+ }
+ s++;
+ }
+ if (action == -1)
+ return 0;
+ cmd.driver = card->myid;
+ cmd.arg = channel;
+ switch (action) {
+ case 1:
+ card->flags |= (channel) ?
+ ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
+ break;
+ case 2:
+ card->flags &= ~((channel) ?
+ ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
+ icn_free_queue(card, channel);
+ save_flags(flags);
+ cli();
+ card->rcvidx[channel] = 0;
+ restore_flags(flags);
+ dflag |= (channel + 1);
+ break;
+ case 3:
+ {
+ char *t = status + 6;
+ char *s = strpbrk(t, ",");
+
+ *s++ = '\0';
+ strncpy(cmd.parm.setup.phone, t,
+ sizeof(cmd.parm.setup.phone));
+ s = strpbrk(t = s, ",");
+ *s++ = '\0';
+ if (!strlen(t))
+ cmd.parm.setup.si1 = 0;
+ else
+ cmd.parm.setup.si1 =
+ simple_strtoul(t, NULL, 10);
+ s = strpbrk(t = s, ",");
+ *s++ = '\0';
+ if (!strlen(t))
+ cmd.parm.setup.si2 = 0;
+ else
+ cmd.parm.setup.si2 =
+ simple_strtoul(t, NULL, 10);
+ strncpy(cmd.parm.setup.eazmsn, s,
+ sizeof(cmd.parm.setup.eazmsn));
+ }
+ cmd.parm.setup.plan = 0;
+ cmd.parm.setup.screen = 0;
+ break;
+ case 4:
+ sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
+ sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
+ cmd.parm.setup.si1 = 7;
+ cmd.parm.setup.si2 = 0;
+ cmd.parm.setup.plan = 0;
+ cmd.parm.setup.screen = 0;
+ break;
+ case 5:
+ strncpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num) - 1);
+ break;
+ case 6:
+ sprintf(cmd.parm.num, "%d",
+ (int) simple_strtoul(status + 7, NULL, 16));
+ break;
+ case 7:
+ status += 3;
+ if (strlen(status) == 4)
+ sprintf(cmd.parm.num, "%s%c%c",
+ status + 2, *status, *(status + 1));
+ else
+ strncpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num) - 1);
+ break;
+ case 8:
+ dflag = 3;
+ card->flags &= ~ICN_FLAGS_B1ACTIVE;
+ icn_free_queue(card, 0);
+ save_flags(flags);
+ cli();
+ card->rcvidx[0] = 0;
+ restore_flags(flags);
+ cmd.arg = 0;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = 0;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_BHUP;
+ card->flags &= ~ICN_FLAGS_B2ACTIVE;
+ icn_free_queue(card, 1);
+ save_flags(flags);
+ cli();
+ card->rcvidx[1] = 0;
+ restore_flags(flags);
+ cmd.arg = 1;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ cmd.command = ISDN_STAT_DHUP;
+ cmd.arg = 1;
+ cmd.driver = card->myid;
+ break;
+ }
+ card->interface.statcallb(&cmd);
+ return dflag;
}
-static void icn_putmsg(icn_card *card, unsigned char c)
+static void
+icn_putmsg(icn_card * card, unsigned char c)
{
- ulong flags;
-
- save_flags(flags);
- cli();
- *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
- if (card->msg_buf_write == card->msg_buf_read) {
- if (++card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
- restore_flags(flags);
+ ulong flags;
+
+ save_flags(flags);
+ cli();
+ *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
+ if (card->msg_buf_write == card->msg_buf_read) {
+ if (++card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+ if (card->msg_buf_write > card->msg_buf_end)
+ card->msg_buf_write = card->msg_buf;
+ restore_flags(flags);
}
-static void icn_polldchan(unsigned long data)
+static void
+icn_polldchan(unsigned long data)
{
- icn_card *card = (icn_card *)data;
- int mch = card->secondhalf ? 2 : 0;
- int avail = 0;
- int dflag = 0;
- int left;
- u_char c;
- int ch;
- int flags;
- int i;
- u_char *p;
- isdn_ctrl cmd;
-
- if (icn_trymaplock_channel(card,mch)) {
- avail = msg_avail;
- for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
- c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
- icn_putmsg(card, c);
- if (c == 0xff) {
- card->imsg[card->iptr] = 0;
- card->iptr = 0;
- if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
- card->imsg[1] <= '2' && card->imsg[2] == ';') {
- ch = (card->imsg[1] - '0') - 1;
- p = &card->imsg[3];
- dflag |= icn_parse_status(p, ch, card);
- } else {
- p = card->imsg;
- if (!strncmp(p, "DRV1.", 5)) {
- u_char vstr[10];
- u_char *q = vstr;
-
- printk(KERN_INFO "icn: (%s) %s\n",CID,p);
- if (!strncmp(p + 7, "TC", 2)) {
- card->ptype = ISDN_PTYPE_1TR6;
- card->interface.features |= ISDN_FEATURE_P_1TR6;
- printk(KERN_INFO
- "icn: (%s) 1TR6-Protocol loaded and running\n",CID);
- }
- if (!strncmp(p + 7, "EC", 2)) {
- card->ptype = ISDN_PTYPE_EURO;
- card->interface.features |= ISDN_FEATURE_P_EURO;
- printk(KERN_INFO
- "icn: (%s) Euro-Protocol loaded and running\n",CID);
- }
- p = strstr(card->imsg,"BRV") + 3;
- while (*p) {
- if (*p>='0' && *p<='9')
- *q++ = *p;
- p++;
- }
- *q = '\0';
- strcat(vstr,"000");
- vstr[3] = '\0';
- card->fw_rev = (int)simple_strtoul(vstr,NULL,10);
- continue;
-
- }
- }
- } else {
- card->imsg[card->iptr] = c;
- if (card->iptr < 59)
- card->iptr++;
- }
- }
- writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
- icn_release_channel();
- }
- if (avail) {
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = avail;
- card->interface.statcallb(&cmd);
- }
- if (dflag & 1)
- card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0);
- if (dflag & 2)
- card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0);
- if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
- if (!(card->flags & ICN_FLAGS_RBTIMER)) {
- /* schedule b-channel polling */
- card->flags |= ICN_FLAGS_RBTIMER;
- save_flags(flags);
- cli();
- del_timer(&card->rb_timer);
- card->rb_timer.function = icn_pollbchan;
- card->rb_timer.data = (unsigned long)card;
- card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- restore_flags(flags);
- }
- /* schedule again */
- save_flags(flags);
- cli();
- del_timer(&card->st_timer);
- card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
- add_timer(&card->st_timer);
- restore_flags(flags);
+ icn_card *card = (icn_card *) data;
+ int mch = card->secondhalf ? 2 : 0;
+ int avail = 0;
+ int dflag = 0;
+ int left;
+ u_char c;
+ int ch;
+ int flags;
+ int i;
+ u_char *p;
+ isdn_ctrl cmd;
+
+ if (icn_trymaplock_channel(card, mch)) {
+ avail = msg_avail;
+ for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
+ c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
+ icn_putmsg(card, c);
+ if (c == 0xff) {
+ card->imsg[card->iptr] = 0;
+ card->iptr = 0;
+ if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
+ card->imsg[1] <= '2' && card->imsg[2] == ';') {
+ ch = (card->imsg[1] - '0') - 1;
+ p = &card->imsg[3];
+ dflag |= icn_parse_status(p, ch, card);
+ } else {
+ p = card->imsg;
+ if (!strncmp(p, "DRV1.", 5)) {
+ u_char vstr[10];
+ u_char *q = vstr;
+
+ printk(KERN_INFO "icn: (%s) %s\n", CID, p);
+ if (!strncmp(p + 7, "TC", 2)) {
+ card->ptype = ISDN_PTYPE_1TR6;
+ card->interface.features |= ISDN_FEATURE_P_1TR6;
+ printk(KERN_INFO
+ "icn: (%s) 1TR6-Protocol loaded and running\n", CID);
+ }
+ if (!strncmp(p + 7, "EC", 2)) {
+ card->ptype = ISDN_PTYPE_EURO;
+ card->interface.features |= ISDN_FEATURE_P_EURO;
+ printk(KERN_INFO
+ "icn: (%s) Euro-Protocol loaded and running\n", CID);
+ }
+ p = strstr(card->imsg, "BRV") + 3;
+ while (*p) {
+ if (*p >= '0' && *p <= '9')
+ *q++ = *p;
+ p++;
+ }
+ *q = '\0';
+ strcat(vstr, "000");
+ vstr[3] = '\0';
+ card->fw_rev = (int) simple_strtoul(vstr, NULL, 10);
+ continue;
+
+ }
+ }
+ } else {
+ card->imsg[card->iptr] = c;
+ if (card->iptr < 59)
+ card->iptr++;
+ }
+ }
+ writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
+ icn_release_channel();
+ }
+ if (avail) {
+ cmd.command = ISDN_STAT_STAVAIL;
+ cmd.driver = card->myid;
+ cmd.arg = avail;
+ card->interface.statcallb(&cmd);
+ }
+ if (dflag & 1)
+ card->interface.rcvcallb(card->myid, 0, card->rcvbuf[0], 0);
+ if (dflag & 2)
+ card->interface.rcvcallb(card->myid, 1, card->rcvbuf[1], 0);
+ if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
+ if (!(card->flags & ICN_FLAGS_RBTIMER)) {
+ /* schedule b-channel polling */
+ card->flags |= ICN_FLAGS_RBTIMER;
+ save_flags(flags);
+ cli();
+ del_timer(&card->rb_timer);
+ card->rb_timer.function = icn_pollbchan;
+ card->rb_timer.data = (unsigned long) card;
+ card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
+ add_timer(&card->rb_timer);
+ restore_flags(flags);
+ }
+ /* schedule again */
+ save_flags(flags);
+ cli();
+ del_timer(&card->st_timer);
+ card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+ add_timer(&card->st_timer);
+ restore_flags(flags);
}
/* Append a packet to the transmit buffer-queue.
* Number of bytes transferred, -E??? on error
*/
-static int icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
+static int
+icn_sendbuf(int channel, struct sk_buff *skb, icn_card * card)
{
- int len = skb->len;
- unsigned long flags;
- struct sk_buff *nskb;
-
- if (len > 4000) {
- printk(KERN_WARNING
- "icn: Send packet too large\n");
- return -EINVAL;
- }
- if (len) {
- if (!(card->flags & (channel)?ICN_FLAGS_B2ACTIVE:ICN_FLAGS_B1ACTIVE))
- return 0;
- if (card->sndcount[channel] > ICN_MAX_SQUEUE)
- return 0;
- save_flags(flags);
- cli();
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (nskb) {
- skb_queue_tail(&card->spqueue[channel], nskb);
- dev_kfree_skb(skb, FREE_WRITE);
- } else
- len = 0;
- card->sndcount[channel] += len;
- restore_flags(flags);
- }
- return len;
+ int len = skb->len;
+ unsigned long flags;
+ struct sk_buff *nskb;
+
+ if (len > 4000) {
+ printk(KERN_WARNING
+ "icn: Send packet too large\n");
+ return -EINVAL;
+ }
+ if (len) {
+ if (!(card->flags & (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE))
+ return 0;
+ if (card->sndcount[channel] > ICN_MAX_SQUEUE)
+ return 0;
+ save_flags(flags);
+ cli();
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (nskb) {
+ skb_queue_tail(&card->spqueue[channel], nskb);
+ dev_kfree_skb(skb, FREE_WRITE);
+ } else
+ len = 0;
+ card->sndcount[channel] += len;
+ restore_flags(flags);
+ }
+ return len;
}
/*
* 0 on success (Boot loader ready)
* -EIO on failure (timeout)
*/
-static int icn_check_loader(int cardnumber)
+static int
+icn_check_loader(int cardnumber)
{
- int timer = 0;
+ int timer = 0;
- while (1) {
+ while (1) {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
+ printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
#endif
- if (readb(&dev.shmem->data_control.scns) ||
- readb(&dev.shmem->data_control.scnr)) {
- if (timer++ > 5) {
- printk(KERN_WARNING
- "icn: Boot-Loader %d timed out.\n",
- cardnumber);
- icn_release_channel();
- return -EIO;
- }
+ if (readb(&dev.shmem->data_control.scns) ||
+ readb(&dev.shmem->data_control.scnr)) {
+ if (timer++ > 5) {
+ printk(KERN_WARNING
+ "icn: Boot-Loader %d timed out.\n",
+ cardnumber);
+ icn_release_channel();
+ return -EIO;
+ }
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
+ printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
#endif
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
- schedule();
- } else {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+ schedule();
+ } else {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
+ printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
#endif
- icn_release_channel();
- return 0;
- }
- }
+ icn_release_channel();
+ return 0;
+ }
+ }
}
/* Load the boot-code into the interface-card's memory and start it.
* Always called from user-process.
- *
+ *
* Parameters:
* buffer = pointer to packet
* Return:
#define SLEEP(sec)
#endif
-static int icn_loadboot(u_char * buffer, icn_card * card)
+static int
+icn_loadboot(u_char * buffer, icn_card * card)
{
- int ret;
- ulong flags;
+ int ret;
+ ulong flags;
u_char *codebuf;
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
+ printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer);
#endif
- if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1)))
- return ret;
- if (!(codebuf = kmalloc(ICN_CODE_STAGE1,GFP_KERNEL))) {
- printk(KERN_WARNING "icn: Could not allocate code buffer\n");
- return -ENOMEM;
- }
- save_flags(flags);
- cli();
- if (!card->rvalid) {
- if (check_region(card->port, ICN_PORTLEN)) {
- printk(KERN_WARNING
- "icn: (%s) ports 0x%03x-0x%03x in use.\n",
- CID,
- card->port,
- card->port + ICN_PORTLEN);
- restore_flags(flags);
- kfree(codebuf);
- return -EBUSY;
- }
- request_region(card->port, ICN_PORTLEN, card->regname);
- card->rvalid = 1;
- if (card->doubleS0)
- card->other->rvalid = 1;
- }
- if (!dev.mvalid) {
- if (check_shmem((ulong) dev.shmem, 0x4000)) {
- printk(KERN_WARNING
- "icn: memory at 0x%08lx in use.\n",
- (ulong) dev.shmem);
- restore_flags(flags);
- return -EBUSY;
- }
- request_shmem((ulong) dev.shmem, 0x4000, "icn");
- dev.mvalid = 1;
- }
- restore_flags(flags);
- OUTB_P(0, ICN_RUN); /* Reset Controller */
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */
- icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10); /* Set RAM-Addr. */
+ if (!(codebuf = kmalloc(ICN_CODE_STAGE1, GFP_KERNEL))) {
+ printk(KERN_WARNING "icn: Could not allocate code buffer\n");
+ return -ENOMEM;
+ }
+ if ((ret = copy_from_user(codebuf, buffer, ICN_CODE_STAGE1))) {
+ kfree(codebuf);
+ return ret;
+ }
+ save_flags(flags);
+ cli();
+ if (!card->rvalid) {
+ if (check_region(card->port, ICN_PORTLEN)) {
+ printk(KERN_WARNING
+ "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+ CID,
+ card->port,
+ card->port + ICN_PORTLEN);
+ restore_flags(flags);
+ kfree(codebuf);
+ return -EBUSY;
+ }
+ request_region(card->port, ICN_PORTLEN, card->regname);
+ card->rvalid = 1;
+ if (card->doubleS0)
+ card->other->rvalid = 1;
+ }
+ if (!dev.mvalid) {
+ if (check_shmem((ulong) dev.shmem, 0x4000)) {
+ printk(KERN_WARNING
+ "icn: memory at 0x%08lx in use.\n",
+ (ulong) dev.shmem);
+ restore_flags(flags);
+ return -EBUSY;
+ }
+ request_shmem((ulong) dev.shmem, 0x4000, "icn");
+ dev.mvalid = 1;
+ }
+ restore_flags(flags);
+ OUTB_P(0, ICN_RUN); /* Reset Controller */
+ OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
+ icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */
+ icn_shiftout(ICN_CFG, (unsigned long) dev.shmem, 23, 10); /* Set RAM-Addr. */
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
+ printk(KERN_DEBUG "shmem=%08lx\n", (ulong) dev.shmem);
#endif
- SLEEP(1);
+ SLEEP(1);
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 0\n");
+ printk(KERN_DEBUG "Map Bank 0\n");
#endif
- save_flags(flags);
- cli();
- icn_map_channel(card,0); /* Select Bank 0 */
- icn_lock_channel(card,0); /* Lock Bank 0 */
- restore_flags(flags);
- SLEEP(1);
- copy_from_user(codebuf, buffer, ICN_CODE_STAGE1);
- memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
+ save_flags(flags);
+ cli();
+ icn_map_channel(card, 0); /* Select Bank 0 */
+ icn_lock_channel(card, 0); /* Lock Bank 0 */
+ restore_flags(flags);
+ SLEEP(1);
+ memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Bootloader transfered\n");
+ printk(KERN_DEBUG "Bootloader transfered\n");
#endif
- if (card->doubleS0) {
- SLEEP(1);
+ if (card->doubleS0) {
+ SLEEP(1);
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 8\n");
+ printk(KERN_DEBUG "Map Bank 8\n");
#endif
- save_flags(flags);
- cli();
- icn_release_channel();
- icn_map_channel(card,2); /* Select Bank 8 */
- icn_lock_channel(card,2); /* Lock Bank 8 */
- restore_flags(flags);
- SLEEP(1);
- memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
+ save_flags(flags);
+ cli();
+ icn_release_channel();
+ icn_map_channel(card, 2); /* Select Bank 8 */
+ icn_lock_channel(card, 2); /* Lock Bank 8 */
+ restore_flags(flags);
+ SLEEP(1);
+ memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Bootloader transfered\n");
+ printk(KERN_DEBUG "Bootloader transfered\n");
#endif
- }
- kfree(codebuf);
- SLEEP(1);
- OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
- if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1)))
- return ret;
- if (!card->doubleS0)
- return 0;
- /* reached only, if we have a Double-S0-Card */
+ }
+ kfree(codebuf);
+ SLEEP(1);
+ OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
+ if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1)))
+ return ret;
+ if (!card->doubleS0)
+ return 0;
+ /* reached only, if we have a Double-S0-Card */
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 0\n");
+ printk(KERN_DEBUG "Map Bank 0\n");
#endif
- save_flags(flags);
- cli();
- icn_map_channel(card,0); /* Select Bank 0 */
- icn_lock_channel(card,0); /* Lock Bank 0 */
- restore_flags(flags);
- SLEEP(1);
- return (icn_check_loader(1));
+ save_flags(flags);
+ cli();
+ icn_map_channel(card, 0); /* Select Bank 0 */
+ icn_lock_channel(card, 0); /* Lock Bank 0 */
+ restore_flags(flags);
+ SLEEP(1);
+ return (icn_check_loader(1));
}
-static int icn_loadproto(u_char * buffer, icn_card * card)
+static int
+icn_loadproto(u_char * buffer, icn_card * card)
{
- register u_char *p = buffer;
- u_char codebuf[256];
- uint left = ICN_CODE_STAGE2;
- uint cnt;
- int timer;
- int ret;
- unsigned long flags;
+ register u_char *p = buffer;
+ u_char codebuf[256];
+ uint left = ICN_CODE_STAGE2;
+ uint cnt;
+ int timer;
+ int ret;
+ unsigned long flags;
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "icn_loadproto called\n");
+ printk(KERN_DEBUG "icn_loadproto called\n");
#endif
- if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2)))
- return ret;
- timer = 0;
- save_flags(flags);
- cli();
- if (card->secondhalf) {
- icn_map_channel(card, 2);
- icn_lock_channel(card, 2);
- } else {
- icn_map_channel(card, 0);
- icn_lock_channel(card, 0);
- }
- restore_flags(flags);
- while (left) {
- if (sbfree) { /* If there is a free buffer... */
- cnt = MIN(256, left);
- copy_from_user(codebuf, p, cnt);
- memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */
- sbnext; /* switch to next buffer */
- p += cnt;
- left -= cnt;
- timer = 0;
- } else {
+ if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE2)))
+ return ret;
+ timer = 0;
+ save_flags(flags);
+ cli();
+ if (card->secondhalf) {
+ icn_map_channel(card, 2);
+ icn_lock_channel(card, 2);
+ } else {
+ icn_map_channel(card, 0);
+ icn_lock_channel(card, 0);
+ }
+ restore_flags(flags);
+ while (left) {
+ if (sbfree) { /* If there is a free buffer... */
+ cnt = MIN(256, left);
+ if (copy_from_user(codebuf, p, cnt)) {
+ icn_maprelease_channel(card, 0);
+ return -EFAULT;
+ }
+ memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */
+ sbnext; /* switch to next buffer */
+ p += cnt;
+ left -= cnt;
+ timer = 0;
+ } else {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "boot 2 !sbfree\n");
+ printk(KERN_DEBUG "boot 2 !sbfree\n");
#endif
- if (timer++ > 5) {
- icn_maprelease_channel(card, 0);
- return -EIO;
- }
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 10;
- schedule();
- }
- }
- writeb (0x20, &sbuf_n);
- timer = 0;
- while (1) {
- if (readb(&cmd_o) || readb(&cmd_i)) {
+ if (timer++ > 5) {
+ icn_maprelease_channel(card, 0);
+ return -EIO;
+ }
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 10;
+ schedule();
+ }
+ }
+ writeb(0x20, &sbuf_n);
+ timer = 0;
+ while (1) {
+ if (readb(&cmd_o) || readb(&cmd_i)) {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto?\n");
+ printk(KERN_DEBUG "Proto?\n");
#endif
- if (timer++ > 5) {
- printk(KERN_WARNING
- "icn: (%s) Protocol timed out.\n",
- CID);
+ if (timer++ > 5) {
+ printk(KERN_WARNING
+ "icn: (%s) Protocol timed out.\n",
+ CID);
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto TO!\n");
+ printk(KERN_DEBUG "Proto TO!\n");
#endif
- icn_maprelease_channel(card, 0);
- return -EIO;
- }
+ icn_maprelease_channel(card, 0);
+ return -EIO;
+ }
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto TO?\n");
+ printk(KERN_DEBUG "Proto TO?\n");
#endif
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
- schedule();
- } else {
- if ((card->secondhalf) || (!card->doubleS0)) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+ schedule();
+ } else {
+ if ((card->secondhalf) || (!card->doubleS0)) {
#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
- card->secondhalf);
+ printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
+ card->secondhalf);
#endif
- save_flags(flags);
- cli();
- init_timer(&card->st_timer);
- card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
- card->st_timer.function = icn_polldchan;
- card->st_timer.data = (unsigned long)card;
- add_timer(&card->st_timer);
- card->flags |= ICN_FLAGS_RUNNING;
- if (card->doubleS0) {
- init_timer(&card->other->st_timer);
- card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
- card->other->st_timer.function = icn_polldchan;
- card->other->st_timer.data = (unsigned long)card->other;
- add_timer(&card->other->st_timer);
- card->other->flags |= ICN_FLAGS_RUNNING;
- }
- restore_flags(flags);
- }
- icn_maprelease_channel(card, 0);
- return 0;
- }
- }
+ save_flags(flags);
+ cli();
+ init_timer(&card->st_timer);
+ card->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+ card->st_timer.function = icn_polldchan;
+ card->st_timer.data = (unsigned long) card;
+ add_timer(&card->st_timer);
+ card->flags |= ICN_FLAGS_RUNNING;
+ if (card->doubleS0) {
+ init_timer(&card->other->st_timer);
+ card->other->st_timer.expires = jiffies + ICN_TIMER_DCREAD;
+ card->other->st_timer.function = icn_polldchan;
+ card->other->st_timer.data = (unsigned long) card->other;
+ add_timer(&card->other->st_timer);
+ card->other->flags |= ICN_FLAGS_RUNNING;
+ }
+ restore_flags(flags);
+ }
+ icn_maprelease_channel(card, 0);
+ return 0;
+ }
+ }
}
/* Read the Status-replies from the Interface */
-static int icn_readstatus(u_char * buf, int len, int user, icn_card * card)
+static int
+icn_readstatus(u_char * buf, int len, int user, icn_card * card)
{
- int count;
- u_char *p;
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (card->msg_buf_read == card->msg_buf_write)
- return count;
- if (user)
- put_user(*card->msg_buf_read++, p);
- else
- *p = *card->msg_buf_read++;
- if (card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- return count;
+ int count;
+ u_char *p;
+
+ for (p = buf, count = 0; count < len; p++, count++) {
+ if (card->msg_buf_read == card->msg_buf_write)
+ return count;
+ if (user)
+ put_user(*card->msg_buf_read++, p);
+ else
+ *p = *card->msg_buf_read++;
+ if (card->msg_buf_read > card->msg_buf_end)
+ card->msg_buf_read = card->msg_buf;
+ }
+ return count;
}
/* Put command-strings into the command-queue of the Interface */
-static int icn_writecmd(const u_char * buf, int len, int user, icn_card * card)
+static int
+icn_writecmd(const u_char * buf, int len, int user, icn_card * card)
{
int mch = card->secondhalf ? 2 : 0;
- int avail;
- int pp;
- int i;
- int count;
- int xcount;
- int ocount;
- int loop;
- unsigned long flags;
- int lastmap_channel;
- struct icn_card *lastmap_card;
- u_char *p;
- isdn_ctrl cmd;
- u_char msg[0x100];
-
- ocount = 1;
- xcount = loop = 0;
- while (len) {
- save_flags(flags);
- cli();
- lastmap_card = dev.mcard;
- lastmap_channel = dev.channel;
- icn_map_channel(card, mch);
-
- avail = cmd_free;
- count = MIN(avail, len);
- if (user)
- copy_from_user(msg, buf, count);
- else
- memcpy(msg, buf, count);
- icn_putmsg(card, '>');
- for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
- ++) {
- writeb((*p == '\n') ? 0xff : *p,
- &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
- len--;
- xcount++;
- icn_putmsg(card, *p);
- if ((*p == '\n') && (i > 1)) {
- icn_putmsg(card, '>');
- ocount++;
- }
- ocount++;
- }
- writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
- if (lastmap_card)
- icn_map_channel(lastmap_card, lastmap_channel);
- restore_flags(flags);
- if (len) {
- udelay(1000);
- if (loop++ > 20)
- break;
- } else
- break;
- }
- if (len && (!user))
- printk(KERN_WARNING "icn: writemsg incomplete!\n");
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = ocount;
- card->interface.statcallb(&cmd);
- return xcount;
+ int avail;
+ int pp;
+ int i;
+ int count;
+ int xcount;
+ int ocount;
+ int loop;
+ unsigned long flags;
+ int lastmap_channel;
+ struct icn_card *lastmap_card;
+ u_char *p;
+ isdn_ctrl cmd;
+ u_char msg[0x100];
+
+ ocount = 1;
+ xcount = loop = 0;
+ while (len) {
+ save_flags(flags);
+ cli();
+ lastmap_card = dev.mcard;
+ lastmap_channel = dev.channel;
+ icn_map_channel(card, mch);
+
+ avail = cmd_free;
+ count = MIN(avail, len);
+ if (user)
+ copy_from_user(msg, buf, count);
+ else
+ memcpy(msg, buf, count);
+ icn_putmsg(card, '>');
+ for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
+ ++) {
+ writeb((*p == '\n') ? 0xff : *p,
+ &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
+ len--;
+ xcount++;
+ icn_putmsg(card, *p);
+ if ((*p == '\n') && (i > 1)) {
+ icn_putmsg(card, '>');
+ ocount++;
+ }
+ ocount++;
+ }
+ writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
+ if (lastmap_card)
+ icn_map_channel(lastmap_card, lastmap_channel);
+ restore_flags(flags);
+ if (len) {
+ udelay(1000);
+ if (loop++ > 20)
+ break;
+ } else
+ break;
+ }
+ if (len && (!user))
+ printk(KERN_WARNING "icn: writemsg incomplete!\n");
+ cmd.command = ISDN_STAT_STAVAIL;
+ cmd.driver = card->myid;
+ cmd.arg = ocount;
+ card->interface.statcallb(&cmd);
+ return xcount;
}
/*
* Delete card's pending timers, send STOP to linklevel
*/
-static void icn_stopcard(icn_card * card)
+static void
+icn_stopcard(icn_card * card)
{
- unsigned long flags;
- isdn_ctrl cmd;
-
- save_flags(flags);
- cli();
- if (card->flags & ICN_FLAGS_RUNNING) {
- card->flags &= ~ICN_FLAGS_RUNNING;
- del_timer(&card->st_timer);
- del_timer(&card->rb_timer);
- cmd.command = ISDN_STAT_STOP;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- if (card->doubleS0)
- icn_stopcard(card->other);
- }
- restore_flags(flags);
+ unsigned long flags;
+ isdn_ctrl cmd;
+
+ save_flags(flags);
+ cli();
+ if (card->flags & ICN_FLAGS_RUNNING) {
+ card->flags &= ~ICN_FLAGS_RUNNING;
+ del_timer(&card->st_timer);
+ del_timer(&card->rb_timer);
+ cmd.command = ISDN_STAT_STOP;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ if (card->doubleS0)
+ icn_stopcard(card->other);
+ }
+ restore_flags(flags);
}
-static void icn_stopallcards(void)
+static void
+icn_stopallcards(void)
{
- icn_card *p = cards;
+ icn_card *p = cards;
- while (p) {
- icn_stopcard(p);
- p = p->next;
- }
+ while (p) {
+ icn_stopcard(p);
+ p = p->next;
+ }
}
-static int icn_command(isdn_ctrl * c, icn_card * card)
+/*
+ * Unmap all cards, because some of them may be mapped accidetly during
+ * autoprobing of some network drivers (SMC-driver?)
+ */
+static void
+icn_disable_cards(void)
{
- ulong a;
- ulong flags;
- int i;
- char cbuf[60];
- isdn_ctrl cmd;
- icn_cdef cdef;
-
- switch (c->command) {
- case ISDN_CMD_IOCTL:
- memcpy(&a, c->num, sizeof(ulong));
- switch (c->arg) {
- case ICN_IOCTL_SETMMIO:
- if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {
- if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
- printk(KERN_WARNING
- "icn: memory at 0x%08lx in use.\n",
- (ulong) (a & 0x0ffc000));
- return -EINVAL;
- }
- icn_stopallcards();
- save_flags(flags);
- cli();
- if (dev.mvalid)
- release_shmem((ulong) dev.shmem, 0x4000);
- dev.mvalid = 0;
- dev.shmem = (icn_shmem *) (a & 0x0ffc000);
- restore_flags(flags);
- printk(KERN_INFO
- "icn: (%s) mmio set to 0x%08lx\n",
- CID,
- (unsigned long) dev.shmem);
- }
- break;
- case ICN_IOCTL_GETMMIO:
- return (long) dev.shmem;
- case ICN_IOCTL_SETPORT:
- if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
- || a == 0x340 || a == 0x350 || a == 0x360 ||
- a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
- || a == 0x348 || a == 0x358 || a == 0x368) {
- if (card->port != (unsigned short) a) {
- if (check_region((unsigned short) a, ICN_PORTLEN)) {
- printk(KERN_WARNING
- "icn: (%s) ports 0x%03x-0x%03x in use.\n",
- CID, (int) a, (int) a + ICN_PORTLEN);
- return -EINVAL;
- }
- icn_stopcard(card);
- save_flags(flags);
- cli();
- if (card->rvalid)
- release_region(card->port, ICN_PORTLEN);
- card->port = (unsigned short) a;
- card->rvalid = 0;
- if (card->doubleS0) {
- card->other->port = (unsigned short) a;
- card->other->rvalid = 0;
- }
- restore_flags(flags);
- printk(KERN_INFO
- "icn: (%s) port set to 0x%03x\n",
- CID, card->port);
- }
- } else
- return -EINVAL;
- break;
- case ICN_IOCTL_GETPORT:
- return (int) card->port;
- case ICN_IOCTL_GETDOUBLE:
- return (int) card->doubleS0;
- case ICN_IOCTL_DEBUGVAR:
- if ((i = verify_area(VERIFY_WRITE,
- (void *) a,
- sizeof(ulong) * 2)))
- return i;
- copy_from_user((char *)a,
- (char *)&card, sizeof(ulong));
- a += sizeof(ulong);
- {
- ulong l = (ulong)&dev;
- copy_from_user((char *)a,
- (char *)&l, sizeof(ulong));
- }
- return 0;
- case ICN_IOCTL_LOADBOOT:
- icn_stopcard(card);
- return (icn_loadboot((u_char *) a, card));
- case ICN_IOCTL_LOADPROTO:
- icn_stopcard(card);
- if ((i = (icn_loadproto((u_char *) a, card))))
- return i;
- if (card->doubleS0)
- i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other);
- return i;
- break;
- case ICN_IOCTL_ADDCARD:
- if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(icn_cdef))))
- return i;
- copy_from_user((char *)&cdef, (char *)a, sizeof(cdef));
- return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
- break;
- case ICN_IOCTL_LEASEDCFG:
- if (a) {
- if (!card->leased) {
- card->leased = 1;
- while (card->ptype == ISDN_PTYPE_UNKNOWN) {
- current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
- schedule();
- }
- current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
- schedule();
- sprintf(cbuf, "00;FV2ON\n01;EAZ1\n");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- printk(KERN_INFO
- "icn: (%s) Leased-line mode enabled\n",
- CID);
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- } else {
- if (card->leased) {
- card->leased = 0;
- sprintf(cbuf, "00;FV2OFF\n");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- printk(KERN_INFO
- "icn: (%s) Leased-line mode disabled\n",
- CID);
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- }
- return 0;
- default:
- return -EINVAL;
- }
- break;
- case ISDN_CMD_DIAL:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if (card->leased)
- break;
- if ((c->arg & 255) < ICN_BCH) {
- char *p;
- char *p2;
- char dial[50];
- char sis[50];
- char dcode[4];
- int si1, si2;
-
- a = c->arg;
- strcpy(sis, c->num);
- p = strrchr(sis, ',');
- *p++ = '\0';
- si2 = simple_strtoul(p,NULL,10);
- p = strrchr(sis, ',') + 1;
- si1 = simple_strtoul(p,NULL,10);
- p = c->num;
- if (*p == 's' || *p == 'S') {
- /* Dial for SPV */
- p++;
- strcpy(dcode, "SCA");
- } else
- /* Normal Dial */
- strcpy(dcode, "CAL");
- strcpy(dial, p);
- p = strchr(dial, ',');
- *p++ = '\0';
- p2 = strchr(p, ',');
- *p2 = '\0';
- sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), dcode, dial, si1,
- si2, p);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_ACCEPTD:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (card->fw_rev >= 300) {
- switch (card->l2_proto[a-1]) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int) a);
- break;
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int) a);
- break;
- }
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- sprintf(cbuf, "%02d;DCON_R\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_ACCEPTB:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (card->fw_rev >= 300)
- switch (card->l2_proto[a-1]) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
- break;
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
- break;
- }
- else
- sprintf(cbuf, "%02d;BCON_R\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_HANGUP:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_SETEAZ:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if (card->leased)
- break;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (card->ptype == ISDN_PTYPE_EURO) {
- sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
- c->num[0] ? "N" : "ALL", c->num);
- } else
- sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
- c->num[0] ? c->num : "0123456789");
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_CLREAZ:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if (card->leased)
- break;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (card->ptype == ISDN_PTYPE_EURO)
- sprintf(cbuf, "%02d;MSNC\n", (int) a);
- else
- sprintf(cbuf, "%02d;EAZC\n", (int) a);
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_SETL2:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if ((c->arg & 255) < ICN_BCH) {
- a = c->arg;
- switch (a >> 8) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
- break;
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
- break;
- default:
- return -EINVAL;
- }
- i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
- card->l2_proto[a & 255] = (a >> 8);
- }
- break;
- case ISDN_CMD_GETL2:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if ((c->arg & 255) < ICN_BCH)
- return card->l2_proto[c->arg & 255];
- else
- return -ENODEV;
- case ISDN_CMD_SETL3:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- return 0;
- case ISDN_CMD_GETL3:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- if ((c->arg & 255) < ICN_BCH)
- return ISDN_PROTO_L3_TRANS;
- else
- return -ENODEV;
- case ISDN_CMD_GETEAZ:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- break;
- case ISDN_CMD_SETSIL:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- break;
- case ISDN_CMD_GETSIL:
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- break;
- case ISDN_CMD_LOCK:
- MOD_INC_USE_COUNT;
- break;
- case ISDN_CMD_UNLOCK:
- MOD_DEC_USE_COUNT;
- break;
- default:
- return -EINVAL;
- }
- return 0;
+ icn_card *card = cards;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ while (card) {
+ if (check_region(card->port, ICN_PORTLEN)) {
+ printk(KERN_WARNING
+ "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+ CID,
+ card->port,
+ card->port + ICN_PORTLEN);
+ cli();
+ } else {
+ OUTB_P(0, ICN_RUN); /* Reset Controller */
+ OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
+ }
+ card = card->next;
+ }
+ restore_flags(flags);
+}
+
+static int
+icn_command(isdn_ctrl * c, icn_card * card)
+{
+ ulong a;
+ ulong flags;
+ int i;
+ char cbuf[60];
+ isdn_ctrl cmd;
+ icn_cdef cdef;
+
+ switch (c->command) {
+ case ISDN_CMD_IOCTL:
+ memcpy(&a, c->parm.num, sizeof(ulong));
+ switch (c->arg) {
+ case ICN_IOCTL_SETMMIO:
+ if ((unsigned long) dev.shmem != (a & 0x0ffc000)) {
+ if (check_shmem((ulong) (a & 0x0ffc000), 0x4000)) {
+ printk(KERN_WARNING
+ "icn: memory at 0x%08lx in use.\n",
+ (ulong) (a & 0x0ffc000));
+ return -EINVAL;
+ }
+ icn_stopallcards();
+ save_flags(flags);
+ cli();
+ if (dev.mvalid)
+ release_shmem((ulong) dev.shmem, 0x4000);
+ dev.mvalid = 0;
+ dev.shmem = (icn_shmem *) (a & 0x0ffc000);
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s) mmio set to 0x%08lx\n",
+ CID,
+ (unsigned long) dev.shmem);
+ }
+ break;
+ case ICN_IOCTL_GETMMIO:
+ return (long) dev.shmem;
+ case ICN_IOCTL_SETPORT:
+ if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
+ || a == 0x340 || a == 0x350 || a == 0x360 ||
+ a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
+ || a == 0x348 || a == 0x358 || a == 0x368) {
+ if (card->port != (unsigned short) a) {
+ if (check_region((unsigned short) a, ICN_PORTLEN)) {
+ printk(KERN_WARNING
+ "icn: (%s) ports 0x%03x-0x%03x in use.\n",
+ CID, (int) a, (int) a + ICN_PORTLEN);
+ return -EINVAL;
+ }
+ icn_stopcard(card);
+ save_flags(flags);
+ cli();
+ if (card->rvalid)
+ release_region(card->port, ICN_PORTLEN);
+ card->port = (unsigned short) a;
+ card->rvalid = 0;
+ if (card->doubleS0) {
+ card->other->port = (unsigned short) a;
+ card->other->rvalid = 0;
+ }
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s) port set to 0x%03x\n",
+ CID, card->port);
+ }
+ } else
+ return -EINVAL;
+ break;
+ case ICN_IOCTL_GETPORT:
+ return (int) card->port;
+ case ICN_IOCTL_GETDOUBLE:
+ return (int) card->doubleS0;
+ case ICN_IOCTL_DEBUGVAR:
+ if ((i = copy_to_user((char *) a,
+ (char *) &card, sizeof(ulong))))
+ return i;
+ a += sizeof(ulong);
+ {
+ ulong l = (ulong) & dev;
+ if ((i = copy_to_user((char *) a,
+ (char *) &l, sizeof(ulong))))
+ return i;
+ }
+ return 0;
+ case ICN_IOCTL_LOADBOOT:
+ if (dev.firstload) {
+ icn_disable_cards();
+ dev.firstload = 0;
+ }
+ icn_stopcard(card);
+ return (icn_loadboot((u_char *) a, card));
+ case ICN_IOCTL_LOADPROTO:
+ icn_stopcard(card);
+ if ((i = (icn_loadproto((u_char *) a, card))))
+ return i;
+ if (card->doubleS0)
+ i = icn_loadproto((u_char *) (a + ICN_CODE_STAGE2), card->other);
+ return i;
+ break;
+ case ICN_IOCTL_ADDCARD:
+ if (!dev.firstload)
+ return -EBUSY;
+ if ((i = copy_from_user((char *) &cdef, (char *) a, sizeof(cdef))))
+ return i;
+ return (icn_addcard(cdef.port, cdef.id1, cdef.id2));
+ break;
+ case ICN_IOCTL_LEASEDCFG:
+ if (a) {
+ if (!card->leased) {
+ card->leased = 1;
+ while (card->ptype == ISDN_PTYPE_UNKNOWN) {
+ current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+ schedule();
+ }
+ current->timeout = jiffies + ICN_BOOT_TIMEOUT1;
+ schedule();
+ sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n)02;EAZ%c\n",
+ (a & 1)?'1':'C', (a & 2)?'2':'C');
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ printk(KERN_INFO
+ "icn: (%s) Leased-line mode enabled\n",
+ CID);
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ card->interface.statcallb(&cmd);
+ }
+ } else {
+ if (card->leased) {
+ card->leased = 0;
+ sprintf(cbuf, "00;FV2OFF\n");
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ printk(KERN_INFO
+ "icn: (%s) Leased-line mode disabled\n",
+ CID);
+ cmd.command = ISDN_STAT_RUN;
+ cmd.driver = card->myid;
+ cmd.arg = 0;
+ card->interface.statcallb(&cmd);
+ }
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case ISDN_CMD_DIAL:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if ((c->arg & 255) < ICN_BCH) {
+ char *p;
+ char dial[50];
+ char dcode[4];
+
+ a = c->arg;
+ p = c->parm.setup.phone;
+ if (*p == 's' || *p == 'S') {
+ /* Dial for SPV */
+ p++;
+ strcpy(dcode, "SCA");
+ } else
+ /* Normal Dial */
+ strcpy(dcode, "CAL");
+ strcpy(dial, p);
+ sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
+ dcode, dial, c->parm.setup.si1,
+ c->parm.setup.si2, c->parm.setup.eazmsn);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_ACCEPTD:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ if (card->fw_rev >= 300) {
+ switch (card->l2_proto[a - 1]) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BX75\n", (int) a);
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BTRA\n", (int) a);
+ break;
+ }
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ sprintf(cbuf, "%02d;DCON_R\n", (int) a);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_ACCEPTB:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ if (card->fw_rev >= 300)
+ switch (card->l2_proto[a - 1]) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);
+ break;
+ } else
+ sprintf(cbuf, "%02d;BCON_R\n", (int) a);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_HANGUP:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_SETEAZ:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ if (card->ptype == ISDN_PTYPE_EURO) {
+ sprintf(cbuf, "%02d;MS%s%s\n", (int) a,
+ c->parm.num[0] ? "N" : "ALL", c->parm.num);
+ } else
+ sprintf(cbuf, "%02d;EAZ%s\n", (int) a,
+ c->parm.num[0] ? c->parm.num : "0123456789");
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_CLREAZ:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if (card->leased)
+ break;
+ if (c->arg < ICN_BCH) {
+ a = c->arg + 1;
+ if (card->ptype == ISDN_PTYPE_EURO)
+ sprintf(cbuf, "%02d;MSNC\n", (int) a);
+ else
+ sprintf(cbuf, "%02d;EAZC\n", (int) a);
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ }
+ break;
+ case ISDN_CMD_SETL2:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ICN_BCH) {
+ a = c->arg;
+ switch (a >> 8) {
+ case ISDN_PROTO_L2_X75I:
+ sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ i = icn_writecmd(cbuf, strlen(cbuf), 0, card);
+ card->l2_proto[a & 255] = (a >> 8);
+ }
+ break;
+ case ISDN_CMD_GETL2:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ICN_BCH)
+ return card->l2_proto[c->arg & 255];
+ else
+ return -ENODEV;
+ case ISDN_CMD_SETL3:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ return 0;
+ case ISDN_CMD_GETL3:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ if ((c->arg & 255) < ICN_BCH)
+ return ISDN_PROTO_L3_TRANS;
+ else
+ return -ENODEV;
+ case ISDN_CMD_GETEAZ:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_SETSIL:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_GETSIL:
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ break;
+ case ISDN_CMD_LOCK:
+ MOD_INC_USE_COUNT;
+ break;
+ case ISDN_CMD_UNLOCK:
+ MOD_DEC_USE_COUNT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
/*
* Find card with given driverId
*/
static inline icn_card *
- icn_findcard(int driverid)
+icn_findcard(int driverid)
{
- icn_card *p = cards;
-
- while (p) {
- if (p->myid == driverid)
- return p;
- p = p->next;
- }
- return (icn_card *)0;
+ icn_card *p = cards;
+
+ while (p) {
+ if (p->myid == driverid)
+ return p;
+ p = p->next;
+ }
+ return (icn_card *) 0;
}
/*
* Wrapper functions for interface to linklevel
*/
-static int if_command(isdn_ctrl * c)
+static int
+if_command(isdn_ctrl * c)
{
- icn_card *card = icn_findcard(c->driver);
-
- if (card)
- return (icn_command(c, card));
- printk(KERN_ERR
- "icn: if_command %d called with invalid driverId %d!\n",
- c->command, c->driver);
- return -ENODEV;
+ icn_card *card = icn_findcard(c->driver);
+
+ if (card)
+ return (icn_command(c, card));
+ printk(KERN_ERR
+ "icn: if_command %d called with invalid driverId %d!\n",
+ c->command, c->driver);
+ return -ENODEV;
}
-static int if_writecmd(const u_char * buf, int len, int user, int id, int channel)
+static int
+if_writecmd(const u_char * buf, int len, int user, int id, int channel)
{
- icn_card *card = icn_findcard(id);
-
- if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- return (icn_writecmd(buf, len, user, card));
- }
- printk(KERN_ERR
- "icn: if_writecmd called with invalid driverId!\n");
- return -ENODEV;
+ icn_card *card = icn_findcard(id);
+
+ if (card) {
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ return (icn_writecmd(buf, len, user, card));
+ }
+ printk(KERN_ERR
+ "icn: if_writecmd called with invalid driverId!\n");
+ return -ENODEV;
}
-static int if_readstatus(u_char * buf, int len, int user, int id, int channel)
+static int
+if_readstatus(u_char * buf, int len, int user, int id, int channel)
{
- icn_card *card = icn_findcard(id);
-
- if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- return (icn_readstatus(buf, len, user, card));
- }
- printk(KERN_ERR
- "icn: if_readstatus called with invalid driverId!\n");
- return -ENODEV;
+ icn_card *card = icn_findcard(id);
+
+ if (card) {
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ return (icn_readstatus(buf, len, user, card));
+ }
+ printk(KERN_ERR
+ "icn: if_readstatus called with invalid driverId!\n");
+ return -ENODEV;
}
-static int if_sendbuf(int id, int channel, struct sk_buff *skb)
+static int
+if_sendbuf(int id, int channel, struct sk_buff *skb)
{
- icn_card *card = icn_findcard(id);
-
- if (card) {
- if (!card->flags & ICN_FLAGS_RUNNING)
- return -ENODEV;
- return (icn_sendbuf(channel, skb, card));
- }
- printk(KERN_ERR
- "icn: if_sendbuf called with invalid driverId!\n");
- return -ENODEV;
+ icn_card *card = icn_findcard(id);
+
+ if (card) {
+ if (!card->flags & ICN_FLAGS_RUNNING)
+ return -ENODEV;
+ return (icn_sendbuf(channel, skb, card));
+ }
+ printk(KERN_ERR
+ "icn: if_sendbuf called with invalid driverId!\n");
+ return -ENODEV;
}
/*
* Allocate a new card-struct, initialize it
* link it into cards-list and register it at linklevel.
*/
-static icn_card *icn_initcard(int port, char *id) {
- icn_card *card;
- int i;
-
- if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
- printk(KERN_WARNING
- "icn: (%s) Could not allocate card-struct.\n", id);
- return (icn_card *)0;
- }
- memset((char *) card, 0, sizeof(icn_card));
- card->port = port;
- card->interface.channels = ICN_BCH;
- card->interface.maxbufsize = 4000;
- card->interface.command = if_command;
+static icn_card *
+icn_initcard(int port, char *id)
+{
+ icn_card *card;
+ int i;
+
+ if (!(card = (icn_card *) kmalloc(sizeof(icn_card), GFP_KERNEL))) {
+ printk(KERN_WARNING
+ "icn: (%s) Could not allocate card-struct.\n", id);
+ return (icn_card *) 0;
+ }
+ memset((char *) card, 0, sizeof(icn_card));
+ card->port = port;
+ card->interface.channels = ICN_BCH;
+ card->interface.maxbufsize = 4000;
+ card->interface.command = if_command;
card->interface.writebuf_skb = if_sendbuf;
- card->interface.writecmd = if_writecmd;
- card->interface.readstat = if_readstatus;
- card->interface.features = ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_UNKNOWN;
- card->ptype = ISDN_PTYPE_UNKNOWN;
- strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
- card->msg_buf_write = card->msg_buf;
- card->msg_buf_read = card->msg_buf;
- card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
- for (i=0;i<ICN_BCH;i++) {
- card->l2_proto[i] = ISDN_PROTO_L2_X75I;
- skb_queue_head_init(&card->spqueue[i]);
- }
- card->next = cards;
- cards = card;
- if (!register_isdn(&card->interface)) {
- cards = cards->next;
- printk(KERN_WARNING
- "icn: Unable to register %s\n", id);
- kfree(card);
- return (icn_card*)0;
- }
- card->myid = card->interface.channels;
- sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
- return card;
+ card->interface.writecmd = if_writecmd;
+ card->interface.readstat = if_readstatus;
+ card->interface.features = ISDN_FEATURE_L2_X75I |
+ ISDN_FEATURE_L2_HDLC |
+ ISDN_FEATURE_L3_TRANS |
+ ISDN_FEATURE_P_UNKNOWN;
+ card->ptype = ISDN_PTYPE_UNKNOWN;
+ strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
+ card->msg_buf_write = card->msg_buf;
+ card->msg_buf_read = card->msg_buf;
+ card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
+ for (i = 0; i < ICN_BCH; i++) {
+ card->l2_proto[i] = ISDN_PROTO_L2_X75I;
+ skb_queue_head_init(&card->spqueue[i]);
+ }
+ card->next = cards;
+ cards = card;
+ if (!register_isdn(&card->interface)) {
+ cards = cards->next;
+ printk(KERN_WARNING
+ "icn: Unable to register %s\n", id);
+ kfree(card);
+ return (icn_card *) 0;
+ }
+ card->myid = card->interface.channels;
+ sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
+ return card;
}
-static int icn_addcard(int port, char *id1, char *id2)
+static int
+icn_addcard(int port, char *id1, char *id2)
{
- ulong flags;
- icn_card *card;
- icn_card *card2;
-
- save_flags(flags);
- cli();
- if (!(card = icn_initcard(port,id1))) {
- restore_flags(flags);
- return -EIO;
- }
- if (!strlen(id2)) {
- restore_flags(flags);
- printk(KERN_INFO
- "icn: (%s) ICN-2B, port 0x%x added\n",
- card->interface.id, port);
- return 0;
- }
- if (!(card2 = icn_initcard(port,id2))) {
- restore_flags(flags);
- printk(KERN_INFO
- "icn: (%s) half ICN-4B, port 0x%x added\n",
- card2->interface.id, port);
- return 0;
- }
- card->doubleS0 = 1;
- card->secondhalf = 0;
- card->other = card2;
- card2->doubleS0 = 1;
- card2->secondhalf = 1;
- card2->other = card;
- restore_flags(flags);
- printk(KERN_INFO
- "icn: (%s and %s) ICN-4B, port 0x%x added\n",
- card->interface.id, card2->interface.id, port);
- return 0;
+ ulong flags;
+ icn_card *card;
+ icn_card *card2;
+
+ save_flags(flags);
+ cli();
+ if (!(card = icn_initcard(port, id1))) {
+ restore_flags(flags);
+ return -EIO;
+ }
+ if (!strlen(id2)) {
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s) ICN-2B, port 0x%x added\n",
+ card->interface.id, port);
+ return 0;
+ }
+ if (!(card2 = icn_initcard(port, id2))) {
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s) half ICN-4B, port 0x%x added\n",
+ card2->interface.id, port);
+ return 0;
+ }
+ card->doubleS0 = 1;
+ card->secondhalf = 0;
+ card->other = card2;
+ card2->doubleS0 = 1;
+ card2->secondhalf = 1;
+ card2->other = card;
+ restore_flags(flags);
+ printk(KERN_INFO
+ "icn: (%s and %s) ICN-4B, port 0x%x added\n",
+ card->interface.id, card2->interface.id, port);
+ return 0;
}
#ifdef MODULE
#define icn_init init_module
#else
-void icn_setup(char *str, int *ints)
+void
+icn_setup(char *str, int *ints)
{
- char *p;
- static char sid[20];
- static char sid2[20];
-
- if (ints[0])
- portbase = ints[1];
- if (ints[0]>1)
- membase = ints[2];
- if (strlen(str)) {
- strcpy(sid,str);
- icn_id = sid;
- if ((p = strchr(sid,','))) {
- *p++ = 0;
- strcpy(sid2,p);
- icn_id2 = sid2;
- }
- }
+ char *p;
+ static char sid[20];
+ static char sid2[20];
+
+ if (ints[0])
+ portbase = ints[1];
+ if (ints[0] > 1)
+ membase = ints[2];
+ if (strlen(str)) {
+ strcpy(sid, str);
+ icn_id = sid;
+ if ((p = strchr(sid, ','))) {
+ *p++ = 0;
+ strcpy(sid2, p);
+ icn_id2 = sid2;
+ }
+ }
}
#endif
-int icn_init(void)
+int
+icn_init(void)
{
- char *p;
- char rev[10];
-
- memset(&dev, 0, sizeof(icn_dev));
- dev.shmem = (icn_shmem *) ((unsigned long)membase & 0x0ffc000);
- dev.channel = -1;
- dev.mcard = NULL;
-
- /* No symbols to export, hide all symbols */
- register_symtab(NULL);
-
- if ((p = strchr(revision, ':'))) {
- strcpy(rev, p + 1);
- p = strchr(rev, '$');
- *p = 0;
- } else
- strcpy(rev, " ??? ");
- printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
- (ulong) dev.shmem);
- return (icn_addcard(portbase,icn_id,icn_id2));
+ char *p;
+ char rev[10];
+
+ memset(&dev, 0, sizeof(icn_dev));
+ dev.shmem = (icn_shmem *) ((unsigned long) membase & 0x0ffc000);
+ dev.channel = -1;
+ dev.mcard = NULL;
+ dev.firstload = 1;
+
+ /* No symbols to export, hide all symbols */
+#if (LINUX_VERSION_CODE < 0x020111)
+ register_symtab(NULL);
+#else
+ EXPORT_NO_SYMBOLS;
+#endif
+
+ if ((p = strchr(revision, ':'))) {
+ strcpy(rev, p + 1);
+ p = strchr(rev, '$');
+ *p = 0;
+ } else
+ strcpy(rev, " ??? ");
+ printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
+ (ulong) dev.shmem);
+ return (icn_addcard(portbase, icn_id, icn_id2));
}
#ifdef MODULE
-void cleanup_module(void)
+void
+cleanup_module(void)
{
- isdn_ctrl cmd;
- icn_card *card = cards;
- icn_card *last;
- int i;
-
- icn_stopallcards();
- while (card) {
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- if (card->rvalid) {
- OUTB_P(0, ICN_RUN); /* Reset Controller */
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- if (card->secondhalf || (!card->doubleS0)) {
- release_region(card->port, ICN_PORTLEN);
- card->rvalid = 0;
- }
- for (i = 0; i < ICN_BCH; i++)
- icn_free_queue(&card->spqueue[i]);
- }
- card = card->next;
- }
- card = cards;
- while (card) {
- last = card;
- card = card->next;
- kfree(last);
- }
- if (dev.mvalid)
- release_shmem((ulong) dev.shmem, 0x4000);
- printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
+ isdn_ctrl cmd;
+ icn_card *card = cards;
+ icn_card *last;
+ int i;
+
+ icn_stopallcards();
+ while (card) {
+ cmd.command = ISDN_STAT_UNLOAD;
+ cmd.driver = card->myid;
+ card->interface.statcallb(&cmd);
+ if (card->rvalid) {
+ OUTB_P(0, ICN_RUN); /* Reset Controller */
+ OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
+ if (card->secondhalf || (!card->doubleS0)) {
+ release_region(card->port, ICN_PORTLEN);
+ card->rvalid = 0;
+ }
+ for (i = 0; i < ICN_BCH; i++)
+ icn_free_queue(card, i);
+ }
+ card = card->next;
+ }
+ card = cards;
+ while (card) {
+ last = card;
+ card = card->next;
+ kfree(last);
+ }
+ if (dev.mvalid)
+ release_shmem((ulong) dev.shmem, 0x4000);
+ printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
}
#endif
-/* $Id: icn.h,v 1.22 1996/11/13 02:37:33 fritz Exp $
- *
+/* $Id: icn.h,v 1.26 1997/02/14 12:23:16 fritz Exp $
+
* ISDN lowlevel-module for the ICN active ISDN-Card.
*
* Copyright 1994 by Fritz Elfert (fritz@wuemaus.franken.de)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: icn.h,v $
+ * 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.
*
/* Struct for adding new cards */
typedef struct icn_cdef {
- int port;
- char id1[10];
- char id2[10];
+ int port;
+ char id1[10];
+ char id2[10];
} icn_cdef;
#if defined(__KERNEL__) || defined(__DEBUGVAR__)
#include <linux/delay.h>
#include <linux/isdnif.h>
-#endif /* __KERNEL__ */
+#endif /* __KERNEL__ */
/* some useful macros for debugging */
#ifdef ICN_DEBUG_PORT
#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_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 100 /* Delay for Boot-download (jiffies) */
-#define ICN_CHANLOCK_DELAY 10 /* Delay for Channel-mapping (jiffies) */
+#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 1 /* B-Channel poll-cycle */
-#define ICN_TIMER_DCREAD 50 /* D-Channel poll-cycle */
+#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_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 */
+#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 */
+#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];
+ 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;
+ 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 */
- 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() */
+ 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 */
+ 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 */
+ 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_card *cards = (icn_card *) 0;
+static u_char chan2bank[] =
+{0, 4, 8, 12}; /* for icn_map_channel() */
-static icn_dev dev;
+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.
*/
-int portbase = ICN_BASEADDR;
-int membase = ICN_MEMADDR;
-char *icn_id = "\0";
-char *icn_id2 = "\0";
+static int portbase = ICN_BASEADDR;
+static int membase = ICN_MEMADDR;
+static char *icn_id = "\0";
+static char *icn_id2 = "\0";
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE > 0x020111)
+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
-#endif /* __KERNEL__ */
+#endif /* __KERNEL__ */
/* Utility-Macros */
/* 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))
+ 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))
+ &dev.shmem->data_control.scns))
/* Shortcuts for transmit-buffer-access */
#define sbuf_n dev.shmem->data_control.scns
/* Return true, if there is receive-data is available */
#define rbavl (readb(&dev.shmem->data_control.ecnr) != \
- readb(&dev.shmem->data_control.ecns))
+ 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))
+ &dev.shmem->data_control.ecnr))
/* Shortcuts for receive-buffer-access */
#define rbuf_n dev.shmem->data_control.ecnr
/* 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))
+ 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)
/* 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))
+ 0x100-readb(&msg_o)+readb(&msg_i): \
+ readb(&msg_i)-readb(&msg_o))
#define CID (card->interface.id)
#define release_shmem release_region
#define request_shmem request_region
-#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif /* icn_h */
+#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
+#endif /* icn_h */
-/* $Id: isdn_audio.c,v 1.6 1996/06/06 14:43:31 fritz Exp $
- *
+/* $Id: isdn_audio.c,v 1.8 1997/03/02 14:29:16 fritz Exp $
+
* Linux ISDN subsystem, audio conversion and compression (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
- *
+ *
* 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)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_audio.c,v $
+ * 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.
*
#include "isdn_audio.h"
#include "isdn_common.h"
-char *isdn_audio_revision = "$Revision: 1.6 $";
+char *isdn_audio_revision = "$Revision: 1.8 $";
/*
* 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
+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
+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
+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
+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 HIGRP 1
typedef struct {
- int grp; /* low/high group */
- int k; /* k */
- int k2; /* k fuer 2. harmonic */
+ 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 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 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'}
+static char dtmf_matrix[4][4] =
+{
+ {'1', '2', '3', 'A'},
+ {'4', '5', '6', 'B'},
+ {'7', '8', '9', 'C'},
+ {'*', '0', '#', 'D'}
};
#if ((CPU == 386) || (CPU == 486) || (CPU == 586))
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");
+ __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[*buff];
+ while (n--)
+ *buff++ = table[*buff];
}
#endif
void
isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len)
{
- isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, 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);
+ isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len);
}
/*
*/
-#define ZEROTRAP /* turn on the trap as per the MIL-STD */
+#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 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);
+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;
+ /* optional CCITT trap */
+ if (ulawbyte == 0)
+ ulawbyte = 0x02;
#endif
- return(ulawbyte);
+ 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 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 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)
+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];
+ 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)
+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;
- }
+ 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)
+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;
+ 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)
+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;
+ 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)
+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 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)
+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;
+ 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)
+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;
- }
+ 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;
+ return olen;
}
/*
* Result is stored into an sk_buff and queued up for later
* evaluation.
*/
-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);
- skb->free = 1;
- skb->users = 0;
- 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);
+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;
+ }
+ SET_SKB_FREE(skb);
+ 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)
+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);
- 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, FREE_READ);
- s->last = what;
- }
+ 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, FREE_READ);
+ 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, FREE_READ);
+ s->last = what;
+ }
}
/*
* fmt = audio data format (0 = ulaw, 1 = alaw)
*/
void
-isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt)
+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;
- }
+ 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;
+ }
}
-
-
-/* $Id: isdn_audio.h,v 1.4 1996/06/06 14:43:32 fritz Exp $
- *
+/* $Id: isdn_audio.h,v 1.5 1997/02/03 22:45:21 fritz Exp $
+
* Linux ISDN subsystem, audio conversion and compression (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_audio.h,v $
+ * 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.
*
*
*/
-#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
+#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */
typedef struct adpcm_state {
- int a;
- int d;
- int word;
- int nleft;
- int nbits;
+ int a;
+ int d;
+ int word;
+ int nleft;
+ int nbits;
} adpcm_state;
typedef struct dtmf_state {
- char last;
- int idx;
- int buf[DTMF_NPOINTS];
+ char last;
+ int idx;
+ int buf[DTMF_NPOINTS];
} dtmf_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 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 *);
-/* $Id: isdn_cards.c,v 1.2 1996/10/13 19:52:17 keil Exp $
- *
+/* $Id: isdn_cards.c,v 1.6 1997/04/23 18:56:03 fritz Exp $
+
* Linux ISDN subsystem, initialization for non-modularized drivers.
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_cards.c,v $
+ * 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
*
extern void icn_init(void);
#endif
-#ifdef CONFIG_ISDN_DRV_TELES
-extern void teles_init(void);
-#endif
-
#ifdef CONFIG_ISDN_DRV_HISAX
extern void HiSax_init(void);
#endif
extern void pcbit_init(void);
#endif
-void isdn_cards_init(void)
+#ifdef CONFIG_ISDN_DRV_AVMB1
+extern void avmb1_init(void);
+extern void capi_init(void);
+extern void capidrv_init(void);
+#ifdef CONFIG_PCI
+extern int b1pci_init(void);
+#endif
+#endif
+
+void
+isdn_cards_init(void)
{
#if CONFIG_ISDN_DRV_ICN
- icn_init();
-#endif
-#if CONFIG_ISDN_DRV_TELES
- teles_init();
+ icn_init();
#endif
#ifdef CONFIG_ISDN_DRV_HISAX
HiSax_init();
#endif
#if CONFIG_ISDN_DRV_PCBIT
- pcbit_init();
+ pcbit_init();
+#endif
+#ifdef CONFIG_ISDN_DRV_AVMB1
+ avmb1_init();
+#ifdef CONFIG_PCI
+ b1pci_init();
+#endif
+ capi_init();
+ capidrv_init();
#endif
}
-
-/* $Id: isdn_cards.h,v 1.1 1996/04/20 16:04:03 fritz Exp $
- *
+/* $Id: isdn_cards.h,v 1.2 1997/02/03 23:31:55 fritz Exp $
+
* Linux ISDN subsystem, initialization for non-modularized drivers.
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.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)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_cards.h,v $
+ * 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);
-
-/* $Id: isdn_common.c,v 1.28 1996/11/13 02:33:19 fritz Exp $
- *
+/* $Id: isdn_common.c,v 1.44 1997/05/27 15:17:23 fritz Exp $
+
* Linux ISDN subsystem, common used functions (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.44 1997/05/27 15:17:23 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.43 1997/03/31 14:09:43 fritz
+ * Fixed memory leak in isdn_close().
+ *
+ * Revision 1.42 1997/03/30 16:51:08 calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.41 1997/03/24 22:54:41 fritz
+ * Some small fixes in debug code.
+ *
+ * Revision 1.40 1997/03/08 08:13:51 fritz
+ * Bugfix: IIOCSETMAP (Set mapping) was broken.
+ *
+ * Revision 1.39 1997/03/07 01:32:54 fritz
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.38 1997/03/05 21:15:02 fritz
+ * Fix: reduced stack usage of isdn_ioctl() and isdn_set_allcfg()
+ *
+ * Revision 1.37 1997/03/02 14:29:18 fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.36 1997/02/28 02:32:40 fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ * to isdn_tty.c
+ * Bugfix: Bisync protocol did not behave like documented.
+ *
+ * Revision 1.35 1997/02/21 13:01:19 fritz
+ * Changes CAUSE message output in kernel log.
+ *
+ * Revision 1.34 1997/02/10 20:12:43 fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.33 1997/02/10 10:05:42 fritz
+ * More changes for Kernel 2.1.X
+ * Symbol information moved to isdn_syms.c
+ *
+ * Revision 1.32 1997/02/03 22:55:26 fritz
+ * Reformatted according CodingStyle.
+ * Changed isdn_writebuf_stub static.
+ * Slow down tty-RING counter.
+ * skb->free stuff replaced by macro.
+ * Bugfix in audio-skb locking.
+ * Bugfix in HL-driver locking.
+ *
+ * Revision 1.31 1997/01/17 01:19:18 fritz
+ * Applied chargeint patch.
+ *
+ * Revision 1.30 1997/01/14 01:27:47 fritz
+ * Changed audio receive not to rely on skb->users and skb->lock.
+ * Added ATI2 and related variables.
+ * Started adding full-duplex audio capability.
+ *
+ * Revision 1.29 1997/01/12 23:33:03 fritz
+ * Made isdn_all_eaz foolproof.
+ *
* Revision 1.28 1996/11/13 02:33:19 fritz
* Fixed a race condition.
*
*/
#include <linux/config.h>
+#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
-#ifndef __GENKSYMS__ /* Don't want genksyms report unneeded structs */
-#include <linux/isdn.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <asm/poll.h>
#endif
+#include <linux/isdn.h>
#include "isdn_common.h"
#include "isdn_tty.h"
#include "isdn_net.h"
#include "isdn_cards.h"
/* Debugflags */
-#undef ISDN_DEBUG_STATCALLB
-#define NEW_ISDN_TIMER_CTRL
+#undef ISDN_DEBUG_STATCALLB
isdn_dev *dev = (isdn_dev *) 0;
-static int has_exported = 0;
-static char *isdn_revision = "$Revision: 1.28 $";
+static char *isdn_revision = "$Revision: 1.44 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
static char *isdn_audio_revision = ": none $";
#endif
-void isdn_MOD_INC_USE_COUNT(void)
+static int isdn_writebuf_stub(int, int, const u_char *, int, int);
+
+void
+isdn_MOD_INC_USE_COUNT(void)
{
MOD_INC_USE_COUNT;
}
-void isdn_MOD_DEC_USE_COUNT(void)
+void
+isdn_MOD_DEC_USE_COUNT(void)
{
MOD_DEC_USE_COUNT;
}
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-void isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
+void
+isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
{
int dumpc;
}
#endif
-static __inline void isdn_trash_skb(struct sk_buff *skb, int rw)
+static __inline void
+isdn_trash_skb(struct sk_buff *skb, int rw)
{
- skb->free = 1;
- kfree_skb(skb, rw);
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, rw);
}
-static void isdn_free_queue(struct sk_buff_head *queue)
+static void
+isdn_free_queue(struct sk_buff_head *queue)
{
- struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (skb_queue_len(queue))
- while ((skb = skb_dequeue(queue)))
- isdn_trash_skb(skb, FREE_READ);
- restore_flags(flags);
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (skb_queue_len(queue))
+ while ((skb = skb_dequeue(queue)))
+ isdn_trash_skb(skb, FREE_READ);
+ restore_flags(flags);
}
-int isdn_dc2minor(int di, int ch)
+int
+isdn_dc2minor(int di, int ch)
{
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
static int isdn_timer_cnt1 = 0;
static int isdn_timer_cnt2 = 0;
+static int isdn_timer_cnt3 = 0;
-static void isdn_timer_funct(ulong dummy)
+static void
+isdn_timer_funct(ulong dummy)
{
int tf = dev->tflags;
if (tf & ISDN_TIMER_NETDIAL)
isdn_net_dial();
}
- if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
- isdn_timer_cnt2 = 0;
- if (tf & ISDN_TIMER_NETHANGUP)
- isdn_net_autohup();
- if (tf & ISDN_TIMER_MODEMRING)
- isdn_tty_modem_ring();
+ if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
+ isdn_timer_cnt2 = 0;
+ if (tf & ISDN_TIMER_NETHANGUP)
+ isdn_net_autohup();
+ if (++isdn_timer_cnt3 > ISDN_TIMER_RINGING) {
+ isdn_timer_cnt3 = 0;
+ if (tf & ISDN_TIMER_MODEMRING)
+ isdn_tty_modem_ring();
+ }
#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
- if (tf & ISDN_TIMER_IPPP)
- isdn_ppp_timer_timeout();
+ if (tf & ISDN_TIMER_IPPP)
+ isdn_ppp_timer_timeout();
#endif
- }
+ }
}
if (tf) {
- int flags;
+ int flags;
save_flags(flags);
cli();
- del_timer(&dev->timer);
-#ifndef NEW_ISDN_TIMER_CTRL
- dev->timer.function = isdn_timer_funct;
-#endif
+ del_timer(&dev->timer);
dev->timer.expires = jiffies + ISDN_TIMER_RES;
add_timer(&dev->timer);
restore_flags(flags);
}
}
-void isdn_timer_ctrl(int tf, int onoff)
+void
+isdn_timer_ctrl(int tf, int onoff)
{
int flags;
dev->tflags |= tf;
else
dev->tflags &= ~tf;
-#ifdef NEW_ISDN_TIMER_CTRL
if (dev->tflags) {
- if (!del_timer(&dev->timer)) /* del_timer is 1, when active */
- dev->timer.expires = jiffies + ISDN_TIMER_RES;
+ if (!del_timer(&dev->timer)) /* del_timer is 1, when active */
+ dev->timer.expires = jiffies + ISDN_TIMER_RES;
add_timer(&dev->timer);
}
-#else
- if (dev->tflags) {
- del_timer(&dev->timer);
- dev->timer.function = isdn_timer_funct;
- dev->timer.expires = jiffies + ISDN_TIMER_RES;
- add_timer(&dev->timer);
- }
-#endif
restore_flags(flags);
}
/*
* Receive a packet from B-Channel. (Called from low-level-module)
*/
-static void isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
+static void
+isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
{
- ulong flags;
int i;
- int midx;
-#ifdef CONFIG_ISDN_AUDIO
- int ifmt;
-#endif
- modem_info *info;
-
- if ((i = isdn_dc2minor(di,channel))==-1) {
- isdn_trash_skb(skb, FREE_READ);
- return;
- }
+
+ if ((i = isdn_dc2minor(di, channel)) == -1) {
+ isdn_trash_skb(skb, FREE_READ);
+ return;
+ }
/* Update statistics */
- dev->ibytes[i] += skb->len;
+ dev->ibytes[i] += skb->len;
/* First, try to deliver data to network-device */
if (isdn_net_rcv_skb(i, skb))
return;
/* No network-device found, deliver to tty or raw-channel */
- skb->free = 1;
+ SET_SKB_FREE(skb);
if (skb->len) {
- if ((midx = dev->m_idx[i])<0) {
- /* if midx is invalid, drop packet */
- isdn_trash_skb(skb, FREE_READ);
- return;
- }
- info = &dev->mdm.info[midx];
-#ifdef CONFIG_ISDN_AUDIO
- ifmt = 1;
-
- if (info->vonline)
- isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
-#endif
- if ((info->online < 2) &&
- (!(info->vonline & 1))) {
- /* If Modem not listening, drop data */
- isdn_trash_skb(skb, FREE_READ);
- return;
- }
- if (info->emu.mdmreg[13] & 2)
- /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
- if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
- skb_pull(skb,4);
- /* The users field of an sk_buff is used in a special way
- * with tty's incoming data:
- * users is set to the number of DLE codes when in audio mode.
- */
- skb->users = 0;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 1) {
- /* voice conversion/compression */
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm
- * Since compressed data takes less
- * space, we can overwrite the buffer.
- */
- skb_trim(skb,isdn_audio_xlaw2adpcm(info->adpcmr,
- ifmt,
- skb->data,
- skb->data,
- skb->len));
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_ulaw2alaw(skb->data,skb->len);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_alaw2ulaw(skb->data,skb->len);
- break;
- }
- skb->users = isdn_tty_countDLE(skb->data,skb->len);
- }
-#endif
- /* Try to deliver directly via tty-flip-buf if queue is empty */
- save_flags(flags);
- cli();
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
- if (isdn_tty_try_read(info, skb)) {
- restore_flags(flags);
- return;
- }
- /* Direct deliver failed or queue wasn't empty.
- * Queue up for later dequeueing via timer-irq.
- */
- __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
- dev->drv[di]->rcvcount[channel] += (skb->len + skb->users);
- 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[channel]);
+ if (isdn_tty_rcv_skb(i, di, channel, skb))
+ return;
+ wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
} else
- isdn_trash_skb(skb, FREE_READ);
+ isdn_trash_skb(skb, FREE_READ);
}
-void isdn_all_eaz(int di, int ch)
+void
+isdn_all_eaz(int di, int ch)
{
isdn_ctrl cmd;
+ if (di < 0)
+ return;
cmd.driver = di;
cmd.arg = ch;
cmd.command = ISDN_CMD_SETEAZ;
- cmd.num[0] = '\0';
+ cmd.parm.num[0] = '\0';
(void) dev->drv[di]->interface->command(&cmd);
}
-static int isdn_status_callback(isdn_ctrl * c)
+static int
+isdn_status_callback(isdn_ctrl * c)
{
int di;
- int mi;
ulong flags;
int i;
int r;
- int retval=0;
- modem_info *info;
+ int retval = 0;
isdn_ctrl cmd;
di = c->driver;
- i = isdn_dc2minor(di, c->arg);
+ i = isdn_dc2minor(di, c->arg);
switch (c->command) {
- case ISDN_STAT_BSENT:
- if (i<0)
+ case ISDN_STAT_BSENT:
+ if (i < 0)
return -1;
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c->command))
- return 0;
- isdn_tty_bsent(di, c->arg);
- wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
- break;
- case ISDN_STAT_STAVAIL:
- save_flags(flags);
- cli();
- dev->drv[di]->stavail += c->arg;
- restore_flags(flags);
- wake_up_interruptible(&dev->drv[di]->st_waitq);
- break;
- case ISDN_STAT_RUN:
- dev->drv[di]->running = 1;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di)
- isdn_all_eaz(di, dev->chanmap[i]);
- break;
- case ISDN_STAT_STOP:
- dev->drv[di]->running = 0;
- break;
- case ISDN_STAT_ICALL:
- if (i<0)
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ if (isdn_net_stat_callback(i, c->command))
+ return 0;
+ if (isdn_tty_stat_callback(i, c))
+ return 0;
+ wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
+ break;
+ case ISDN_STAT_STAVAIL:
+ save_flags(flags);
+ cli();
+ dev->drv[di]->stavail += c->arg;
+ restore_flags(flags);
+ wake_up_interruptible(&dev->drv[di]->st_waitq);
+ break;
+ case ISDN_STAT_RUN:
+ dev->drv[di]->running = 1;
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ if (dev->drvmap[i] == di)
+ isdn_all_eaz(di, dev->chanmap[i]);
+ break;
+ case ISDN_STAT_STOP:
+ dev->drv[di]->running = 0;
+ break;
+ case ISDN_STAT_ICALL:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->num);
+ printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
- return 0;
- }
-
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED) {
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_HANGUP;
+ dev->drv[di]->interface->command(&cmd);
+ return 0;
+ }
/* Try to find a network-interface which will accept incoming call */
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_LOCK;
- dev->drv[di]->interface->command(&cmd);
- r = isdn_net_find_icall(di, c->arg, i, c->num);
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_LOCK;
+ dev->drv[di]->interface->command(&cmd);
+ r = isdn_net_find_icall(di, c->arg, i, c->parm.setup);
switch (r) {
- case 0:
- /* No network-device replies. Schedule RING-message to
- * tty and set RI-bit of modem-status.
- */
- if ((mi = isdn_tty_find_icall(di, c->arg, c->num)) >= 0) {
- info = &dev->mdm.info[mi];
- info->msr |= UART_MSR_RI;
- isdn_tty_modem_result(2, info);
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
- return 1;
- } else if (dev->drv[di]->reject_bus) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
- retval=2;
- }
- break;
- case 1:
- /* Schedule connection-setup */
- isdn_net_dial();
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTD;
- dev->drv[di]->interface->command(&cmd);
- return 1;
- break;
- case 2: /* For calling back, first reject incoming call ... */
- case 3: /* Interface found, but down, reject call actively */
- retval=2;
- printk(KERN_INFO "isdn: Rejecting Call\n");
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- dev->drv[di]->interface->command(&cmd);
- if (r == 3)
- break;
- /* Fall through */
- case 4:
- /* ... then start callback. */
- isdn_net_dial();
- return 2;
+ case 0:
+ /* No network-device replies.
+ * Try ttyI's
+ */
+ if (isdn_tty_find_icall(di, c->arg, c->parm.setup) >= 0)
+ retval = 1;
+ else if (dev->drv[di]->reject_bus) {
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_HANGUP;
+ dev->drv[di]->interface->command(&cmd);
+ retval = 2;
+ }
+ break;
+ case 1:
+ /* Schedule connection-setup */
+ isdn_net_dial();
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_ACCEPTD;
+ dev->drv[di]->interface->command(&cmd);
+ retval = 1;
+ break;
+ case 2: /* For calling back, first reject incoming call ... */
+ case 3: /* Interface found, but down, reject call actively */
+ retval = 2;
+ printk(KERN_INFO "isdn: Rejecting Call\n");
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_HANGUP;
+ dev->drv[di]->interface->command(&cmd);
+ if (r == 3)
+ break;
+ /* Fall through */
+ case 4:
+ /* ... then start callback. */
+ isdn_net_dial();
+ break;
+ }
+ if (retval != 1) {
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_UNLOCK;
+ dev->drv[di]->interface->command(&cmd);
}
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_UNLOCK;
- dev->drv[di]->interface->command(&cmd);
- return retval;
- break;
- case ISDN_STAT_CINF:
- if (i<0)
+ return retval;
+ break;
+ case ISDN_STAT_CINF:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->num);
+ printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (strcmp(c->num, "0"))
- isdn_net_stat_callback(i, c->command);
- break;
- case ISDN_STAT_CAUSE:
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ if (strcmp(c->parm.num, "0"))
+ isdn_net_stat_callback(i, c->command);
+ break;
+ case ISDN_STAT_CAUSE:
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->num);
+ printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);
#endif
- printk(KERN_INFO "isdn: cause: %s\n", c->num);
- break;
- case ISDN_STAT_DCONN:
- if (i<0)
+ printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
+ dev->drvid[di], c->arg, c->parm.num);
+ isdn_tty_stat_callback(i, c);
+ break;
+ case ISDN_STAT_DCONN:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
+ printk(KERN_DEBUG "DCONN: %ld\n", c->arg);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- /* Find any network-device, waiting for D-channel setup */
- if (isdn_net_stat_callback(i, c->command))
- break;
-
- if ((mi = dev->m_idx[i]) >= 0) {
- /* If any tty has just dialed-out, setup B-Channel */
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- if (info->dialing == 1) {
- info->dialing = 2;
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTB;
- dev->drv[di]->interface->command(&cmd);
- return 0;
- }
- }
- }
- break;
- case ISDN_STAT_DHUP:
- if (i<0)
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ /* Find any net-device, waiting for D-channel setup */
+ if (isdn_net_stat_callback(i, c->command))
+ break;
+ /* Find any ttyI, waiting for D-channel setup */
+ if (isdn_tty_stat_callback(i, c)) {
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_ACCEPTB;
+ dev->drv[di]->interface->command(&cmd);
+ break;
+ }
+ break;
+ case ISDN_STAT_DHUP:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
-#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->flags &= ~(1 << (c->arg));
- isdn_info_update();
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c->command))
- break;
- if ((mi = dev->m_idx[i]) >= 0) {
- /* Signal hangup to tty-device */
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- if (info->dialing == 1) {
- info->dialing = 0;
- isdn_tty_modem_result(7, info);
- }
- if (info->online)
- isdn_tty_modem_result(3, info);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
+ printk(KERN_DEBUG "DHUP: %ld\n", c->arg);
#endif
- isdn_tty_modem_hup(info);
- return 0;
- }
- }
- break;
- case ISDN_STAT_BCONN:
- if (i<0)
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ dev->drv[di]->flags &= ~(1 << (c->arg));
+ isdn_info_update();
+ /* Signal hangup to network-devices */
+ if (isdn_net_stat_callback(i, c->command))
+ break;
+ if (isdn_tty_stat_callback(i, c))
+ break;
+ break;
+ case ISDN_STAT_BCONN:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
+ printk(KERN_DEBUG "BCONN: %ld\n", c->arg);
#endif
- /* Signal B-channel-connect to network-devices */
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->flags |= (1 << (c->arg));
- isdn_info_update();
- if (isdn_net_stat_callback(i, c->command))
- break;
- if ((mi = dev->m_idx[i]) >= 0) {
- /* Schedule CONNECT-Message to any tty, waiting for it and
- * set DCD-bit of its modem-status.
- */
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- info->msr |= UART_MSR_DCD;
- if (info->dialing)
- info->dialing = 0;
- info->rcvsched = 1;
- if (USG_MODEM(dev->usage[i]))
- isdn_tty_modem_result(5, info);
- if (USG_VOICE(dev->usage[i]))
- isdn_tty_modem_result(11, info);
- }
- }
- break;
- case ISDN_STAT_BHUP:
- if (i<0)
+ /* Signal B-channel-connect to network-devices */
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ dev->drv[di]->flags |= (1 << (c->arg));
+ isdn_info_update();
+ if (isdn_net_stat_callback(i, c->command))
+ break;
+ if (isdn_tty_stat_callback(i, c))
+ break;
+ break;
+ case ISDN_STAT_BHUP:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
+ printk(KERN_DEBUG "BHUP: %ld\n", c->arg);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- dev->drv[di]->flags &= ~(1 << (c->arg));
- isdn_info_update();
- if ((mi = dev->m_idx[i]) >= 0) {
- /* Signal hangup to tty-device, schedule NO CARRIER-message */
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- if (info->msr & UART_MSR_DCD)
- isdn_tty_modem_result(3, info);
- info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
-#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
-#endif
- isdn_tty_modem_hup(info);
- }
- }
- break;
- case ISDN_STAT_NODCH:
- if (i<0)
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ dev->drv[di]->flags &= ~(1 << (c->arg));
+ isdn_info_update();
+ if (isdn_tty_stat_callback(i, c))
+ break;
+ break;
+ case ISDN_STAT_NODCH:
+ if (i < 0)
return -1;
#ifdef ISDN_DEBUG_STATCALLB
- printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
+ printk(KERN_DEBUG "NODCH: %ld\n", c->arg);
#endif
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
- if (isdn_net_stat_callback(i, c->command))
- break;
- if ((mi = dev->m_idx[i]) >= 0) {
- info = &dev->mdm.info[mi];
- if (info->flags &
- (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
- if (info->dialing) {
- info->dialing = 0;
- isdn_tty_modem_result(6, info);
- }
- info->msr &= ~UART_MSR_DCD;
- if (info->online) {
- isdn_tty_modem_result(3, info);
- info->online = 0;
- }
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+ if (isdn_net_stat_callback(i, c->command))
+ break;
+ if (isdn_tty_stat_callback(i, c))
+ break;
+ break;
+ case ISDN_STAT_ADDCH:
+ break;
+ case ISDN_STAT_UNLOAD:
+ save_flags(flags);
+ cli();
+ isdn_tty_stat_callback(i, c);
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ if (dev->drvmap[i] == di) {
+ dev->drvmap[i] = -1;
+ dev->chanmap[i] = -1;
}
- }
- break;
- case ISDN_STAT_ADDCH:
- break;
- case ISDN_STAT_UNLOAD:
- save_flags(flags);
- cli();
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (dev->drvmap[i] == di) {
- dev->drvmap[i] = -1;
- dev->chanmap[i] = -1;
- }
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
-
- if (info->isdn_driver == di) {
- info->isdn_driver = -1;
- info->isdn_channel = -1;
- if (info->online) {
- isdn_tty_modem_result(3, info);
- isdn_tty_modem_hup(info);
- }
- }
- }
- dev->drivers--;
- dev->channels -= dev->drv[di]->channels;
- kfree(dev->drv[di]->rcverr);
- kfree(dev->drv[di]->rcvcount);
- for (i = 0; i < dev->drv[di]->channels; i++)
- isdn_free_queue(&dev->drv[di]->rpqueue[i]);
- kfree(dev->drv[di]->rpqueue);
- kfree(dev->drv[di]->rcv_waitq);
- kfree(dev->drv[di]->snd_waitq);
- kfree(dev->drv[di]);
- dev->drv[di] = NULL;
- dev->drvid[di][0] = '\0';
- isdn_info_update();
- restore_flags(flags);
- return 0;
- default:
- return -1;
+ dev->drivers--;
+ dev->channels -= dev->drv[di]->channels;
+ kfree(dev->drv[di]->rcverr);
+ kfree(dev->drv[di]->rcvcount);
+ for (i = 0; i < dev->drv[di]->channels; i++)
+ isdn_free_queue(&dev->drv[di]->rpqueue[i]);
+ kfree(dev->drv[di]->rpqueue);
+ kfree(dev->drv[di]->rcv_waitq);
+ kfree(dev->drv[di]->snd_waitq);
+ kfree(dev->drv[di]);
+ dev->drv[di] = NULL;
+ dev->drvid[di][0] = '\0';
+ isdn_info_update();
+ restore_flags(flags);
+ return 0;
+ default:
+ return -1;
}
return 0;
}
/*
* Get integer from char-pointer, set pointer to end of number
*/
-int isdn_getnum(char **p)
+int
+isdn_getnum(char **p)
{
int v = -1;
* isdn_readbchan() tries to get data from the read-queue.
* It MUST be called with interrupts off.
*/
-int isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
+int
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, int user)
{
int left;
int count;
int count_pull;
- int count_put;
+ int count_put;
int dflag;
- struct sk_buff *skb;
+ struct sk_buff *skb;
u_char *cp;
if (!dev->drv[di])
cp = buf;
count = 0;
while (left) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
- break;
- if (skb->lock)
- break;
- skb->lock = 1;
- if (skb->users) {
- /* users is the count of DLE's in
- * this buff when in voice mode.
- */
- char *p = skb->data;
- unsigned long DLEmask = (1 << channel);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (left-- > 0)) {
- if (dev->drv[di]->DLEflag & DLEmask) {
- if (user)
- put_user(DLE,cp++);
- else
- *cp++ = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- if (user)
- put_user(*p,cp++);
- else
- *cp++ = *p;
- if (*p == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- skb->users--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > left) {
- count_pull = left;
- dflag = 0;
- }
- count_put = count_pull;
- if (user)
- copy_to_user(cp, skb->data, count_put);
- else
- memcpy(cp, skb->data, count_put);
- cp += count_put;
- left -= count_put;
- }
- count += count_put;
- if (fp) {
- memset(fp, 0, count_put);
- fp += count_put;
- }
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
+ if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
+ break;
+#ifdef CONFIG_ISDN_AUDIO
+ if (ISDN_AUDIO_SKB_LOCK(skb))
+ break;
+ ISDN_AUDIO_SKB_LOCK(skb) = 1;
+ if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+ char *p = skb->data;
+ unsigned long DLEmask = (1 << channel);
+
+ dflag = 0;
+ count_pull = count_put = 0;
+ while ((count_pull < skb->len) && (left-- > 0)) {
+ if (dev->drv[di]->DLEflag & DLEmask) {
+ if (user)
+ put_user(DLE, cp++);
+ else
+ *cp++ = DLE;
+ dev->drv[di]->DLEflag &= ~DLEmask;
+ } else {
+ if (user)
+ put_user(*p, cp++);
+ else
+ *cp++ = *p;
+ if (*p == DLE) {
+ dev->drv[di]->DLEflag |= DLEmask;
+ (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
+ }
+ p++;
+ count_pull++;
+ }
+ count_put++;
+ }
+ if (count_pull >= skb->len)
+ dflag = 1;
+ } else {
+#endif
+ /* No DLE's in buff, so simply copy it */
+ dflag = 1;
+ if ((count_pull = skb->len) > left) {
+ count_pull = left;
+ dflag = 0;
+ }
+ count_put = count_pull;
+ if (user)
+ copy_to_user(cp, skb->data, count_put);
+ else
+ memcpy(cp, skb->data, count_put);
+ cp += count_put;
+ left -= count_put;
+#ifdef CONFIG_ISDN_AUDIO
+ }
+#endif
+ count += count_put;
+ if (fp) {
+ memset(fp, 0, count_put);
+ fp += count_put;
+ }
+ if (dflag) {
+ /* We got all the data in this buff.
+ * Now we can dequeue it.
+ */
if (fp)
*(fp - 1) = 0xff;
- skb->lock = 0;
- skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
- isdn_trash_skb(skb, FREE_READ);
+#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+ skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
+ isdn_trash_skb(skb, FREE_READ);
} else {
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb,count_pull);
- skb->lock = 0;
- }
+ /* Not yet emptied this buff, so it
+ * must stay in the queue, for further calls
+ * but we pull off the data we got until now.
+ */
+ skb_pull(skb, count_pull);
+#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+ }
dev->drv[di]->rcvcount[channel] -= count_put;
}
return count;
}
-static __inline int isdn_minor2drv(int minor)
+static __inline int
+isdn_minor2drv(int minor)
{
return (dev->drvmap[minor]);
}
-static __inline int isdn_minor2chan(int minor)
+static __inline int
+isdn_minor2chan(int minor)
{
return (dev->chanmap[minor]);
}
-#define INF_DV 0x01 /* Data version for /dev/isdninfo */
+#define INF_DV 0x01 /* Data version for /dev/isdninfo */
static char *
- isdn_statstr(void)
+isdn_statstr(void)
{
static char istatbuf[2048];
char *p;
/* Module interface-code */
-void isdn_info_update(void)
+void
+isdn_info_update(void)
{
infostruct *p = dev->infochain;
wake_up_interruptible(&(dev->info_waitq));
}
-static RWTYPE isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
+static RWTYPE
+isdn_read(struct inode *inode, struct file *file, char *buf, RWARG count)
{
uint minor = MINOR(inode->i_rdev);
int len = 0;
if (minor == ISDN_MINOR_STATUS) {
char *p;
if (!file->private_data) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
interruptible_sleep_on(&(dev->info_waitq));
- }
+ }
p = isdn_statstr();
file->private_data = 0;
if ((len = strlen(p)) <= count) {
- copy_to_user(buf, p, len);
+ if (copy_to_user(buf, p, len))
+ return -EFAULT;
file->f_pos += len;
return len;
}
if (!dev->drv[drvidx]->running)
return -ENODEV;
chidx = isdn_minor2chan(minor);
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
len = isdn_readbchan(drvidx, chidx, buf, 0, count, 1);
file->f_pos += len;
- restore_flags(flags);
+ restore_flags(flags);
return len;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
if (drvidx < 0)
return -ENODEV;
if (!dev->drv[drvidx]->stavail) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
- }
+ }
if (dev->drv[drvidx]->interface->readstat)
len = dev->drv[drvidx]->interface->
readstat(buf, MIN(count, dev->drv[drvidx]->stavail),
len = 0;
save_flags(flags);
cli();
- if (len)
- dev->drv[drvidx]->stavail -= len;
- else
- dev->drv[drvidx]->stavail = 0;
+ if (len)
+ dev->drv[drvidx]->stavail -= len;
+ else
+ dev->drv[drvidx]->stavail = 0;
restore_flags(flags);
file->f_pos += len;
return len;
return -ENODEV;
}
-static LSTYPE isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
+static LSTYPE
+isdn_lseek(struct inode *inode, struct file *file, LSARG offset, int orig)
{
return -ESPIPE;
}
-static RWTYPE isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
+static RWTYPE
+isdn_write(struct inode *inode, struct file *file, const char *buf, RWARG count)
{
uint minor = MINOR(inode->i_rdev);
int drvidx;
return -ENODEV;
}
-static int isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
+#if (LINUX_VERSION_CODE < 0x020117)
+static int
+isdn_select(struct inode *inode, struct file *file, int type, select_table * st)
{
uint minor = MINOR(inode->i_rdev);
- int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
if (minor == ISDN_MINOR_STATUS) {
if (file->private_data)
if (drvidx < 0)
return -ENODEV;
if (dev->drv[drvidx]->stavail)
- return 1;
- else {
- if (st)
- select_wait(&(dev->drv[drvidx]->st_waitq), st);
- return 0;
- }
+ return 1;
+ else {
+ if (st)
+ select_wait(&(dev->drv[drvidx]->st_waitq), st);
+ return 0;
+ }
return 1;
- }
+ }
#ifdef CONFIG_ISDN_PPP
if (minor <= ISDN_MINOR_PPPMAX)
return (isdn_ppp_select(minor - ISDN_MINOR_PPP, file, type, st));
#endif
return -ENODEV;
}
+#else
+static unsigned int
+isdn_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask = 0;
+ unsigned int minor = MINOR(file->f_inode->i_rdev);
+ int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+
+ if (minor == ISDN_MINOR_STATUS) {
+ poll_wait(&(dev->info_waitq), wait);
+ /* mask = POLLOUT | POLLWRNORM; */
+ if (file->private_data) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+ return mask;
+ }
+ if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
+ poll_wait(&(dev->drv[drvidx]->st_waitq), wait);
+ if (drvidx < 0) {
+ printk(KERN_ERR "isdn_common: isdn_poll 1 -> what the hell\n");
+ return POLLERR;
+ }
+ mask = POLLOUT | POLLWRNORM;
+ if (dev->drv[drvidx]->stavail) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+ return mask;
+ }
+#ifdef CONFIG_ISDN_PPP
+ if (minor <= ISDN_MINOR_PPPMAX)
+ return (isdn_ppp_poll(file, wait));
+#endif
+ printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
+ return POLLERR;
+}
+#endif
-static int isdn_set_allcfg(char *src)
+static int
+isdn_set_allcfg(char *src)
{
int ret;
int i;
ulong flags;
- char buf[1024];
isdn_net_ioctl_cfg cfg;
isdn_net_ioctl_phone phone;
if ((ret = isdn_net_rmall()))
return ret;
+ if ((ret = copy_from_user((char *) &i, src, sizeof(int))))
+ return ret;
save_flags(flags);
cli();
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(int)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user((char *) &i, src, sizeof(int));
- src += sizeof(int);
+ src += sizeof(int);
while (i) {
- char *c;
- char *c2;
+ int phone_len;
+ int out_flag;
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(cfg)))) {
+ if ((ret = copy_from_user((char *) &cfg, src, sizeof(cfg)))) {
restore_flags(flags);
return ret;
}
- copy_from_user((char *) &cfg, src, sizeof(cfg));
src += sizeof(cfg);
if (!isdn_net_new(cfg.name, NULL)) {
restore_flags(flags);
restore_flags(flags);
return ret;
}
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user(buf, src, sizeof(buf));
- src += sizeof(buf);
- c = buf;
- while (*c) {
- if ((c2 = strchr(c, ' ')))
- *c2++ = '\0';
- strcpy(phone.phone, c);
- strcpy(phone.name, cfg.name);
- phone.outgoing = 0;
- if ((ret = isdn_net_addphone(&phone))) {
+ phone_len = out_flag = 0;
+ while (out_flag < 2) {
+ if ((ret = verify_area(VERIFY_READ, src, 1))) {
restore_flags(flags);
return ret;
}
- if (c2)
- c = c2;
- else
- c += strlen(c);
- }
- if ((ret = verify_area(VERIFY_READ, (void *) src, sizeof(buf)))) {
- restore_flags(flags);
- return ret;
- }
- copy_from_user(buf, src, sizeof(buf));
- src += sizeof(buf);
- c = buf;
- while (*c) {
- if ((c2 = strchr(c, ' ')))
- *c2++ = '\0';
- strcpy(phone.phone, c);
- strcpy(phone.name, cfg.name);
- phone.outgoing = 1;
- if ((ret = isdn_net_addphone(&phone))) {
- restore_flags(flags);
- return ret;
+ GET_USER(phone.phone[phone_len], src++);
+ if ((phone.phone[phone_len] == ' ') ||
+ (phone.phone[phone_len] == '\0')) {
+ if (phone_len) {
+ phone.phone[phone_len] = '\0';
+ strcpy(phone.name, cfg.name);
+ phone.outgoing = out_flag;
+ if ((ret = isdn_net_addphone(&phone))) {
+ restore_flags(flags);
+ return ret;
+ }
+ } else
+ out_flag++;
+ phone_len = 0;
}
- if (c2)
- c = c2;
- else
- c += strlen(c);
+ if (++phone_len >= sizeof(phone.phone))
+ printk(KERN_WARNING
+ "%s: IIOCSETSET phone number too long, ignored\n",
+ cfg.name);
}
i--;
}
return 0;
}
-static int isdn_get_allcfg(char *dest)
+static int
+isdn_get_allcfg(char *dest)
{
isdn_net_ioctl_cfg cfg;
isdn_net_ioctl_phone phone;
cli();
p = dev->netdev;
while (p) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 10))) {
+ if ((ret = verify_area(VERIFY_WRITE, (void *) dest, sizeof(cfg) + 200))) {
restore_flags(flags);
return ret;
}
cfg.p_encap = p->local.p_encap;
cfg.secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
cfg.callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0;
- cfg.chargehup = (p->local.hupflags & 4) ? 1 : 0;
- cfg.ihup = (p->local.hupflags & 8) ? 1 : 0;
- copy_to_user(dest, p->local.name, 10);
+ cfg.chargehup = (p->local.hupflags & ISDN_CHARGEHUP) ? 1 : 0;
+ cfg.ihup = (p->local.hupflags & ISDN_INHUP) ? 1 : 0;
+ cfg.chargeint = p->local.chargeint;
+ if (copy_to_user(dest, p->local.name, 10)) {
+ restore_flags(flags);
+ return -EFAULT;
+ }
dest += 10;
- copy_to_user(dest, (char *) &cfg, sizeof(cfg));
+ if (copy_to_user(dest, (char *) &cfg, sizeof(cfg))) {
+ restore_flags(flags);
+ return -EFAULT;
+ }
dest += sizeof(cfg);
strcpy(phone.name, p->local.name);
phone.outgoing = 0;
return ret;
} else
dest += ret;
+ put_user(0, dest);
p = p->next;
}
restore_flags(flags);
return 0;
}
-static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+static int
+isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
{
uint minor = MINOR(inode->i_rdev);
isdn_ctrl c;
int drvidx;
int chidx;
int ret;
+ int i;
+ char *p;
char *s;
- char name[10];
- char bname[21];
- isdn_ioctl_struct iocts;
- isdn_net_ioctl_phone phone;
- isdn_net_ioctl_cfg cfg;
+ union iocpar {
+ char name[10];
+ char bname[22];
+ isdn_ioctl_struct iocts;
+ isdn_net_ioctl_phone phone;
+ isdn_net_ioctl_cfg cfg;
+ } iocpar;
+
+#define name iocpar.name
+#define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg iocpar.cfg
if (minor == ISDN_MINOR_STATUS) {
- switch (cmd) {
- case IIOCGETDVR:
- return(TTY_DV +
- (NET_DV << 8) +
- (INF_DV << 16));
- case IIOCGETCPS:
- if (arg) {
- ulong *p = (ulong *)arg;
- int i;
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(ulong)*ISDN_MAX_CHANNELS*2)))
- return ret;
- for (i = 0;i<ISDN_MAX_CHANNELS;i++) {
- put_user(dev->ibytes[i],p++);
- put_user(dev->obytes[i],p++);
- }
- return 0;
- } else
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- }
+ switch (cmd) {
+ case IIOCGETDVR:
+ return (TTY_DV +
+ (NET_DV << 8) +
+ (INF_DV << 16));
+ case IIOCGETCPS:
+ if (arg) {
+ ulong *p = (ulong *) arg;
+ int i;
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+ return ret;
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ put_user(dev->ibytes[i], p++);
+ put_user(dev->obytes[i], p++);
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
if (!dev->drivers)
return -ENODEV;
if (minor < ISDN_MINOR_CTRL) {
if (minor <= ISDN_MINOR_CTRLMAX) {
switch (cmd) {
#ifdef CONFIG_NETDEVICES
- case IIOCNETAIF:
- /* Add a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- s = name;
- } else
- s = NULL;
- if ((s = isdn_net_new(s, NULL))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
- return ret;
- copy_to_user((char *) arg, s, strlen(s) + 1);
- return 0;
- } else
- return -ENODEV;
- case IIOCNETASL:
- /* Add a slave to a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(bname))))
- return ret;
- copy_from_user(bname, (char *) arg, sizeof(bname));
- } else
- return -EINVAL;
- if ((s = isdn_net_newslave(bname))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, strlen(s) + 1)))
- return ret;
- copy_to_user((char *) arg, s, strlen(s) + 1);
- return 0;
- } else
- return -ENODEV;
- case IIOCNETDIF:
- /* Delete a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_rm(name);
- } else
- return -EINVAL;
- case IIOCNETSCF:
- /* Set configurable parameters of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
- return ret;
- copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
- return isdn_net_setcfg(&cfg);
- } else
- return -EINVAL;
- case IIOCNETGCF:
- /* Get configurable parameters of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(cfg))))
- return ret;
- copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg));
- if (!(ret = isdn_net_getcfg(&cfg))) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(cfg))))
- return ret;
- copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg));
- }
- return ret;
- } else
- return -EINVAL;
- case IIOCNETANM:
- /* Add a phone-number to a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_addphone(&phone);
- } else
- return -EINVAL;
- case IIOCNETGNM:
- /* Get list of phone-numbers of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_getphones(&phone, (char *) arg);
- } else
- return -EINVAL;
- case IIOCNETDNM:
- /* Delete a phone-number of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
- return ret;
- copy_from_user((char *) &phone, (char *) arg, sizeof(phone));
- return isdn_net_delphone(&phone);
- } else
- return -EINVAL;
- case IIOCNETDIL:
- /* Force dialing of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_force_dial(name);
- } else
- return -EINVAL;
+ case IIOCNETAIF:
+ /* Add a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ s = name;
+ } else
+ s = NULL;
+ if ((s = isdn_net_new(s, NULL))) {
+ if ((ret = copy_to_user((char *) arg, s, strlen(s) + 1)))
+ return ret;
+ return 0;
+ } else
+ return -ENODEV;
+ case IIOCNETASL:
+ /* Add a slave to a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user(bname, (char *) arg, sizeof(bname) - 1)))
+ return ret;
+ } else
+ return -EINVAL;
+ if ((s = isdn_net_newslave(bname))) {
+ if ((ret = copy_to_user((char *) arg, s, strlen(s) + 1)))
+ return ret;
+ return 0;
+ } else
+ return -ENODEV;
+ case IIOCNETDIF:
+ /* Delete a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_net_rm(name);
+ } else
+ return -EINVAL;
+ case IIOCNETSCF:
+ /* Set configurable parameters of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))))
+ return ret;
+ return isdn_net_setcfg(&cfg);
+ } else
+ return -EINVAL;
+ case IIOCNETGCF:
+ /* Get configurable parameters of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))))
+ return ret;
+ if (!(ret = isdn_net_getcfg(&cfg))) {
+ if ((ret = copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))))
+ return ret;
+ }
+ return ret;
+ } else
+ return -EINVAL;
+ case IIOCNETANM:
+ /* Add a phone-number to a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+ return ret;
+ return isdn_net_addphone(&phone);
+ } else
+ return -EINVAL;
+ case IIOCNETGNM:
+ /* Get list of phone-numbers of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+ return ret;
+ return isdn_net_getphones(&phone, (char *) arg);
+ } else
+ return -EINVAL;
+ case IIOCNETDNM:
+ /* Delete a phone-number of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user((char *) &phone, (char *) arg, sizeof(phone))))
+ return ret;
+ return isdn_net_delphone(&phone);
+ } else
+ return -EINVAL;
+ case IIOCNETDIL:
+ /* Force dialing of a network-interface */
+ if (arg) {
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_net_force_dial(name);
+ } else
+ return -EINVAL;
#ifdef CONFIG_ISDN_PPP
- case IIOCNETALN:
- if(arg) {
- if ((ret = verify_area(VERIFY_READ,
- (void*)arg,
- sizeof(name))))
- return ret;
- } else
- return -EINVAL;
- copy_from_user(name,(char*)arg,sizeof(name));
- return isdn_ppp_dial_slave(name);
- case IIOCNETDLN:
- if(arg) {
- if ((ret = verify_area(VERIFY_READ,
- (void*)arg,
- sizeof(name))))
- return ret;
- } else
- return -EINVAL;
- copy_from_user(name,(char*)arg,sizeof(name));
- return isdn_ppp_hangup_slave(name);
+ case IIOCNETALN:
+ if (!arg)
+ return -EINVAL;
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_ppp_dial_slave(name);
+ case IIOCNETDLN:
+ if (!arg)
+ return -EINVAL;
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_ppp_hangup_slave(name);
#endif
- case IIOCNETHUP:
- /* Force hangup of a network-interface */
- if (arg) {
- if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(name))))
- return ret;
- copy_from_user(name, (char *) arg, sizeof(name));
- return isdn_net_force_hangup(name);
- } else
- return -EINVAL;
- break;
-#endif /* CONFIG_NETDEVICES */
- case IIOCSETVER:
- dev->net_verbose = arg;
- printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
- return 0;
- case IIOCSETGST:
- if (arg)
- dev->global_flags |= ISDN_GLOBAL_STOPPED;
- else
- dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
- printk(KERN_INFO "isdn: Global Mode %s\n",
- (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
- return 0;
- case IIOCSETBRJ:
- drvidx = -1;
- if (arg) {
- int i;
- char *p;
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg,
- sizeof(isdn_ioctl_struct));
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- }
- }
- if (drvidx == -1)
- return -ENODEV;
- dev->drv[drvidx]->reject_bus = iocts.arg;
- return 0;
- case IIOCGETSET:
- /* Get complete setup (all network-interfaces and profile-
- settings of all tty-devices */
- if (arg)
- return (isdn_get_allcfg((char *) arg));
- else
- return -EINVAL;
- break;
- case IIOCSETSET:
- /* Set complete setup (all network-interfaces and profile-
- settings of all tty-devices */
- if (arg)
- return (isdn_set_allcfg((char *) arg));
- else
- return -EINVAL;
- break;
- case IIOCSIGPRF:
- dev->profd = current;
- return 0;
- break;
- case IIOCGETPRF:
- /* Get all Modem-Profiles */
- if (arg) {
- char *p = (char *) arg;
- int i;
-
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- copy_to_user(p, dev->mdm.info[i].emu.profile,
- ISDN_MODEM_ANZREG);
- p += ISDN_MODEM_ANZREG;
- copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN);
- p += ISDN_MSNLEN;
- }
- return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
- } else
- return -EINVAL;
- break;
- case IIOCSETPRF:
- /* Set all Modem-Profiles */
- if (arg) {
- char *p = (char *) arg;
- int i;
-
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
- * ISDN_MAX_CHANNELS)))
- return ret;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_ANZREG);
- p += ISDN_MODEM_ANZREG;
- copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN);
- p += ISDN_MSNLEN;
- }
- return 0;
- } else
- return -EINVAL;
- break;
- case IIOCSETMAP:
- case IIOCGETMAP:
- /* Set/Get MSN->EAZ-Mapping for a driver */
- if (arg) {
- int i;
- char *p;
- char nstring[255];
-
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
- if (strlen(iocts.drvid)) {
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if (cmd == IIOCSETMAP) {
- if ((ret = verify_area(VERIFY_READ, (void *) iocts.arg, 255)))
- return ret;
- copy_from_user(nstring, (char *) iocts.arg, 255);
- memset(dev->drv[drvidx]->msn2eaz, 0,
- sizeof(dev->drv[drvidx]->msn2eaz));
- p = strtok(nstring, ",");
- i = 0;
- while ((p) && (i < 10)) {
- strcpy(dev->drv[drvidx]->msn2eaz[i++], p);
- p = strtok(NULL, ",");
- }
- } else {
- p = nstring;
- for (i = 0; i < 10; i++)
- p += sprintf(p, "%s%s",
- strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "-",
- (i < 9) ? "," : "\0");
- if ((ret = verify_area(VERIFY_WRITE, (void *) iocts.arg,
- strlen(nstring) + 1)))
- return ret;
- copy_to_user((char *) iocts.arg, nstring, strlen(nstring) + 1);
- }
- return 0;
- } else
- return -EINVAL;
- case IIOCDBGVAR:
- if (arg) {
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong))))
- return ret;
- copy_to_user((char *) arg, (char *) &dev, sizeof(ulong));
- return 0;
- } else
- return -EINVAL;
- break;
- default:
- if ((cmd&IIOCDRVCTL)==IIOCDRVCTL)
- cmd = ((cmd>>_IOC_NRSHIFT)&_IOC_NRMASK)& ISDN_DRVIOCTL_MASK;
+ case IIOCNETHUP:
+ /* Force hangup of a network-interface */
+ if (!arg)
+ return -EINVAL;
+ if ((ret = copy_from_user(name, (char *) arg, sizeof(name))))
+ return ret;
+ return isdn_net_force_hangup(name);
+ break;
+#endif /* CONFIG_NETDEVICES */
+ case IIOCSETVER:
+ dev->net_verbose = arg;
+ printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+ return 0;
+ case IIOCSETGST:
+ if (arg)
+ dev->global_flags |= ISDN_GLOBAL_STOPPED;
+ else
+ dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+ printk(KERN_INFO "isdn: Global Mode %s\n",
+ (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+ return 0;
+ case IIOCSETBRJ:
+ drvidx = -1;
+ if (arg) {
+ int i;
+ char *p;
+ if ((ret = copy_from_user((char *) &iocts, (char *) arg,
+ sizeof(isdn_ioctl_struct))))
+ return ret;
+ if (strlen(iocts.drvid)) {
+ if ((p = strchr(iocts.drvid, ',')))
+ *p = 0;
+ drvidx = -1;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
+ }
+ }
+ }
+ if (drvidx == -1)
+ return -ENODEV;
+ dev->drv[drvidx]->reject_bus = iocts.arg;
+ return 0;
+ case IIOCGETSET:
+ /* Get complete setup (all network-interfaces and profile-
+ settings of all tty-devices */
+ if (arg)
+ return (isdn_get_allcfg((char *) arg));
else
return -EINVAL;
- if (arg) {
- int i;
- char *p;
- if ((ret = verify_area(VERIFY_READ, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct));
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
- if (drvidx == -1)
- return -ENODEV;
- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(isdn_ioctl_struct))))
- return ret;
- c.driver = drvidx;
- c.command = ISDN_CMD_IOCTL;
- c.arg = cmd;
- memcpy(c.num, (char *) &iocts.arg, sizeof(ulong));
- ret = dev->drv[drvidx]->interface->command(&c);
- memcpy((char *) &iocts.arg, c.num, sizeof(ulong));
- copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct));
- return ret;
- } else
- return -EINVAL;
+ break;
+ case IIOCSETSET:
+ /* Set complete setup (all network-interfaces and profile-
+ settings of all tty-devices */
+ if (arg)
+ return (isdn_set_allcfg((char *) arg));
+ else
+ return -EINVAL;
+ break;
+ case IIOCSIGPRF:
+ dev->profd = current;
+ return 0;
+ break;
+ case IIOCGETPRF:
+ /* Get all Modem-Profiles */
+ if (arg) {
+ char *p = (char *) arg;
+ int i;
+
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
+ * ISDN_MAX_CHANNELS)))
+ return ret;
+
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+ ISDN_MODEM_ANZREG))
+ return -EFAULT;
+ p += ISDN_MODEM_ANZREG;
+ if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+ return -EFAULT;
+ p += ISDN_MSNLEN;
+ }
+ return (ISDN_MODEM_ANZREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS;
+ } else
+ return -EINVAL;
+ break;
+ case IIOCSETPRF:
+ /* Set all Modem-Profiles */
+ if (arg) {
+ char *p = (char *) arg;
+ int i;
+
+ if ((ret = verify_area(VERIFY_READ, (void *) arg,
+ (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
+ * ISDN_MAX_CHANNELS)))
+ return ret;
+
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if ((ret = copy_from_user(dev->mdm.info[i].emu.profile, p,
+ ISDN_MODEM_ANZREG)))
+ return ret;
+ p += ISDN_MODEM_ANZREG;
+ if ((ret = copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)))
+ return ret;
+ p += ISDN_MSNLEN;
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ case IIOCSETMAP:
+ case IIOCGETMAP:
+ /* Set/Get MSN->EAZ-Mapping for a driver */
+ if (arg) {
+
+ if ((ret = copy_from_user((char *) &iocts,
+ (char *) arg,
+ sizeof(isdn_ioctl_struct))))
+ return ret;
+ if (strlen(iocts.drvid)) {
+ drvidx = -1;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
+ }
+ } else
+ drvidx = 0;
+ if (drvidx == -1)
+ return -ENODEV;
+ if (cmd == IIOCSETMAP) {
+ int loop = 1;
+
+ p = (char *) iocts.arg;
+ i = 0;
+ while (loop) {
+ int j = 0;
+
+ while (1) {
+ if ((ret = verify_area(VERIFY_READ, p, 1)))
+ return ret;
+ GET_USER(bname[j], p++);
+ switch (bname[j]) {
+ case '\0':
+ loop = 0;
+ /* Fall through */
+ case ',':
+ bname[j] = '\0';
+ strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+ j = ISDN_MSNLEN;
+ break;
+ default:
+ j++;
+ }
+ if (j >= ISDN_MSNLEN)
+ break;
+ }
+ if (++i > 9)
+ break;
+ }
+ } else {
+ p = (char *) iocts.arg;
+ for (i = 0; i < 10; i++) {
+ sprintf(bname, "%s%s",
+ strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+ dev->drv[drvidx]->msn2eaz[i] : "-",
+ (i < 9) ? "," : "\0");
+ if ((ret = copy_to_user(p, bname, strlen(bname) + 1)))
+ return ret;
+ p += strlen(bname);
+ }
+ }
+ return 0;
+ } else
+ return -EINVAL;
+ case IIOCDBGVAR:
+ if (arg) {
+ if ((ret = copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))))
+ return ret;
+ return 0;
+ } else
+ return -EINVAL;
+ break;
+ default:
+ if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+ cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+ else
+ return -EINVAL;
+ if (arg) {
+ int i;
+ char *p;
+ if ((ret = copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))))
+ return ret;
+ if (strlen(iocts.drvid)) {
+ if ((p = strchr(iocts.drvid, ',')))
+ *p = 0;
+ drvidx = -1;
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+ if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+ drvidx = i;
+ break;
+ }
+ } else
+ drvidx = 0;
+ if (drvidx == -1)
+ return -ENODEV;
+ if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(isdn_ioctl_struct))))
+ return ret;
+ c.driver = drvidx;
+ c.command = ISDN_CMD_IOCTL;
+ c.arg = cmd;
+ memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+ ret = dev->drv[drvidx]->interface->command(&c);
+ memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+ if ((copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))))
+ return -EFAULT;
+ return ret;
+ } else
+ return -EINVAL;
}
}
#ifdef CONFIG_ISDN_PPP
return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
#endif
return -ENODEV;
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
}
/*
* MOD_INC_USE_COUNT make sure that the driver memory is not freed
* while the device is in use.
*/
-static int isdn_open(struct inode *ino, struct file *filep)
+static int
+isdn_open(struct inode *ino, struct file *filep)
{
uint minor = MINOR(ino->i_rdev);
int drvidx;
if (minor <= ISDN_MINOR_PPPMAX) {
int ret;
if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
- MOD_INC_USE_COUNT;
+ MOD_INC_USE_COUNT;
return ret;
}
#endif
return -ENODEV;
}
-static void isdn_close(struct inode *ino, struct file *filep)
+static CLOSETYPE
+isdn_close(struct inode *ino, struct file *filep)
{
uint minor = MINOR(ino->i_rdev);
int drvidx;
isdn_ctrl c;
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
if (minor == ISDN_MINOR_STATUS) {
infostruct *p = dev->infochain;
infostruct *q = NULL;
else
dev->infochain = (infostruct *) (p->next);
kfree(p);
- return;
+ return CLOSEVAL;
+ kfree(p);
}
q = p;
p = (infostruct *) (p->next);
}
+ return CLOSEVAL;
printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
- return;
}
if (minor < ISDN_MINOR_CTRL) {
drvidx = isdn_minor2drv(minor);
+ return CLOSEVAL;
if (drvidx < 0)
- return;
c.command = ISDN_CMD_UNLOCK;
c.driver = drvidx;
+ return CLOSEVAL;
(void) dev->drv[drvidx]->interface->command(&c);
- return;
}
if (minor <= ISDN_MINOR_CTRLMAX) {
drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ return CLOSEVAL;
if (drvidx < 0)
- return;
if (dev->profd == current)
dev->profd = NULL;
c.command = ISDN_CMD_UNLOCK;
c.driver = drvidx;
+ return CLOSEVAL;
(void) dev->drv[drvidx]->interface->command(&c);
- return;
}
#ifdef CONFIG_ISDN_PPP
if (minor <= ISDN_MINOR_PPPMAX)
isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
+ return CLOSEVAL;
#endif
}
isdn_lseek,
isdn_read,
isdn_write,
- NULL, /* isdn_readdir */
- isdn_select, /* isdn_select */
- isdn_ioctl, /* isdn_ioctl */
- NULL, /* isdn_mmap */
+ NULL, /* isdn_readdir */
+#if (LINUX_VERSION_CODE < 0x020117)
+ isdn_select, /* isdn_select */
+#else
+ isdn_poll, /* isdn_poll */
+#endif
+ isdn_ioctl, /* isdn_ioctl */
+ NULL, /* isdn_mmap */
isdn_open,
isdn_close,
- NULL /* fsync */
+ NULL /* fsync */
};
char *
- isdn_map_eaz2msn(char *msn, int di)
+isdn_map_eaz2msn(char *msn, int di)
{
driver *this = dev->drv[di];
int i;
* Find an unused ISDN-channel, whose feature-flags match the
* given L2- and L3-protocols.
*/
-int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
- ,int pre_chan)
+int
+isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
+ ,int pre_chan)
{
int i;
ulong flags;
ulong features;
- isdn_ctrl cmd;
+ isdn_ctrl cmd;
save_flags(flags);
cli();
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
isdn_info_update();
- cmd.driver = d;
- cmd.arg = 0;
- cmd.command = ISDN_CMD_LOCK;
- (void) dev->drv[d]->interface->command(&cmd);
+ cmd.driver = d;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_LOCK;
+ (void) dev->drv[d]->interface->command(&cmd);
restore_flags(flags);
return i;
} else {
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
isdn_info_update();
- cmd.driver = d;
- cmd.arg = 0;
- cmd.command = ISDN_CMD_LOCK;
- (void) dev->drv[d]->interface->command(&cmd);
+ cmd.driver = d;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_LOCK;
+ (void) dev->drv[d]->interface->command(&cmd);
restore_flags(flags);
return i;
}
/*
* Set state of ISDN-channel to 'unused'
*/
-void isdn_free_channel(int di, int ch, int usage)
+void
+isdn_free_channel(int di, int ch, int usage)
{
int i;
ulong flags;
(dev->chanmap[i] == ch)) {
dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE);
strcpy(dev->num[i], "???");
- dev->ibytes[i] = 0;
- dev->obytes[i] = 0;
+ dev->ibytes[i] = 0;
+ dev->obytes[i] = 0;
isdn_info_update();
- isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
- cmd.driver = di;
- cmd.arg = ch;
- cmd.command = ISDN_CMD_UNLOCK;
- restore_flags(flags);
- (void) dev->drv[di]->interface->command(&cmd);
+ isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
+ cmd.driver = di;
+ cmd.arg = ch;
+ cmd.command = ISDN_CMD_UNLOCK;
+ restore_flags(flags);
+ (void) dev->drv[di]->interface->command(&cmd);
return;
}
restore_flags(flags);
/*
* Cancel Exclusive-Flag for ISDN-channel
*/
-void isdn_unexclusive_channel(int di, int ch)
+void
+isdn_unexclusive_channel(int di, int ch)
{
int i;
ulong flags;
* len = Length of packet-data
*
*/
-void isdn_receive_callback(int drvidx, int chan, u_char *buf, int len)
+static void
+isdn_receive_callback(int drvidx, int chan, u_char * buf, int len)
{
- struct sk_buff *skb;
+ struct sk_buff *skb;
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
return;
- skb = dev_alloc_skb(len);
- if (skb) {
- memcpy(skb_put(skb, len), buf, len);
- isdn_receive_skb_callback(drvidx, chan, skb);
- } else
- printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n");
+ skb = dev_alloc_skb(len);
+ if (skb) {
+ memcpy(skb_put(skb, len), buf, len);
+ isdn_receive_skb_callback(drvidx, chan, skb);
+ } else
+ printk(KERN_WARNING "isdn: rcv alloc_skb failed, packet dropped.\n");
}
/*
* writebuf replacement for SKB_ABLE drivers
*/
-int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len,
- int user)
+static int
+isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
+ int user)
{
int ret;
- if (dev->drv[drvidx]->interface->writebuf)
- ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
- len, user);
- else {
- struct sk_buff * skb;
-
- skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len,
- GFP_ATOMIC);
- if (skb == NULL)
- return 0;
-
- skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
- skb->free = 1;
-
- if (user)
- copy_from_user(skb_put(skb, len), buf, len);
- else
- memcpy(skb_put(skb, len), buf, len);
-
- ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
- chan, skb);
- if (ret <= 0)
- kfree_skb(skb, FREE_WRITE);
- }
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx,chan)] += ret;
- return ret;
+ if (dev->drv[drvidx]->interface->writebuf)
+ ret = dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf,
+ len, user);
+ else {
+ struct sk_buff *skb;
+
+ skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len,
+ GFP_ATOMIC);
+ if (skb == NULL)
+ return 0;
+
+ skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen);
+ SET_SKB_FREE(skb);
+
+ if (user)
+ copy_from_user(skb_put(skb, len), buf, len);
+ else
+ memcpy(skb_put(skb, len), buf, len);
+
+ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
+ chan, skb);
+ if (ret <= 0)
+ kfree_skb(skb, FREE_WRITE);
+ }
+ if (ret > 0)
+ dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
+ return ret;
}
/*
* Return: length of data on success, -ERRcode on failure.
*/
-int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
+int
+isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff *skb)
{
- int ret;
- int len = skb->len; /* skb pointer no longer valid after free */
+ int ret;
+ int len = skb->len; /* skb pointer no longer valid after free */
- if (dev->drv[drvidx]->interface->writebuf_skb)
+ if (dev->drv[drvidx]->interface->writebuf_skb)
ret = dev->drv[drvidx]->interface->
- writebuf_skb(drvidx, chan, skb);
+ writebuf_skb(drvidx, chan, skb);
else {
if ((ret = dev->drv[drvidx]->interface->
- writebuf(drvidx,chan,skb->data,skb->len,0)) == len)
- dev_kfree_skb(skb, FREE_WRITE);
- }
- if (ret > 0)
- dev->obytes[isdn_dc2minor(drvidx,chan)] += len;
- return ret;
+ writebuf(drvidx, chan, skb->data, skb->len, 0)) == len)
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+ if (ret > 0)
+ dev->obytes[isdn_dc2minor(drvidx, chan)] += len;
+ return ret;
}
/*
* Low-level-driver registration
*/
-int register_isdn(isdn_if * i)
+int
+register_isdn(isdn_if * i)
{
driver *d;
- int n, j, k;
+ int n,
+ j,
+ k;
ulong flags;
int drvidx;
return 0;
}
if ((!i->writebuf_skb) && (!i->writebuf)) {
- printk(KERN_WARNING "register_isdn: No write routine given.\n");
- return 0;
- }
+ printk(KERN_WARNING "register_isdn: No write routine given.\n");
+ return 0;
+ }
if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) {
printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
return 0;
return 0;
}
memset((char *) d->rcvcount, 0, sizeof(int) * n);
- if (!(d->rpqueue =
- (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
- kfree(d->rcvcount);
- kfree(d->rcverr);
- kfree(d);
- return 0;
- }
- for (j = 0; j < n; j++) {
- skb_queue_head_init(&d->rpqueue[j]);
- }
+ if (!(d->rpqueue =
+ (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * n, GFP_KERNEL))) {
+ printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
+ kfree(d->rcvcount);
+ kfree(d->rcverr);
+ kfree(d);
+ return 0;
+ }
+ for (j = 0; j < n; j++) {
+ skb_queue_head_init(&d->rpqueue[j]);
+ }
if (!(d->rcv_waitq = (struct wait_queue **)
kmalloc(sizeof(struct wait_queue *) * n, GFP_KERNEL))) {
printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
if (!dev->drv[drvidx])
break;
i->channels = drvidx;
-
+
i->rcvcallb_skb = isdn_receive_skb_callback;
- i->rcvcallb = isdn_receive_callback;
- i->statcallb = isdn_status_callback;
+ i->rcvcallb = isdn_receive_callback;
+ i->statcallb = isdn_status_callback;
if (!strlen(i->id))
sprintf(i->id, "line%d", drvidx);
save_flags(flags);
cli();
- for (j = 0; j < drvidx; j++)
- if (!strcmp(i->id,dev->drvid[j]))
- sprintf(i->id, "line%d", drvidx);
+ for (j = 0; j < drvidx; j++)
+ if (!strcmp(i->id, dev->drvid[j]))
+ sprintf(i->id, "line%d", drvidx);
for (j = 0; j < n; j++)
for (k = 0; k < ISDN_MAX_CHANNELS; k++)
if (dev->chanmap[k] < 0) {
#define isdn_init init_module
#endif
-static char *isdn_getrev(const char *revision)
+static char *
+isdn_getrev(const char *revision)
{
char *rev;
char *p;
return rev;
}
-static struct symbol_table isdn_syms = {
-#include <linux/symtab_begin.h>
- X(register_isdn),
-#include <linux/symtab_end.h>
-};
-
-static void isdn_export_syms(void)
-{
- register_symtab(&isdn_syms);
- has_exported = 1;
-}
-
/*
* Allocate and initialize all data, register modem-devices
*/
-int isdn_init(void)
+int
+isdn_init(void)
{
int i;
- char irev[50];
- char trev[50];
- char nrev[50];
- char prev[50];
- char arev[50];
+ char irev[50];
+ char trev[50];
+ char nrev[50];
+ char prev[50];
+ char arev[50];
sti();
if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
return -EIO;
}
memset((char *) dev, 0, sizeof(isdn_dev));
-#ifdef NEW_ISDN_TIMER_CTRL
- init_timer(&dev->timer);
- dev->timer.function = isdn_timer_funct;
-#endif
+ init_timer(&dev->timer);
+ dev->timer.function = isdn_timer_funct;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
kfree(dev);
return -EIO;
}
-#endif /* CONFIG_ISDN_PPP */
+#endif /* CONFIG_ISDN_PPP */
- if (!has_exported)
- isdn_export_syms();
+ isdn_export_syms();
- strcpy(irev,isdn_revision);
- strcpy(trev,isdn_tty_revision);
- strcpy(nrev,isdn_net_revision);
- strcpy(prev,isdn_ppp_revision);
- strcpy(arev,isdn_audio_revision);
+ strcpy(irev, isdn_revision);
+ strcpy(trev, isdn_tty_revision);
+ strcpy(nrev, isdn_net_revision);
+ strcpy(prev, isdn_ppp_revision);
+ strcpy(arev, isdn_audio_revision);
printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(irev));
- printk("%s/", isdn_getrev(trev));
- printk("%s/", isdn_getrev(nrev));
- printk("%s/", isdn_getrev(prev));
- printk("%s", isdn_getrev(arev));
+ printk("%s/", isdn_getrev(trev));
+ printk("%s/", isdn_getrev(nrev));
+ printk("%s/", isdn_getrev(prev));
+ printk("%s", isdn_getrev(arev));
#ifdef MODULE
printk(" loaded\n");
/*
* Unload module
*/
-void cleanup_module(void)
+void
+cleanup_module(void)
{
int flags;
int i;
return;
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
- kfree(dev->mdm.info[i].xmit_buf - 4);
- }
+ isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
+ kfree(dev->mdm.info[i].xmit_buf - 4);
+ }
if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
} else {
-/* $Id: isdn_common.h,v 1.3 1996/05/19 00:13:05 fritz Exp $
- *
+/* $Id: isdn_common.h,v 1.6 1997/02/28 02:32:44 fritz Exp $
+
* header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.h,v $
+ * Revision 1.6 1997/02/28 02:32:44 fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ * to isdn_tty.c
+ * Bugfix: Bisync protocol did not behave like documented.
+ *
+ * Revision 1.5 1997/02/10 10:05:45 fritz
+ * More changes for Kernel 2.1.X
+ * Symbol information moved to isdn_syms.c
+ *
+ * Revision 1.4 1997/02/03 22:56:50 fritz
+ * Removed isdn_writebuf_stub prototype.
+ *
* Revision 1.3 1996/05/19 00:13:05 fritz
* Removed debug flag.
*
#undef ISDN_DEBUG_MODEM_HUP
#undef ISDN_DEBUG_MODEM_ICALL
#undef ISDN_DEBUG_MODEM_DUMP
+#undef ISDN_DEBUG_MODEM_VOICE
#undef ISDN_DEBUG_AT
#undef ISDN_DEBUG_NET_DUMP
#undef ISDN_DEBUG_NET_DIAL
#undef ISDN_DEBUG_NET_ICALL
/* Prototypes */
-extern void isdn_MOD_INC_USE_COUNT(void);
-extern void isdn_MOD_DEC_USE_COUNT(void);
-extern void isdn_free_channel(int di, int ch, int usage);
-extern void isdn_all_eaz(int di, int ch);
-extern int isdn_dc2minor(int di, int ch);
-extern void isdn_info_update(void);
-extern char* isdn_map_eaz2msn(char *msn, int di);
-extern void isdn_timer_ctrl(int tf, int onoff);
-extern void isdn_unexclusive_channel(int di, int ch);
-extern int isdn_getnum(char **);
-extern int isdn_readbchan (int, int, u_char *, u_char *, int, int);
-extern int isdn_get_free_channel(int, int, int, int, int);
-extern int isdn_writebuf_stub(int, int, const u_char *, int, int);
-extern int isdn_writebuf_skb_stub(int, int, struct sk_buff *);
+extern void isdn_MOD_INC_USE_COUNT(void);
+extern void isdn_MOD_DEC_USE_COUNT(void);
+extern void isdn_free_channel(int di, int ch, int usage);
+extern void isdn_all_eaz(int di, int ch);
+extern int isdn_dc2minor(int di, int ch);
+extern void isdn_info_update(void);
+extern char *isdn_map_eaz2msn(char *msn, int di);
+extern void isdn_timer_ctrl(int tf, int onoff);
+extern void isdn_unexclusive_channel(int di, int ch);
+extern int isdn_getnum(char **);
+extern int isdn_readbchan(int, int, u_char *, u_char *, int, int);
+extern int isdn_get_free_channel(int, int, int, int, int);
+extern int isdn_writebuf_skb_stub(int, int, struct sk_buff *);
+extern int register_isdn(isdn_if * i);
+#if (LINUX_VERSION_CODE < 0x020111)
+extern void isdn_export_syms(void);
+#else
+#define isdn_export_syms()
+#endif
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
-extern void isdn_dumppkt(char *, u_char *, int, int);
+extern void isdn_dumppkt(char *, u_char *, int, int);
#endif
-/* $Id: isdn_net.c,v 1.29 1996/11/13 02:31:38 fritz Exp $
- *
+/* $Id: isdn_net.c,v 1.47 1997/06/21 10:52:05 fritz Exp $
+
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.47 1997/06/21 10:52:05 fritz
+ * Removed wrong SET_SKB_FREE in isdn_net_send_skb()
+ *
+ * Revision 1.46 1997/06/17 13:05:24 hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ *
+ * Revision 1.45 1997/06/10 16:24:22 hipp
+ * hard_header changes for syncPPP (now behaves like RAWIP)
+ *
+ * Revision 1.44 1997/05/27 15:17:26 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.43 1997/03/30 16:51:13 calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.42 1997/03/11 08:43:51 fritz
+ * Perform a hangup if number is deleted while dialing.
+ *
+ * Revision 1.41 1997/03/08 08:16:31 fritz
+ * Bugfix: Deleting a phone number during dial gave unpredictable results.
+ *
+ * Revision 1.40 1997/03/05 21:16:08 fritz
+ * Fix: did not compile with 2.1.27
+ *
+ * Revision 1.39 1997/03/04 21:36:52 fritz
+ * Added sending ICMP messages when no connetion is possible.
+ *
+ * Revision 1.38 1997/02/23 23:41:14 fritz
+ * Bugfix: Slave interfaces have to be hung up before master.
+ *
+ * Revision 1.37 1997/02/11 18:32:51 fritz
+ * Bugfix in isdn_ppp_free_mpqueue().
+ *
+ * Revision 1.36 1997/02/10 21:31:11 fritz
+ * Changed setup-interface (incoming and outgoing).
+ *
+ * Revision 1.35 1997/02/10 20:12:45 fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.34 1997/02/03 23:15:07 fritz
+ * Reformatted according CodingStyle.
+ * replaced arp_find prototype by proper include.
+ * made dev_purge_queues static.
+ * Bugfix in bogocps calculation.
+ * removed isdn_net_receive_callback - was never used ;-)
+ * Misc. fixes for Kernel 2.1.X comaptibility.
+ *
+ * Revision 1.33 1997/01/17 01:19:25 fritz
+ * Applied chargeint patch.
+ *
+ * Revision 1.32 1997/01/14 01:29:31 fritz
+ * Bugfix: isdn_net_hangup() did not reset ISDN_NET_CONNECTED.
+ *
+ * Revision 1.31 1997/01/11 23:30:42 fritz
+ * Speed up dial statemachine.
+ *
+ * Revision 1.30 1996/11/25 17:20:50 hipp
+ * fixed pppbind bug in isdn_net_find_icall()
+ *
* Revision 1.29 1996/11/13 02:31:38 fritz
* Minor cleanup.
*
#include <linux/module.h>
#include <linux/isdn.h>
#include <linux/if_arp.h>
+#include <net/arp.h>
+#include <net/icmp.h>
#include "isdn_common.h"
#include "isdn_net.h"
#ifdef CONFIG_ISDN_PPP
#include "isdn_ppp.h"
#endif
-/* In ksyms.c, but why not in some .h ??? */
-extern int arp_find(unsigned char *, u32, struct device *, u32,
- struct sk_buff *);
-
/* Prototypes */
int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_wildmat(char *s, char *p);
static int isdn_net_start_xmit(struct sk_buff *, struct device *);
static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
-
-extern void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */
+static void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */
-char *isdn_net_revision = "$Revision: 1.29 $";
+char *isdn_net_revision = "$Revision: 1.47 $";
/*
* Code for raw-networking over ISDN
*/
+static void
+isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
+{
+ printk(KERN_DEBUG "isdn_net: %s: %s, send ICMP\n",
+ dev->name, reason);
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0
+#if (LINUX_VERSION_CODE < 0x02010f) /* 2.1.15 */
+ ,dev
+#endif
+ );
+}
+
static void
isdn_net_reset(struct device *dev)
{
ulong flags;
save_flags(flags);
- cli(); /* Avoid glitch on writes to CMD regs */
+ cli(); /* Avoid glitch on writes to CMD regs */
dev->interrupt = 0;
dev->tbusy = 0;
restore_flags(flags);
dev->dev_addr[i] = 0xfc;
memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(u32));
- /* If this interface has slaves, start them also */
+ /* If this interface has slaves, start them also */
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
while (p) {
p = (((isdn_net_local *) p->priv)->slave);
}
}
-
isdn_MOD_INC_USE_COUNT();
return 0;
}
static void
isdn_net_bind_channel(isdn_net_local * lp, int idx)
{
- ulong flags;
+ ulong flags;
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
lp->isdn_device = dev->drvmap[idx];
lp->isdn_channel = dev->chanmap[idx];
- dev->rx_netdev[idx] = lp->netdev;
- dev->st_netdev[idx] = lp->netdev;
- restore_flags(flags);
+ dev->rx_netdev[idx] = lp->netdev;
+ dev->st_netdev[idx] = lp->netdev;
+ restore_flags(flags);
}
/*
save_flags(flags);
cli();
- if (lp->first_skb) {
- dev_kfree_skb(lp->first_skb,FREE_WRITE);
- lp->first_skb = NULL;
- }
- if(lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb,FREE_WRITE);
+ if (lp->first_skb) {
+ dev_kfree_skb(lp->first_skb, FREE_WRITE);
+ lp->first_skb = NULL;
+ }
+ if (lp->sav_skb) {
+ dev_kfree_skb(lp->sav_skb, FREE_WRITE);
lp->sav_skb = NULL;
}
- if(!lp->master) /* purge only for master device */
+ if (!lp->master) /* purge only for master device */
dev_purge_queues(&lp->netdev->dev);
lp->dialstate = 0;
- dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
- dev->st_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL;
+ dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
+ dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
lp->flags &= ~ISDN_NET_CONNECTED;
lp->isdn_device = -1;
lp->isdn_channel = -1;
- restore_flags(flags);
+ restore_flags(flags);
}
/*
isdn_net_autohup()
{
isdn_net_dev *p = dev->netdev;
- int anymore;
+ int anymore;
- anymore = 0;
+ anymore = 0;
while (p) {
isdn_net_local *l = (isdn_net_local *) & (p->local);
if ((jiffies - last_jiffies) == 0)
- l->cps = 0;
+ l->cps = l->transcount;
else
- l->cps = l->transcount / (jiffies - last_jiffies);
+ l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
l->transcount = 0;
if (dev->net_verbose > 3)
printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
- anymore = 1;
+ anymore = 1;
l->huptimer++;
if ((l->onhtime) && (l->huptimer > l->onhtime))
- if (l->outgoing) {
- if (l->hupflags & 4) {
- if (l->hupflags & 1)
+ if (l->hupflags & ISDN_MANCHARGE &&
+ l->hupflags & ISDN_CHARGEHUP) {
+ while (jiffies - l->chargetime > l->chargeint)
+ l->chargetime += l->chargeint;
+ if (jiffies - l->chargetime >= l->chargeint - 2 * HZ)
+ if (l->outgoing || l->hupflags & ISDN_INHUP)
isdn_net_hangup(&p->dev);
- else if (jiffies - l->chargetime > l->chargeint)
+ } else if (l->outgoing) {
+ if (l->hupflags & ISDN_CHARGEHUP) {
+ if (l->hupflags & ISDN_WAITCHARGE) {
+ printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
+ l->name, l->hupflags);
isdn_net_hangup(&p->dev);
+ } else if (jiffies - l->chargetime > l->chargeint) {
+ printk(KERN_DEBUG
+ "isdn_net: %s: chtime = %d, chint = %d\n",
+ l->name, l->chargetime, l->chargeint);
+ isdn_net_hangup(&p->dev);
+ }
} else
isdn_net_hangup(&p->dev);
- } else if (l->hupflags & 8)
+ } else if (l->hupflags & ISDN_INHUP)
isdn_net_hangup(&p->dev);
}
p = (isdn_net_dev *) p->next;
}
last_jiffies = jiffies;
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,anymore);
+ isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
}
/*
if (p) {
isdn_net_local *lp = &(p->local);
- switch (cmd) {
+ switch (cmd) {
case ISDN_STAT_BSENT:
/* A packet has successfully been sent out */
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
lp->stats.tx_packets++;
- if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
+ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
struct device *mdev;
- if(lp->master)
+ if (lp->master)
mdev = lp->master;
else
mdev = &lp->netdev->dev;
- if(!isdn_net_send_skb(mdev,lp,lp->sav_skb)) {
+ if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
lp->sav_skb = NULL;
mark_bh(NET_BH);
- }
- else {
+ } else {
return 1;
}
}
- if (clear_bit(0,(void*)&(p->dev.tbusy)))
- mark_bh(NET_BH);
+ if (test_and_clear_bit(0, (void *) &(p->dev.tbusy)))
+ mark_bh(NET_BH);
}
return 1;
case ISDN_STAT_DCONN:
/* D-Channel is up */
- switch (lp->dialstate) {
- case 4:
- case 7:
- case 8:
- lp->dialstate++;
- return 1;
- case 12:
- lp->dialstate = 5;
- return 1;
- }
+ switch (lp->dialstate) {
+ case 4:
+ case 7:
+ case 8:
+ lp->dialstate++;
+ return 1;
+ case 12:
+ lp->dialstate = 5;
+ return 1;
+ }
break;
case ISDN_STAT_DHUP:
/* Either D-Channel-hangup or error during dialout */
if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
lp->flags &= ~ISDN_NET_CONNECTED;
- if(lp->first_skb) {
- dev_kfree_skb(lp->first_skb,FREE_WRITE);
+ if (lp->first_skb) {
+ dev_kfree_skb(lp->first_skb, FREE_WRITE);
lp->first_skb = NULL;
}
- if(lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb,FREE_WRITE);
+ if (lp->sav_skb) {
+ dev_kfree_skb(lp->sav_skb, FREE_WRITE);
lp->sav_skb = NULL;
}
isdn_free_channel(lp->isdn_device, lp->isdn_channel,
- ISDN_USAGE_NET);
+ ISDN_USAGE_NET);
#ifdef CONFIG_ISDN_PPP
isdn_ppp_free(lp);
#endif
lp->isdn_channel = -1;
dev->st_netdev[idx] = NULL;
dev->rx_netdev[idx] = NULL;
- return 1;
+ return 1;
}
- break;
+ break;
case ISDN_STAT_BCONN:
/* B-Channel is up */
- switch (lp->dialstate) {
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 12:
- if (lp->dialstate <= 6) {
- dev->usage[idx] |= ISDN_USAGE_OUTGOING;
- isdn_info_update();
- } else
- dev->rx_netdev[idx] = p;
- lp->dialstate = 0;
- isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,1);
- printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
- /* If first Chargeinfo comes before B-Channel connect,
- * we correct the timestamp here.
- */
- lp->chargetime = jiffies;
- /* Immediately send first skb to speed up arp */
+ switch (lp->dialstate) {
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 12:
+ if (lp->dialstate <= 6) {
+ dev->usage[idx] |= ISDN_USAGE_OUTGOING;
+ isdn_info_update();
+ } else
+ dev->rx_netdev[idx] = p;
+ lp->dialstate = 0;
+ isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
+ printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
+ /* If first Chargeinfo comes before B-Channel connect,
+ * we correct the timestamp here.
+ */
+ lp->chargetime = jiffies;
+ printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n",
+ lp->name, lp->chargetime);
+ /* Immediately send first skb to speed up arp */
#ifdef CONFIG_ISDN_PPP
- if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_wakeup_daemon(lp);
#endif
- if (lp->first_skb) {
- if (!(isdn_net_xmit(&p->dev,lp,lp->first_skb)))
- lp->first_skb = NULL;
- }
- return 1;
+ if (lp->first_skb) {
+ if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
+ lp->first_skb = NULL;
+ }
+ return 1;
}
break;
case ISDN_STAT_NODCH:
/* No D-Channel avail. */
if (lp->dialstate == 4) {
lp->dialstate--;
- return 1;
- }
+ return 1;
+ }
break;
case ISDN_STAT_CINF:
/* Charge-info from TelCo. Calculate interval between
* usage by isdn_net_autohup()
*/
lp->charge++;
- if (lp->hupflags & 2) {
- lp->hupflags &= ~1;
+ if (lp->hupflags & ISDN_HAVECHARGE) {
+ lp->hupflags &= ~ISDN_WAITCHARGE;
lp->chargeint = jiffies - lp->chargetime - (2 * HZ);
}
- if (lp->hupflags & 1)
- lp->hupflags |= 2;
+ if (lp->hupflags & ISDN_WAITCHARGE)
+ lp->hupflags |= ISDN_HAVECHARGE;
lp->chargetime = jiffies;
+ printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %d\n",
+ lp->name, lp->chargetime);
return 1;
- }
+ }
}
- return 0;
+ return 0;
}
/*
isdn_net_dev *p = dev->netdev;
int anymore = 0;
int i;
+ int flags;
isdn_ctrl cmd;
while (p) {
#ifdef ISDN_DEBUG_NET_DIAL
- if (p->local.dialstate)
- printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name,p->local.dialstate);
+ if (p->local.dialstate)
+ printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name, p->local.dialstate);
#endif
switch (p->local.dialstate) {
- case 0:
- /* Nothing to do for this interface */
- break;
- case 1:
- /* Initiate dialout. Set phone-number-pointer to first number
- * of interface.
- */
- p->local.dial = p->local.phone[1];
- anymore = 1;
- p->local.dialstate++;
- break;
- /* Prepare dialing. Clear EAZ, then set EAZ. */
- case 2:
- cmd.driver = p->local.isdn_device;
- cmd.arg = p->local.isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- sprintf(cmd.num, "%s", isdn_map_eaz2msn(p->local.msn, cmd.driver));
- cmd.command = ISDN_CMD_SETEAZ;
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- p->local.dialretry = 0;
- anymore = 1;
- p->local.dialstate++;
- break;
- case 3:
- /* Setup interface, dial current phone-number, switch to next number.
- * If list of phone-numbers is exhausted, increment
- * retry-counter.
- */
- cmd.driver = p->local.isdn_device;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- cmd.driver = p->local.isdn_device;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- cmd.driver = p->local.isdn_device;
- cmd.arg = p->local.isdn_channel;
- p->local.huptimer = 0;
- p->local.outgoing = 1;
- p->local.hupflags |= 1;
- p->local.hupflags &= ~2;
- if (!strcmp(p->local.dial->num, "LEASED")) {
- p->local.dialstate = 4;
- printk(KERN_INFO "%s: Open leased line ...\n", p->local.name);
- } else {
- cmd.command = ISDN_CMD_DIAL;
- sprintf(cmd.num, "%s,%s,7,0", p->local.dial->num,
- isdn_map_eaz2msn(p->local.msn, cmd.driver));
- i = isdn_dc2minor(p->local.isdn_device, p->local.isdn_channel);
- if (i >= 0) {
- strcpy(dev->num[i], p->local.dial->num);
- isdn_info_update();
+ case 0:
+ /* Nothing to do for this interface */
+ break;
+ case 1:
+ /* Initiate dialout. Set phone-number-pointer to first number
+ * of interface.
+ */
+ save_flags(flags);
+ cli();
+ p->local.dial = p->local.phone[1];
+ restore_flags(flags);
+ if (!p->local.dial) {
+ printk(KERN_WARNING "%s: phone number deleted?\n",
+ p->local.name);
+ isdn_net_hangup(&p->dev);
+ break;
}
- printk(KERN_INFO "%s: dialing %d %s...\n", p->local.name,
- p->local.dialretry, p->local.dial->num);
- /*
- * Switch to next number or back to start if at end of list.
+ anymore = 1;
+ p->local.dialstate++;
+ /* Fall through */
+ case 2:
+ /* Prepare dialing. Clear EAZ, then set EAZ. */
+ cmd.driver = p->local.isdn_device;
+ cmd.arg = p->local.isdn_channel;
+ cmd.command = ISDN_CMD_CLREAZ;
+ dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(p->local.msn, cmd.driver));
+ cmd.command = ISDN_CMD_SETEAZ;
+ dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ p->local.dialretry = 0;
+ anymore = 1;
+ p->local.dialstate++;
+ /* Falls through */
+ case 3:
+ /* Setup interface, dial current phone-number, switch to next number.
+ * If list of phone-numbers is exhausted, increment
+ * retry-counter.
*/
- if (!(p->local.dial = (isdn_net_phone *) p->local.dial->next)) {
- p->local.dial = p->local.phone[1];
- p->local.dialretry++;
+ cmd.driver = p->local.isdn_device;
+ cmd.command = ISDN_CMD_SETL2;
+ cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
+ dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ cmd.driver = p->local.isdn_device;
+ cmd.command = ISDN_CMD_SETL3;
+ cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
+ dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ cmd.driver = p->local.isdn_device;
+ cmd.arg = p->local.isdn_channel;
+ save_flags(flags);
+ cli();
+ if (!p->local.dial) {
+ restore_flags(flags);
+ printk(KERN_WARNING "%s: phone number deleted?\n",
+ p->local.name);
+ isdn_net_hangup(&p->dev);
+ break;
}
- p->local.dtimer = 0;
+ if (!strcmp(p->local.dial->num, "LEASED")) {
+ restore_flags(flags);
+ p->local.dialstate = 4;
+ printk(KERN_INFO "%s: Open leased line ...\n", p->local.name);
+ } else {
+ sprintf(cmd.parm.setup.phone, "%s", p->local.dial->num);
+ /*
+ * Switch to next number or back to start if at end of list.
+ */
+ if (!(p->local.dial = (isdn_net_phone *) p->local.dial->next)) {
+ p->local.dial = p->local.phone[1];
+ p->local.dialretry++;
+ }
+ restore_flags(flags);
+ cmd.command = ISDN_CMD_DIAL;
+ cmd.parm.setup.si1 = 7;
+ cmd.parm.setup.si2 = 0;
+ sprintf(cmd.parm.setup.eazmsn, "%s",
+ isdn_map_eaz2msn(p->local.msn, cmd.driver));
+ i = isdn_dc2minor(p->local.isdn_device, p->local.isdn_channel);
+ if (i >= 0) {
+ strcpy(dev->num[i], cmd.parm.setup.phone);
+ isdn_info_update();
+ }
+ printk(KERN_INFO "%s: dialing %d %s...\n", p->local.name,
+ p->local.dialretry - 1, cmd.parm.setup.phone);
+ p->local.dtimer = 0;
#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dial: d=%d c=%d\n", p->local.isdn_device,
- p->local.isdn_channel);
+ printk(KERN_DEBUG "dial: d=%d c=%d\n", p->local.isdn_device,
+ p->local.isdn_channel);
#endif
+ dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ }
+ p->local.huptimer = 0;
+ p->local.outgoing = 1;
+ if (p->local.chargeint) {
+ p->local.hupflags |= ISDN_HAVECHARGE;
+ p->local.hupflags &= ~ISDN_WAITCHARGE;
+ } else {
+ p->local.hupflags |= ISDN_WAITCHARGE;
+ p->local.hupflags &= ~ISDN_HAVECHARGE;
+ }
+ anymore = 1;
+ p->local.dialstate =
+ (p->local.cbdelay &&
+ (p->local.flags & ISDN_NET_CBOUT)) ? 12 : 4;
+ break;
+ case 4:
+ /* Wait for D-Channel-connect.
+ * If timeout and max retries not
+ * reached, switch back to state 3.
+ */
+ if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
+ if (p->local.dialretry < p->local.dialmax) {
+ p->local.dialstate = 3;
+ } else
+ isdn_net_hangup(&p->dev);
+ anymore = 1;
+ break;
+ case 5:
+ /* Got D-Channel-Connect, send B-Channel-request */
+ cmd.driver = p->local.isdn_device;
+ cmd.arg = p->local.isdn_channel;
+ cmd.command = ISDN_CMD_ACCEPTB;
+ anymore = 1;
+ p->local.dtimer = 0;
+ p->local.dialstate++;
dev->drv[p->local.isdn_device]->interface->command(&cmd);
- }
- anymore = 1;
- p->local.dialstate =
- (p->local.cbdelay &&
- (p->local.flags & ISDN_NET_CBOUT))?12:4;
- break;
- case 4:
- /* Wait for D-Channel-connect.
- * If timeout and max retries not
- * reached, switch back to state 3.
- */
- if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
- if (p->local.dialretry < p->local.dialmax) {
- p->local.dialstate = 3;
- } else
- isdn_net_hangup(&p->dev);
- anymore = 1;
- break;
- case 5:
- /* Got D-Channel-Connect, send B-Channel-request */
- cmd.driver = p->local.isdn_device;
- cmd.arg = p->local.isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTB;
- anymore = 1;
- p->local.dtimer = 0;
- p->local.dialstate++;
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- break;
- case 6:
- /* Wait for B- or D-Channel-connect. If timeout,
- * switch back to state 3.
- */
+ break;
+ case 6:
+ /* Wait for B- or D-Channel-connect. If timeout,
+ * switch back to state 3.
+ */
#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer2: %d\n", p->local.dtimer);
+ printk(KERN_DEBUG "dialtimer2: %d\n", p->local.dtimer);
#endif
- if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
- p->local.dialstate = 3;
- anymore = 1;
- break;
- case 7:
- /* Got incoming Call, setup L2 and L3 protocols,
- * then wait for D-Channel-connect
- */
+ if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
+ p->local.dialstate = 3;
+ anymore = 1;
+ break;
+ case 7:
+ /* Got incoming Call, setup L2 and L3 protocols,
+ * then wait for D-Channel-connect
+ */
#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
+ printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
#endif
- cmd.driver = p->local.isdn_device;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- cmd.driver = p->local.isdn_device;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT15)
- isdn_net_hangup(&p->dev);
- else {
+ cmd.driver = p->local.isdn_device;
+ cmd.command = ISDN_CMD_SETL2;
+ cmd.arg = p->local.isdn_channel + (p->local.l2_proto << 8);
+ dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ cmd.driver = p->local.isdn_device;
+ cmd.command = ISDN_CMD_SETL3;
+ cmd.arg = p->local.isdn_channel + (p->local.l3_proto << 8);
+ dev->drv[p->local.isdn_device]->interface->command(&cmd);
+ if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT15)
+ isdn_net_hangup(&p->dev);
+ else {
+ anymore = 1;
+ p->local.dialstate++;
+ }
+ break;
+ case 9:
+ /* Got incoming D-Channel-Connect, send B-Channel-request */
+ cmd.driver = p->local.isdn_device;
+ cmd.arg = p->local.isdn_channel;
+ cmd.command = ISDN_CMD_ACCEPTB;
+ dev->drv[p->local.isdn_device]->interface->command(&cmd);
anymore = 1;
- p->local.dialstate++;
- }
- break;
- case 9:
- /* Got incoming D-Channel-Connect, send B-Channel-request */
- cmd.driver = p->local.isdn_device;
- cmd.arg = p->local.isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTB;
- dev->drv[p->local.isdn_device]->interface->command(&cmd);
- anymore = 1;
- p->local.dtimer = 0;
- p->local.dialstate++;
- break;
- case 8:
- case 10:
- /* Wait for B- or D-channel-connect */
+ p->local.dtimer = 0;
+ p->local.dialstate++;
+ break;
+ case 8:
+ case 10:
+ /* Wait for B- or D-channel-connect */
#ifdef ISDN_DEBUG_NET_DIAL
- printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
+ printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer);
#endif
- if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
- isdn_net_hangup(&p->dev);
- else
+ if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10)
+ isdn_net_hangup(&p->dev);
+ else
+ anymore = 1;
+ break;
+ case 11:
+ /* Callback Delay */
+ if (p->local.dtimer++ > p->local.cbdelay)
+ p->local.dialstate = 1;
anymore = 1;
- break;
- case 11:
- /* Callback Delay */
- if (p->local.dtimer++ > p->local.cbdelay)
- p->local.dialstate = 1;
- anymore = 1;
- break;
- case 12:
- /* Remote does callback. Hangup after cbdelay, then wait for incoming
- * call (in state 4).
- */
- if (p->local.dtimer++ > p->local.cbdelay) {
- printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name);
- p->local.dtimer = 0;
- p->local.dialstate = 4;
- cmd.driver = p->local.isdn_device;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = p->local.isdn_channel;
- (void) dev->drv[cmd.driver]->interface->command(&cmd);
- isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel);
- }
- anymore = 1;
- break;
- default:
- printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
- p->local.dialstate, p->local.name);
+ break;
+ case 12:
+ /* Remote does callback. Hangup after cbdelay, then wait for incoming
+ * call (in state 4).
+ */
+ if (p->local.dtimer++ > p->local.cbdelay) {
+ printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name);
+ p->local.dtimer = 0;
+ p->local.dialstate = 4;
+ cmd.driver = p->local.isdn_device;
+ cmd.command = ISDN_CMD_HANGUP;
+ cmd.arg = p->local.isdn_channel;
+ (void) dev->drv[cmd.driver]->interface->command(&cmd);
+ isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel);
+ }
+ anymore = 1;
+ break;
+ default:
+ printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
+ p->local.dialstate, p->local.name);
}
p = (isdn_net_dev *) p->next;
}
isdn_ctrl cmd;
if (lp->flags & ISDN_NET_CONNECTED) {
+ lp->flags &= ~ISDN_NET_CONNECTED;
printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
#ifdef CONFIG_ISDN_PPP
isdn_ppp_free(lp);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
}
- isdn_net_unbind_channel(lp);
+ isdn_net_unbind_channel(lp);
}
typedef struct {
static void
isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
{
- u_char *p = buf;
+ u_char *p = buf;
unsigned short proto = ETH_P_IP;
- int data_ofs;
+ int data_ofs;
ip_ports *ipp;
char addinfo[100];
- addinfo[0] = '\0';
- switch (lp->p_encap) {
- case ISDN_NET_ENCAP_IPTYP:
- proto = ntohs(*(unsigned short *)&buf[0]);
- p = &buf[2];
- break;
- case ISDN_NET_ENCAP_ETHER:
- proto = ntohs(*(unsigned short *)&buf[12]);
- p = &buf[14];
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- proto = ntohs(*(unsigned short *)&buf[2]);
- p = &buf[4];
- break;
- }
+ addinfo[0] = '\0';
+ switch (lp->p_encap) {
+ case ISDN_NET_ENCAP_IPTYP:
+ proto = ntohs(*(unsigned short *) &buf[0]);
+ p = &buf[2];
+ break;
+ case ISDN_NET_ENCAP_ETHER:
+ proto = ntohs(*(unsigned short *) &buf[12]);
+ p = &buf[14];
+ break;
+ case ISDN_NET_ENCAP_CISCOHDLC:
+ proto = ntohs(*(unsigned short *) &buf[2]);
+ p = &buf[4];
+ break;
+ }
data_ofs = ((p[0] & 15) * 4);
- switch (proto) {
+ switch (proto) {
case ETH_P_IP:
switch (p[9]) {
- case 1:
- strcpy(addinfo, " ICMP");
- break;
- case 2:
- strcpy(addinfo, " IGMP");
- break;
- case 4:
- strcpy(addinfo, " IPIP");
- break;
- case 6:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 8:
- strcpy(addinfo, " EGP");
- break;
- case 12:
- strcpy(addinfo, " PUP");
- break;
- case 17:
- ipp = (ip_ports *) (&p[data_ofs]);
- sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
- ntohs(ipp->dest));
- break;
- case 22:
- strcpy(addinfo, " IDP");
- break;
+ case 1:
+ strcpy(addinfo, " ICMP");
+ break;
+ case 2:
+ strcpy(addinfo, " IGMP");
+ break;
+ case 4:
+ strcpy(addinfo, " IPIP");
+ break;
+ case 6:
+ ipp = (ip_ports *) (&p[data_ofs]);
+ sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source),
+ ntohs(ipp->dest));
+ break;
+ case 8:
+ strcpy(addinfo, " EGP");
+ break;
+ case 12:
+ strcpy(addinfo, " PUP");
+ break;
+ case 17:
+ ipp = (ip_ports *) (&p[data_ofs]);
+ sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source),
+ ntohs(ipp->dest));
+ break;
+ case 22:
+ strcpy(addinfo, " IDP");
+ break;
}
printk(KERN_INFO "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
p[12], p[13], p[14], p[15],
p[14], p[15], p[16], p[17],
p[24], p[25], p[26], p[27]);
break;
- }
+ }
}
/*
* Side-effects: ndev->tbusy is cleared on success.
*/
int
-isdn_net_send_skb(struct device *ndev, isdn_net_local *lp,
- struct sk_buff *skb)
+isdn_net_send_skb(struct device *ndev, isdn_net_local * lp,
+ struct sk_buff *skb)
{
int ret;
- int len = skb->len; /* save len */
-
- ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb);
+ int len = skb->len; /* save len */
+
+ ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb);
if (ret == len) {
lp->transcount += len;
- clear_bit(0, (void *)&(ndev->tbusy));
+ clear_bit(0, (void *) &(ndev->tbusy));
+ return 0;
+ }
+ if (ret < 0) {
+ dev_kfree_skb(skb, FREE_WRITE);
+ lp->stats.tx_errors++;
+ clear_bit(0, (void *) &(ndev->tbusy));
return 0;
}
- if (ret < 0) {
- skb->free = 1;
- dev_kfree_skb(skb, FREE_WRITE);
- lp->stats.tx_errors++;
- clear_bit(0, (void *)&(ndev->tbusy));
- return 0;
- }
return 1;
-}
-
+}
+
/*
* Helper function for isdn_net_start_xmit.
*/
static int
-isdn_net_xmit(struct device *ndev, isdn_net_local *lp, struct sk_buff *skb)
+isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
{
- int ret;
+ int ret;
/* For the other encaps the header has already been built */
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
return isdn_ppp_xmit(skb, ndev);
}
-#endif
+#endif
/* Reset hangup-timeout */
lp->huptimer = 0;
- if (lp->cps > 7000) {
+ if (lp->cps > lp->triggercps) {
/* Device overloaded */
- /*
- * Packet-delivery via round-robin over master
+ /*
+ * Packet-delivery via round-robin over master
* and all connected slaves.
*/
if (lp->master)
/* First time overload: set timestamp only */
lp->sqfull = 1;
lp->sqfull_stamp = jiffies;
- }
- else {
+ } else {
/* subsequent overload: if slavedelay exceeded, start dialing */
if ((jiffies - lp->sqfull_stamp) > lp->slavedelay)
isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
}
}
- }
- else {
+ } else {
/* Not overloaded, deliver locally */
ret = isdn_net_send_skb(ndev, lp, skb);
- if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10*HZ) )))
+ if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ))))
lp->sqfull = 0;
}
return ret;
if (ndev->tbusy) {
if (jiffies - ndev->trans_start < (2 * HZ))
return 1;
- if (!lp->dialstate)
- lp->stats.tx_errors++;
+ if (!lp->dialstate)
+ lp->stats.tx_errors++;
ndev->tbusy = 0;
ndev->trans_start = jiffies;
}
return 0;
}
/* Avoid timer-based retransmission conflicts. */
- if (set_bit(0, (void *) &ndev->tbusy) != 0)
+ if (test_and_set_bit(0, (void *) &ndev->tbusy) != 0)
printk(KERN_WARNING
- "%s: Transmitter access conflict.\n",
- ndev->name);
+ "%s: Transmitter access conflict.\n",
+ ndev->name);
else {
u_char *buf = skb->data;
#ifdef ISDN_DEBUG_NET_DUMP
save_flags(flags);
cli();
/* Grab a free ISDN-Channel */
- if ((chi =
- isdn_get_free_channel(ISDN_USAGE_NET,
- lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
- lp->pre_channel)) < 0) {
- printk(KERN_WARNING
- "isdn_net_start_xmit: No channel for %s\n",
- ndev->name);
+ if ((chi =
+ isdn_get_free_channel(ISDN_USAGE_NET,
+ lp->l2_proto,
+ lp->l3_proto,
+ lp->pre_device,
+ lp->pre_channel)) < 0) {
restore_flags(flags);
- /* we probably should drop the skb here and return 0 to omit
- 'socket destroy delayed' messages */
+#if 0
+ printk(KERN_WARNING
+ "isdn_net_start_xmit: No channel for %s\n",
+ ndev->name);
+ /* we probably should drop the skb here and return 0 to omit
+ 'socket destroy delayed' messages */
return 1;
+#else
+ isdn_net_unreachable(ndev, skb,
+ "No channel");
+ dev_kfree_skb(skb, FREE_WRITE);
+ ndev->tbusy = 0;
+ return 0;
+#endif
}
- /* Log packet, which triggered dialing */
+ /* Log packet, which triggered dialing */
if (dev->net_verbose)
- isdn_net_log_packet(buf, lp);
+ isdn_net_log_packet(buf, lp);
lp->dialstate = 1;
lp->flags |= ISDN_NET_CONNECTED;
/* Connect interface with channel */
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
/* no 'first_skb' handling for syncPPP */
if (isdn_ppp_bind(lp) < 0) {
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb, FREE_WRITE);
isdn_net_unbind_channel(lp);
- restore_flags(flags);
+ restore_flags(flags);
return 0; /* STN (skb to nirvana) ;) */
}
restore_flags(flags);
- isdn_net_dial(); /* Initiate dialing */
+ isdn_net_dial(); /* Initiate dialing */
return 1; /* let upper layer requeue skb packet */
}
#endif
- /* remember first skb to speed up arp
- * when using encap ETHER
- */
- if (lp->first_skb) {
- printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n");
- dev_kfree_skb(lp->first_skb,FREE_WRITE);
- lp->first_skb = NULL;
- }
- lp->first_skb = skb;
+ /* remember first skb to speed up arp
+ * when using encap ETHER
+ */
+ if (lp->first_skb) {
+ printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n");
+ dev_kfree_skb(lp->first_skb, FREE_WRITE);
+ lp->first_skb = NULL;
+ }
+ lp->first_skb = skb;
/* Initiate dialing */
- ndev->tbusy = 0;
+ ndev->tbusy = 0;
restore_flags(flags);
isdn_net_dial();
- return 0;
+ return 0;
} else {
- /*
- * Having no phone-number is a permanent
- * failure or misconfiguration.
- * Instead of just dropping, we should also
- * have the upper layers to respond
- * with an ICMP No route to host in the
- * future, however at the moment, i don't
- * know a simple way to do that.
- * The same applies, when the telecom replies
- * "no destination" to our dialing-attempt.
- */
- printk(KERN_WARNING
- "isdn_net: No phone number for %s, packet dropped\n",
- ndev->name);
+ isdn_net_unreachable(ndev, skb,
+ "No phone number");
dev_kfree_skb(skb, FREE_WRITE);
ndev->tbusy = 0;
- return 0;
+ return 0;
}
} else {
- /* Connection is established, try sending */
+ /* Connection is established, try sending */
ndev->trans_start = jiffies;
if (!lp->dialstate) {
- if (lp->first_skb) {
- if (isdn_net_xmit(ndev,lp,lp->first_skb))
- return 1;
- lp->first_skb = NULL;
- }
- return(isdn_net_xmit(ndev, lp, skb));
+ if (lp->first_skb) {
+ if (isdn_net_xmit(ndev, lp, lp->first_skb))
+ return 1;
+ lp->first_skb = NULL;
+ }
+ return (isdn_net_xmit(ndev, lp, skb));
} else
ndev->tbusy = 1;
}
dev->tbusy = 1;
dev->start = 0;
- isdn_net_hangup(dev);
if ((p = (((isdn_net_local *) dev->priv)->slave))) {
/* If this interface has slaves, stop them also */
while (p) {
p = (((isdn_net_local *) p->priv)->slave);
}
}
+ isdn_net_hangup(dev);
isdn_MOD_DEC_USE_COUNT();
return 0;
}
* Get statistics
*/
static struct enet_statistics *
- isdn_net_get_stats(struct device *dev)
+isdn_net_get_stats(struct device *dev)
{
isdn_net_local *lp = (isdn_net_local *) dev->priv;
return &lp->stats;
* This is normal practice and works for any 'now in use' protocol.
*/
-unsigned short isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
+static unsigned short
+isdn_net_type_trans(struct sk_buff *skb, struct device *dev)
{
- struct ethhdr *eth;
- unsigned char *rawp;
-
- skb_pull(skb,ETH_HLEN);
- eth= skb->mac.ethernet;
-
- if(*eth->h_dest&1) {
- if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
- skb->pkt_type=PACKET_BROADCAST;
- else
- skb->pkt_type=PACKET_MULTICAST;
- }
-
- /*
- * This ALLMULTI check should be redundant by 1.4
- * so don't forget to remove it.
- */
-
- else if (dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) {
- if (memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
- skb->pkt_type=PACKET_OTHERHOST;
- }
-
- if (ntohs(eth->h_proto) >= 1536)
- return eth->h_proto;
-
- rawp = skb->data;
-
- /*
- * This is a magic hack to spot IPX packets. Older Novell breaks
- * the protocol design and runs IPX over 802.3 without an 802.2 LLC
- * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
- * won't work for fault tolerant netware but does for the rest.
- */
- if (*(unsigned short *)rawp == 0xFFFF)
- return htons(ETH_P_802_3);
- /*
- * Real 802.2 LLC
- */
- return htons(ETH_P_802_2);
+ struct ethhdr *eth;
+ unsigned char *rawp;
+
+ skb_pull(skb, ETH_HLEN);
+ eth = skb->mac.ethernet;
+
+ if (*eth->h_dest & 1) {
+ if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
+ skb->pkt_type = PACKET_BROADCAST;
+ else
+ skb->pkt_type = PACKET_MULTICAST;
+ }
+ /*
+ * This ALLMULTI check should be redundant by 1.4
+ * so don't forget to remove it.
+ */
+
+ else if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+ if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
+ skb->pkt_type = PACKET_OTHERHOST;
+ }
+ if (ntohs(eth->h_proto) >= 1536)
+ return eth->h_proto;
+
+ rawp = skb->data;
+
+ /*
+ * This is a magic hack to spot IPX packets. Older Novell breaks
+ * the protocol design and runs IPX over 802.3 without an 802.2 LLC
+ * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+ * won't work for fault tolerant netware but does for the rest.
+ */
+ if (*(unsigned short *) rawp == 0xFFFF)
+ return htons(ETH_P_802_3);
+ /*
+ * Real 802.2 LLC
+ */
+ return htons(ETH_P_802_2);
}
-/*
+/*
* Got a packet from ISDN-Channel.
*/
static void
{
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
#ifdef CONFIG_ISDN_PPP
- isdn_net_local *olp = lp; /* original 'lp' */
- int proto = PPP_PROTOCOL(skb->data);
+ isdn_net_local *olp = lp; /* original 'lp' */
+ int proto = PPP_PROTOCOL(skb->data);
#endif
lp->transcount += skb->len;
lp->stats.rx_packets++;
#ifdef CONFIG_ISDN_PPP
- /*
- * If encapsulation is syncppp, don't reset
- * huptimer on LCP packets.
- */
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
- (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
+ /*
+ * If encapsulation is syncppp, don't reset
+ * huptimer on LCP packets.
+ */
+ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
+ (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
#endif
- lp->huptimer = 0;
+ lp->huptimer = 0;
if (lp->master) {
/* Bundling: If device is a slave-device, deliver to master, also
lp = (isdn_net_local *) ndev->priv;
lp->stats.rx_packets++;
#ifdef CONFIG_ISDN_PPP
- /*
- * If encapsulation is syncppp, don't reset
- * huptimer on LCP packets.
- */
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
- (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
+ /*
+ * If encapsulation is syncppp, don't reset
+ * huptimer on LCP packets.
+ */
+ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP ||
+ (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && proto != PPP_LCP))
#endif
- lp->huptimer = 0;
+ lp->huptimer = 0;
}
-
skb->dev = ndev;
skb->pkt_type = PACKET_HOST;
- skb->mac.raw = skb->data;
+ skb->mac.raw = skb->data;
#ifdef ISDN_DEBUG_NET_DUMP
- isdn_dumppkt("R:", skb->data, skb->len, 40);
+ isdn_dumppkt("R:", skb->data, skb->len, 40);
#endif
switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- /* Ethernet over ISDN */
- skb->protocol = isdn_net_type_trans(skb,ndev);
- break;
- case ISDN_NET_ENCAP_UIHDLC:
- /* HDLC with UI-frame (for ispa with -h1 option) */
- skb_pull(skb,2);
- /* Fall through */
- case ISDN_NET_ENCAP_RAWIP:
- /* RAW-IP without MAC-Header */
- skb->protocol = htons(ETH_P_IP);
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
- /* CISCO-HDLC IP with type field and fake I-frame-header */
- skb_pull(skb, 2);
- /* Fall through */
- case ISDN_NET_ENCAP_IPTYP:
- /* IP with type field */
- skb->protocol = *(unsigned short *)&(skb->data[0]);
- skb_pull(skb, 2);
- if (*(unsigned short *)skb->data == 0xFFFF)
- skb->protocol = htons(ETH_P_802_3);
- break;
+ case ISDN_NET_ENCAP_ETHER:
+ /* Ethernet over ISDN */
+ skb->protocol = isdn_net_type_trans(skb, ndev);
+ break;
+ case ISDN_NET_ENCAP_UIHDLC:
+ /* HDLC with UI-frame (for ispa with -h1 option) */
+ skb_pull(skb, 2);
+ /* Fall through */
+ case ISDN_NET_ENCAP_RAWIP:
+ /* RAW-IP without MAC-Header */
+ skb->protocol = htons(ETH_P_IP);
+ break;
+ case ISDN_NET_ENCAP_CISCOHDLC:
+ /* CISCO-HDLC IP with type field and fake I-frame-header */
+ skb_pull(skb, 2);
+ /* Fall through */
+ case ISDN_NET_ENCAP_IPTYP:
+ /* IP with type field */
+ skb->protocol = *(unsigned short *) &(skb->data[0]);
+ skb_pull(skb, 2);
+ if (*(unsigned short *) skb->data == 0xFFFF)
+ skb->protocol = htons(ETH_P_802_3);
+ break;
#ifdef CONFIG_ISDN_PPP
- case ISDN_NET_ENCAP_SYNCPPP:
- isdn_ppp_receive(lp->netdev, olp, skb);
- return;
+ case ISDN_NET_ENCAP_SYNCPPP:
+ isdn_ppp_receive(lp->netdev, olp, skb);
+ return;
#endif
- default:
- printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
- lp->name);
- kfree_skb(skb,FREE_READ);
- return;
+ default:
+ printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
+ lp->name);
+ kfree_skb(skb, FREE_READ);
+ return;
}
netif_rx(skb);
return;
* else return 0.
*/
int
-isdn_net_receive_callback(int idx, u_char * buf, int len)
-{
- isdn_net_dev *p = dev->rx_netdev[idx];
- struct sk_buff *skb;
-
- if (p) {
- isdn_net_local *lp = &p->local;
- if ((lp->flags & ISDN_NET_CONNECTED) &&
- (!lp->dialstate)) {
- skb = dev_alloc_skb(len);
- if (skb == NULL) {
- printk(KERN_WARNING "out of memory\n");
- return 0;
- }
- memcpy(skb_put(skb, len), buf, len);
- isdn_net_receive(&p->dev, skb);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * receive callback for lowlevel drivers, which support skb's
- */
-
-int
-isdn_net_rcv_skb(int idx, struct sk_buff *skb)
+isdn_net_rcv_skb(int idx, struct sk_buff *skb)
{
isdn_net_dev *p = dev->rx_netdev[idx];
static int
my_eth_header(struct sk_buff *skb, struct device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
+ void *daddr, void *saddr, unsigned len)
{
- struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN);
+ struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
- /*
+ /*
* Set the protocol type. For a packet of type ETH_P_802_3 we
- * put the length here instead. It is up to the 802.2 layer to
- * carry protocol information.
+ * put the length here instead. It is up to the 802.2 layer to
+ * carry protocol information.
*/
-
- if(type!=ETH_P_802_3)
+
+ if (type != ETH_P_802_3)
eth->h_proto = htons(type);
else
eth->h_proto = htons(len);
/*
- * Set the source hardware address.
+ * Set the source hardware address.
*/
- if(saddr)
- memcpy(eth->h_source,saddr,dev->addr_len);
+ if (saddr)
+ memcpy(eth->h_source, saddr, dev->addr_len);
else
- memcpy(eth->h_source,dev->dev_addr,dev->addr_len);
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
/*
- * Anyway, the loopback-device should never use this function...
+ * Anyway, the loopback-device should never use this function...
*/
if (dev->flags & IFF_LOOPBACK) {
memset(eth->h_dest, 0, dev->addr_len);
- return(dev->hard_header_len);
+ return (dev->hard_header_len);
}
-
- if(daddr) {
- memcpy(eth->h_dest,daddr,dev->addr_len);
+ if (daddr) {
+ memcpy(eth->h_dest, daddr, dev->addr_len);
return dev->hard_header_len;
}
-
return -dev->hard_header_len;
}
* build an header
* depends on encaps that is being used.
*/
-
+
static int
isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned plen)
+ void *daddr, void *saddr, unsigned plen)
{
isdn_net_local *lp = dev->priv;
ushort len = 0;
-
+
switch (lp->p_encap) {
- case ISDN_NET_ENCAP_ETHER:
- len = my_eth_header(skb, dev, type, daddr, saddr, plen);
- break;
- case ISDN_NET_ENCAP_RAWIP:
- printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
+ case ISDN_NET_ENCAP_ETHER:
+ len = my_eth_header(skb, dev, type, daddr, saddr, plen);
+ break;
+#ifdef CONFIG_ISDN_PPP
+ case ISDN_NET_ENCAP_SYNCPPP:
+ /* stick on a fake header to keep fragmentation code happy. */
+ len = IPPP_MAX_HEADER;
+ skb_push(skb,len);
+ break;
+#endif
+ case ISDN_NET_ENCAP_RAWIP:
+ printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
len = 0;
- break;
- case ISDN_NET_ENCAP_IPTYP:
- /* ethernet type field */
- *((ushort*) skb_push(skb, 2)) = htons(type);
- len = 2;
- break;
- case ISDN_NET_ENCAP_UIHDLC:
- /* HDLC with UI-Frames (for ispa with -h1 option) */
- *((ushort*) skb_push(skb, 2)) = htons(0x0103);
- len = 2;
- break;
- case ISDN_NET_ENCAP_CISCOHDLC:
+ break;
+ case ISDN_NET_ENCAP_IPTYP:
+ /* ethernet type field */
+ *((ushort *) skb_push(skb, 2)) = htons(type);
+ len = 2;
+ break;
+ case ISDN_NET_ENCAP_UIHDLC:
+ /* HDLC with UI-Frames (for ispa with -h1 option) */
+ *((ushort *) skb_push(skb, 2)) = htons(0x0103);
+ len = 2;
+ break;
+ case ISDN_NET_ENCAP_CISCOHDLC:
skb_push(skb, 4);
- skb->data[0] = 0x0f;
- skb->data[1] = 0x00;
- *((ushort*)&skb->data[2]) = htons(type);
- len = 4;
- break;
+ skb->data[0] = 0x0f;
+ skb->data[1] = 0x00;
+ *((ushort *) & skb->data[2]) = htons(type);
+ len = 4;
+ break;
}
return len;
}
/* We don't need to send arp, because we have point-to-point connections. */
-
+#if (LINUX_VERSION_CODE < 0x02010F)
static int
isdn_net_rebuild_header(void *buff, struct device *dev, unsigned long dst,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
isdn_net_local *lp = dev->priv;
- int ret = 0;
-
- if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
- struct ethhdr *eth = (struct ethhdr *)buff;
-
- /*
- * Only ARP/IP is currently supported
- */
-
- if(eth->h_proto != htons(ETH_P_IP)) {
- printk(KERN_WARNING
- "isdn_net: %s don't know how to resolve type %d addresses?\n",
- dev->name, (int)eth->h_proto);
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- return 0;
- }
- /*
- * Try to get ARP to resolve the header.
- */
-#ifdef CONFIG_INET
- ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;
-#endif
- }
+ int ret = 0;
+
+ if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
+ struct ethhdr *eth = (struct ethhdr *) buff;
+
+ /*
+ * Only ARP/IP is currently supported
+ */
+
+ if (eth->h_proto != htons(ETH_P_IP)) {
+ printk(KERN_WARNING
+ "isdn_net: %s don't know how to resolve type %d addresses?\n",
+ dev->name, (int) eth->h_proto);
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ return 0;
+ }
+ /*
+ * Try to get ARP to resolve the header.
+ */
+#ifdef CONFIG_INET
+ ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb) ? 1 : 0;
+#endif
+ }
return ret;
}
+#else
+static int
+isdn_net_rebuild_header(struct sk_buff *skb)
+{
+ struct device *dev = skb->dev;
+ isdn_net_local *lp = dev->priv;
+ int ret = 0;
+
+ if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
+ struct ethhdr *eth = (struct ethhdr *) skb->data;
+ /*
+ * Only ARP/IP is currently supported
+ */
+
+ if (eth->h_proto != htons(ETH_P_IP)) {
+ printk(KERN_WARNING
+ "isdn_net: %s don't know how to resolve type %d addresses?\n",
+ dev->name, (int) eth->h_proto);
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ return 0;
+ }
+ /*
+ * Try to get ARP to resolve the header.
+ */
+#ifdef CONFIG_INET
+ ret = arp_find(eth->h_dest, skb) ? 1 : 0;
+#endif
+ }
+ return ret;
+}
+#endif
/*
* Interface-setup. (called just after registering a new interface)
*/
isdn_net_init(struct device *ndev)
{
ushort max_hlhdr_len = 0;
- isdn_net_local *lp = (isdn_net_local *)ndev->priv;
- int drvidx, i;
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+ int drvidx,
+ i;
if (ndev == NULL) {
printk(KERN_WARNING "isdn_net_init: dev = NULL!\n");
printk(KERN_WARNING "isdn_net_init: dev->priv = NULL!\n");
return -ENODEV;
}
-
- ether_setup(ndev);
- lp->org_hcb = ndev->header_cache_bind;
- lp->org_hcu = ndev->header_cache_update;
+ ether_setup(ndev);
+#if (LINUX_VERSION_CODE < 0x02010F)
+ lp->org_hcb = ndev->header_cache_bind;
+#else
+ lp->org_hhc = ndev->hard_header_cache;
+#endif
+ lp->org_hcu = ndev->header_cache_update;
/* Setup the generic properties */
- ndev->hard_header = NULL;
- ndev->header_cache_bind = NULL;
- ndev->header_cache_update = NULL;
- ndev->mtu = 1500;
- ndev->flags = IFF_NOARP;
- ndev->family = AF_INET;
- ndev->type = ARPHRD_ETHER;
- ndev->addr_len = ETH_ALEN;
- ndev->pa_addr = 0;
- ndev->pa_brdaddr = 0;
- ndev->pa_mask = 0;
- ndev->pa_alen = 4;
-
- for (i = 0; i < ETH_ALEN; i++)
- ndev->broadcast[i]=0xff;
+ ndev->hard_header = NULL;
+#if (LINUX_VERSION_CODE < 0x02010F)
+ ndev->header_cache_bind = NULL;
+#else
+ ndev->hard_header_cache = NULL;
+#endif
+ ndev->header_cache_update = NULL;
+ ndev->mtu = 1500;
+ ndev->flags = IFF_NOARP;
+ ndev->family = AF_INET;
+ ndev->type = ARPHRD_ETHER;
+ ndev->addr_len = ETH_ALEN;
+ ndev->pa_addr = 0;
+ ndev->pa_brdaddr = 0;
+ ndev->pa_mask = 0;
+ ndev->pa_alen = 4;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ ndev->broadcast[i] = 0xff;
for (i = 0; i < DEV_NUMBUFFS; i++)
- skb_queue_head_init(&ndev->buffs[i]);
-
+ skb_queue_head_init(&ndev->buffs[i]);
+
/* The ISDN-specific entries in the device structure. */
- ndev->open = &isdn_net_open;
- ndev->hard_start_xmit = &isdn_net_start_xmit;
+ ndev->open = &isdn_net_open;
+ ndev->hard_start_xmit = &isdn_net_start_xmit;
- /*
+ /*
* up till binding we ask the protocol layer to reserve as much
* as we might need for HL layer
- */
-
+ */
+
for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
if (dev->drv[drvidx])
if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen)
max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
- ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
+ ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
- ndev->stop = &isdn_net_close;
- ndev->get_stats = &isdn_net_get_stats;
- ndev->rebuild_header = &isdn_net_rebuild_header;
+ ndev->stop = &isdn_net_close;
+ ndev->get_stats = &isdn_net_get_stats;
+ ndev->rebuild_header = &isdn_net_rebuild_header;
#ifdef CONFIG_ISDN_PPP
- ndev->do_ioctl = isdn_ppp_dev_ioctl;
+ ndev->do_ioctl = isdn_ppp_dev_ioctl;
#endif
return 0;
}
for (; *p; s++, p++)
switch (*p) {
- case '\\':
- /*
- * Literal match with following character,
- * fall through.
- */
- p++;
- default:
- if (*s != *p)
- return (0);
- continue;
- case '?':
- /* Match anything. */
- if (*s == '\0')
- return (0);
- continue;
- case '*':
- /* Trailing star matches everything. */
- return (*++p ? isdn_net_Star(s, p) : 1);
- case '[':
- /* [^....] means inverse character class. */
- if ((reverse = (p[1] == '^')))
- p++;
- for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
- /* This next line requires a good C compiler. */
- if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
- matched = 1;
- if (matched == reverse)
- return (0);
- continue;
+ case '\\':
+ /*
+ * Literal match with following character,
+ * fall through.
+ */
+ p++;
+ default:
+ if (*s != *p)
+ return (0);
+ continue;
+ case '?':
+ /* Match anything. */
+ if (*s == '\0')
+ return (0);
+ continue;
+ case '*':
+ /* Trailing star matches everything. */
+ return (*++p ? isdn_net_Star(s, p) : 1);
+ case '[':
+ /* [^....] means inverse character class. */
+ if ((reverse = (p[1] == '^')))
+ p++;
+ for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)
+ /* This next line requires a good C compiler. */
+ if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
+ matched = 1;
+ if (matched == reverse)
+ return (0);
+ continue;
}
return (*s == '\0');
}
while (p) {
if (p->local.pre_device == drvidx)
switch (p->local.pre_channel) {
- case 0:
- p->local.pre_channel = 1;
- break;
- case 1:
- p->local.pre_channel = 0;
- break;
+ case 0:
+ p->local.pre_channel = 1;
+ break;
+ case 1:
+ p->local.pre_channel = 0;
+ break;
}
p = (isdn_net_dev *) p->next;
}
* 4 = Wait cbdelay, then call back
*/
int
-isdn_net_find_icall(int di, int ch, int idx, char *num)
+isdn_net_find_icall(int di, int ch, int idx, setup_parm setup)
{
char *eaz;
int si1;
isdn_net_dev *p;
isdn_net_phone *n;
ulong flags;
- char nr[31];
- char *s;
+ char nr[32];
/* Search name in netdev-chain */
save_flags(flags);
cli();
- if (num[0] == ',') {
+ if (!setup.phone[0]) {
nr[0] = '0';
- strncpy(&nr[1], num, 30);
+ nr[1] = '\0';
printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
} else
- strncpy(nr, num, 30);
- s = strtok(nr, ",");
- s = strtok(NULL, ",");
- if (!s) {
- printk(KERN_WARNING "isdn_net: Incoming callinfo garbled, ignored: %s\n",
- num);
- restore_flags(flags);
- return 0;
- }
- si1 = (int)simple_strtoul(s,NULL,10);
- s = strtok(NULL, ",");
- if (!s) {
- printk(KERN_WARNING "isdn_net: Incoming callinfo garbled, ignored: %s\n",
- num);
- restore_flags(flags);
- return 0;
- }
- si2 = (int)simple_strtoul(s,NULL,10);
- eaz = strtok(NULL, ",");
- if (!eaz) {
+ strcpy(nr, setup.phone);
+ si1 = (int) setup.si1;
+ si2 = (int) setup.si2;
+ if (!setup.eazmsn[0]) {
printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n");
eaz = "0";
- }
+ } else
+ eaz = setup.eazmsn;
if (dev->net_verbose > 1)
printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
/* Accept only calls with Si1 = 7 (Data-Transmission) */
while (p) {
/* If last check has triggered as binding-swap, revert it */
switch (swapped) {
- case 2:
- isdn_net_swap_usage(idx, sidx);
- /* fall through */
- case 1:
- isdn_net_swapbind(di);
- break;
+ case 2:
+ isdn_net_swap_usage(idx, sidx);
+ /* fall through */
+ case 1:
+ isdn_net_swapbind(di);
+ break;
}
swapped = 0;
if (!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz))
printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
p->local.name, p->local.msn, p->local.flags, p->local.dialstate);
#endif
- if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */
- (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */
- (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
- ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) && /* if dialing */
- (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */
+ if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */
+ (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */
+ (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
+ ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) && /* if dialing */
+ (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */
))) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
if ((p->local.pre_channel != ch) ||
(p->local.pre_device != di)) {
/* Here we got a problem:
- If using an ICN-Card, an incoming call is always signaled on
- on the first channel of the card, if both channels are
- down. However this channel may be bound exclusive. If the
- second channel is free, this call should be accepted.
- The solution is horribly but it runs, so what:
- We exchange the exclusive bindings of the two channels, the
- corresponding variables in the interface-structs.
+ * If using an ICN-Card, an incoming call is always signaled on
+ * on the first channel of the card, if both channels are
+ * down. However this channel may be bound exclusive. If the
+ * second channel is free, this call should be accepted.
+ * The solution is horribly but it runs, so what:
+ * We exchange the exclusive bindings of the two channels, the
+ * corresponding variables in the interface-structs.
*/
if (ch == 0) {
sidx = isdn_dc2minor(di, 1);
#endif
if (USG_NONE(dev->usage[sidx])) {
/* Second Channel is free, now see if it is bound
- exclusive too. */
+ * exclusive too. */
if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) {
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n");
#endif
/* Yes, swap bindings only, if the original
- binding is bound to channel 1 of this driver */
+ * binding is bound to channel 1 of this driver */
if ((p->local.pre_device == di) &&
(p->local.pre_channel == 1)) {
isdn_net_swapbind(di);
continue;
}
}
- } /* if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) */
+ }
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: match2\n");
#endif
return 0;
}
/* Setup dialstate. */
- lp->dtimer = 0;
+ lp->dtimer = 0;
lp->dialstate = 11;
lp->flags |= ISDN_NET_CONNECTED;
/* Connect interface with channel */
#endif
/* Initiate dialing by returning 2 or 4 */
restore_flags(flags);
- return (lp->flags & ISDN_NET_CBHUP)?2:4;
+ return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
} else
printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name);
restore_flags(flags);
device, so free this device */
if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) {
#ifdef CONFIG_ISDN_PPP
- if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
- isdn_ppp_free(lp);
+ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+ isdn_ppp_free(lp);
#endif
isdn_free_channel(p->local.isdn_device, p->local.isdn_channel,
ISDN_USAGE_NET);
- }
+ }
dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[idx] |= ISDN_USAGE_NET;
strcpy(dev->num[idx], nr);
isdn_info_update();
- dev->st_netdev[idx] = lp->netdev;
+ dev->st_netdev[idx] = lp->netdev;
p->local.isdn_device = di;
p->local.isdn_channel = ch;
p->local.ppp_slot = -1;
- p->local.pppbind = -1;
p->local.flags |= ISDN_NET_CONNECTED;
p->local.dialstate = 7;
p->local.dtimer = 0;
p->local.outgoing = 0;
p->local.huptimer = 0;
- p->local.hupflags |= 1;
- p->local.hupflags &= ~2;
+ p->local.hupflags |= ISDN_WAITCHARGE;
+ p->local.hupflags &= ~ISDN_HAVECHARGE;
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
if (isdn_ppp_bind(lp) < 0) {
* Search list of net-interfaces for an interface with given name.
*/
isdn_net_dev *
- isdn_net_findif(char *name)
+isdn_net_findif(char *name)
{
isdn_net_dev *p = dev->netdev;
* This is called from the userlevel-routine below or
* from isdn_net_start_xmit().
*/
-int isdn_net_force_dial_lp(isdn_net_local * lp)
+int
+isdn_net_force_dial_lp(isdn_net_local * lp)
{
if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
int chi;
cli();
/* Grab a free ISDN-Channel */
if ((chi = isdn_get_free_channel(ISDN_USAGE_NET, lp->l2_proto,
- lp->l3_proto,
- lp->pre_device,
+ lp->l3_proto,
+ lp->pre_device,
lp->pre_channel)) < 0) {
printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
restore_flags(flags);
* Force a net-interface to dial out.
* This is always called from within userspace (ISDN_IOCTL_NET_DIAL).
*/
-int
+int
isdn_net_force_dial(char *name)
{
isdn_net_dev *p = isdn_net_findif(name);
strcpy(netdev->local.name, " ");
else
strcpy(netdev->local.name, name);
- netdev->dev.name = netdev->local.name;
- netdev->dev.priv = &netdev->local;
- netdev->dev.init = isdn_net_init;
+ netdev->dev.name = netdev->local.name;
+ netdev->dev.priv = &netdev->local;
+ netdev->dev.init = isdn_net_init;
netdev->local.p_encap = ISDN_NET_ENCAP_RAWIP;
if (master) {
/* Device shall be a slave */
netdev->local.magic = ISDN_NET_MAGIC;
#ifdef CONFIG_ISDN_PPP
- netdev->mp_last = NULL; /* mpqueue is empty */
+ netdev->mp_last = NULL; /* mpqueue is empty */
netdev->ib.next_num = 0;
netdev->ib.last = NULL;
#endif
netdev->local.exclusive = -1;
netdev->local.ppp_slot = -1;
netdev->local.pppbind = -1;
- netdev->local.sav_skb = NULL;
- netdev->local.first_skb = NULL;
+ netdev->local.sav_skb = NULL;
+ netdev->local.first_skb = NULL;
netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
+ netdev->local.triggercps = 6000;
netdev->local.slavedelay = 10 * HZ;
netdev->local.srobin = &netdev->dev;
- netdev->local.hupflags = 8; /* Do hangup even on incoming calls */
+ netdev->local.hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
netdev->local.onhtime = 10; /* Default hangup-time for saving costs
- of those who forget configuring this */
+ of those who forget configuring this */
netdev->local.dialmax = 1;
- netdev->local.flags = ISDN_NET_CBHUP; /* Hangup before Callback */
- netdev->local.cbdelay = 25; /* Wait 5 secs before Callback */
+ netdev->local.flags = ISDN_NET_CBHUP; /* Hangup before Callback */
+ netdev->local.cbdelay = 25; /* Wait 5 secs before Callback */
/* Put into to netdev-chain */
netdev->next = (void *) dev->netdev;
dev->netdev = netdev;
/* Master must be a real interface, not a slave */
if (n->local.master)
return NULL;
+ /* Master must not be started yet */
+ if (n->dev.start)
+ return NULL;
return (isdn_net_new(newname, &(n->dev)));
}
return NULL;
* for not overwriting existing setups. It has to get the current
* setup first, if only selected parameters are to be changed.
*/
-int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
+int
+isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
{
isdn_net_dev *p = isdn_net_findif(cfg->name);
ulong features;
printk(KERN_WARNING "isdn_net: No driver with selected features\n");
return -ENODEV;
}
- if (p->local.p_encap != cfg->p_encap)
- if (p->dev.start) {
- printk(KERN_WARNING
- "%s: cannot change encap when if is up\n",
- p->local.name);
- return -EBUSY;
- }
- if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
+ if (p->local.p_encap != cfg->p_encap)
+ if (p->dev.start) {
+ printk(KERN_WARNING
+ "%s: cannot change encap when if is up\n",
+ p->local.name);
+ return -EBUSY;
+ }
+ if (cfg->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
#ifndef CONFIG_ISDN_PPP
- printk(KERN_WARNING "%s: SyncPPP support not configured\n",
- p->local.name);
- return -EINVAL;
+ printk(KERN_WARNING "%s: SyncPPP support not configured\n",
+ p->local.name);
+ return -EINVAL;
#else
- p->dev.type = ARPHRD_PPP; /* change ARP type */
- p->dev.addr_len = 0;
+ p->dev.type = ARPHRD_PPP; /* change ARP type */
+ p->dev.addr_len = 0;
#endif
- }
+ }
if (strlen(cfg->drvid)) {
/* A bind has been requested ... */
- char *c,*e;
+ char *c,
+ *e;
drvidx = -1;
chidx = -1;
strcpy(drvid, cfg->drvid);
if ((c = strchr(drvid, ','))) {
/* The channel-number is appended to the driver-Id with a comma */
- chidx = (int)simple_strtoul(c + 1,&e,10);
+ chidx = (int) simple_strtoul(c + 1, &e, 10);
if (e == c)
chidx = -1;
*c = '\0';
/* If binding is exclusive, try to grab the channel */
save_flags(flags);
if ((i = isdn_get_free_channel(ISDN_USAGE_NET, p->local.l2_proto,
- p->local.l3_proto,
- drvidx,
- chidx)) < 0) {
+ p->local.l3_proto,
+ drvidx,
+ chidx)) < 0) {
/* Grab failed, because desired channel is in use */
p->local.exclusive = -1;
restore_flags(flags);
p->local.exclusive = -1;
if ((p->local.pre_device != -1) && (cfg->exclusive == -1)) {
isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
- isdn_free_channel(p->local.pre_device, p->local.pre_channel,ISDN_USAGE_NET);
+ isdn_free_channel(p->local.pre_device, p->local.pre_channel, ISDN_USAGE_NET);
drvidx = -1;
chidx = -1;
}
}
strcpy(p->local.msn, cfg->eaz);
- p->local.pre_device = drvidx;
+ p->local.pre_device = drvidx;
p->local.pre_channel = chidx;
- p->local.onhtime = cfg->onhtime;
- p->local.charge = cfg->charge;
- p->local.l2_proto = cfg->l2_proto;
- p->local.l3_proto = cfg->l3_proto;
- p->local.cbdelay = cfg->cbdelay;
- p->local.dialmax = cfg->dialmax;
- p->local.slavedelay = cfg->slavedelay * HZ;
- p->local.pppbind = cfg->pppbind;
+ p->local.onhtime = cfg->onhtime;
+ p->local.charge = cfg->charge;
+ p->local.l2_proto = cfg->l2_proto;
+ p->local.l3_proto = cfg->l3_proto;
+ p->local.cbdelay = cfg->cbdelay;
+ p->local.dialmax = cfg->dialmax;
+ p->local.triggercps = cfg->triggercps;
+ p->local.slavedelay = cfg->slavedelay * HZ;
+ p->local.pppbind = cfg->pppbind;
if (cfg->secure)
p->local.flags |= ISDN_NET_SECURE;
else
else
p->local.flags &= ~ISDN_NET_CBHUP;
switch (cfg->callback) {
- case 0:
- p->local.flags &= ~(ISDN_NET_CALLBACK|ISDN_NET_CBOUT);
- break;
- case 1:
- p->local.flags |= ISDN_NET_CALLBACK;
- p->local.flags &= ~ISDN_NET_CBOUT;
- break;
- case 2:
- p->local.flags |= ISDN_NET_CBOUT;
- p->local.flags &= ~ISDN_NET_CALLBACK;
- break;
- }
+ case 0:
+ p->local.flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
+ break;
+ case 1:
+ p->local.flags |= ISDN_NET_CALLBACK;
+ p->local.flags &= ~ISDN_NET_CBOUT;
+ break;
+ case 2:
+ p->local.flags |= ISDN_NET_CBOUT;
+ p->local.flags &= ~ISDN_NET_CALLBACK;
+ break;
+ }
if (cfg->chargehup)
- p->local.hupflags |= 4;
+ p->local.hupflags |= ISDN_CHARGEHUP;
else
- p->local.hupflags &= ~4;
+ p->local.hupflags &= ~ISDN_CHARGEHUP;
if (cfg->ihup)
- p->local.hupflags |= 8;
+ p->local.hupflags |= ISDN_INHUP;
else
- p->local.hupflags &= ~8;
+ p->local.hupflags &= ~ISDN_INHUP;
+ if (cfg->chargeint > 10) {
+ p->local.hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE;
+ p->local.chargeint = cfg->chargeint * HZ;
+ }
if (cfg->p_encap != p->local.p_encap) {
- if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
- p->dev.hard_header = NULL;
- p->dev.header_cache_bind = NULL;
- p->dev.header_cache_update = NULL;
- p->dev.flags = IFF_NOARP;
- } else {
- p->dev.hard_header = isdn_net_header;
- if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
- p->dev.header_cache_bind = p->local.org_hcb;
- p->dev.header_cache_update = p->local.org_hcu;
- p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
- } else {
- p->dev.header_cache_bind = NULL;
- p->dev.header_cache_update = NULL;
- p->dev.flags = IFF_NOARP;
- }
- }
- }
- p->local.p_encap = cfg->p_encap;
- return 0;
+ if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
+ p->dev.hard_header = NULL;
+#if (LINUX_VERSION_CODE < 0x02010F)
+ p->dev.header_cache_bind = NULL;
+#else
+ p->dev.hard_header_cache = NULL;
+#endif
+ p->dev.header_cache_update = NULL;
+ p->dev.flags = IFF_NOARP;
+ } else {
+ p->dev.hard_header = isdn_net_header;
+ if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
+#if (LINUX_VERSION_CODE < 0x02010F)
+ p->dev.header_cache_bind = p->local.org_hcb;
+#else
+ p->dev.hard_header_cache = p->local.org_hhc;
+#endif
+ p->dev.header_cache_update = p->local.org_hcu;
+ p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
+ } else {
+#if (LINUX_VERSION_CODE < 0x02010F)
+ p->dev.header_cache_bind = NULL;
+#else
+ p->dev.hard_header_cache = NULL;
+#endif
+ p->dev.header_cache_update = NULL;
+ p->dev.flags = IFF_NOARP;
+ }
+ }
+ }
+ p->local.p_encap = cfg->p_encap;
+ return 0;
}
return -ENODEV;
}
/*
* Perform get-interface-parameters.ioctl
*/
-int isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
+int
+isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
{
isdn_net_dev *p = isdn_net_findif(cfg->name);
cfg->p_encap = p->local.p_encap;
cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0;
cfg->callback = 0;
- if (p->local.flags & ISDN_NET_CALLBACK)
- cfg->callback = 1;
- if (p->local.flags & ISDN_NET_CBOUT)
- cfg->callback = 2;
+ if (p->local.flags & ISDN_NET_CALLBACK)
+ cfg->callback = 1;
+ if (p->local.flags & ISDN_NET_CBOUT)
+ cfg->callback = 2;
cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0;
cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0;
cfg->ihup = (p->local.hupflags & 8) ? 1 : 0;
- cfg->cbdelay = p->local.cbdelay;
- cfg->dialmax = p->local.dialmax;
+ cfg->cbdelay = p->local.cbdelay;
+ cfg->dialmax = p->local.dialmax;
+ cfg->triggercps = p->local.triggercps;
cfg->slavedelay = p->local.slavedelay / HZ;
+ cfg->chargeint = (p->local.hupflags & ISDN_CHARGEHUP) ?
+ (p->local.chargeint / HZ) : 0;
cfg->pppbind = p->local.pppbind;
if (p->local.slave)
strcpy(cfg->slave, ((isdn_net_local *) p->local.slave->priv)->name);
/*
* Add a phone-number to an interface.
*/
-int isdn_net_addphone(isdn_net_ioctl_phone * phone)
+int
+isdn_net_addphone(isdn_net_ioctl_phone * phone)
{
isdn_net_dev *p = isdn_net_findif(phone->name);
isdn_net_phone *n;
/*
* Return a string of all phone-numbers of an interface.
*/
-int isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
+int
+isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
{
isdn_net_dev *p = isdn_net_findif(phone->name);
int inout = phone->outgoing & 1;
save_flags(flags);
cli();
inout &= 1;
- for (n = p->local.phone[inout]; n; n = n->next) {
+ for (n = p->local.phone[inout]; n; n = n->next) {
if (more) {
put_user(' ', phones++);
count++;
}
- if ((ret = verify_area(VERIFY_WRITE, (void *) phones, strlen(n->num) + 1))) {
+ if ((ret = copy_to_user(phones, n->num, strlen(n->num) + 1))) {
restore_flags(flags);
return ret;
}
- copy_to_user(phones, n->num, strlen(n->num) + 1);
phones += strlen(n->num);
count += strlen(n->num);
more = 1;
}
- put_user(0,phones);
- count++;
+ put_user(0, phones);
+ count++;
restore_flags(flags);
return count;
}
* Delete a phone-number from an interface.
*/
-int isdn_net_delphone(isdn_net_ioctl_phone * phone)
+int
+isdn_net_delphone(isdn_net_ioctl_phone * phone)
{
isdn_net_dev *p = isdn_net_findif(phone->name);
int inout = phone->outgoing & 1;
isdn_net_phone *n;
isdn_net_phone *m;
+ int flags;
if (p) {
+ save_flags(flags);
+ cli();
n = p->local.phone[inout];
m = NULL;
while (n) {
if (!strcmp(n->num, phone->phone)) {
+ if (p->local.dial == n)
+ p->local.dial = n->next;
if (m)
m->next = n->next;
else
m = n;
n = (isdn_net_phone *) n->next;
}
+ restore_flags(flags);
return -EINVAL;
}
return -ENODEV;
/*
* Delete all phone-numbers of an interface.
*/
-static int isdn_net_rmallphone(isdn_net_dev * p)
+static int
+isdn_net_rmallphone(isdn_net_dev * p)
{
isdn_net_phone *n;
isdn_net_phone *m;
}
p->local.phone[i] = NULL;
}
+ p->local.dial = NULL;
restore_flags(flags);
return 0;
}
/*
* Force a hangup of a network-interface.
*/
-int isdn_net_force_hangup(char *name)
+int
+isdn_net_force_hangup(char *name)
{
isdn_net_dev *p = isdn_net_findif(name);
struct device *q;
if (p) {
if (p->local.isdn_device < 0)
return 1;
- isdn_net_hangup(&p->dev);
q = p->local.slave;
/* If this interface has slaves, do a hangup for them also. */
while (q) {
isdn_net_hangup(q);
q = (((isdn_net_local *) q->priv)->slave);
}
+ isdn_net_hangup(&p->dev);
return 0;
}
return -ENODEV;
/*
* Helper-function for isdn_net_rm: Do the real work.
*/
-static int isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
+static int
+isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
{
int flags;
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
restore_flags(flags);
-#ifdef CONFIG_ISDN_MPP
- isdn_ppp_free_mpqueue(p); /* still necessary? */
-#endif
kfree(p);
return 0;
/*
* Remove a single network-interface.
*/
-int isdn_net_rm(char *name)
+int
+isdn_net_rm(char *name)
{
isdn_net_dev *p;
isdn_net_dev *q;
/*
* Remove all network-interfaces
*/
-int isdn_net_rmall(void)
+int
+isdn_net_rmall(void)
{
int flags;
int ret;
/* Remove master-devices only, slaves get removed with their master */
if ((ret = isdn_net_realrm(dev->netdev, NULL))) {
restore_flags(flags);
- return ret;
+ return ret;
}
}
}
return 0;
}
-/*
+/*
* helper function to flush device queues
* the better place would be net/core/dev.c
*/
-void dev_purge_queues(struct device *dev)
+static void
+dev_purge_queues(struct device *dev)
{
int i;
- for(i=0;i<DEV_NUMBUFFS;i++) {
+ for (i = 0; i < DEV_NUMBUFFS; i++) {
struct sk_buff *skb;
- while((skb=skb_dequeue(&dev->buffs[i])))
- dev_kfree_skb(skb,FREE_WRITE);
- }
-
+ while ((skb = skb_dequeue(&dev->buffs[i])))
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+
}
-/* $Id: isdn_net.h,v 1.2 1996/04/20 16:29:43 fritz Exp $
- *
+/* $Id: isdn_net.h,v 1.5 1997/02/10 20:12:47 fritz Exp $
+
* header for Linux ISDN subsystem, network related functions (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.h,v $
+ * Revision 1.5 1997/02/10 20:12:47 fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.4 1997/02/03 23:16:48 fritz
+ * Removed isdn_net_receive_callback prototype.
+ *
+ * Revision 1.3 1997/01/17 01:19:30 fritz
+ * Applied chargeint patch.
+ *
* Revision 1.2 1996/04/20 16:29:43 fritz
* Misc. typos
*
*
*/
-extern char* isdn_net_new(char *, struct device *);
-extern char* isdn_net_newslave(char *);
-extern int isdn_net_rm(char *);
-extern int isdn_net_rmall(void);
-extern int isdn_net_stat_callback(int, int);
-extern int isdn_net_receive_callback(int, u_char *, int);
-extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
-extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
-extern int isdn_net_addphone(isdn_net_ioctl_phone *);
-extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *);
-extern int isdn_net_delphone(isdn_net_ioctl_phone *);
-extern int isdn_net_find_icall(int, int, int, char *);
-extern void isdn_net_hangup(struct device *);
-extern void isdn_net_dial(void);
-extern void isdn_net_autohup(void);
-extern int isdn_net_force_hangup(char *);
-extern int isdn_net_force_dial(char *);
-extern isdn_net_dev* isdn_net_findif(char *);
-extern int isdn_net_send_skb(struct device *, isdn_net_local *,
- struct sk_buff *);
-extern int isdn_net_rcv_skb(int, struct sk_buff *);
+ /* Definitions for hupflags: */
+#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */
+#define ISDN_HAVECHARGE 2 /* We know a charge info */
+#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */
+#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
+#define ISDN_MANCHARGE 16 /* Charge Interval manually set */
+
+extern char *isdn_net_new(char *, struct device *);
+extern char *isdn_net_newslave(char *);
+extern int isdn_net_rm(char *);
+extern int isdn_net_rmall(void);
+extern int isdn_net_stat_callback(int, int);
+extern int isdn_net_setcfg(isdn_net_ioctl_cfg *);
+extern int isdn_net_getcfg(isdn_net_ioctl_cfg *);
+extern int isdn_net_addphone(isdn_net_ioctl_phone *);
+extern int isdn_net_getphones(isdn_net_ioctl_phone *, char *);
+extern int isdn_net_delphone(isdn_net_ioctl_phone *);
+extern int isdn_net_find_icall(int, int, int, setup_parm);
+extern void isdn_net_hangup(struct device *);
+extern void isdn_net_dial(void);
+extern void isdn_net_autohup(void);
+extern int isdn_net_force_hangup(char *);
+extern int isdn_net_force_dial(char *);
+extern isdn_net_dev *isdn_net_findif(char *);
+extern int isdn_net_send_skb(struct device *, isdn_net_local *,
+ struct sk_buff *);
+extern int isdn_net_rcv_skb(int, struct sk_buff *);
-/* $Id: isdn_ppp.c,v 1.20 1996/10/30 12:21:58 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.28 1997/06/17 13:05:57 hipp Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.28 1997/06/17 13:05:57 hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ * more compression changes (but disabled at the moment)
+ * changed one copy_to_user() to run with enabled IRQs
+ * a few MP changes
+ * changed 'proto' handling in the isdn_ppp receive code
+ *
+ * Revision 1.27 1997/03/30 16:51:17 calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.26 1997/02/23 16:53:44 hipp
+ * minor cleanup
+ * some initial changes for future PPP compresion
+ * added AC,PC compression for outgoing frames
+ *
+ * Revision 1.25 1997/02/12 20:37:35 hipp
+ * New ioctl() PPPIOCGCALLINFO, minor cleanup
+ *
+ * Revision 1.24 1997/02/11 18:32:56 fritz
+ * Bugfix in isdn_ppp_free_mpqueue().
+ *
+ * Revision 1.23 1997/02/10 11:12:19 fritz
+ * More changes for Kernel 2.1.X compatibility.
+ *
+ * Revision 1.22 1997/02/06 15:03:51 hipp
+ * changed GFP_KERNEL kmalloc to GFP_ATOMIC in isdn_ppp_fill_mpqueue()
+ *
+ * Revision 1.21 1997/02/03 23:29:38 fritz
+ * Reformatted according CodingStyle
+ * Bugfix: removed isdn_ppp_skb_destructor, used by upper layers.
+ * Misc changes for Kernel 2.1.X compatibility.
+ *
* Revision 1.20 1996/10/30 12:21:58 fritz
* Cosmetic fix: Compiler warning when compiling without MPP.
*
/* TODO: right tbusy handling when using MP */
+/*
+ * experimental for dynamic addressing: readdress IP frames
+ */
#undef ISDN_SYNCPPP_READDRESS
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/isdn.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <asm/poll.h>
+#endif
#include "isdn_common.h"
#include "isdn_ppp.h"
#include "isdn_net.h"
#ifndef PPP_IPX
-#define PPP_IPX 0x002b
+#define PPP_IPX 0x002b
#endif
/* set this if you use dynamic addressing */
-
+
/* Prototypes */
-static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot);
+static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
static int isdn_ppp_closewait(int slot);
static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
- struct sk_buff *skb, int proto);
+ struct sk_buff *skb, int proto);
static int isdn_ppp_if_get_unit(char *namebuf);
+static int isdn_ppp_set_compressor(struct ippp_struct *is,int num);
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
+ struct ippp_struct *,struct ippp_struct *);
+static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
+ struct sk_buff *skb);
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+ struct ippp_struct *is,struct ippp_struct *master,int type);
#ifdef CONFIG_ISDN_MPP
static int isdn_ppp_bundle(struct ippp_struct *, int unit);
static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask);
static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min);
-static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev,isdn_net_local *, long min);
+static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev, isdn_net_local *, long min);
+static void isdn_ppp_free_sqqueue(isdn_net_dev *);
static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
- int BEbyte, long *sqno, int min_sqno);
+ int BEbyte, long *sqno, int min_sqno);
+static void isdn_ppp_free_mpqueue(isdn_net_dev *);
#endif
-char *isdn_ppp_revision = "$Revision: 1.20 $";
+char *isdn_ppp_revision = "$Revision: 1.28 $";
-struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+static struct isdn_ppp_compressor *ipc_head = NULL;
extern int isdn_net_force_dial_lp(isdn_net_local *);
/*
* frame log (debug)
*/
-static void isdn_ppp_frame_log(char *info,char *data,int len,int maxlen)
+static void
+isdn_ppp_frame_log(char *info, char *data, int len, int maxlen)
{
- int cnt,j,i;
+ int cnt,
+ j,
+ i;
char buf[80];
- if(len < maxlen)
+ if (len < maxlen)
maxlen = len;
-
- for(i=0,cnt=0;cnt<maxlen;i++) {
- for(j=0;j<16 && cnt<maxlen;j++,cnt++)
- sprintf(buf+j*3,"%02x ",(unsigned char) data[cnt]);
- printk(KERN_DEBUG "%s[%d]: %s\n",info,i,buf);
+
+ for (i = 0, cnt = 0; cnt < maxlen; i++) {
+ for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
+ sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
+ printk(KERN_DEBUG "%s[%d]: %s\n", info, i, buf);
}
}
/*
- * unbind isdn_net_local <=> ippp-device
+ * unbind isdn_net_local <=> ippp-device
* note: it can happen, that we hangup/free the master before the slaves
*/
-int isdn_ppp_free(isdn_net_local *lp)
+int
+isdn_ppp_free(isdn_net_local * lp)
{
#ifdef CONFIG_ISDN_MPP
- isdn_net_local *master_lp=lp;
+ isdn_net_local *master_lp = lp;
#endif
unsigned long flags;
struct ippp_struct *is;
save_flags(flags);
cli();
#ifdef CONFIG_ISDN_MPP
- if(lp->master)
+ if (lp->master)
master_lp = (isdn_net_local *) lp->master->priv;
lp->last->next = lp->next;
lp->next->last = lp->last;
- if(master_lp->netdev->queue == lp) {
+ if (master_lp->netdev->queue == lp) {
master_lp->netdev->queue = lp->next;
- if(lp->next == lp) { /* last link in queue? */
+ if (lp->next == lp) { /* last link in queue? */
master_lp->netdev->ib.bundled = 0;
isdn_ppp_free_mpqueue(master_lp->netdev);
isdn_ppp_free_sqqueue(master_lp->netdev);
lp->next = lp->last = lp; /* (re)set own pointers */
#endif
- if( (is->state & IPPP_CONNECT) )
+ if ((is->state & IPPP_CONNECT))
isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
- else if(is->state & IPPP_ASSIGNED)
+ else if (is->state & IPPP_ASSIGNED)
is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGEND' staet */
-
- if(is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp,(long) is->lp);
- is->lp = NULL; /* link is down .. set lp to NULL */
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
+
+ is->lp = NULL; /* link is down .. set lp to NULL */
#ifdef ISDN_SYNCPPP_READDRESS
is->old_pa_addr = 0x0;
is->old_pa_dstaddr = 0x0;
#endif
- lp->ppp_slot = -1; /* is this OK ?? */
+ lp->ppp_slot = -1; /* is this OK ?? */
restore_flags(flags);
return 0;
/*
* bind isdn_net_local <=> ippp-device
*/
-int isdn_ppp_bind(isdn_net_local * lp)
+int
+isdn_ppp_bind(isdn_net_local * lp)
{
int i;
int unit = 0;
save_flags(flags);
cli();
- if(lp->pppbind < 0) /* device bounded to ippp device ? */
- {
- isdn_net_dev *net_dev = dev->netdev;
+ if (lp->pppbind < 0) { /* device bounded to ippp device ? */
+ isdn_net_dev *net_dev = dev->netdev;
char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
- memset(exclusive,0,ISDN_MAX_CHANNELS);
+ memset(exclusive, 0, ISDN_MAX_CHANNELS);
while (net_dev) { /* step through net devices to find exclusive minors */
isdn_net_local *lp = &net_dev->local;
- if(lp->pppbind >= 0)
+ if (lp->pppbind >= 0)
exclusive[lp->pppbind] = 1;
net_dev = net_dev->next;
}
* search a free device / slot
*/
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
+ if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
break;
}
}
- }
- else {
- for(i=0;i<ISDN_MAX_CHANNELS;i++)
- if(ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN)
+ } else {
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ if (ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN)
break;
}
printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n");
return -1;
}
-
- unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */
- if(unit < 0) {
- printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",lp->name);
+ unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */
+ if (unit < 0) {
+ printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
return -1;
}
-
lp->ppp_slot = i;
is = ippp_table[i];
is->lp = lp;
* (wakes up daemon after B-channel connect)
*/
-void isdn_ppp_wakeup_daemon(isdn_net_local *lp)
+void
+isdn_ppp_wakeup_daemon(isdn_net_local * lp)
{
- if(lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
+ if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
return;
ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
/*
* there was a hangup on the netdevice
- * force wakeup of the ippp device
+ * force wakeup of the ippp device
* go into 'device waits for release' state
*/
-static int isdn_ppp_closewait(int slot)
+static int
+isdn_ppp_closewait(int slot)
{
struct ippp_struct *is;
* isdn_ppp_find_slot / isdn_ppp_free_slot
*/
-static int isdn_ppp_get_slot(void)
+static int
+isdn_ppp_get_slot(void)
{
int i;
- for(i=0;i<ISDN_MAX_CHANNELS;i++) {
- if(!ippp_table[i]->state)
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if (!ippp_table[i]->state)
return i;
}
return -1;
}
/*
- * isdn_ppp_open
+ * isdn_ppp_open
*/
-int isdn_ppp_open(int min, struct file *file)
+int
+isdn_ppp_open(int min, struct file *file)
{
int slot;
struct ippp_struct *is;
- if(min < 0 || min > ISDN_MAX_CHANNELS)
+ if (min < 0 || min > ISDN_MAX_CHANNELS)
return -ENODEV;
slot = isdn_ppp_get_slot();
- if(slot < 0) {
+ if (slot < 0) {
return -EBUSY;
}
is = file->private_data = ippp_table[slot];
- if(is->debug & 0x1)
- printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",slot, min,is->state);
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+
+ /* compression stuff */
+ is->compressor = NULL;
+ is->decomp_stat = is->comp_stat = NULL;
+ is->link_compressor = NULL;
+ is->link_decomp_stat = is->link_comp_stat = NULL;
- is->lp = 0;
- is->mp_seqno = 0; /* MP sequence number */
- is->pppcfg = 0; /* ppp configuration */
- is->mpppcfg = 0; /* mppp configuration */
- is->range = 0x1000000; /* MP: 24 bit range */
+ is->lp = NULL;
+ is->mp_seqno = 0; /* MP sequence number */
+ is->pppcfg = 0; /* ppp configuration */
+ is->mpppcfg = 0; /* mppp configuration */
+ is->range = 0x1000000; /* MP: 24 bit range */
is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
- is->unit = -1; /* set, when we have our interface */
- is->mru = 1524; /* MRU, default 1524 */
- is->maxcid = 16; /* VJ: maxcid */
+ is->unit = -1; /* set, when we have our interface */
+ is->mru = 1524; /* MRU, default 1524 */
+ is->maxcid = 16; /* VJ: maxcid */
is->tk = current;
- is->wq = NULL; /* read() wait queue */
- is->wq1 = NULL; /* select() wait queue */
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
+ is->wq = NULL; /* read() wait queue */
+ is->wq1 = NULL; /* select() wait queue */
+ is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
is->minor = min;
#ifdef CONFIG_ISDN_PPP_VJ
- /*
- * VJ header compression init
- */
+ /*
+ * VJ header compression init
+ */
is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
#endif
/*
* release ippp device
*/
-void isdn_ppp_release(int min, struct file *file)
+void
+isdn_ppp_release(int min, struct file *file)
{
int i;
struct ippp_struct *is;
return;
is = file->private_data;
- if(is->debug & 0x1)
+ if (is->debug & 0x1)
printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
- if (is->lp) { /* a lp address says: this link is still up */
+ if (is->lp) { /* a lp address says: this link is still up */
isdn_net_dev *p = is->lp->netdev;
-
- is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
- /*
+
+ is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
+ /*
* isdn_net_hangup() calls isdn_ppp_free()
* isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
* removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
is->rq[i].buf = NULL;
}
}
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
+ is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
+ is->last = is->rq;
#ifdef CONFIG_ISDN_PPP_VJ
slhc_free(is->slcomp);
/*
* get_arg .. ioctl helper
*/
-static int get_arg(void *b,void *val,int len)
+static int
+get_arg(void *b, void *val, int len)
{
int r;
- if(len <= 0)
- len = sizeof(unsigned long);
- if ((r = verify_area(VERIFY_READ, (void *) b, len )))
- return r;
- copy_from_user((void *) val, b, len );
+ if (len <= 0)
+ len = sizeof(unsigned long);
+ if ((r = copy_from_user((void *) val, b, len)))
+ return r;
return 0;
}
/*
* set arg .. ioctl helper
*/
-static int set_arg(void *b, unsigned long val,void *str)
+static int
+set_arg(void *b, unsigned long val, void *str)
{
int r;
- if(!str) {
- if ((r = verify_area(VERIFY_WRITE, b, 4 )))
- return r;
- copy_to_user(b, (void *) &val, 4 );
- }
- else {
- if ((r = verify_area(VERIFY_WRITE, b,val)))
+ if (!str) {
+ if ((r = copy_to_user(b, (void *) &val, 4)))
+ return r;
+ } else {
+ if ((r = copy_to_user(b, str, val)))
return r;
- copy_to_user(b,str,val);
}
return 0;
}
/*
- * ippp device ioctl
+ * ippp device ioctl
*/
-int isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
+int
+isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned long val;
- int r;
+ int num,r;
struct ippp_struct *is;
+ isdn_net_local *lp;
- is = file->private_data;
+ is = (struct ippp_struct *) file->private_data;
+ lp = is->lp;
- if(is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n",min,cmd,is->state);
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
if (!(is->state & IPPP_OPEN))
return -EINVAL;
switch (cmd) {
- case PPPIOCBUNDLE:
+ case PPPIOCBUNDLE:
#ifdef CONFIG_ISDN_MPP
- if( !(is->state & IPPP_CONNECT) )
- return -EINVAL;
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
- (int) min, (int) is->unit, (int) val);
- return isdn_ppp_bundle(is, val);
+ if (!(is->state & IPPP_CONNECT))
+ return -EINVAL;
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
+ (int) min, (int) is->unit, (int) val);
+ return isdn_ppp_bundle(is, val);
#else
- return -1;
+ return -1;
#endif
- break;
- case PPPIOCGUNIT: /* get ppp/isdn unit number */
- if ((r = set_arg((void *) arg, is->unit,NULL)))
- return r;
- break;
- case PPPIOCGMPFLAGS: /* get configuration flags */
- if ((r = set_arg((void *) arg, is->mpppcfg,NULL)))
- return r;
- break;
- case PPPIOCSMPFLAGS: /* set configuration flags */
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- is->mpppcfg = val;
- break;
- case PPPIOCGFLAGS: /* get configuration flags */
- if ((r = set_arg((void *) arg, is->pppcfg,NULL)))
- return r;
- break;
- case PPPIOCSFLAGS: /* set configuration flags */
- if ((r = get_arg((void *) arg, &val,0))) {
- return r;
- }
- if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT) ) {
- isdn_net_local *lp = is->lp;
- if(lp) {
- lp->netdev->dev.tbusy = 0;
- mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+ break;
+ case PPPIOCGUNIT: /* get ppp/isdn unit number */
+ if ((r = set_arg((void *) arg, is->unit, NULL)))
+ return r;
+ break;
+ case PPPIOCGMPFLAGS: /* get configuration flags */
+ if ((r = set_arg((void *) arg, is->mpppcfg, NULL)))
+ return r;
+ break;
+ case PPPIOCSMPFLAGS: /* set configuration flags */
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ is->mpppcfg = val;
+ break;
+ case PPPIOCGFLAGS: /* get configuration flags */
+ if ((r = set_arg((void *) arg, is->pppcfg, NULL)))
+ return r;
+ break;
+ case PPPIOCSFLAGS: /* set configuration flags */
+ if ((r = get_arg((void *) arg, &val, 0))) {
+ return r;
}
- }
- is->pppcfg = val;
- break;
+ if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
+ if (lp) {
+ lp->netdev->dev.tbusy = 0;
+ mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+ }
+ }
+ is->pppcfg = val;
+ break;
#if 0
- case PPPIOCGSTAT: /* read PPP statistic information */
- break;
+ case PPPIOCGSTAT: /* read PPP statistic information */
+ break;
#endif
- case PPPIOCGIDLE: /* get idle time information */
- if(is->lp)
- {
- struct ppp_idle pidle;
- pidle.xmit_idle = pidle.recv_idle = is->lp->huptimer;
- if((r = set_arg((void *) arg,sizeof(struct ppp_idle),&pidle)))
- return r;
- }
- break;
- case PPPIOCSMRU: /* set receive unit size for PPP */
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- is->mru = val;
- break;
- case PPPIOCSMPMRU:
- break;
- case PPPIOCSMPMTU:
- break;
- case PPPIOCSMAXCID: /* set the maximum compression slot id */
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- val++;
- if(is->maxcid != val) {
+ case PPPIOCGIDLE: /* get idle time information */
+ if (lp) {
+ struct ppp_idle pidle;
+ pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
+ if ((r = set_arg((void *) arg, sizeof(struct ppp_idle), &pidle)))
+ return r;
+ }
+ break;
+ case PPPIOCSMRU: /* set receive unit size for PPP */
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ is->mru = val;
+ break;
+ case PPPIOCSMPMRU:
+ break;
+ case PPPIOCSMPMTU:
+ break;
+ case PPPIOCSMAXCID: /* set the maximum compression slot id */
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ val++;
+ if (is->maxcid != val) {
#ifdef CONFIG_ISDN_PPP_VJ
- struct slcompress *sltmp;
+ struct slcompress *sltmp;
#endif
- if(is->debug & 0x1)
- printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n",val);
- is->maxcid = val;
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
+ is->maxcid = val;
#ifdef CONFIG_ISDN_PPP_VJ
- sltmp = slhc_init(16,val);
- if(!sltmp) {
- printk(KERN_ERR "ippp, can't realloc slhc struct\n");
- return -ENOMEM;
- }
- if(is->slcomp)
- slhc_free(is->slcomp);
- is->slcomp = sltmp;
+ sltmp = slhc_init(16, val);
+ if (!sltmp) {
+ printk(KERN_ERR "ippp, can't realloc slhc struct\n");
+ return -ENOMEM;
+ }
+ if (is->slcomp)
+ slhc_free(is->slcomp);
+ is->slcomp = sltmp;
#endif
- }
- break;
- case PPPIOCGDEBUG:
- if ((r = set_arg((void *) arg, is->debug,0)))
- return r;
- break;
- case PPPIOCSDEBUG:
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- is->debug = val;
- break;
- case PPPIOCSCOMPRESS:
-#if 0
- {
- struct ppp_option_data pod;
- r = get_arg((void *) arg,&pod,sizeof(struct ppp_option_data));
- if(r)
+ }
+ break;
+ case PPPIOCGDEBUG:
+ if ((r = set_arg((void *) arg, is->debug, 0)))
return r;
- ippp_set_compression(is,&pod);
- }
-#endif
- break;
- default:
- break;
+ break;
+ case PPPIOCSDEBUG:
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ is->debug = val;
+ break;
+ case PPPIOCGCOMPRESSORS:
+ {
+ unsigned long protos = 0;
+ struct isdn_ppp_compressor *ipc = ipc_head;
+ while(ipc) {
+ protos |= (0x1<<ipc->num);
+ ipc = ipc->next;
+ }
+ if ((r = set_arg((void *) arg, protos, 0)))
+ return r;
+ }
+ break;
+ case PPPIOCSCOMPRESSOR:
+ if ((r = get_arg((void *) arg, &num, sizeof(int))))
+ return r;
+ return isdn_ppp_set_compressor(is, num);
+ break;
+ case PPPIOCGCALLINFO:
+ {
+ struct pppcallinfo pci;
+ memset((char *) &pci,0,sizeof(struct pppcallinfo));
+ if(lp)
+ {
+ strncpy(pci.local_num,lp->msn,63);
+ if(lp->dial) {
+ strncpy(pci.remote_num,lp->dial->num,63);
+ }
+ pci.charge_units = lp->charge;
+ if(lp->outgoing)
+ pci.calltype = CALLTYPE_OUTGOING;
+ else
+ pci.calltype = CALLTYPE_INCOMING;
+ if(lp->flags & ISDN_NET_CALLBACK)
+ pci.calltype |= CALLTYPE_CALLBACK;
+ }
+ return set_arg((void *)arg,sizeof(struct pppcallinfo),&pci);
+ }
+ default:
+ break;
}
return 0;
}
-int isdn_ppp_select(int min, struct file *file, int type, select_table * st)
+#if (LINUX_VERSION_CODE < 0x020117)
+int
+isdn_ppp_select(int min, struct file *file, int type, select_table * st)
{
- struct ippp_buf_queue *bf, *bl;
+ struct ippp_buf_queue *bf,
+ *bl;
unsigned long flags;
struct ippp_struct *is;
is = file->private_data;
- if(is->debug & 0x2)
- printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",min,type);
+ if (is->debug & 0x2)
+ printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n", min, type);
if (!(is->state & IPPP_OPEN))
return -EINVAL;
switch (type) {
- case SEL_IN:
- save_flags(flags);
- cli();
- bl = is->last;
- bf = is->first;
- /*
- * if IPPP_NOBLOCK is set we return even if we have nothing to read
- */
- if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) {
- select_wait(&is->wq, st);
+ case SEL_IN:
+ save_flags(flags);
+ cli();
+ bl = is->last;
+ bf = is->first;
+ /*
+ * if IPPP_NOBLOCK is set we return even if we have nothing to read
+ */
+ if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) {
+ select_wait(&is->wq, st);
+ restore_flags(flags);
+ return 0;
+ }
+ is->state &= ~IPPP_NOBLOCK;
restore_flags(flags);
+ return 1;
+ case SEL_OUT:
+ /* we're always ready to send .. */
+ return 1;
+ case SEL_EX:
+ select_wait(&is->wq1, st);
return 0;
- }
- is->state &= ~IPPP_NOBLOCK;
- restore_flags(flags);
- return 1;
- case SEL_OUT:
- /* we're always ready to send .. */
- return 1;
- case SEL_EX:
- select_wait(&is->wq1, st);
- return 0;
}
return 1;
}
+#else
+unsigned int
+isdn_ppp_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask;
+ struct ippp_buf_queue *bf;
+ struct ippp_buf_queue *bl;
+ unsigned long flags;
+ struct ippp_struct *is;
+
+ is = file->private_data;
+
+ if (is->debug & 0x2)
+ printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_inode->i_rdev));
+
+ poll_wait(&is->wq, wait);
+
+ if (!(is->state & IPPP_OPEN)) {
+ printk(KERN_DEBUG "isdn_ppp: device not open\n");
+ return POLLERR;
+ }
+ /* we're always ready to send .. */
+ mask = POLLOUT | POLLWRNORM;
+
+ save_flags(flags);
+ cli();
+ bl = is->last;
+ bf = is->first;
+ /*
+ * if IPPP_NOBLOCK is set we return even if we have nothing to read
+ */
+ if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
+ is->state &= ~IPPP_NOBLOCK;
+ mask |= POLLIN | POLLRDNORM;
+ }
+ restore_flags(flags);
+ return mask;
+}
+#endif
+
/*
* fill up isdn_ppp_read() queue ..
*/
-static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot)
+static int
+isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
{
- struct ippp_buf_queue *bf, *bl;
+ struct ippp_buf_queue *bf,
+ *bl;
unsigned long flags;
unsigned char *nbuf;
struct ippp_struct *is;
printk(KERN_DEBUG "ippp: device not activated.\n");
return 0;
}
-
- nbuf = (unsigned char *) kmalloc(len+4, GFP_ATOMIC);
- if(!nbuf) {
+ nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
+ if (!nbuf) {
printk(KERN_WARNING "ippp: Can't alloc buf\n");
return 0;
}
nbuf[1] = PPP_UI;
nbuf[2] = proto >> 8;
nbuf[3] = proto & 0xff;
- memcpy(nbuf+4, buf, len);
+ memcpy(nbuf + 4, buf, len);
save_flags(flags);
cli();
is->first = bf;
}
bl->buf = (char *) nbuf;
- bl->len = len+4;
+ bl->len = len + 4;
is->last = bl->next;
restore_flags(flags);
* reports, that there is data
*/
-int isdn_ppp_read(int min, struct file *file, char *buf, int count)
+int
+isdn_ppp_read(int min, struct file *file, char *buf, int count)
{
struct ippp_struct *is;
struct ippp_buf_queue *b;
int r;
unsigned long flags;
+ unsigned char *save_buf;
is = file->private_data;
cli();
b = is->first->next;
- if (!b->buf) {
+ save_buf = b->buf;
+ if (!save_buf) {
restore_flags(flags);
return -EAGAIN;
}
if (b->len < count)
count = b->len;
- copy_to_user(buf, b->buf, count);
- kfree(b->buf);
b->buf = NULL;
is->first = b;
+
restore_flags(flags);
+ copy_to_user(buf, save_buf, count);
+ kfree(save_buf);
+
return count;
}
/*
* ipppd wanna write a packet to the card .. non-blocking
*/
-
-int isdn_ppp_write(int min, struct file *file, const char *buf, int count)
+
+int
+isdn_ppp_write(int min, struct file *file, const char *buf, int count)
{
isdn_net_local *lp;
struct ippp_struct *is;
if (!lp)
printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
else {
- /*
- * Don't reset huptimer for
- * LCP packets. (Echo requests).
- */
- copy_from_user(protobuf, buf, 4);
- proto = PPP_PROTOCOL(protobuf);
- if (proto != PPP_LCP)
+ /*
+ * Don't reset huptimer for
+ * LCP packets. (Echo requests).
+ */
+ if (copy_from_user(protobuf, buf, 4))
+ return -EFAULT;
+ proto = PPP_PROTOCOL(protobuf);
+ if (proto != PPP_LCP)
lp->huptimer = 0;
-
+
if (lp->isdn_device < 0 || lp->isdn_channel < 0)
return 0;
int cnt;
struct sk_buff *skb;
skb = dev_alloc_skb(count);
- if(!skb) {
+ if (!skb) {
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
return count;
}
- skb->free = 1;
- copy_from_user(skb_put(skb, count), buf, count);
- if(is->debug & 0x40) {
- printk(KERN_DEBUG "ppp xmit: len %ld\n",skb->len);
- isdn_ppp_frame_log("xmit",skb->data,skb->len,32);
+ SET_SKB_FREE(skb);
+ if (copy_from_user(skb_put(skb, count), buf, count))
+ return -EFAULT;
+ if (is->debug & 0x40) {
+ printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
+ isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
}
- if( (cnt=isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb)) != count) {
- if(lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb,FREE_WRITE);
- printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n",cnt,count);
- }
- else
- printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n",cnt,count);
+ if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) {
+ if (lp->sav_skb) {
+ dev_kfree_skb(lp->sav_skb, FREE_WRITE);
+ printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
+ } else
+ printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count);
lp->sav_skb = skb;
}
}
}
/*
- * init memory, structures etc.
+ * init memory, structures etc.
*/
-int isdn_ppp_init(void)
+int
+isdn_ppp_init(void)
{
- int i, j;
+ int i,
+ j;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!(ippp_table[i] = (struct ippp_struct *)
- kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
+ if (!(ippp_table[i] = (struct ippp_struct *)
+ kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
+ printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
for (j = 0; j < i; j++)
kfree(ippp_table[i]);
- return -1;
- }
+ return -1;
+ }
memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
ippp_table[i]->state = 0;
ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
return 0;
}
-void isdn_ppp_cleanup(void)
+void
+isdn_ppp_cleanup(void)
{
- int i;
+ int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- kfree(ippp_table[i]);
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ kfree(ippp_table[i]);
+}
+
+/*
+ * get the PPP protocol header and pull skb
+ */
+static int isdn_ppp_strip_proto(struct sk_buff *skb)
+{
+ int proto;
+ if (skb->data[0] & 0x1) {
+ proto = skb->data[0];
+ skb_pull(skb, 1); /* protocol ID is only 8 bit */
+ } else {
+ proto = ((int) skb->data[0] << 8) + skb->data[1];
+ skb_pull(skb, 2);
+ }
+ return proto;
}
+
/*
* handler for incoming packets on a syncPPP interface
*/
void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
{
struct ippp_struct *is;
+ int proto;
+
is = ippp_table[lp->ppp_slot];
- if(is->debug & 0x4) {
- printk(KERN_DEBUG "ippp_receive: len: %ld\n",skb->len);
- isdn_ppp_frame_log("receive",skb->data,skb->len,32);
+ if (is->debug & 0x4) {
+ printk(KERN_DEBUG "ippp_receive: len: %d\n", (int) skb->len);
+ isdn_ppp_frame_log("receive", skb->data, skb->len, 32);
}
-
- if(net_dev->local.master) {
+ if (net_dev->local.master) {
printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
- net_dev = ((isdn_net_local*) net_dev->local.master->priv)->netdev;
+ net_dev = ((isdn_net_local *) net_dev->local.master->priv)->netdev;
}
-
- if(skb->data[0] == 0xff && skb->data[1] == 0x03)
- skb_pull(skb,2);
+ if (skb->data[0] == 0xff && skb->data[1] == 0x03)
+ skb_pull(skb, 2);
else if (is->pppcfg & SC_REJ_COMP_AC) {
- skb->free = 1;
- dev_kfree_skb(skb,0 /* FREE_READ */ );
- return; /* discard it silently */
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
+ return; /* discard it silently */
}
+ proto = isdn_ppp_strip_proto(skb);
+
#ifdef CONFIG_ISDN_MPP
if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
- int proto;
int sqno_end;
- if (skb->data[0] & 0x1) {
- proto = skb->data[0];
- skb_pull(skb,1); /* protocol ID is only 8 bit */
- } else {
- proto = ((int) skb->data[0] << 8) + skb->data[1];
- skb_pull(skb,2);
+
+ if(proto == PPP_LINK_COMP) {
+ printk(KERN_DEBUG "received single link compressed frame\n");
+ skb = isdn_ppp_decompress(skb,is,NULL);
+ if(!skb)
+ return;
+ proto = isdn_ppp_strip_proto(skb);
}
+
if (proto == PPP_MP) {
isdn_net_local *lpq;
long sqno, min_sqno, tseq;
+
u_char BEbyte = skb->data[0];
- if(is->debug & 0x8)
- printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto ,
- (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
- (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
+ if (is->debug & 0x8)
+ printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto,
+ (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
+ (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
if (!(is->mpppcfg & SC_IN_SHORT_SEQ)) {
sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3];
- skb_pull(skb,4);
+ skb_pull(skb, 4);
} else {
sqno = (((int) skb->data[0] & 0xf) << 8) + (int) skb->data[1];
- skb_pull(skb,2);
+ skb_pull(skb, 2);
}
+ /*
+ * new sequence number lower than last number? (this is only allowed
+ * for overflow case)
+ */
if ((tseq = is->last_link_seqno) >= sqno) {
int range = is->range;
- if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
+ if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %ld, last: %ld !!!\n", sqno, tseq);
else {
sqno += range;
is->last_link_seqno = sqno;
}
- } else
+ } else {
+ /* here, we should also add an redundancy check */
is->last_link_seqno = sqno;
+ }
+ /*
+ * step over all links to find lowest link number
+ */
for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) {
long lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
if (lls >= 0 && lls < min_sqno)
if (lpq == net_dev->queue)
break;
}
- if (min_sqno >= ippp_table[lpq->ppp_slot]->range) { /* OK, every link overflowed */
- int mask = ippp_table[lpq->ppp_slot]->range - 1; /* range is a power of 2 */
-#if 0
- isdn_ppp_cleanup_queue(net_dev, min_sqno);
-#endif
+
+ /*
+ * for the case, that the last frame numbers of all
+ * links are overflowed: mask/reduce the sequenece number to
+ * 'normal' numbering.
+ */
+ if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {
+ int mask = ippp_table[lpq->ppp_slot]->range-1; /* range is power of two, so a mask will do the job */
isdn_ppp_mask_queue(net_dev, mask);
net_dev->ib.next_num &= mask;
{
}
}
if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) {
- printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot);
- if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb , BEbyte, &sqno, min_sqno)) < 0) {
+ static int dmes = 0;
+ if( !dmes ) {
+ printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot);
+ dmes = 1;
+ }
+ if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb, BEbyte, &sqno, min_sqno)) < 0) {
net_dev->ib.modify = 1; /* block timeout-timer */
- isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno);
+ isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
net_dev->ib.modify = 0;
- return; /* no packet complete */
+ return; /* no packet complete */
}
} else
sqno_end = sqno;
- if(is->debug & 0x40)
- printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n",min_sqno,sqno_end,net_dev->ib.next_num );
+ if (is->debug & 0x40)
+ printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n", min_sqno, sqno_end, net_dev->ib.next_num);
/*
* MP buffer management .. reorders incoming packets ..
* first check whether there is more than one link in the bundle
* then check whether the number is in order
*/
- net_dev->ib.modify = 1; /* block timeout-timer */
+ net_dev->ib.modify = 1; /* block timeout-timer */
if (net_dev->ib.bundled && net_dev->ib.next_num != sqno) {
/*
* packet is not 'in order'
if (!q) {
net_dev->ib.modify = 0;
printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
- skb->free = 1;
+ SET_SKB_FREE(skb);
dev_kfree_skb(skb, 0 /* FREE_READ */ );
- return; /* discard */
+ return; /* discard */
}
q->skb = skb;
q->sqno_end = sqno_end;
}
}
} else {
- /*
- * packet was 'in order' .. push it higher
+ /*
+ * packet was 'in order' .. push it higher
*/
net_dev->ib.next_num = sqno_end + 1;
- isdn_ppp_push_higher(net_dev, lp, skb, -1);
+ proto = isdn_ppp_strip_proto(skb);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
- isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno);
+ isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
net_dev->ib.modify = 0;
} else
- isdn_ppp_push_higher(net_dev, lp, skb , proto);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
} else
#endif
- isdn_ppp_push_higher(net_dev, lp, skb , -1);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
/*
* push frame to higher layers
* note: net_dev has to be master net_dev
*/
-static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb,int proto)
+static void
+isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
{
struct device *dev = &net_dev->dev;
struct ippp_struct *is = ippp_table[lp->ppp_slot];
- if (proto < 0) { /* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */
- if (skb->data[0] & 0x01) { /* is it odd? */
- proto = (unsigned char) skb->data[0];
- skb_pull(skb,1); /* protocol ID is only 8 bit */
- } else {
- proto = ((int) (unsigned char) skb->data[0] << 8) + (unsigned char) skb->data[1];
- skb_pull(skb,2);
- }
+ if (is->debug & 0x10) {
+ printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
+ isdn_ppp_frame_log("rpush", skb->data, skb->len, 32);
}
- if(is->debug & 0x10) {
- printk(KERN_DEBUG "push, skb %ld %04x\n",skb->len,proto);
- isdn_ppp_frame_log("rpush",skb->data,skb->len,32);
+ if(proto == PPP_COMP) {
+ if(!lp->master)
+ skb = isdn_ppp_decompress(skb,is,is);
+ else
+ skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]);
+ if(!skb)
+ return;
+ proto = isdn_ppp_strip_proto(skb);
}
switch (proto) {
- case PPP_IPX: /* untested */
- if(is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IPX\n");
- skb->dev = dev;
- skb->mac.raw = skb->data;
- skb->protocol = htons(ETH_P_IPX);
- break;
-#ifdef CONFIG_ISDN_PPP_VJ
- case PPP_VJC_UNCOMP:
- if(is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
- if(slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
- printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
- net_dev->local.stats.rx_dropped++;
- skb->free = 1;
- dev_kfree_skb(skb,0 /* FREE_READ */ );
- return;
- }
-#endif
- case PPP_IP:
- if(is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IP\n");
- skb->dev = dev;
- skb->mac.raw = skb->data;
- skb->protocol = htons(ETH_P_IP);
- break;
- case PPP_VJC_COMP:
- if(is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
+ case PPP_IPX: /* untested */
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: IPX\n");
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ skb->protocol = htons(ETH_P_IPX);
+ break;
#ifdef CONFIG_ISDN_PPP_VJ
- {
- struct sk_buff *skb_old = skb;
- int pkt_len;
- skb = dev_alloc_skb(skb_old->len + 40);
-
- skb_old->free = 1;
-
- if (!skb) {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+ case PPP_VJC_UNCOMP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+ if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+ printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
net_dev->local.stats.rx_dropped++;
- dev_kfree_skb(skb_old,0 /* FREE_READ */ );
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
return;
}
+#endif
+ case PPP_IP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: IP\n");
skb->dev = dev;
- skb_put(skb,skb_old->len + 40);
- memcpy(skb->data, skb_old->data, skb_old->len);
skb->mac.raw = skb->data;
- pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
- skb->data, skb_old->len);
- dev_kfree_skb(skb_old,0 /* FREE_READ */ );
- if(pkt_len < 0) {
- skb->free = 1;
- dev_kfree_skb(skb, 0 /* FREE_READ */ );
- lp->stats.rx_dropped++;
- return;
- }
- skb_trim(skb, pkt_len);
skb->protocol = htons(ETH_P_IP);
- }
+ break;
+ case PPP_VJC_COMP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
+#ifdef CONFIG_ISDN_PPP_VJ
+ {
+ struct sk_buff *skb_old = skb;
+ int pkt_len;
+ skb = dev_alloc_skb(skb_old->len + 40);
+
+ SET_SKB_FREE(skb_old);
+
+ if (!skb) {
+ printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+ net_dev->local.stats.rx_dropped++;
+ dev_kfree_skb(skb_old, 0 /* FREE_READ */ );
+ return;
+ }
+ skb->dev = dev;
+ skb_put(skb, skb_old->len + 40);
+ memcpy(skb->data, skb_old->data, skb_old->len);
+ skb->mac.raw = skb->data;
+ pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
+ skb->data, skb_old->len);
+ dev_kfree_skb(skb_old, 0 /* FREE_READ */ );
+ if (pkt_len < 0) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
+ lp->stats.rx_dropped++;
+ return;
+ }
+ skb_trim(skb, pkt_len);
+ skb->protocol = htons(ETH_P_IP);
+ }
#else
- printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
- lp->stats.rx_dropped++;
- skb->free = 1;
- dev_kfree_skb(skb,0 /* FREE_READ */ );
- return;
+ printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
+ lp->stats.rx_dropped++;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
+ return;
#endif
- break;
- default:
- isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_slot); /* push data to pppd device */
- skb->free = 1;
- dev_kfree_skb(skb,0 /* FREE_READ */ );
- return;
+ break;
+ case PPP_CCP:
+ isdn_ppp_receive_ccp(net_dev,lp,skb);
+ /* fall through */
+ default:
+ isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
+ return;
}
netif_rx(skb);
-/* net_dev->local.stats.rx_packets++; */ /* done in isdn_net.c */
+ /* net_dev->local.stats.rx_packets++; *//* done in isdn_net.c */
/* Reset hangup-timer */
lp->huptimer = 0;
}
/*
- * send ppp frame .. we expect a PIDCOMPressable proto --
- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
- *
- * VJ compression may change skb pointer!!! .. requeue with old
- * skb isn't allowed!!
+ * isdn_ppp_skb_push ..
+ * checks whether we have enough space at the beginning of the SKB
+ * and allocs a new SKB if necessary
*/
-
-static void isdn_ppp_skb_destructor(struct sk_buff *skb) /* debug function */
+static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
{
- char outstr[80],*outpnt=outstr;
- int i;
+ struct sk_buff *skb = *skb_p;
- *outpnt = 0;
- for(i=0;i<24 && i<skb->len;i++) {
- sprintf(outpnt,"%02x ",skb->data[i]);
- outpnt += 3;
+ if(skb_headroom(skb) < len) {
+ printk(KERN_ERR "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
+ dev_kfree_skb(skb,FREE_WRITE);
+ return NULL;
}
- printk(KERN_DEBUG "ippp_dstrct: %s\n",outstr);
+ return skb_push(skb,len);
}
-int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
+
+/*
+ * send ppp frame .. we expect a PIDCOMPressable proto --
+ * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
+ *
+ * VJ compression may change skb pointer!!! .. requeue with old
+ * skb isn't allowed!!
+ */
+
+int
+isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
{
- struct device *mdev = ((isdn_net_local *) (dev->priv) )->master; /* get master (for redundancy) */
+ struct device *mdev = ((isdn_net_local *) (dev->priv))->master; /* get master (for redundancy) */
isdn_net_local *lp,*mlp;
isdn_net_dev *nd;
- int proto = PPP_IP; /* 0x21 */
+ unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
- if(mdev)
- mlp = (isdn_net_local *) (mdev->priv);
+ if (mdev)
+ mlp = (isdn_net_local *) (mdev->priv);
else {
mdev = dev;
mlp = (isdn_net_local *) (dev->priv);
}
- nd = mlp->netdev; /* get master lp */
+ nd = mlp->netdev; /* get master lp */
ipts = ippp_table[mlp->ppp_slot];
- if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
+ if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
#ifdef ISDN_SYNCPPP_READDRESS
- if(!ipts->old_pa_addr)
+ if (!ipts->old_pa_addr)
ipts->old_pa_addr = mdev->pa_addr;
- if(!ipts->old_pa_dstaddr)
+ if (!ipts->old_pa_dstaddr)
ipts->old_pa_dstaddr = mdev->pa_dstaddr;
#endif
- if(ipts->debug & 0x1) {
- printk(KERN_INFO "%s: IP frame delayed.\n",dev->name);
- skb->destructor = isdn_ppp_skb_destructor;
- }
- return 1;
+ if (ipts->debug & 0x1)
+ printk(KERN_INFO "%s: IP frame delayed.\n", dev->name);
+ return 1;
}
- skb->destructor = NULL;
-
- switch(ntohs(skb->protocol)) {
+ switch (ntohs(skb->protocol)) {
case ETH_P_IP:
proto = PPP_IP;
#ifdef ISDN_SYNCPPP_READDRESS
- if(ipts->old_pa_addr != mdev->pa_addr)
- {
+ if (ipts->old_pa_addr != mdev->pa_addr) {
struct iphdr *ipfr;
ipfr = (struct iphdr *) skb->data;
-printk(KERN_DEBUG "IF-address changed from %lx to %lx\n",ipts->old_pa_addr,mdev->pa_addr);
- if(ipfr->version == 4) {
- if(ipfr->saddr == ipts->old_pa_addr) {
-printk(KERN_DEBUG "readdressing %lx to %lx\n",ipfr->saddr,mdev->pa_addr);
+ if(ipts->debug & 0x4)
+ printk(KERN_DEBUG "IF-address changed from %lx to %lx\n", ipts->old_pa_addr, mdev->pa_addr);
+ if (ipfr->version == 4) {
+ if (ipfr->saddr == ipts->old_pa_addr) {
+ printk(KERN_DEBUG "readdressing %lx to %lx\n", ipfr->saddr, mdev->pa_addr);
ipfr->saddr = mdev->pa_addr;
}
}
}
- /* dstaddr change not so improtant */
+ /* dstaddr change not so important */
#endif
break;
case ETH_P_IPX:
proto = PPP_IPX; /* untested */
break;
+ default:
+ dev_kfree_skb(skb, FREE_WRITE);
+ printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocoll: %#x.\n", skb->protocol);
+ return 0;
}
- lp = nd->queue; /* get lp on top of queue */
+ lp = nd->queue; /* get lp on top of queue */
- if(lp->sav_skb) { /* find a non-busy device */
+ if (lp->sav_skb) { /* find a non-busy device */
isdn_net_local *nlp = lp->next;
- while(lp->sav_skb) {
- if(lp == nlp)
+ while (lp->sav_skb) {
+ if (lp == nlp)
return 1;
nlp = nd->queue = nd->queue->next;
}
}
ipt = ippp_table[lp->ppp_slot];
- lp->huptimer = 0;
+ lp->huptimer = 0;
/*
- * after this line .. requeueing in the device queue is no longer allowed!!!
+ * after this line .. requeueing in the device queue is no longer allowed!!!
*/
- if(ipt->debug & 0x4)
- printk(KERN_DEBUG "xmit skb, len %ld\n",skb->len);
+ /* Pull off the fake header we stuck on earlier to keep
+ * the fragemntation code happy.
+ * this will break the ISDN_SYNCPPP_READDRESS hack a few lines
+ * above. So, enabling this is no longer allowed
+ */
+ skb_pull(skb,IPPP_MAX_HEADER);
+
+ if (ipt->debug & 0x4)
+ printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
#ifdef CONFIG_ISDN_PPP_VJ
- if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but this check again */
+ if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
struct sk_buff *new_skb;
new_skb = dev_alloc_skb(skb->len);
- if(new_skb) {
+ if (new_skb) {
u_char *buf;
int pktlen;
new_skb->dev = skb->dev;
- new_skb->free = 1;
- skb_put(new_skb,skb->len);
+ SET_SKB_FREE(new_skb);
+ skb_put(new_skb, skb->len);
buf = skb->data;
pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
- &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
+ &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
- if(buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*) */
- if(new_skb->data != buf)
+ if (buf != skb->data) {
+ if (new_skb->data != buf)
printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb, FREE_WRITE);
skb = new_skb;
- }
- else {
- dev_kfree_skb(new_skb,0 /* FREE_WRITE */ );
+ } else {
+ dev_kfree_skb(new_skb, 0 /* FREE_WRITE */ );
}
- skb_trim(skb,pktlen);
+ skb_trim(skb, pktlen);
if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
proto = PPP_VJC_COMP;
skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
}
#endif
- if(ipt->debug & 0x24)
- printk(KERN_DEBUG "xmit2 skb, len %ld, proto %04x\n",skb->len,proto);
+ /*
+ * normal or bundle compression
+ */
+ skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
+
+ if (ipt->debug & 0x24)
+ printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
#ifdef CONFIG_ISDN_MPP
if (ipt->mpppcfg & SC_MP_PROT) {
ipts->mp_seqno++;
nd->queue = nd->queue->next;
if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
- skb_push(skb, 3);
+ unsigned char *data = isdn_ppp_skb_push(&skb, 3);
+ if(!data)
+ return 0;
mp_seqno &= 0xfff;
- skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8); /* (B)egin & (E)ndbit .. */
- skb->data[1] = mp_seqno & 0xff;
- skb->data[2] = proto; /* PID compression */
+ data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
+ data[1] = mp_seqno & 0xff;
+ data[2] = proto; /* PID compression */
} else {
- skb_push(skb, 5);
- skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
- skb->data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
- skb->data[2] = (mp_seqno >> 8) & 0xff;
- skb->data[3] = (mp_seqno >> 0) & 0xff;
- skb->data[4] = proto; /* PID compression */
+ unsigned char *data = isdn_ppp_skb_push(&skb, 5);
+ if(!data)
+ return 0;
+ data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
+ data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
+ data[2] = (mp_seqno >> 8) & 0xff;
+ data[3] = (mp_seqno >> 0) & 0xff;
+ data[4] = proto; /* PID compression */
}
proto = PPP_MP; /* MP Protocol, 0x003d */
}
#endif
- skb_push(skb,4);
- skb->data[0] = 0xff; /* All Stations */
- skb->data[1] = 0x03; /* Unnumbered information */
- skb->data[2] = proto >> 8;
- skb->data[3] = proto & 0xff;
- /* tx-stats are now updated via BSENT-callback */
+ /*
+ * 'link' compression
+ */
+ skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
- if(ipts->debug & 0x40) {
- printk(KERN_DEBUG "skb xmit: len: %ld\n",skb->len);
- isdn_ppp_frame_log("xmit",skb->data,skb->len,32);
+ if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
+ unsigned char *data = isdn_ppp_skb_push(&skb,1);
+ if(!data)
+ return 0;
+ data[0] = proto & 0xff;
+ }
+ else {
+ unsigned char *data = isdn_ppp_skb_push(&skb,2);
+ if(!data)
+ return 0;
+ data[0] = (proto >> 8) & 0xff;
+ data[1] = proto & 0xff;
+ }
+ if(!(ipt->pppcfg & SC_COMP_AC)) {
+ unsigned char *data = isdn_ppp_skb_push(&skb,2);
+ if(!data)
+ return 0;
+ data[0] = 0xff; /* All Stations */
+ data[1] = 0x03; /* Unnumbered information */
}
- if(isdn_net_send_skb(dev , lp , skb)) {
- if(lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */
- printk(KERN_ERR "%s: whoops .. there is another stored skb!\n",dev->name);
- dev_kfree_skb(skb,FREE_WRITE);
- }
- else
+ /* tx-stats are now updated via BSENT-callback */
+
+ if (ipts->debug & 0x40) {
+ printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
+ isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
+ }
+ if (isdn_net_send_skb(dev, lp, skb)) {
+ if (lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */
+ printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", dev->name);
+ dev_kfree_skb(skb, FREE_WRITE);
+ } else
lp->sav_skb = skb;
}
return 0;
#ifdef CONFIG_ISDN_MPP
-void isdn_ppp_free_sqqueue(isdn_net_dev * p)
+static void
+isdn_ppp_free_sqqueue(isdn_net_dev * p)
{
struct sqqueue *q = p->ib.sq;
p->ib.sq = NULL;
- while(q) {
+ while (q) {
struct sqqueue *qn = q->next;
- if(q->skb) {
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+ if (q->skb) {
+ SET_SKB_FREE(q->skb);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
}
kfree(q);
q = qn;
}
-void isdn_ppp_free_mpqueue(isdn_net_dev * p)
+static void
+isdn_ppp_free_mpqueue(isdn_net_dev * p)
{
- struct mpqueue *ql, *q = p->mp_last;
+ struct mpqueue *q = p->mp_last;
+ p->mp_last = NULL;
+
while (q) {
- ql = q->next;
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+ struct mpqueue *ql = q->next;
+ SET_SKB_FREE(q->skb);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
kfree(q);
q = ql;
}
}
-static int isdn_ppp_bundle(struct ippp_struct *is, int unit)
+static int
+isdn_ppp_bundle(struct ippp_struct *is, int unit)
{
char ifn[IFNAMSIZ + 1];
long flags;
isdn_net_dev *p;
- isdn_net_local *lp,*nlp;
+ isdn_net_local *lp,
+ *nlp;
sprintf(ifn, "ippp%d", unit);
p = isdn_net_findif(ifn);
}
-static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
+static void
+isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
{
struct mpqueue *q = dev->mp_last;
while (q) {
}
}
-static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int BEbyte, long *sqnop, int min_sqno)
+static int
+isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno)
{
- struct mpqueue *qe, *q1, *q;
- long cnt, flags;
- int pktlen, sqno_end;
+ struct mpqueue *qe,
+ *q1,
+ *q;
+ long cnt,
+ flags;
+ int pktlen,
+ sqno_end;
int sqno = *sqnop;
- q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_KERNEL);
+ q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_ATOMIC);
if (!q1) {
printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n");
save_flags(flags);
q1->last = NULL;
isdn_ppp_cleanup_mpqueue(dev, min_sqno); /* not necessary */
restore_flags(flags);
- return -1;
+ return -1; /* -1 is not an error. Just says, that this fragment hasn't complete a full frame */
}
- for (;;) { /* the faster way would be to step from the queue-end to the start */
+ for (;;) { /* the faster way would be to step from the queue-end to the start */
if (sqno > q->sqno) {
if (q->next) {
q = q->next;
isdn_ppp_cleanup_mpqueue(dev, min_sqno);
restore_flags(flags);
- *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
+ *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
if (!(*skb)) {
while (q) {
struct mpqueue *ql = q->next;
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+ SET_SKB_FREE(q->skb);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
kfree(q);
q = ql;
}
return -2;
}
cnt = 0;
- skb_put(*skb,pktlen);
+ skb_put(*skb, pktlen);
while (q) {
struct mpqueue *ql = q->next;
memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
cnt += q->skb->len;
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+ SET_SKB_FREE(q->skb);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
kfree(q);
q = ql;
}
* or packets with a sqno less or equal to min_sqno
* net_dev: master netdevice , lp: 'real' local connection
*/
-static void isdn_ppp_cleanup_sqqueue(isdn_net_dev *net_dev, isdn_net_local *lp,long min_sqno)
+static void
+isdn_ppp_cleanup_sqqueue(isdn_net_dev * net_dev, isdn_net_local * lp, long min_sqno)
{
struct sqqueue *q;
- while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno) ) {
- if(q->sqno_start != net_dev->ib.next_num) {
- printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n",net_dev->ib.next_num);
+ while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno)) {
+ int proto;
+ if (q->sqno_start != net_dev->ib.next_num) {
+ printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n", net_dev->ib.next_num);
#ifdef CONFIG_ISDN_PPP_VJ
slhc_toss(ippp_table[net_dev->local.ppp_slot]->slcomp);
#endif
}
- isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
+ proto = isdn_ppp_strip_proto(q->skb);
+ isdn_ppp_push_higher(net_dev, lp, q->skb, proto);
net_dev->ib.sq = q->next;
net_dev->ib.next_num = q->sqno_end + 1;
kfree(q);
- }
+ }
}
/*
* remove stale packets from list
*/
-static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
+static void
+isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
{
#ifdef CONFIG_ISDN_PPP_VJ
int toss = 0;
/* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft:
eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen
wenn sqno<min_sqno und Luecken vorhanden sind: auch weg (die koennen nicht mehr gefuellt werden)
- bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete
+ bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete
groesser als mrru ist: raus damit , Pakete muessen allerdings zusammenhaengen sonst koennte
ja ein Paket mit B und eins mit E dazwischenpassen */
- struct mpqueue *ql, *q = dev->mp_last;
- while (q) {
- if (q->sqno < min_sqno) {
- if (q->BEbyte & MP_END_FRAG) {
- printk(KERN_DEBUG "ippp: freeing stale packet!\n");
- if ((dev->mp_last = q->next))
- q->next->last = NULL;
- while (q) {
- ql = q->last;
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
- kfree(q);
+ struct mpqueue *ql,
+ *q = dev->mp_last;
+ while(q && (q->sqno < min_sqno) ) {
+ if ( (q->BEbyte & MP_END_FRAG) ||
+ (q->next && (q->next->sqno <= min_sqno) && (q->next->BEbyte & MP_BEGIN_FRAG)) ) {
+ printk(KERN_DEBUG "ippp: freeing stale packet(s), min_sq: %ld!\n",min_sqno);
+ if ((dev->mp_last = q->next))
+ q->next->last = NULL;
+ while (q) {
+ ql = q->last;
+ SET_SKB_FREE(q->skb);
+ printk(KERN_DEBUG "ippp, freeing packet with sqno: %ld\n",q->sqno);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
+ kfree(q);
#ifdef CONFIG_ISDN_PPP_VJ
- toss = 1;
+ toss = 1;
#endif
- q = ql;
- }
- q = dev->mp_last;
- } else
- q = q->next;
+ q = ql;
+ }
+ q = dev->mp_last;
} else
- break;
+ q = q->next;
}
#ifdef CONFIG_ISDN_PPP_VJ
/* did we free a stale frame ? */
- if(toss)
+ if (toss)
slhc_toss(ippp_table[dev->local.ppp_slot]->slcomp);
#endif
}
#endif
-void isdn_ppp_timer_timeout(void)
+void
+isdn_ppp_timer_timeout(void)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *net_dev = dev->netdev;
- struct sqqueue *q, *ql = NULL, *qn;
+ struct sqqueue *q,
+ *ql = NULL,
+ *qn;
while (net_dev) {
isdn_net_local *lp = &net_dev->local;
- if (net_dev->ib.modify || lp->master) { /* interface locked or slave?*/
+ if (net_dev->ib.modify || lp->master) { /* interface locked or slave? */
net_dev = net_dev->next;
continue;
}
-
q = net_dev->ib.sq;
while (q) {
if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) {
#ifdef CONFIG_ISDN_PPP_VJ
/* did we step over a missing frame ? */
- if(q->sqno_start != net_dev->ib.next_num)
+ if (q->sqno_start != net_dev->ib.next_num)
slhc_toss(ippp_table[lp->ppp_slot]->slcomp);
#endif
net_dev->ib.next_num = q->sqno_end + 1;
q->next = NULL;
for (; ql;) {
- isdn_ppp_push_higher(net_dev, lp, ql->skb, -1);
+ int proto = isdn_ppp_strip_proto(ql->skb);
+ isdn_ppp_push_higher(net_dev, lp, ql->skb, proto);
qn = ql->next;
kfree(ql);
ql = qn;
* network device ioctl handlers
*/
-static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *dev)
+static int
+isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct device *dev)
{
- struct ppp_stats *res, t;
+ struct ppp_stats *res,
+ t;
isdn_net_local *lp = (isdn_net_local *) dev->priv;
int err;
- res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
- err = verify_area (VERIFY_WRITE, res,sizeof(struct ppp_stats));
+ res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+ err = verify_area(VERIFY_WRITE, res, sizeof(struct ppp_stats));
- if(err)
+ if (err)
return err;
/* build a temporary stat struct and copy it to user space */
- memset (&t, 0, sizeof(struct ppp_stats));
- if(dev->flags & IFF_UP) {
+ memset(&t, 0, sizeof(struct ppp_stats));
+ if (dev->flags & IFF_UP) {
t.p.ppp_ipackets = lp->stats.rx_packets;
t.p.ppp_ierrors = lp->stats.rx_errors;
t.p.ppp_opackets = lp->stats.tx_packets;
t.p.ppp_oerrors = lp->stats.tx_errors;
#ifdef CONFIG_ISDN_PPP_VJ
- if(slot >= 0 && ippp_table[slot]->slcomp) {
+ if (slot >= 0 && ippp_table[slot]->slcomp) {
struct slcompress *slcomp = ippp_table[slot]->slcomp;
- t.vj.vjs_packets = slcomp->sls_o_compressed+slcomp->sls_o_uncompressed;
+ t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
t.vj.vjs_compressed = slcomp->sls_o_compressed;
t.vj.vjs_searches = slcomp->sls_o_searches;
- t.vj.vjs_misses = slcomp->sls_o_misses;
- t.vj.vjs_errorin = slcomp->sls_i_error;
- t.vj.vjs_tossed = slcomp->sls_i_tossed;
+ t.vj.vjs_misses = slcomp->sls_o_misses;
+ t.vj.vjs_errorin = slcomp->sls_i_error;
+ t.vj.vjs_tossed = slcomp->sls_i_tossed;
t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
t.vj.vjs_compressedin = slcomp->sls_i_compressed;
}
#endif
}
- copy_to_user (res, &t, sizeof (struct ppp_stats));
- return 0;
-
+ return copy_to_user(res, &t, sizeof(struct ppp_stats));
}
-int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+int
+isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
{
int error;
char *r;
isdn_net_local *lp = (isdn_net_local *) dev->priv;
#if 0
- printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_slot);
+ printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n", cmd, lp->ppp_slot);
#endif
if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
case SIOCGPPPVER:
r = (char *) ifr->ifr_ifru.ifru_data;
len = strlen(PPP_VERSION) + 1;
- error = verify_area(VERIFY_WRITE, r, len);
- if (!error)
- copy_to_user(r, PPP_VERSION, len);
+ error = copy_to_user(r, PPP_VERSION, len);
break;
case SIOCGPPPSTATS:
- error = isdn_ppp_dev_ioctl_stats (lp->ppp_slot, ifr, dev);
+ error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
break;
default:
error = -EINVAL;
return error;
}
-static int isdn_ppp_if_get_unit(char *name)
+static int
+isdn_ppp_if_get_unit(char *name)
{
- int len, i, unit = 0, deci;
+ int len,
+ i,
+ unit = 0,
+ deci;
len = strlen(name);
- if(strncmp("ippp",name,4) || len > 8)
+ if (strncmp("ippp", name, 4) || len > 8)
return -1;
for (i = 0, deci = 1; i < len; i++, deci *= 10) {
- char a = name[len-i-1];
+ char a = name[len - i - 1];
if (a >= '0' && a <= '9')
unit += (a - '0') * deci;
else
break;
}
- if (!i || len-i != 4)
+ if (!i || len - i != 4)
unit = -1;
return unit;
}
-int isdn_ppp_dial_slave(char *name)
+int
+isdn_ppp_dial_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *ndev;
isdn_net_local *lp;
struct device *sdev;
- if(!(ndev = isdn_net_findif(name)))
+ if (!(ndev = isdn_net_findif(name)))
return 1;
lp = &ndev->local;
- if(!(lp->flags & ISDN_NET_CONNECTED))
+ if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
sdev = lp->slave;
- while(sdev)
- {
+ while (sdev) {
isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
- if(!(mlp->flags & ISDN_NET_CONNECTED))
+ if (!(mlp->flags & ISDN_NET_CONNECTED))
break;
sdev = mlp->slave;
}
- if(!sdev)
+ if (!sdev)
return 2;
isdn_net_force_dial_lp((isdn_net_local *) sdev->priv);
#endif
}
-int isdn_ppp_hangup_slave(char *name)
+int
+isdn_ppp_hangup_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *ndev;
- isdn_net_local *lp;
- struct device *sdev;
+ isdn_net_dev *ndev;
+ isdn_net_local *lp;
+ struct device *sdev;
- if(!(ndev = isdn_net_findif(name)))
+ if (!(ndev = isdn_net_findif(name)))
return 1;
lp = &ndev->local;
- if(!(lp->flags & ISDN_NET_CONNECTED))
+ if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
sdev = lp->slave;
- while(sdev)
- {
+ while (sdev) {
isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
- if((mlp->flags & ISDN_NET_CONNECTED))
+ if ((mlp->flags & ISDN_NET_CONNECTED))
break;
sdev = mlp->slave;
}
- if(!sdev)
+ if (!sdev)
return 2;
isdn_net_hangup(sdev);
#endif
}
+/*
+ * PPP compression stuff
+ */
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master)
+{
+#if 1
+ printk(KERN_ERR "compression not included!\n");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb,FREE_WRITE);
+ return NULL;
+#else
+ if(!master) {
+ /*
+ * single link compression
+ */
+ if(!is->link_compressor) {
+ printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb,FREE_WRITE);
+ return NULL;
+ }
+ if(!is->link_decomp_stat) {
+ printk(KERN_DEBUG "ippp: initialize link compressor\n");
+ }
+/*
+ -> decompress link
+*/
+ }
+ else {
+ /*
+ * 'normal' or bundle-compression
+ */
+ if(!master->compressor) {
+ printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb,FREE_WRITE);
+ return NULL;
+ }
+ if(!master->decomp_stat) {
+#if 0
+ master->decomp_stat = (master->compressor->decomp_alloc)( .. );
+#endif
+ printk(KERN_DEBUG "ippp: initialize compressor\n");
+ }
+ }
+
+ return skb;
+#endif
+}
+
+/*
+ * compress a frame
+ * type=0: normal/bundle compression
+ * =1: link compression
+ * returns original skb if we haven't compressed the frame
+ * and a new skb pointer if we've done it
+ */
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+ struct ippp_struct *is,struct ippp_struct *master,int type)
+{
+#if 1
+ return skb_in;
+#else
+ int ret;
+ int new_proto;
+ struct isdn_ppp_compressor *compressor;
+ void *stat;
+ struct sk_buff *skb_out;
+
+ if(type) { /* type=1 => Link compression */
+ compressor = is->link_compressor;
+ stat = is->link_comp_stat;
+ new_proto = PPP_LINK_COMP;
+ }
+ else {
+ if(!master) {
+ compressor = is->compressor;
+ stat = is->comp_stat;
+ }
+ else {
+ compressor = master->compressor;
+ stat = master->comp_stat;
+ }
+ new_proto = PPP_COMP;
+ }
+
+ if(!compressor) {
+ printk(KERN_ERR "No compressor set!\n");
+ return skb_in;
+ }
+ if(!stat) {
+ /* init here ? */
+ return skb_in;
+ }
+
+ skb_out = dev_alloc_skb(skb_in->len);
+ if(!skb_out)
+ return skb_in;
+
+ ret = (compressor->compress)(stat,skb_in,skb_out,*proto);
+ if(!ret) {
+ SET_SKB_FREE(skb_out);
+ dev_kfree_skb(skb_out,0);
+ return skb_in;
+ }
+
+ dev_kfree_skb(skb_in,FREE_WRITE);
+ *proto = new_proto;
+ return skb_out;
+#endif
+
+}
+
+/*
+ * we received a CCP frame ..
+ * not a clean solution, but we SHOULD handle a few cased in the kernel
+ */
+static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+ struct sk_buff *skb)
+{
#if 0
-static struct symbol_table isdn_ppp_syms = {
+ printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ skb->data[0],skb->data[1],skb->data[2],skb->data[3],
+ skb->data[4],skb->data[5],skb->data[6],skb->data[7] );
+#endif
+}
+
+int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
+{
+ ipc->next = ipc_head;
+ ipc->prev = NULL;
+ if(ipc_head) {
+ ipc_head->prev = ipc;
+ }
+ ipc_head = ipc;
+ return 0;
+}
+
+int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
+{
+ if(ipc->prev)
+ ipc->prev->next = ipc->next;
+ else
+ ipc_head = ipc->next;
+ if(ipc->next)
+ ipc->next->prev = ipc->prev;
+ ipc->prev = ipc->next = NULL;
+ return 0;
+}
+
+static int isdn_ppp_set_compressor(struct ippp_struct *is,int num)
+{
+ struct isdn_ppp_compressor *ipc = ipc_head;
+
+ while(ipc) {
+ if(ipc->num == num) {
+ return 0;
+ is->compressor = ipc;
+ is->link_compressor = ipc;
+ }
+ ipc = ipc->next;
+ }
+ return -EINVAL;
+}
+
+
+#if 0
+static struct symbol_table isdn_ppp_syms =
+{
#include <linux/symtab_begin.h>
- X(isdn_ppp_register_compressor),
- X(isdn_ppp_unregister_compressor),
+ X(isdn_ppp_register_compressor),
+ X(isdn_ppp_unregister_compressor),
#include <linux/symtab_end.h>
};
#endif
+
+
-/* $Id: isdn_ppp.h,v 1.6 1996/09/23 01:58:11 fritz Exp $
- *
+/* $Id: isdn_ppp.h,v 1.10 1997/06/17 13:06:00 hipp Exp $
+
* header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.h,v $
+ * Revision 1.10 1997/06/17 13:06:00 hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ * more compression changes (but disabled at the moment)
+ * changed one copy_to_user() to run with enabled IRQs
+ * a few MP changes
+ * changed 'proto' handling in the isdn_ppp receive code
+ *
+ * Revision 1.9 1997/02/11 18:32:59 fritz
+ * Bugfix in isdn_ppp_free_mpqueue().
+ *
+ * Revision 1.8 1997/02/10 10:11:33 fritz
+ * More changes for Kernel 2.1.X compatibility.
+ *
+ * Revision 1.7 1997/02/03 23:18:57 fritz
+ * Removed isdn_ppp_free_sqqueue prototype
+ * and ippp_table (both static in isdn_ppp.c).
+ *
* Revision 1.6 1996/09/23 01:58:11 fritz
* Fix: With syncPPP encapsulation, discard LCP packets
* when calculating hangup timeout.
*
*/
-#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
+#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
extern void isdn_ppp_timer_timeout(void);
-extern int isdn_ppp_read(int , struct file *, char *, int);
-extern int isdn_ppp_write(int , struct file *, const char *, int);
-extern int isdn_ppp_open(int , struct file *);
-extern int isdn_ppp_init(void);
+extern int isdn_ppp_read(int, struct file *, char *, int);
+extern int isdn_ppp_write(int, struct file *, const char *, int);
+extern int isdn_ppp_open(int, struct file *);
+extern int isdn_ppp_init(void);
extern void isdn_ppp_cleanup(void);
-extern int isdn_ppp_free(isdn_net_local *);
-extern int isdn_ppp_bind(isdn_net_local *);
-extern int isdn_ppp_xmit(struct sk_buff *, struct device *);
+extern int isdn_ppp_free(isdn_net_local *);
+extern int isdn_ppp_bind(isdn_net_local *);
+extern int isdn_ppp_xmit(struct sk_buff *, struct device *);
extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
-extern int isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int);
-extern void isdn_ppp_free_mpqueue(isdn_net_dev *);
-extern void isdn_ppp_free_sqqueue(isdn_net_dev *);
-extern int isdn_ppp_select(int, struct file *, int, select_table *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
+extern int isdn_ppp_dev_ioctl(struct device *, struct ifreq *, int);
+#if (LINUX_VERSION_CODE < 0x020117)
+extern int isdn_ppp_select(int, struct file *, int, select_table *);
+#else
+extern unsigned int isdn_ppp_poll(struct file *, poll_table *);
+#endif
+extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
extern void isdn_ppp_release(int, struct file *);
-extern int isdn_ppp_dial_slave(char *);
+extern int isdn_ppp_dial_slave(char *);
extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
-extern struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
-
#define IPPP_OPEN 0x01
#define IPPP_CONNECT 0x02
#define IPPP_CLOSEWAIT 0x04
#define IPPP_NOBLOCK 0x08
#define IPPP_ASSIGNED 0x10
+#define IPPP_MAX_HEADER 10
+
+
--- /dev/null
+/* $Id: isdn_syms.c,v 1.3 1997/02/16 01:02:47 fritz Exp $
+
+ * Linux ISDN subsystem, exported symbols (linklevel).
+ *
+ * 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: isdn_syms.c,v $
+ * Revision 1.3 1997/02/16 01:02:47 fritz
+ * Added GPL-Header, Id and Log
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#ifndef __GENKSYMS__ /* Don't want genksyms report unneeded structs */
+#include <linux/isdn.h>
+#endif
+#include "isdn_common.h"
+
+#if (LINUX_VERSION_CODE < 0x020111)
+static int has_exported;
+
+static struct symbol_table isdn_syms = {
+#include <linux/symtab_begin.h>
+ X(register_isdn),
+#include <linux/symtab_end.h>
+};
+
+void
+isdn_export_syms(void)
+{
+ if (has_exported)
+ return;
+ register_symtab(&isdn_syms);
+ has_exported = 1;
+}
+
+#else
+
+EXPORT_SYMBOL(register_isdn);
+
+#endif
-/* $Id: isdn_tty.c,v 1.23 1996/10/22 23:14:02 fritz Exp $
- *
+/* $Id: isdn_tty.c,v 1.41 1997/05/27 15:17:31 fritz Exp $
+
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- *
+ *
* 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)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.41 1997/05/27 15:17:31 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.40 1997/03/24 22:55:27 fritz
+ * Added debug code for status callbacks.
+ *
+ * Revision 1.39 1997/03/21 18:25:56 fritz
+ * Corrected CTS handling.
+ *
+ * Revision 1.38 1997/03/07 12:13:35 fritz
+ * Bugfix: Send audio in adpcm format was broken.
+ * Bugfix: CTS handling was wrong.
+ *
+ * Revision 1.37 1997/03/07 01:37:34 fritz
+ * Bugfix: Did not compile with CONFIG_ISDN_AUDIO disabled.
+ * Bugfix: isdn_tty_tint() did not handle lowlevel errors correctly.
+ * Bugfix: conversion was wrong when sending ulaw audio.
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.36 1997/03/04 21:41:55 fritz
+ * Fix: Excessive stack usage of isdn_tty_senddown()
+ * and isdn_tty_end_vrx() could lead to problems.
+ *
+ * Revision 1.35 1997/03/02 19:05:52 fritz
+ * Bugfix: Avoid recursion.
+ *
+ * Revision 1.34 1997/03/02 14:29:22 fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.33 1997/02/28 02:32:45 fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ * to isdn_tty.c
+ * Bugfix: Bisync protocol did not behave like documented.
+ *
+ * Revision 1.32 1997/02/23 15:43:03 fritz
+ * Small change in handling of incoming calls
+ * documented in newest version of ttyI.4
+ *
+ * Revision 1.31 1997/02/21 13:05:57 fritz
+ * Bugfix: Remote hangup did not set location-info on ttyI's
+ *
+ * Revision 1.30 1997/02/18 09:41:05 fritz
+ * Added support for bitwise access to modem registers (ATSx.y=n, ATSx.y?).
+ * Beautified output of AT&V.
+ *
+ * Revision 1.29 1997/02/16 12:11:51 fritz
+ * Added S13,Bit4 option.
+ *
+ * Revision 1.28 1997/02/10 22:07:08 fritz
+ * Added 2 modem registers for numbering plan and screening info.
+ *
+ * Revision 1.27 1997/02/10 21:31:14 fritz
+ * Changed setup-interface (incoming and outgoing).
+ *
+ * Revision 1.26 1997/02/10 20:12:48 fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.25 1997/02/03 23:04:30 fritz
+ * Reformatted according CodingStyle.
+ * skb->free stuff replaced by macro.
+ * Finished full-duplex audio.
+ *
+ * Revision 1.24 1997/01/14 01:32:42 fritz
+ * Changed audio receive not to rely on skb->users and skb->lock.
+ * Added ATI2 and related variables.
+ * Started adding full-duplex audio capability.
+ *
* Revision 1.23 1996/10/22 23:14:02 fritz
* Changes for compatibility to 2.0.X and 2.1.X kernels.
*
* Initial revision
*
*/
+#undef ISDN_TTY_STAT_DEBUG
#define __NO_VERSION__
#include <linux/config.h>
/* Prototypes */
-static int isdn_tty_edit_at(const char *, int, modem_info *, int);
+static int isdn_tty_edit_at(const char *, int, modem_info *, int);
static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int);
static void isdn_tty_modem_reset_regs(modem_info *, int);
static void isdn_tty_cmd_ATA(modem_info *);
static void isdn_tty_at_cout(char *, modem_info *);
static void isdn_tty_flush_buffer(struct tty_struct *);
+static void isdn_tty_modem_result(int, modem_info *);
+#ifdef CONFIG_ISDN_AUDIO
+static int isdn_tty_countDLE(unsigned char *, int);
+#endif
/* Leave this unchanged unless you know what you do! */
#define MODEM_PARANOIA_CHECK
#define MODEM_DO_RESTART
static char *isdn_ttyname_ttyI = "ttyI";
-static char *isdn_ttyname_cui = "cui";
-static int bit2si[8] = {1,5,7,7,7,7,7,7};
-static int si2bit[8] = {4,1,4,4,4,4,4,4};
-
-char *isdn_tty_revision = "$Revision: 1.23 $";
+static char *isdn_ttyname_cui = "cui";
+static int bit2si[8] =
+{1, 5, 7, 7, 7, 7, 7, 7};
+static int si2bit[8] =
+{4, 1, 4, 4, 4, 4, 4, 4};
+
+char *isdn_tty_revision = "$Revision: 1.41 $";
#define DLE 0x10
#define ETX 0x03
#define DC4 0x14
-/* isdn_tty_try_read() is called from within isdn_receive_callback()
+/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
* to stuff incoming data directly into a tty's flip-buffer. This
* is done to speed up tty-receiving if the receive-queue is empty.
* This routine MUST be called with interrupts off.
* 0 = Failure, data has to be buffered and later processed by
* isdn_tty_readmodem().
*/
-int isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
+static int
+isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
{
- int c;
- int len;
- struct tty_struct *tty;
+ int c;
+ int len;
+ struct tty_struct *tty;
if (info->online) {
if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) {
c = TTY_FLIPBUF_SIZE - tty->flip.count;
- len = skb->len + skb->users;
+ len = skb->len
+#ifdef CONFIG_ISDN_AUDIO
+ + ISDN_AUDIO_SKB_DLECOUNT(skb)
+#endif
+ ;
if (c >= len) {
- if (skb->users)
- while (skb->len--) {
- if (*skb->data == DLE)
- tty_insert_flip_char(tty, DLE, 0);
- tty_insert_flip_char(tty, *skb->data++, 0);
- }
- else {
- memcpy(tty->flip.char_buf_ptr,
- skb->data, len);
- tty->flip.count += len;
- tty->flip.char_buf_ptr += len;
- memset(tty->flip.flag_buf_ptr, 0, len);
- tty->flip.flag_buf_ptr += len;
- }
- if (info->emu.mdmreg[12] & 128)
- tty->flip.flag_buf_ptr[len - 1] = 0xff;
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
- skb->free = 1;
- kfree_skb(skb, FREE_READ);
+#ifdef CONFIG_ISDN_AUDIO
+ if (ISDN_AUDIO_SKB_DLECOUNT(skb))
+ while (skb->len--) {
+ if (*skb->data == DLE)
+ tty_insert_flip_char(tty, DLE, 0);
+ tty_insert_flip_char(tty, *skb->data++, 0);
+ } else {
+#endif
+ memcpy(tty->flip.char_buf_ptr,
+ skb->data, len);
+ tty->flip.count += len;
+ tty->flip.char_buf_ptr += len;
+ memset(tty->flip.flag_buf_ptr, 0, len);
+ tty->flip.flag_buf_ptr += len;
+#ifdef CONFIG_ISDN_AUDIO
+ }
+#endif
+ if (info->emu.mdmreg[12] & 128)
+ tty->flip.flag_buf_ptr[len - 1] = 0xff;
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, FREE_READ);
return 1;
}
}
* It tries getting received data from the receive queue an stuff it into
* the tty's flip-buffer.
*/
-void isdn_tty_readmodem(void)
+void
+isdn_tty_readmodem(void)
{
int resched = 0;
int midx;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if ((midx = dev->m_idx[i]) >= 0) {
- info = &dev->mdm.info[midx];
+ info = &dev->mdm.info[midx];
if (info->online) {
r = 0;
#ifdef CONFIG_ISDN_AUDIO
if (info->mcr & UART_MCR_RTS) {
c = TTY_FLIPBUF_SIZE - tty->flip.count;
if (c > 0) {
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
- tty->flip.char_buf_ptr,
- tty->flip.flag_buf_ptr, c, 0);
- /* CISCO AsyncPPP Hack */
+ tty->flip.char_buf_ptr,
+ tty->flip.flag_buf_ptr, c, 0);
+ /* CISCO AsyncPPP Hack */
if (!(info->emu.mdmreg[12] & 128))
memset(tty->flip.flag_buf_ptr, 0, r);
tty->flip.count += r;
tty->flip.flag_buf_ptr += r;
tty->flip.char_buf_ptr += r;
if (r)
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
- restore_flags(flags);
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ restore_flags(flags);
}
} else
r = 1;
} else
info->rcvsched = 1;
}
- }
+ }
}
if (!resched)
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
}
-void isdn_tty_cleanup_xmit(modem_info *info)
+int
+isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
+{
+ ulong flags;
+ int midx;
+#ifdef CONFIG_ISDN_AUDIO
+ int ifmt;
+#endif
+ modem_info *info;
+
+ if ((midx = dev->m_idx[i]) < 0) {
+ /* if midx is invalid, packet is not for tty */
+ return 0;
+ }
+ info = &dev->mdm.info[midx];
+#ifdef CONFIG_ISDN_AUDIO
+ ifmt = 1;
+
+ if (info->vonline)
+ isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
+#endif
+ if ((info->online < 2)
+#ifdef CONFIG_ISDN_AUDIO
+ && (!(info->vonline & 1))
+#endif
+ ) {
+ /* If Modem not listening, drop data */
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, FREE_READ);
+ return 1;
+ }
+ if (info->emu.mdmreg[13] & 2)
+ /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
+ if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
+ skb_pull(skb, 4);
+#ifdef CONFIG_ISDN_AUDIO
+ if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
+ printk(KERN_WARNING
+ "isdn_audio: insufficient skb_headroom, dropping\n");
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, FREE_READ);
+ return 1;
+ }
+ ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+ if (info->vonline & 1) {
+ /* voice conversion/compression */
+ switch (info->emu.vpar[3]) {
+ case 2:
+ case 3:
+ case 4:
+ /* adpcm
+ * Since compressed data takes less
+ * space, we can overwrite the buffer.
+ */
+ skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
+ ifmt,
+ skb->data,
+ skb->data,
+ skb->len));
+ break;
+ case 5:
+ /* a-law */
+ if (!ifmt)
+ isdn_audio_ulaw2alaw(skb->data, skb->len);
+ break;
+ case 6:
+ /* u-law */
+ if (ifmt)
+ isdn_audio_alaw2ulaw(skb->data, skb->len);
+ break;
+ }
+ ISDN_AUDIO_SKB_DLECOUNT(skb) =
+ isdn_tty_countDLE(skb->data, skb->len);
+ }
+#endif
+ /* Try to deliver directly via tty-flip-buf if queue is empty */
+ save_flags(flags);
+ cli();
+ if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
+ if (isdn_tty_try_read(info, skb)) {
+ restore_flags(flags);
+ return 1;
+ }
+ /* Direct deliver failed or queue wasn't empty.
+ * Queue up for later dequeueing via timer-irq.
+ */
+ __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
+ dev->drv[di]->rcvcount[channel] +=
+ (skb->len
+#ifdef CONFIG_ISDN_AUDIO
+ + ISDN_AUDIO_SKB_DLECOUNT(skb)
+#endif
+ );
+ restore_flags(flags);
+ /* Schedule dequeuing */
+ if ((dev->modempoll) && (info->rcvsched))
+ isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+ return 1;
+}
+
+void
+isdn_tty_cleanup_xmit(modem_info * info)
{
- struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (skb_queue_len(&info->xmit_queue))
- while ((skb = skb_dequeue(&info->xmit_queue))) {
- skb->free = 1;
- kfree_skb(skb, FREE_WRITE);
- }
- if (skb_queue_len(&info->dtmf_queue))
- while ((skb = skb_dequeue(&info->dtmf_queue))) {
- skb->free = 1;
- kfree_skb(skb, FREE_WRITE);
- }
- restore_flags(flags);
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (skb_queue_len(&info->xmit_queue))
+ while ((skb = skb_dequeue(&info->xmit_queue))) {
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, FREE_WRITE);
+ }
+#ifdef CONFIG_ISDN_AUDIO
+ if (skb_queue_len(&info->dtmf_queue))
+ while ((skb = skb_dequeue(&info->dtmf_queue))) {
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, FREE_WRITE);
+ }
+#endif
+ restore_flags(flags);
}
-static void isdn_tty_tint(modem_info *info)
+static void
+isdn_tty_tint(modem_info * info)
{
- struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
- int len, slen;
-
- if (!skb)
- return;
- len = skb->len;
- if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
- info->isdn_channel, skb)) == len) {
- struct tty_struct *tty = info->tty;
- info->send_outstanding++;
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
- wake_up_interruptible(&tty->write_wait);
- return;
- }
- if (slen > 0)
- skb_pull(skb,slen);
- skb_queue_head(&info->xmit_queue, skb);
+ struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
+ int len,
+ slen;
+
+ if (!skb)
+ return;
+ len = skb->len;
+ if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
+ info->isdn_channel, skb)) == len) {
+ struct tty_struct *tty = info->tty;
+ info->send_outstanding++;
+ info->msr |= UART_MSR_CTS;
+ info->lsr |= UART_LSR_TEMT;
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+ wake_up_interruptible(&tty->write_wait);
+ return;
+ }
+ if (slen < 0) {
+ /* Error: no channel, already shutdown, or wrong parameter */
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return;
+ }
+ if (slen)
+ skb_pull(skb, slen);
+ skb_queue_head(&info->xmit_queue, skb);
}
#ifdef CONFIG_ISDN_AUDIO
-int isdn_tty_countDLE(unsigned char *buf, int len)
+static int
+isdn_tty_countDLE(unsigned char *buf, int len)
{
- int count = 0;
+ int count = 0;
- while (len--)
- if (*buf++ == DLE)
- count++;
- return count;
+ while (len--)
+ if (*buf++ == DLE)
+ count++;
+ return count;
}
/* This routine is called from within isdn_tty_write() to perform
* DLE-decoding when sending audio-data.
*/
-static int isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
+static int
+isdn_tty_handleDLEdown(modem_info * info, atemu * m, int len)
{
- unsigned char *p = &info->xmit_buf[info->xmit_count];
- int count = 0;
-
- while (len>0) {
- if (m->lastDLE) {
- m->lastDLE = 0;
- switch (*p) {
- case DLE:
- /* Escape code */
- if (len>1)
- memmove(p,p+1,len-1);
- p--;
- count++;
- break;
- case ETX:
- /* End of data */
- info->vonline |= 4;
- return count;
- case DC4:
- /* Abort RX */
- info->vonline &= ~1;
- isdn_tty_at_cout("\020\003", info);
- if (!info->vonline)
- isdn_tty_at_cout("\r\nVCON\r\n", info);
- /* Fall through */
- case 'q':
- case 's':
- /* Silence */
- if (len>1)
- memmove(p,p+1,len-1);
- p--;
- break;
- }
- } else {
- if (*p == DLE)
- m->lastDLE = 1;
- else
- count++;
- }
- p++;
- len--;
- }
- if (len<0) {
- printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
- return 0;
- }
- return count;
+ unsigned char *p = &info->xmit_buf[info->xmit_count];
+ int count = 0;
+
+ while (len > 0) {
+ if (m->lastDLE) {
+ m->lastDLE = 0;
+ switch (*p) {
+ case DLE:
+ /* Escape code */
+ if (len > 1)
+ memmove(p, p + 1, len - 1);
+ p--;
+ count++;
+ break;
+ case ETX:
+ /* End of data */
+ info->vonline |= 4;
+ return count;
+ case DC4:
+ /* Abort RX */
+ info->vonline &= ~1;
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG
+ "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
+ info->line);
+#endif
+ isdn_tty_at_cout("\020\003", info);
+ if (!info->vonline) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG
+ "DLEdown: send VCON on ttyI%d\n",
+ info->line);
+#endif
+ isdn_tty_at_cout("\r\nVCON\r\n", info);
+ }
+ /* Fall through */
+ case 'q':
+ case 's':
+ /* Silence */
+ if (len > 1)
+ memmove(p, p + 1, len - 1);
+ p--;
+ break;
+ }
+ } else {
+ if (*p == DLE)
+ m->lastDLE = 1;
+ else
+ count++;
+ }
+ p++;
+ len--;
+ }
+ if (len < 0) {
+ printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
+ return 0;
+ }
+ return count;
}
/* This routine is called from within isdn_tty_write() when receiving
* audio-data. It interrupts receiving, if an character other than
* ^S or ^Q is sent.
*/
-static int isdn_tty_end_vrx(const char *buf, int c, int from_user)
+static int
+isdn_tty_end_vrx(const char *buf, int c, int from_user)
{
- char tmpbuf[VBUF];
- char *p;
+ char ch;
- if (c > VBUF) {
- printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n");
- return 1;
- }
- if (from_user) {
- copy_from_user(tmpbuf, buf, c);
- p = tmpbuf;
- } else
- p = (char *)buf;
- while (c--) {
- if ((*p != 0x11) && (*p != 0x13))
- return 1;
- p++;
- }
- return 0;
+ while (c--) {
+ if (from_user)
+ GET_USER(ch, buf);
+ else
+ ch = *buf;
+ if ((ch != 0x11) && (ch != 0x13))
+ return 1;
+ buf++;
+ }
+ return 0;
}
-static int voice_cf[7] = { 1, 1, 4, 3, 2, 1, 1 };
+static int voice_cf[7] =
+{0, 0, 4, 3, 2, 0, 0};
-#endif /* CONFIG_ISDN_AUDIO */
+#endif /* CONFIG_ISDN_AUDIO */
/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
* or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
* outgoing data from the tty's xmit-buffer, handles voice-decompression or
* T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
*/
-static void isdn_tty_senddown(modem_info * info)
+static void
+isdn_tty_senddown(modem_info * info)
{
- unsigned char *buf = info->xmit_buf;
- int buflen;
- int skb_res;
- struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (!(buflen = info->xmit_count)) {
- restore_flags(flags);
- return;
- }
- if (info->isdn_driver < 0) {
- info->xmit_count = 0;
- restore_flags(flags);
- return;
- }
- skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
+ int buflen;
+ int skb_res;
+#ifdef CONFIG_ISDN_AUDIO
+ int audio_len;
+#endif
+ struct sk_buff *skb;
+ unsigned long flags;
+
#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2) {
- /* For now, ifmt is fixed to 1 (alaw), since this
- * is used with ISDN everywhere in the world, except
- * US, Canada and Japan.
- * Later, when US-ISDN protocols are implemented,
- * this setting will depend on the D-channel protocol.
- */
- int ifmt = 1;
- int skb_len;
- unsigned char hbuf[VBUF];
-
- memcpy(hbuf,info->xmit_buf,buflen);
- info->xmit_count = 0;
- restore_flags(flags);
- /* voice conversion/decompression */
- skb_len = buflen * voice_cf[info->emu.vpar[3]];
- skb = dev_alloc_skb(skb_len + skb_res);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_tty: Out of memory in ttyI%d senddown\n", info->line);
- return;
- }
- skb_reserve(skb, skb_res);
- switch (info->emu.vpar[3]) {
- case 2:
- case 3:
- case 4:
- /* adpcm, compatible to ZyXel 1496 modem
- * with ROM revision 6.01
- */
- buflen = isdn_audio_adpcm2xlaw(info->adpcms,
- ifmt,
- hbuf,
- skb_put(skb,skb_len),
- buflen);
- skb_trim(skb, buflen);
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_alaw2ulaw(hbuf,buflen);
- memcpy(skb_put(skb,buflen),hbuf,buflen);
- break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_ulaw2alaw(hbuf,buflen);
- memcpy(skb_put(skb,buflen),hbuf,buflen);
- break;
- }
- if (info->vonline & 4) {
- info->vonline &= ~6;
- if (!info->vonline)
- isdn_tty_at_cout("\r\nVCON\r\n",info);
- }
- } else {
-#endif /* CONFIG_ISDN_AUDIO */
- skb = dev_alloc_skb(buflen + skb_res);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_tty: Out of memory in ttyI%d senddown\n", info->line);
- restore_flags(flags);
- return;
- }
- skb_reserve(skb, skb_res);
- memcpy(skb_put(skb,buflen),buf,buflen);
- info->xmit_count = 0;
- restore_flags(flags);
+ if (info->vonline & 4) {
+ info->vonline &= ~6;
+ if (!info->vonline) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG
+ "senddown: send VCON on ttyI%d\n",
+ info->line);
+#endif
+ isdn_tty_at_cout("\r\nVCON\r\n", info);
+ }
+ }
+#endif
+ save_flags(flags);
+ cli();
+ if (!(buflen = info->xmit_count)) {
+ restore_flags(flags);
+ return;
+ }
+ if ((info->emu.mdmreg[12] & 0x10) != 0)
+ info->msr &= ~UART_MSR_CTS;
+ info->lsr &= ~UART_LSR_TEMT;
+ if (info->isdn_driver < 0) {
+ info->xmit_count = 0;
+ restore_flags(flags);
+ return;
+ }
+ skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
+#ifdef CONFIG_ISDN_AUDIO
+ if (info->vonline & 2)
+ audio_len = buflen * voice_cf[info->emu.vpar[3]];
+ else
+ audio_len = 0;
+ skb = dev_alloc_skb(skb_res + buflen + audio_len);
+#else
+ skb = dev_alloc_skb(skb_res + buflen);
+#endif
+ if (!skb) {
+ restore_flags(flags);
+ printk(KERN_WARNING
+ "isdn_tty: Out of memory in ttyI%d senddown\n",
+ info->line);
+ return;
+ }
+ skb_reserve(skb, skb_res);
+ memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
+ info->xmit_count = 0;
+ restore_flags(flags);
#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- skb->free = 1;
- if (info->emu.mdmreg[13] & 2)
- /* Add T.70 simplified header */
- memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
- skb_queue_tail(&info->xmit_queue, skb);
- if ((info->emu.mdmreg[12] & 0x10) != 0)
- info->msr &= UART_MSR_CTS;
- info->lsr &= UART_LSR_TEMT;
+ if (info->vonline & 2) {
+ /* For now, ifmt is fixed to 1 (alaw), since this
+ * is used with ISDN everywhere in the world, except
+ * US, Canada and Japan.
+ * Later, when US-ISDN protocols are implemented,
+ * this setting will depend on the D-channel protocol.
+ */
+ int ifmt = 1;
+
+ /* voice conversion/decompression */
+ switch (info->emu.vpar[3]) {
+ case 2:
+ case 3:
+ case 4:
+ /* adpcm, compatible to ZyXel 1496 modem
+ * with ROM revision 6.01
+ */
+ audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
+ ifmt,
+ skb->data,
+ skb_put(skb, audio_len),
+ buflen);
+ skb_pull(skb, buflen);
+ skb_trim(skb, audio_len);
+ break;
+ case 5:
+ /* a-law */
+ if (!ifmt)
+ isdn_audio_alaw2ulaw(skb->data,
+ buflen);
+ break;
+ case 6:
+ /* u-law */
+ if (ifmt)
+ isdn_audio_ulaw2alaw(skb->data,
+ buflen);
+ break;
+ }
+ }
+#endif /* CONFIG_ISDN_AUDIO */
+ SET_SKB_FREE(skb);
+ if (info->emu.mdmreg[13] & 2)
+ /* Add T.70 simplified header */
+ memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
+ skb_queue_tail(&info->xmit_queue, skb);
}
/************************************************************
* isdn_tty_modem_result() to stuff a "NO CARRIER" Message
* into the tty's flip-buffer.
*/
-static void isdn_tty_modem_do_ncarrier(unsigned long data)
+static void
+isdn_tty_modem_do_ncarrier(unsigned long data)
{
- modem_info * info = (modem_info *)data;
- isdn_tty_modem_result(3, info);
+ modem_info *info = (modem_info *) data;
+ isdn_tty_modem_result(3, info);
}
/* Next routine is called, whenever the DTR-signal is raised.
* It checks the ncarrier-flag, and triggers the above routine
* when necessary. The ncarrier-flag is set, whenever DTR goes
* low.
- */
-static void isdn_tty_modem_ncarrier(modem_info * info)
+ */
+static void
+isdn_tty_modem_ncarrier(modem_info * info)
{
- if (info->ncarrier) {
- info->ncarrier = 0;
- info->nc_timer.expires = jiffies + HZ;
- info->nc_timer.function = isdn_tty_modem_do_ncarrier;
- info->nc_timer.data = (unsigned long)info;
- add_timer(&info->nc_timer);
- }
+ if (info->ncarrier) {
+ info->nc_timer.expires = jiffies + HZ;
+ info->nc_timer.function = isdn_tty_modem_do_ncarrier;
+ info->nc_timer.data = (unsigned long) info;
+ add_timer(&info->nc_timer);
+ }
}
/* isdn_tty_dial() performs dialing of a tty an the necessary
* setup of the lower levels before that.
*/
-static void isdn_tty_dial(char *n, modem_info * info, atemu * m)
+static void
+isdn_tty_dial(char *n, modem_info * info, atemu * m)
{
- int usg = ISDN_USAGE_MODEM;
- int si = 7;
- int l2 = m->mdmreg[14];
+ int usg = ISDN_USAGE_MODEM;
+ int si = 7;
+ int l2 = m->mdmreg[14];
isdn_ctrl cmd;
ulong flags;
int i;
- int j;
+ int j;
- for (j=7;j>=0;j--)
- if (m->mdmreg[18] & (1<<j)) {
- si = bit2si[j];
- break;
- }
+ for (j = 7; j >= 0; j--)
+ if (m->mdmreg[18] & (1 << j)) {
+ si = bit2si[j];
+ break;
+ }
#ifdef CONFIG_ISDN_AUDIO
- if (si == 1) {
- l2 = 4;
- usg = ISDN_USAGE_VOICE;
- }
+ if (si == 1) {
+ l2 = 4;
+ usg = ISDN_USAGE_VOICE;
+ }
#endif
- m->mdmreg[20] = si2bit[si];
+ m->mdmreg[20] = si2bit[si];
save_flags(flags);
cli();
i = isdn_get_free_channel(usg, l2, m->mdmreg[15], -1, -1);
restore_flags(flags);
isdn_tty_modem_result(6, info);
} else {
- info->isdn_driver = dev->drvmap[i];
- info->isdn_channel = dev->chanmap[i];
- info->drv_index = i;
- dev->m_idx[i] = info->line;
- dev->usage[i] |= ISDN_USAGE_OUTGOING;
- isdn_info_update();
- restore_flags(flags);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_CLREAZ;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
- strcpy(cmd.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETEAZ;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- dev->drv[info->isdn_driver]->interface->command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
- dev->drv[info->isdn_driver]->interface->command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- sprintf(cmd.num, "%s,%s,%d,%d", n, isdn_map_eaz2msn(m->msn, info->isdn_driver),
- si, m->mdmreg[19]);
- cmd.command = ISDN_CMD_DIAL;
- info->dialing = 1;
- strcpy(dev->num[i], n);
- isdn_info_update();
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ info->isdn_driver = dev->drvmap[i];
+ info->isdn_channel = dev->chanmap[i];
+ info->drv_index = i;
+ dev->m_idx[i] = info->line;
+ dev->usage[i] |= ISDN_USAGE_OUTGOING;
+ info->last_dir = 1;
+ strcpy(info->last_num, n);
+ isdn_info_update();
+ restore_flags(flags);
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.command = ISDN_CMD_CLREAZ;
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETEAZ;
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETL2;
+ info->last_l2 = l2;
+ cmd.arg = info->isdn_channel + (l2 << 8);
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETL3;
+ cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ sprintf(cmd.parm.setup.phone, "%s", n);
+ sprintf(cmd.parm.setup.eazmsn, "%s",
+ isdn_map_eaz2msn(m->msn, info->isdn_driver));
+ cmd.parm.setup.si1 = si;
+ cmd.parm.setup.si2 = m->mdmreg[19];
+ cmd.command = ISDN_CMD_DIAL;
+ info->dialing = 1;
+ strcpy(dev->num[i], n);
+ isdn_info_update();
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
}
}
* ISDN-line (hangup). The usage-status is cleared
* and some cleanup is done also.
*/
-void isdn_tty_modem_hup(modem_info * info)
+static void
+isdn_tty_modem_hup(modem_info * info, int local)
{
isdn_ctrl cmd;
- int usage;
+ int usage;
- if (!info)
- return;
+ if (!info)
+ return;
#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
-#endif
- info->rcvsched = 0;
- info->online = 0;
- isdn_tty_flush_buffer(info->tty);
- if (info->vonline & 1) {
- /* voice-recording, add DLE-ETX */
- isdn_tty_at_cout("\020\003", info);
- }
- if (info->vonline & 2) {
- /* voice-playing, add DLE-DC4 */
- isdn_tty_at_cout("\020\024", info);
- }
- info->vonline = 0;
+ printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
+#endif
+ info->rcvsched = 0;
+ isdn_tty_flush_buffer(info->tty);
+ if (info->online) {
+ info->last_lhup = local;
+ info->online = 0;
+ /* NO CARRIER message */
+ isdn_tty_modem_result(3, info);
+ }
#ifdef CONFIG_ISDN_AUDIO
- if (info->dtmf_state) {
- kfree(info->dtmf_state);
- info->dtmf_state = NULL;
- }
- if (info->adpcms) {
- kfree(info->adpcms);
- info->adpcms = NULL;
- }
- if (info->adpcmr) {
- kfree(info->adpcmr);
- info->adpcmr = NULL;
- }
-#endif
- info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
- info->lsr |= UART_LSR_TEMT;
+ info->vonline = 0;
+ if (info->dtmf_state) {
+ kfree(info->dtmf_state);
+ info->dtmf_state = NULL;
+ }
+ if (info->adpcms) {
+ kfree(info->adpcms);
+ info->adpcms = NULL;
+ }
+ if (info->adpcmr) {
+ kfree(info->adpcmr);
+ info->adpcmr = NULL;
+ }
+#endif
+ info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
+ info->lsr |= UART_LSR_TEMT;
if (info->isdn_driver >= 0) {
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = info->isdn_channel;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ if (local) {
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_HANGUP;
+ cmd.arg = info->isdn_channel;
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ }
isdn_all_eaz(info->isdn_driver, info->isdn_channel);
- usage = (info->emu.mdmreg[20] == 1)?
- ISDN_USAGE_VOICE:ISDN_USAGE_MODEM;
+ info->emu.mdmreg[1] = 0;
+ usage = (info->emu.mdmreg[20] == 1) ?
+ ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
isdn_free_channel(info->isdn_driver, info->isdn_channel,
- usage);
+ usage);
}
info->isdn_driver = -1;
info->isdn_channel = -1;
- if (info->drv_index >= 0) {
- dev->m_idx[info->drv_index] = -1;
- info->drv_index = -1;
- }
+ if (info->drv_index >= 0) {
+ dev->m_idx[info->drv_index] = -1;
+ info->drv_index = -1;
+ }
}
-static inline int isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
+static inline int
+isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
{
#ifdef MODEM_PARANOIA_CHECK
if (!info) {
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static void isdn_tty_change_speed(modem_info * info)
+static void
+isdn_tty_change_speed(modem_info * info)
{
- uint cflag, cval, fcr, quot;
+ uint cflag,
+ cval,
+ fcr,
+ quot;
int i;
if (!info->tty || !info->tty->termios)
}
if (quot) {
info->mcr |= UART_MCR_DTR;
- isdn_tty_modem_ncarrier(info);
+ isdn_tty_modem_ncarrier(info);
} else {
info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[13] & 4) {
+ if (info->emu.mdmreg[13] & 4) {
#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in changespeed\n");
+ printk(KERN_DEBUG "Mhup in changespeed\n");
#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_reset_regs(info, 0);
- isdn_tty_modem_hup(info);
- }
- return;
+ if (info->online)
+ info->ncarrier = 1;
+ isdn_tty_modem_reset_regs(info, 0);
+ isdn_tty_modem_hup(info, 1);
+ }
+ return;
}
/* byte size and parity */
cval = cflag & (CSIZE | CSTOPB);
}
}
-static int isdn_tty_startup(modem_info * info)
+static int
+isdn_tty_startup(modem_info * info)
{
ulong flags;
return 0;
save_flags(flags);
cli();
- isdn_MOD_INC_USE_COUNT();
+ isdn_MOD_INC_USE_COUNT();
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
#endif
/*
- * Now, initialize the UART
+ * Now, initialize the UART
*/
info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
if (info->tty)
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void isdn_tty_shutdown(modem_info * info)
+static void
+isdn_tty_shutdown(modem_info * info)
{
ulong flags;
printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
#endif
save_flags(flags);
- cli(); /* Disable interrupts */
- isdn_MOD_DEC_USE_COUNT();
+ cli(); /* Disable interrupts */
+ isdn_MOD_DEC_USE_COUNT();
+ info->msr &= ~UART_MSR_RI;
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
- if (info->emu.mdmreg[13] & 4) {
- isdn_tty_modem_reset_regs(info, 0);
+ if (info->emu.mdmreg[13] & 4) {
+ isdn_tty_modem_reset_regs(info, 0);
#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
+ printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
#endif
- isdn_tty_modem_hup(info);
- }
+ isdn_tty_modem_hup(info, 1);
+ }
}
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
* - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed.
* - If dialing, abort dial.
*/
-static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
+static int
+isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
{
- int c, total = 0;
+ int c,
+ total = 0;
ulong flags;
modem_info *info = (modem_info *) tty->driver_data;
return 0;
if (!tty)
return 0;
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
while (1) {
c = MIN(count, info->xmit_size - info->xmit_count);
if (info->isdn_driver >= 0)
c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize);
if (c <= 0)
break;
- if ((info->online > 1) ||
- (info->vonline & 2)) {
- atemu *m = &info->emu;
-
- if (!(info->vonline & 2))
- isdn_tty_check_esc(buf, m->mdmreg[2], c,
- &(m->pluscount),
- &(m->lastplus),
- from_user);
- if (from_user)
- copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c);
- else
- memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
+ if ((info->online > 1)
+#ifdef CONFIG_ISDN_AUDIO
+ || (info->vonline & 3)
+#endif
+ ) {
+ atemu *m = &info->emu;
+
+#ifdef CONFIG_ISDN_AUDIO
+ if (!info->vonline)
+#endif
+ isdn_tty_check_esc(buf, m->mdmreg[2], c,
+ &(m->pluscount),
+ &(m->lastplus),
+ from_user);
+ if (from_user)
+ copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c);
+ else
+ memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2) {
- int cc;
-
- if (!(cc = isdn_tty_handleDLEdown(info,m,c))) {
- /* If DLE decoding results in zero-transmit, but
- * c originally was non-zero, do a wakeup.
- */
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
- wake_up_interruptible(&tty->write_wait);
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- }
- info->xmit_count += cc;
- } else
-#endif
- info->xmit_count += c;
+ if (info->vonline) {
+ int cc = isdn_tty_handleDLEdown(info, m, c);
+ if (info->vonline & 2) {
+ if (!cc) {
+ /* If DLE decoding results in zero-transmit, but
+ * c originally was non-zero, do a wakeup.
+ */
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+ wake_up_interruptible(&tty->write_wait);
+ info->msr |= UART_MSR_CTS;
+ info->lsr |= UART_LSR_TEMT;
+ }
+ info->xmit_count += cc;
+ }
+ if ((info->vonline & 3) == 1) {
+ /* Do NOT handle Ctrl-Q or Ctrl-S
+ * when in full-duplex audio mode.
+ */
+ if (isdn_tty_end_vrx(buf, c, from_user)) {
+ info->vonline &= ~1;
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG
+ "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
+ info->line);
+#endif
+ isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
+ }
+ }
+ } else
+#endif
+ info->xmit_count += c;
if (m->mdmreg[13] & 1) {
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
+ isdn_tty_senddown(info);
+ isdn_tty_tint(info);
+ }
} else {
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
-#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 1) {
- if (isdn_tty_end_vrx(buf, c, from_user)) {
- info->vonline &= ~1;
- isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
- }
- } else
-#endif
- if (info->dialing) {
- info->dialing = 0;
+ info->msr |= UART_MSR_CTS;
+ info->lsr |= UART_LSR_TEMT;
+ if (info->dialing) {
+ info->dialing = 0;
#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
+ printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
#endif
- isdn_tty_modem_result(3, info);
- isdn_tty_modem_hup(info);
- } else
- c = isdn_tty_edit_at(buf, c, info, from_user);
+ isdn_tty_modem_result(3, info);
+ isdn_tty_modem_hup(info, 1);
+ } else
+ c = isdn_tty_edit_at(buf, c, info, from_user);
}
buf += c;
count -= c;
}
if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
- restore_flags(flags);
+ restore_flags(flags);
return total;
}
-static int isdn_tty_write_room(struct tty_struct *tty)
+static int
+isdn_tty_write_room(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
int ret;
return (ret < 0) ? 0 : ret;
}
-static int isdn_tty_chars_in_buffer(struct tty_struct *tty)
+static int
+isdn_tty_chars_in_buffer(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
return (info->xmit_count);
}
-static void isdn_tty_flush_buffer(struct tty_struct *tty)
+static void
+isdn_tty_flush_buffer(struct tty_struct *tty)
{
modem_info *info;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (!tty) {
- restore_flags(flags);
- return;
- }
- info = (modem_info *) tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (!tty) {
+ restore_flags(flags);
+ return;
+ }
+ info = (modem_info *) tty->driver_data;
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) {
- restore_flags(flags);
+ restore_flags(flags);
return;
- }
- isdn_tty_cleanup_xmit(info);
- info->xmit_count = 0;
- restore_flags(flags);
+ }
+ isdn_tty_cleanup_xmit(info);
+ info->xmit_count = 0;
+ restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup) (tty);
}
-static void isdn_tty_flush_chars(struct tty_struct *tty)
+static void
+isdn_tty_flush_chars(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
/*
* ------------------------------------------------------------
* isdn_tty_throttle()
- *
+ *
* This routine is called by the upper-layer tty layer to signal that
* incoming characters should be throttled.
* ------------------------------------------------------------
*/
-static void isdn_tty_throttle(struct tty_struct *tty)
+static void
+isdn_tty_throttle(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
info->mcr &= ~UART_MCR_RTS;
}
-static void isdn_tty_unthrottle(struct tty_struct *tty)
+static void
+isdn_tty_unthrottle(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
- * allows RS485 driver to be written in user space.
+ * allows RS485 driver to be written in user space.
*/
-static int isdn_tty_get_lsr_info(modem_info * info, uint * value)
+static int
+isdn_tty_get_lsr_info(modem_info * info, uint * value)
{
u_char status;
uint result;
}
-static int isdn_tty_get_modem_info(modem_info * info, uint * value)
+static int
+isdn_tty_get_modem_info(modem_info * info, uint * value)
{
- u_char control, status;
+ u_char control,
+ status;
uint result;
ulong flags;
return 0;
}
-static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
+static int
+isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
{
uint arg;
- int pre_dtr;
+ int pre_dtr;
- GET_USER(arg, (uint *)value);
+ GET_USER(arg, (uint *) value);
switch (cmd) {
- case TIOCMBIS:
+ case TIOCMBIS:
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line);
-#endif
- if (arg & TIOCM_RTS) {
- info->mcr |= UART_MCR_RTS;
- }
- if (arg & TIOCM_DTR) {
- info->mcr |= UART_MCR_DTR;
- isdn_tty_modem_ncarrier(info);
- }
- break;
- case TIOCMBIC:
+ printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line);
+#endif
+ if (arg & TIOCM_RTS) {
+ info->mcr |= UART_MCR_RTS;
+ }
+ if (arg & TIOCM_DTR) {
+ info->mcr |= UART_MCR_DTR;
+ isdn_tty_modem_ncarrier(info);
+ }
+ break;
+ case TIOCMBIC:
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line);
-#endif
- if (arg & TIOCM_RTS) {
- info->mcr &= ~UART_MCR_RTS;
- }
- if (arg & TIOCM_DTR) {
- info->mcr &= ~UART_MCR_DTR;
- if (info->emu.mdmreg[13] & 4) {
- isdn_tty_modem_reset_regs(info, 0);
+ printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line);
+#endif
+ if (arg & TIOCM_RTS) {
+ info->mcr &= ~UART_MCR_RTS;
+ }
+ if (arg & TIOCM_DTR) {
+ info->mcr &= ~UART_MCR_DTR;
+ if (info->emu.mdmreg[13] & 4) {
+ isdn_tty_modem_reset_regs(info, 0);
#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
-#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_hup(info);
- }
- }
- break;
- case TIOCMSET:
+ printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
+#endif
+ if (info->online)
+ info->ncarrier = 1;
+ isdn_tty_modem_hup(info, 1);
+ }
+ }
+ break;
+ case TIOCMSET:
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line);
-#endif
- pre_dtr = (info->mcr & UART_MCR_DTR);
- info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
- | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
- | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
- if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
- if (!(info->mcr & UART_MCR_DTR)) {
- if (info->emu.mdmreg[13] & 4) {
- isdn_tty_modem_reset_regs(info, 0);
+ printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line);
+#endif
+ pre_dtr = (info->mcr & UART_MCR_DTR);
+ info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
+ | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+ | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+ if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
+ if (!(info->mcr & UART_MCR_DTR)) {
+ if (info->emu.mdmreg[13] & 4) {
+ isdn_tty_modem_reset_regs(info, 0);
#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "Mhup in TIOCMSET\n");
-#endif
- if (info->online)
- info->ncarrier = 1;
- isdn_tty_modem_hup(info);
- }
- } else
- isdn_tty_modem_ncarrier(info);
- }
- break;
- default:
- return -EINVAL;
+ printk(KERN_DEBUG "Mhup in TIOCMSET\n");
+#endif
+ if (info->online)
+ info->ncarrier = 1;
+ isdn_tty_modem_hup(info, 1);
+ }
+ } else
+ isdn_tty_modem_ncarrier(info);
+ }
+ break;
+ default:
+ return -EINVAL;
}
return 0;
}
-static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
- uint cmd, ulong arg)
+static int
+isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
+ uint cmd, ulong arg)
{
modem_info *info = (modem_info *) tty->driver_data;
int error;
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
return -ENODEV;
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
-#endif
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
+ printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
+#endif
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
-#endif
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- return 0;
- case TIOCGSOFTCAR:
+ printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
+#endif
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ return 0;
+ case TIOCGSOFTCAR:
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
-#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
- if (error)
- return error;
- put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
- return 0;
- case TIOCSSOFTCAR:
+ printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
+#endif
+ error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+ if (error)
+ return error;
+ put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
+ return 0;
+ case TIOCSSOFTCAR:
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
-#endif
- error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
- if (error)
- return error;
- GET_USER(arg, (ulong *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
- case TIOCMGET:
+ printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
+#endif
+ error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
+ if (error)
+ return error;
+ GET_USER(arg, (ulong *) arg);
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return 0;
+ case TIOCMGET:
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
-#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
- if (error)
- return error;
- return isdn_tty_get_modem_info(info, (uint *) arg);
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
- if (error)
- return error;
- return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
- case TIOCSERGETLSR: /* Get line status register */
+ printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
+#endif
+ error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
+ if (error)
+ return error;
+ return isdn_tty_get_modem_info(info, (uint *) arg);
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
+ if (error)
+ return error;
+ return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
+ case TIOCSERGETLSR: /* Get line status register */
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
-#endif
- error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
- if (error)
- return error;
- else
- return isdn_tty_get_lsr_info(info, (uint *) arg);
-
- default:
+ printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
+#endif
+ error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
+ if (error)
+ return error;
+ else
+ return isdn_tty_get_lsr_info(info, (uint *) arg);
+
+ default:
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
+ printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
#endif
- return -ENOIOCTLCMD;
+ return -ENOIOCTLCMD;
}
return 0;
}
-static void isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void
+isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
modem_info *info = (modem_info *) tty->driver_data;
- if (!old_termios)
- isdn_tty_change_speed(info);
- else {
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
- isdn_tty_change_speed(info);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- }
- }
+ if (!old_termios)
+ isdn_tty_change_speed(info);
+ else {
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
+ isdn_tty_change_speed(info);
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ }
+ }
}
/*
* isdn_tty_open() and friends
* ------------------------------------------------------------
*/
-static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
+static int
+isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
{
- struct wait_queue wait = {current, NULL};
+ struct wait_queue wait =
+ {current, NULL};
int do_clocal = 0;
unsigned long flags;
int retval;
*/
if (tty_hung_up_p(filp) ||
(info->flags & ISDN_ASYNC_CLOSING)) {
- if (info->flags & ISDN_ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
+ if (info->flags & ISDN_ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
#ifdef MODEM_DO_RESTART
if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
return -EAGAIN;
* and then exit.
*/
if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
+ (tty->flags & (1 << TTY_IO_ERROR))) {
if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
return -EBUSY;
info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
info->line, info->count);
#endif
- save_flags(flags);
- cli();
- if (!(tty_hung_up_p(filp)))
- info->count--;
- restore_flags(flags);
+ save_flags(flags);
+ cli();
+ if (!(tty_hung_up_p(filp)))
+ info->count--;
+ restore_flags(flags);
info->blocked_open++;
while (1) {
current->state = TASK_INTERRUPTIBLE;
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
*/
-static int isdn_tty_open(struct tty_struct *tty, struct file *filp)
+static int
+isdn_tty_open(struct tty_struct *tty, struct file *filp)
{
modem_info *info;
- int retval, line;
+ int retval,
+ line;
line = MINOR(tty->device) - tty->driver.minor_start;
if (line < 0 || line > ISDN_MAX_CHANNELS)
return 0;
}
-static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
+static void
+isdn_tty_close(struct tty_struct *tty, struct file *filp)
{
modem_info *info = (modem_info *) tty->driver_data;
ulong flags;
if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
info->callout_termios = *tty->termios;
- tty->closing = 1;
+ tty->closing = 1;
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
* line status register.
*/
if (info->flags & ISDN_ASYNC_INITIALIZED) {
- tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+ tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
info->tty = 0;
- info->ncarrier = 0;
+ info->ncarrier = 0;
tty->closing = 0;
if (info->blocked_open) {
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 50;
- schedule();
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 50;
+ schedule();
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE |
/*
* isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
-static void isdn_tty_hangup(struct tty_struct *tty)
+static void
+isdn_tty_hangup(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
/* This routine initializes all emulator-data.
*/
-static void isdn_tty_reset_profile(atemu * m)
+static void
+isdn_tty_reset_profile(atemu * m)
{
m->profile[0] = 0;
m->profile[1] = 0;
m->pmsn[0] = '\0';
}
-static void isdn_tty_modem_reset_vpar(atemu *m)
+#ifdef CONFIG_ISDN_AUDIO
+static void
+isdn_tty_modem_reset_vpar(atemu * m)
{
- m->vpar[0] = 2; /* Voice-device (2 = phone line) */
- m->vpar[1] = 0; /* Silence detection level (0 = none ) */
- m->vpar[2] = 70; /* Silence interval (7 sec. ) */
- m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
+ m->vpar[0] = 2; /* Voice-device (2 = phone line) */
+ m->vpar[1] = 0; /* Silence detection level (0 = none ) */
+ m->vpar[2] = 70; /* Silence interval (7 sec. ) */
+ m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
}
+#endif
-static void isdn_tty_modem_reset_regs(modem_info *info, int force)
+static void
+isdn_tty_modem_reset_regs(modem_info * info, int force)
{
- atemu *m = &info->emu;
+ atemu *m = &info->emu;
if ((m->mdmreg[12] & 32) || force) {
memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
- info->xmit_size = m->mdmreg[16] * 16;
+ info->xmit_size = m->mdmreg[16] * 16;
}
- isdn_tty_modem_reset_vpar(m);
+#ifdef CONFIG_ISDN_AUDIO
+ isdn_tty_modem_reset_vpar(m);
+#endif
m->mdmcmdl = 0;
}
-static void modem_write_profile(atemu * m)
+static void
+modem_write_profile(atemu * m)
{
memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG);
memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
send_sig(SIGIO, dev->profd, 1);
}
-int isdn_tty_modem_init(void)
+int
+isdn_tty_modem_init(void)
{
modem *m;
int i;
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
info = &m->info[i];
+ sprintf(info->last_cause, "0000");
+ sprintf(info->last_num, "none");
+ info->last_dir = 0;
+ info->last_lhup = 1;
+ info->last_l2 = 0;
+ info->last_si = 0;
isdn_tty_reset_profile(&info->emu);
isdn_tty_modem_reset_regs(info, 1);
info->magic = ISDN_ASYNC_MAGIC;
info->isdn_channel = -1;
info->drv_index = -1;
info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
- skb_queue_head_init(&info->xmit_queue);
- skb_queue_head_init(&info->dtmf_queue);
- if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
- printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
- return -3;
- }
- /* Make room for T.70 header */
- info->xmit_buf += 4;
+ skb_queue_head_init(&info->xmit_queue);
+#ifdef CONFIG_ISDN_AUDIO
+ skb_queue_head_init(&info->dtmf_queue);
+#endif
+ if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
+ printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
+ return -3;
+ }
+ /* Make room for T.70 header */
+ info->xmit_buf += 4;
}
return 0;
}
* it to the ISDN-Channel.
* Return Index to dev->mdm or -1 if none found.
*/
-int isdn_tty_find_icall(int di, int ch, char *num)
+int
+isdn_tty_find_icall(int di, int ch, setup_parm setup)
{
char *eaz;
int i;
int idx;
int si1;
int si2;
- char *s;
- char nr[31];
+ char nr[32];
ulong flags;
save_flags(flags);
cli();
- if (num[0] == ',') {
+ if (!setup.phone[0]) {
nr[0] = '0';
- strncpy(&nr[1], num, 29);
+ nr[1] = '\0';
printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
} else
- strncpy(nr, num, 30);
- s = strtok(nr, ",");
- s = strtok(NULL, ",");
- if (!s) {
- printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n",
- num);
- restore_flags(flags);
- return -1;
- }
- si1 = (int)simple_strtoul(s,NULL,10);
- s = strtok(NULL, ",");
- if (!s) {
- printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n",
- num);
- restore_flags(flags);
- return -1;
- }
- si2 = (int)simple_strtoul(s,NULL,10);
- eaz = strtok(NULL, ",");
- if (!eaz) {
+ strcpy(nr, setup.phone);
+ si1 = (int) setup.si1;
+ si2 = (int) setup.si2;
+ if (!setup.eazmsn[0]) {
printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
eaz = "0";
- }
+ } else
+ eaz = setup.eazmsn;
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
#endif
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
+ modem_info *info = &dev->mdm.info[i];
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i,
info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di),
info->emu.mdmreg[18], info->emu.mdmreg[19]);
#endif
if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di),
- eaz)) && /* EAZ is matching */
- (info->emu.mdmreg[18] & si2bit[si1]) && /* SI1 is matching */
- ((info->emu.mdmreg[19] == si2) || !si2)) { /* SI2 is matching or 0 */
+ eaz)) && /* EAZ is matching */
+ (info->emu.mdmreg[18] & si2bit[si1]) && /* SI1 is matching */
+ ((info->emu.mdmreg[19] == si2) || !si2)) { /* SI2 is matching or 0 */
idx = isdn_dc2minor(di, ch);
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: match1\n");
info->drv_index = idx;
dev->m_idx[idx] = info->line;
dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= (si1==1)?ISDN_USAGE_VOICE:ISDN_USAGE_MODEM;
+ dev->usage[idx] |= (si1 == 1) ? ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
strcpy(dev->num[idx], nr);
- info->emu.mdmreg[20] = si2bit[si1];
+ info->emu.mdmreg[20] = si2bit[si1];
+ info->emu.mdmreg[21] = setup.plan;
+ info->emu.mdmreg[22] = setup.screen;
isdn_info_update();
restore_flags(flags);
printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
info->line);
+ info->msr |= UART_MSR_RI;
+ isdn_tty_modem_result(2, info);
+ isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
return info->line;
}
}
return -1;
}
+#define TTY_IS_ACTIVE(info) \
+ (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
+
+int
+isdn_tty_stat_callback(int i, isdn_ctrl * c)
+{
+ int mi;
+ modem_info *info;
+
+ if (i < 0)
+ return 0;
+ if ((mi = dev->m_idx[i]) >= 0) {
+ info = &dev->mdm.info[mi];
+ switch (c->command) {
+ case ISDN_STAT_BSENT:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
+#endif
+ if ((info->isdn_driver == c->driver) &&
+ (info->isdn_channel == c->arg)) {
+ info->msr |= UART_MSR_CTS;
+ if (info->send_outstanding)
+ if (!(--info->send_outstanding))
+ info->lsr |= UART_LSR_TEMT;
+ isdn_tty_tint(info);
+ return 1;
+ }
+ break;
+ case ISDN_STAT_CAUSE:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
+#endif
+ /* Signal cause to tty-device */
+ strncpy(info->last_cause, c->parm.num, 5);
+ return 1;
+ case ISDN_STAT_DCONN:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
+#endif
+ if (TTY_IS_ACTIVE(info)) {
+ if (info->dialing == 1) {
+ info->dialing = 2;
+ return 1;
+ }
+ }
+ break;
+ case ISDN_STAT_DHUP:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
+#endif
+ if (TTY_IS_ACTIVE(info)) {
+ if (info->dialing == 1) {
+ info->dialing = 0;
+ isdn_tty_modem_result(7, info);
+ }
+#ifdef ISDN_DEBUG_MODEM_HUP
+ printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
+#endif
+ isdn_tty_modem_hup(info, 0);
+ return 1;
+ }
+ break;
+ case ISDN_STAT_BCONN:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
+#endif
+ /* Schedule CONNECT-Message to any tty
+ * waiting for it and
+ * set DCD-bit of its modem-status.
+ */
+ if (TTY_IS_ACTIVE(info)) {
+ info->msr |= UART_MSR_DCD;
+ if (info->dialing) {
+ info->dialing = 0;
+ info->last_dir = 1;
+ } else
+ info->last_dir = 0;
+ info->rcvsched = 1;
+ if (USG_MODEM(dev->usage[i]))
+ isdn_tty_modem_result(5, info);
+ if (USG_VOICE(dev->usage[i]))
+ isdn_tty_modem_result(11, info);
+ return 1;
+ }
+ break;
+ case ISDN_STAT_BHUP:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
+#endif
+ if (TTY_IS_ACTIVE(info)) {
+#ifdef ISDN_DEBUG_MODEM_HUP
+ printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
+#endif
+ isdn_tty_modem_hup(info, 0);
+ return 1;
+ }
+ break;
+ case ISDN_STAT_NODCH:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
+#endif
+ if (TTY_IS_ACTIVE(info)) {
+ if (info->dialing) {
+ info->dialing = 0;
+ info->last_l2 = -1;
+ info->last_si = 0;
+ sprintf(info->last_cause, "0000");
+ isdn_tty_modem_result(6, info);
+ }
+ info->msr &= ~UART_MSR_DCD;
+ if (info->online) {
+ isdn_tty_modem_result(3, info);
+ info->online = 0;
+ }
+ return 1;
+ }
+ break;
+ case ISDN_STAT_UNLOAD:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
+#endif
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ info = &dev->mdm.info[i];
+ if (info->isdn_driver == c->driver) {
+ if (info->online)
+ isdn_tty_modem_hup(info, 1);
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*********************************************************************
Modem-Emulator-Routines
*********************************************************************/
* Put a message from the AT-emulator into receive-buffer of tty,
* convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
*/
-static void isdn_tty_at_cout(char *msg, modem_info * info)
+static void
+isdn_tty_at_cout(char *msg, modem_info * info)
{
struct tty_struct *tty;
atemu *m = &info->emu;
tty = info->tty;
for (p = msg; *p; p++) {
switch (*p) {
- case '\r':
- c = m->mdmreg[3];
- break;
- case '\n':
- c = m->mdmreg[4];
- break;
- case '\b':
- c = m->mdmreg[5];
- break;
- default:
- c = *p;
+ case '\r':
+ c = m->mdmreg[3];
+ break;
+ case '\n':
+ c = m->mdmreg[4];
+ break;
+ case '\b':
+ c = m->mdmreg[5];
+ break;
+ default:
+ c = *p;
}
if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
restore_flags(flags);
/*
* Perform ATH Hangup
*/
-static void isdn_tty_on_hook(modem_info * info)
+static void
+isdn_tty_on_hook(modem_info * info)
{
if (info->isdn_channel >= 0) {
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
#endif
- isdn_tty_modem_result(3, info);
- isdn_tty_modem_hup(info);
+ isdn_tty_modem_hup(info, 1);
}
}
-static void isdn_tty_off_hook(void)
+static void
+isdn_tty_off_hook(void)
{
printk(KERN_DEBUG "isdn_tty_off_hook\n");
}
-#define PLUSWAIT1 (HZ/2) /* 0.5 sec. */
-#define PLUSWAIT2 (HZ*3/2) /* 1.5 sec */
+#define PLUSWAIT1 (HZ/2) /* 0.5 sec. */
+#define PLUSWAIT2 (HZ*3/2) /* 1.5 sec */
/*
* Check Buffer for Modem-escape-sequence, activate timer-callback to
* pluscount count of valid escape-characters so far
* lastplus timestamp of last character
*/
-static void isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
- int *lastplus, int from_user)
+static void
+isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
+ int *lastplus, int from_user)
{
char cbuf[3];
* For CONNECT-messages also switch to online-mode.
* For RING-message handle auto-ATA if register 0 != 0
*/
-void isdn_tty_modem_result(int code, modem_info * info)
+static void
+isdn_tty_modem_result(int code, modem_info * info)
{
atemu *m = &info->emu;
static char *msg[] =
"CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
"RINGING", "NO MSN/EAZ", "VCON"};
ulong flags;
- char s[4];
+ char s[10];
switch (code) {
- case 2:
- m->mdmreg[1]++; /* RING */
- if (m->mdmreg[1] == m->mdmreg[0])
- /* Automatically accept incoming call */
- isdn_tty_cmd_ATA(info);
- break;
- case 3:
- /* NO CARRIER */
- save_flags(flags);
- cli();
+ case 2:
+ m->mdmreg[1]++; /* RING */
+ if (m->mdmreg[1] == m->mdmreg[0])
+ /* Automatically accept incoming call */
+ isdn_tty_cmd_ATA(info);
+ break;
+ case 3:
+ /* NO CARRIER */
#ifdef ISDN_DEBUG_MODEM_HUP
- printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
- (info->flags & ISDN_ASYNC_CLOSING),
- (!info->tty));
-#endif
- if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
- restore_flags(flags);
- return;
- }
- restore_flags(flags);
- if (info->vonline & 1) {
- /* voice-recording, add DLE-ETX */
- isdn_tty_at_cout("\020\003", info);
- }
- if (info->vonline & 2) {
- /* voice-playing, add DLE-DC4 */
- isdn_tty_at_cout("\020\024", info);
- }
- break;
- case 1:
- case 5:
- if (!info->online)
- info->online = 2;
- break;
- case 11:
- if (!info->online)
- info->online = 1;
- break;
+ printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
+ (info->flags & ISDN_ASYNC_CLOSING),
+ (!info->tty));
+#endif
+ save_flags(flags);
+ cli();
+ m->mdmreg[1] = 0;
+ del_timer(&info->nc_timer);
+ info->ncarrier = 0;
+ if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+ restore_flags(flags);
+ return;
+ }
+ restore_flags(flags);
+#ifdef CONFIG_ISDN_AUDIO
+ if (info->vonline & 1) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
+ info->line);
+#endif
+ /* voice-recording, add DLE-ETX */
+ isdn_tty_at_cout("\020\003", info);
+ }
+ if (info->vonline & 2) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
+ info->line);
+#endif
+ /* voice-playing, add DLE-DC4 */
+ isdn_tty_at_cout("\020\024", info);
+ }
+#endif
+ break;
+ case 1:
+ case 5:
+ sprintf(info->last_cause, "0000");
+ if (!info->online)
+ info->online = 2;
+ break;
+ case 11:
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
+ info->line);
+#endif
+ sprintf(info->last_cause, "0000");
+ if (!info->online)
+ info->online = 1;
+ break;
}
if (m->mdmreg[12] & 1) {
/* Show results */
sprintf(s, "%d", code);
isdn_tty_at_cout(s, info);
} else {
- if (code == 2) {
+ if ((code == 2) && (!(m->mdmreg[13] & 16))) {
isdn_tty_at_cout("CALLER NUMBER: ", info);
isdn_tty_at_cout(dev->num[info->drv_index], info);
isdn_tty_at_cout("\r\n", info);
}
isdn_tty_at_cout(msg[code], info);
- if (code == 5) {
- /* Append Protocol to CONNECT message */
- isdn_tty_at_cout((m->mdmreg[14] != 3) ? "/X.75" : "/HDLC", info);
- if (m->mdmreg[13] & 2)
- isdn_tty_at_cout("/T.70", info);
+ switch (code) {
+ case 2:
+ /* Print CID only once, _after_ 1.st RING */
+ if ((m->mdmreg[13] & 16) && (m->mdmreg[1] == 1)) {
+ isdn_tty_at_cout("\r\n", info);
+ isdn_tty_at_cout("CALLER NUMBER: ", info);
+ isdn_tty_at_cout(dev->num[info->drv_index], info);
+ }
+ break;
+ case 3:
+ case 6:
+ case 7:
+ case 8:
+ m->mdmreg[1] = 0;
+ /* Append Cause-Message if enabled */
+ if (m->mdmreg[13] & 8) {
+ sprintf(s, "/%s", info->last_cause);
+ isdn_tty_at_cout(s, info);
+ }
+ break;
+ case 5:
+ /* Append Protocol to CONNECT message */
+ isdn_tty_at_cout((m->mdmreg[14] != 3) ? "/X.75" : "/HDLC", info);
+ if (m->mdmreg[13] & 2)
+ isdn_tty_at_cout("/T.70", info);
+ break;
}
}
isdn_tty_at_cout("\r\n", info);
restore_flags(flags);
return;
}
- if (info->tty->ldisc.flush_buffer)
- info->tty->ldisc.flush_buffer(info->tty);
+ if (info->tty->ldisc.flush_buffer)
+ info->tty->ldisc.flush_buffer(info->tty);
if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
(!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
(info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
tty_hangup(info->tty);
- }
+ }
restore_flags(flags);
}
}
/*
* Display a modem-register-value.
*/
-static void isdn_tty_show_profile(int ridx, modem_info * info)
+static void
+isdn_tty_show_profile(int ridx, modem_info * info)
{
char v[6];
/*
* Get MSN-string from char-pointer, set pointer to end of number
*/
-static void isdn_tty_get_msnstr(char *n, char **p)
+static void
+isdn_tty_get_msnstr(char *n, char **p)
{
while ((*p[0] >= '0' && *p[0] <= '9') || (*p[0] == ','))
*n++ = *p[0]++;
/*
* Get phone-number from modem-commandbuffer
*/
-static void isdn_tty_getdial(char *p, char *q)
+static void
+isdn_tty_getdial(char *p, char *q)
{
int first = 1;
#define PARSE_ERROR { isdn_tty_modem_result(4, info); return; }
#define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; }
+static void
+isdn_tty_report(modem_info * info)
+{
+ atemu *m = &info->emu;
+ char s[80];
+
+ isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info);
+ sprintf(s, " Remote Number: %s\r\n", info->last_num);
+ isdn_tty_at_cout(s, info);
+ sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming");
+ isdn_tty_at_cout(s, info);
+ isdn_tty_at_cout(" Layer-2 Protocol: ", info);
+ switch (info->last_l2) {
+ case ISDN_PROTO_L2_X75I:
+ isdn_tty_at_cout("x75i", info);
+ break;
+ case ISDN_PROTO_L2_X75UI:
+ isdn_tty_at_cout("x75ui", info);
+ break;
+ case ISDN_PROTO_L2_X75BUI:
+ isdn_tty_at_cout("x75bui", info);
+ break;
+ case ISDN_PROTO_L2_HDLC:
+ isdn_tty_at_cout("hdlc", info);
+ break;
+ case ISDN_PROTO_L2_TRANS:
+ isdn_tty_at_cout("transparent", info);
+ break;
+ default:
+ isdn_tty_at_cout("unknown", info);
+ break;
+ }
+ isdn_tty_at_cout((m->mdmreg[13] & 2) ? "/t.70\r\n" : "\r\n", info);
+ isdn_tty_at_cout(" Service: ", info);
+ switch (info->last_si) {
+ case 1:
+ isdn_tty_at_cout("audio\r\n", info);
+ break;
+ case 5:
+ isdn_tty_at_cout("btx\r\n", info);
+ break;
+ case 7:
+ isdn_tty_at_cout("data\r\n", info);
+ break;
+ default:
+ sprintf(s, "%d\r\n", info->last_si);
+ isdn_tty_at_cout(s, info);
+ break;
+ }
+ sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote");
+ isdn_tty_at_cout(s, info);
+ sprintf(s, " Last cause: %s\r\n", info->last_cause);
+ isdn_tty_at_cout(s, info);
+}
+
/*
* Parse AT&.. commands.
*/
-static int isdn_tty_cmd_ATand(char **p, modem_info * info)
+static int
+isdn_tty_cmd_ATand(char **p, modem_info * info)
{
- atemu *m = &info->emu;
- int i;
- char rb[100];
-
- switch (*p[0]) {
- case 'B':
- /* &B - Set Buffersize */
- p[0]++;
- i = isdn_getnum(p);
- if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE))
- PARSE_ERROR1;
+ atemu *m = &info->emu;
+ int i;
+ char rb[100];
+
+ switch (*p[0]) {
+ case 'B':
+ /* &B - Set Buffersize */
+ p[0]++;
+ i = isdn_getnum(p);
+ if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE))
+ PARSE_ERROR1;
#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[18] & 1) && (i > VBUF))
- PARSE_ERROR1;
-#endif
- m->mdmreg[16] = i / 16;
- info->xmit_size = m->mdmreg[16] * 16;
- break;
- case 'D':
- /* &D - Set DCD-Low-behavior */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[13] &= ~4;
- m->mdmreg[12] &= ~32;
- break;
- case 2:
- m->mdmreg[13] |= 4;
- m->mdmreg[12] &= ~32;
- break;
- case 3:
- m->mdmreg[13] |= 4;
- m->mdmreg[12] |= 32;
- break;
- default:
- PARSE_ERROR1
- }
- break;
- case 'E':
- /* &E -Set EAZ/MSN */
- p[0]++;
- isdn_tty_get_msnstr(m->msn, p);
- break;
- case 'F':
- /* &F -Set Factory-Defaults */
- p[0]++;
- isdn_tty_reset_profile(m);
- isdn_tty_modem_reset_regs(info, 1);
- break;
- case 'S':
- /* &S - Set Windowsize */
- p[0]++;
- i = isdn_getnum(p);
- if ((i > 0) && (i < 9))
- m->mdmreg[17] = i;
- else
- PARSE_ERROR1;
- break;
- case 'V':
- /* &V - Show registers */
- p[0]++;
- for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
- sprintf(rb, "S%d=%d%s", i,
- m->mdmreg[i], (i == 6) ? "\r\n" : " ");
- isdn_tty_at_cout(rb, info);
- }
- sprintf(rb, "\r\nEAZ/MSN: %s\r\n",
- strlen(m->msn) ? m->msn : "None");
- isdn_tty_at_cout(rb, info);
- break;
- case 'W':
- /* &W - Write Profile */
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- modem_write_profile(m);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 'X':
- /* &X - Switch to BTX-Mode */
- p[0]++;
- switch (isdn_getnum(p)) {
- case 0:
- m->mdmreg[13] &= ~2;
- info->xmit_size = m->mdmreg[16] * 16;
- break;
- case 1:
- m->mdmreg[13] |= 2;
- m->mdmreg[14] = 0;
- info->xmit_size = 112;
- m->mdmreg[18] = 4;
- m->mdmreg[19] = 0;
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
+ if ((m->mdmreg[18] & 1) && (i > VBUF))
+ PARSE_ERROR1;
+#endif
+ m->mdmreg[16] = i / 16;
+ info->xmit_size = m->mdmreg[16] * 16;
+ break;
+ case 'D':
+ /* &D - Set DCD-Low-behavior */
+ p[0]++;
+ switch (isdn_getnum(p)) {
+ case 0:
+ m->mdmreg[13] &= ~4;
+ m->mdmreg[12] &= ~32;
+ break;
+ case 2:
+ m->mdmreg[13] |= 4;
+ m->mdmreg[12] &= ~32;
+ break;
+ case 3:
+ m->mdmreg[13] |= 4;
+ m->mdmreg[12] |= 32;
+ break;
+ default:
+ PARSE_ERROR1
+ }
+ break;
+ case 'E':
+ /* &E -Set EAZ/MSN */
+ p[0]++;
+ isdn_tty_get_msnstr(m->msn, p);
+ break;
+ case 'F':
+ /* &F -Set Factory-Defaults */
+ p[0]++;
+ isdn_tty_reset_profile(m);
+ isdn_tty_modem_reset_regs(info, 1);
+ break;
+ case 'S':
+ /* &S - Set Windowsize */
+ p[0]++;
+ i = isdn_getnum(p);
+ if ((i > 0) && (i < 9))
+ m->mdmreg[17] = i;
+ else
+ PARSE_ERROR1;
+ break;
+ case 'V':
+ /* &V - Show registers */
+ p[0]++;
+ isdn_tty_at_cout("\r\n", info);
+ for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
+ sprintf(rb, "S%02d=%03d%s", i,
+ m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
+ isdn_tty_at_cout(rb, info);
+ }
+ sprintf(rb, "\r\nEAZ/MSN: %s\r\n",
+ strlen(m->msn) ? m->msn : "None");
+ isdn_tty_at_cout(rb, info);
+ break;
+ case 'W':
+ /* &W - Write Profile */
+ p[0]++;
+ switch (*p[0]) {
+ case '0':
+ p[0]++;
+ modem_write_profile(m);
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ case 'X':
+ /* &X - Switch to BTX-Mode */
+ p[0]++;
+ switch (isdn_getnum(p)) {
+ case 0:
+ m->mdmreg[13] &= ~2;
+ info->xmit_size = m->mdmreg[16] * 16;
+ break;
+ case 1:
+ m->mdmreg[13] |= 2;
+ m->mdmreg[14] = 0;
+ info->xmit_size = 112;
+ m->mdmreg[18] = 4;
+ m->mdmreg[19] = 0;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+}
+
+static int
+isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
+{
+ /* Some plausibility checks */
+ switch (mreg) {
+ case 14:
+ if (mval > ISDN_PROTO_L2_TRANS)
+ return 1;
+ break;
+ case 16:
+ if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
+ return 1;
+#ifdef CONFIG_ISDN_AUDIO
+ if ((m->mdmreg[18] & 1) && (mval > VBUFX))
+ return 1;
+#endif
+ info->xmit_size = mval * 16;
+ break;
+ case 20:
+ case 21:
+ case 22:
+ /* readonly registers */
+ return 1;
+ }
+ return 0;
}
/*
* Perform ATS command
*/
-static int isdn_tty_cmd_ATS(char **p, modem_info * info)
+static int
+isdn_tty_cmd_ATS(char **p, modem_info * info)
{
- atemu *m = &info->emu;
- int mreg;
- int mval;
-
- mreg = isdn_getnum(p);
- if (mreg < 0 || mreg > ISDN_MODEM_ANZREG)
- PARSE_ERROR1;
- switch (*p[0]) {
- case '=':
- p[0]++;
- mval = isdn_getnum(p);
- if (mval < 0 || mval > 255)
- PARSE_ERROR1;
- switch (mreg) {
- /* Some plausibility checks */
- case 14:
- if (mval > ISDN_PROTO_L2_TRANS)
- PARSE_ERROR1;
- break;
- case 16:
- if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
- PARSE_ERROR1;
-#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[18] & 1) && (mval > VBUFX))
- PARSE_ERROR1;
-#endif
- info->xmit_size = mval * 16;
- break;
- case 20:
- PARSE_ERROR1;
- }
- m->mdmreg[mreg] = mval;
- break;
- case '?':
- p[0]++;
- isdn_tty_show_profile(mreg, info);
- break;
- default:
- PARSE_ERROR1;
- break;
- }
- return 0;
+ atemu *m = &info->emu;
+ int bitpos;
+ int mreg;
+ int mval;
+ int bval;
+
+ mreg = isdn_getnum(p);
+ if (mreg < 0 || mreg > ISDN_MODEM_ANZREG)
+ PARSE_ERROR1;
+ switch (*p[0]) {
+ case '=':
+ p[0]++;
+ mval = isdn_getnum(p);
+ if (mval < 0 || mval > 255)
+ PARSE_ERROR1;
+ if (isdn_tty_check_ats(mreg, mval, info, m))
+ PARSE_ERROR1;
+ m->mdmreg[mreg] = mval;
+ break;
+ case '.':
+ /* Set/Clear a single bit */
+ p[0]++;
+ bitpos = isdn_getnum(p);
+ if ((bitpos < 0) || (bitpos > 7))
+ PARSE_ERROR1;
+ switch (*p[0]) {
+ case '=':
+ p[0]++;
+ bval = isdn_getnum(p);
+ if (bval < 0 || bval > 1)
+ PARSE_ERROR1;
+ if (bval)
+ mval = m->mdmreg[mreg] | (1 << bitpos);
+ else
+ mval = m->mdmreg[mreg] & ~(1 << bitpos);
+ if (isdn_tty_check_ats(mreg, mval, info, m))
+ PARSE_ERROR1;
+ m->mdmreg[mreg] = mval;
+ break;
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n", info);
+ isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
+ info);
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ case '?':
+ p[0]++;
+ isdn_tty_show_profile(mreg, info);
+ break;
+ default:
+ PARSE_ERROR1;
+ break;
+ }
+ return 0;
}
/*
* Perform ATA command
*/
-static void isdn_tty_cmd_ATA(modem_info * info)
+static void
+isdn_tty_cmd_ATA(modem_info * info)
{
- atemu *m = &info->emu;
- isdn_ctrl cmd;
- int l2;
-
- if (info->msr & UART_MSR_RI) {
- /* Accept incoming call */
- m->mdmreg[1] = 0;
- info->msr &= ~UART_MSR_RI;
- l2 = m->mdmreg[14];
+ atemu *m = &info->emu;
+ isdn_ctrl cmd;
+ int l2;
+
+ if (info->msr & UART_MSR_RI) {
+ /* Accept incoming call */
+ info->last_dir = 0;
+ strcpy(info->last_num, dev->num[info->drv_index]);
+ m->mdmreg[1] = 0;
+ info->msr &= ~UART_MSR_RI;
+ l2 = m->mdmreg[14];
#ifdef CONFIG_ISDN_AUDIO
- /* If more than one bit set in reg18, autoselect Layer2 */
- if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18])
- if (m->mdmreg[20] == 1) l2 = 4;
-#endif
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL2;
- cmd.arg = info->isdn_channel + (l2 << 8);
- dev->drv[info->isdn_driver]->interface->command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_SETL3;
- cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
- dev->drv[info->isdn_driver]->interface->command(&cmd);
- cmd.driver = info->isdn_driver;
- cmd.arg = info->isdn_channel;
- cmd.command = ISDN_CMD_ACCEPTD;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
- } else
- isdn_tty_modem_result(8, info);
+ /* If more than one bit set in reg18, autoselect Layer2 */
+ if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18]) {
+ if (m->mdmreg[20] == 1)
+ l2 = 4;
+ else
+ l2 = 0;
+ }
+#endif
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETL2;
+ cmd.arg = info->isdn_channel + (l2 << 8);
+ info->last_l2 = l2;
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETL3;
+ cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.command = ISDN_CMD_ACCEPTD;
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ } else
+ isdn_tty_modem_result(8, info);
}
#ifdef CONFIG_ISDN_AUDIO
/*
* Parse AT+F.. commands
*/
-static int isdn_tty_cmd_PLUSF(char **p, modem_info * info)
+static int
+isdn_tty_cmd_PLUSF(char **p, modem_info * info)
{
- atemu *m = &info->emu;
- int par;
+ atemu *m = &info->emu;
+ int par;
char rs[20];
- if (!strncmp(p[0],"CLASS",5)) {
- p[0] += 5;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs,"\r\n%d",
- (m->mdmreg[18]&1)?8:0);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- m->mdmreg[18] = 4;
- info->xmit_size =
- m->mdmreg[16] * 16;
- break;
- case '8':
- p[0]++;
- m->mdmreg[18] = 5;
- info->xmit_size = VBUF;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n0,8",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- if (!strncmp(p[0],"AA",2)) {
- p[0] += 2;
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs,"\r\n%d",
- m->mdmreg[0]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- par = isdn_getnum(p);
- if ((par < 0) || (par > 255))
- PARSE_ERROR1;
- m->mdmreg[0]=par;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
- }
- PARSE_ERROR1;
+ if (!strncmp(p[0], "CLASS", 5)) {
+ p[0] += 5;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",
+ (m->mdmreg[18] & 1) ? 8 : 0);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ switch (*p[0]) {
+ case '0':
+ p[0]++;
+ m->mdmreg[18] = 4;
+ info->xmit_size =
+ m->mdmreg[16] * 16;
+ break;
+ case '8':
+ p[0]++;
+ m->mdmreg[18] = 5;
+ info->xmit_size = VBUF;
+ break;
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n0,8",
+ info);
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+ if (!strncmp(p[0], "AA", 2)) {
+ p[0] += 2;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d",
+ m->mdmreg[0]);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ m->mdmreg[0] = par;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+ PARSE_ERROR1;
}
/*
* Parse AT+V.. commands
*/
-static int isdn_tty_cmd_PLUSV(char **p, modem_info * info)
+static int
+isdn_tty_cmd_PLUSV(char **p, modem_info * info)
{
- atemu *m = &info->emu;
- static char *vcmd[] = {"NH","IP","LS","RX","SD","SM","TX",NULL};
- int i;
+ atemu *m = &info->emu;
+ static char *vcmd[] =
+ {"NH", "IP", "LS", "RX", "SD", "SM", "TX", NULL};
+ int i;
int par1;
int par2;
char rs[20];
- i = 0;
- while (vcmd[i]) {
- if (!strncmp(vcmd[i],p[0],2)) {
- p[0] += 2;
- break;
- }
- i++;
- }
- switch (i) {
- case 0:
- /* AT+VNH - Auto hangup feature */
- switch (*p[0]) {
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n1", info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '1':
- p[0]++;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n1", info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 1:
- /* AT+VIP - Reset all voice parameters */
- isdn_tty_modem_reset_vpar(m);
- break;
- case 2:
- /* AT+VLS - Select device, accept incoming call */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs,"\r\n%d",m->vpar[0]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- p[0]++;
- m->vpar[0] = 0;
- break;
- case '2':
- p[0]++;
- m->vpar[0] = 2;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n0,2", info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 3:
- /* AT+VRX - Start recording */
- if (!m->vpar[0])
- PARSE_ERROR1;
- if (info->online != 1) {
- isdn_tty_modem_result(8, info);
- return 1;
- }
- info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
- if (!info->dtmf_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
- PARSE_ERROR1;
- }
- if (m->vpar[3] < 5) {
- info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
- if (!info->adpcmr) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
- PARSE_ERROR1;
- }
- }
- info->vonline = 1;
- isdn_tty_modem_result(1, info);
- return 1;
- break;
- case 4:
- /* AT+VSD - Silence detection */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs,"\r\n<%d>,<%d>",
- m->vpar[1],
- m->vpar[2]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '0':
- case '1':
- case '2':
- case '3':
- par1 = isdn_getnum(p);
- if ((par1 < 0) || (par1 > 31))
- PARSE_ERROR1;
- if (*p[0] != ',')
- PARSE_ERROR1;
- p[0]++;
- par2 = isdn_getnum(p);
- if ((par2 < 0) || (par2 > 255))
- PARSE_ERROR1;
- m->vpar[1] = par1;
- m->vpar[2] = par2;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n<0-31>,<0-255>",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 5:
- /* AT+VSM - Select compression */
- switch (*p[0]) {
- case '?':
- p[0]++;
- sprintf(rs,"\r\n<%d>,<%d><8000>",
- m->vpar[3],
- m->vpar[1]);
- isdn_tty_at_cout(rs, info);
- break;
- case '=':
- p[0]++;
- switch (*p[0]) {
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- par1 = isdn_getnum(p);
- if ((par1 < 2) || (par1 > 6))
- PARSE_ERROR1;
- m->vpar[3] = par1;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
- info);
- isdn_tty_at_cout("5;ALAW;8;0;(8000)",
- info);
- isdn_tty_at_cout("6;ULAW;8;0;(8000)",
- info);
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- default:
- PARSE_ERROR1;
- }
- break;
- case 6:
- /* AT+VTX - Start sending */
- if (!m->vpar[0])
- PARSE_ERROR1;
- if (info->online != 1) {
- isdn_tty_modem_result(8, info);
- return 1;
- }
- info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
- if (!info->dtmf_state) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
- PARSE_ERROR1;
- }
- if (m->vpar[3] < 5) {
- info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
- if (!info->adpcms) {
- printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
- PARSE_ERROR1;
- }
- }
- m->lastDLE = 0;
- info->vonline = 2;
- isdn_tty_modem_result(1, info);
- return 1;
- break;
- default:
- PARSE_ERROR1;
- }
- return 0;
+ i = 0;
+ while (vcmd[i]) {
+ if (!strncmp(vcmd[i], p[0], 2)) {
+ p[0] += 2;
+ break;
+ }
+ i++;
+ }
+ switch (i) {
+ case 0:
+ /* AT+VNH - Auto hangup feature */
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n1", info);
+ break;
+ case '=':
+ p[0]++;
+ switch (*p[0]) {
+ case '1':
+ p[0]++;
+ break;
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n1", info);
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ case 1:
+ /* AT+VIP - Reset all voice parameters */
+ isdn_tty_modem_reset_vpar(m);
+ break;
+ case 2:
+ /* AT+VLS - Select device, accept incoming call */
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n%d", m->vpar[0]);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ switch (*p[0]) {
+ case '0':
+ p[0]++;
+ m->vpar[0] = 0;
+ break;
+ case '2':
+ p[0]++;
+ m->vpar[0] = 2;
+ break;
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n0,2", info);
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ case 3:
+ /* AT+VRX - Start recording */
+ if (!m->vpar[0])
+ PARSE_ERROR1;
+ if (info->online != 1) {
+ isdn_tty_modem_result(8, info);
+ return 1;
+ }
+ info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
+ if (!info->dtmf_state) {
+ printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
+ PARSE_ERROR1;
+ }
+ if (m->vpar[3] < 5) {
+ info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
+ if (!info->adpcmr) {
+ printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
+ PARSE_ERROR1;
+ }
+ }
+#ifdef ISDN_DEBUG_AT
+ printk(KERN_DEBUG "AT: +VRX\n");
+#endif
+ info->vonline |= 1;
+ isdn_tty_modem_result(1, info);
+ return 0;
+ break;
+ case 4:
+ /* AT+VSD - Silence detection */
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n<%d>,<%d>",
+ m->vpar[1],
+ m->vpar[2]);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ switch (*p[0]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ par1 = isdn_getnum(p);
+ if ((par1 < 0) || (par1 > 31))
+ PARSE_ERROR1;
+ if (*p[0] != ',')
+ PARSE_ERROR1;
+ p[0]++;
+ par2 = isdn_getnum(p);
+ if ((par2 < 0) || (par2 > 255))
+ PARSE_ERROR1;
+ m->vpar[1] = par1;
+ m->vpar[2] = par2;
+ break;
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n<0-31>,<0-255>",
+ info);
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ case 5:
+ /* AT+VSM - Select compression */
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs, "\r\n<%d>,<%d><8000>",
+ m->vpar[3],
+ m->vpar[1]);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ switch (*p[0]) {
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ par1 = isdn_getnum(p);
+ if ((par1 < 2) || (par1 > 6))
+ PARSE_ERROR1;
+ m->vpar[3] = par1;
+ break;
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
+ info);
+ isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
+ info);
+ isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
+ info);
+ isdn_tty_at_cout("5;ALAW;8;0;(8000)",
+ info);
+ isdn_tty_at_cout("6;ULAW;8;0;(8000)",
+ info);
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ case 6:
+ /* AT+VTX - Start sending */
+ if (!m->vpar[0])
+ PARSE_ERROR1;
+ if (info->online != 1) {
+ isdn_tty_modem_result(8, info);
+ return 1;
+ }
+ info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
+ if (!info->dtmf_state) {
+ printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
+ PARSE_ERROR1;
+ }
+ if (m->vpar[3] < 5) {
+ info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
+ if (!info->adpcms) {
+ printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
+ PARSE_ERROR1;
+ }
+ }
+#ifdef ISDN_DEBUG_AT
+ printk(KERN_DEBUG "AT: +VTX\n");
+#endif
+ m->lastDLE = 0;
+ info->vonline |= 2;
+ isdn_tty_modem_result(1, info);
+ return 0;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
}
-#endif /* CONFIG_ISDN_AUDIO */
+#endif /* CONFIG_ISDN_AUDIO */
/*
* Parse and perform an AT-command-line.
*/
-static void isdn_tty_parse_at(modem_info * info)
+static void
+isdn_tty_parse_at(modem_info * info)
{
- atemu *m = &info->emu;
- char *p;
- char ds[40];
+ atemu *m = &info->emu;
+ char *p;
+ char ds[40];
#ifdef ISDN_DEBUG_AT
- printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
-#endif
- for (p = &m->mdmcmd[2]; *p;) {
- switch (*p) {
- case 'A':
- /* A - Accept incoming call */
- p++;
- isdn_tty_cmd_ATA(info);
- return;
- break;
- case 'D':
- /* D - Dial */
- isdn_tty_getdial(++p, ds);
- p += strlen(p);
- if (!strlen(m->msn))
- isdn_tty_modem_result(10, info);
- else if (strlen(ds))
- isdn_tty_dial(ds, info, m);
- else
- isdn_tty_modem_result(4, info);
- return;
- case 'E':
- /* E - Turn Echo on/off */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[12] &= ~4;
- break;
- case 1:
- m->mdmreg[12] |= 4;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'H':
- /* H - On/Off-hook */
- p++;
- switch (*p) {
- case '0':
- p++;
- isdn_tty_on_hook(info);
- break;
- case '1':
- p++;
- isdn_tty_off_hook();
- break;
- default:
- isdn_tty_on_hook(info);
- break;
- }
- break;
- case 'I':
- /* I - Information */
- p++;
- isdn_tty_at_cout("\r\nLinux ISDN", info);
- switch (*p) {
- case '0':
- case '1':
- p++;
- break;
- default:
- }
- break;
- case 'O':
- /* O - Go online */
- p++;
- if (info->msr & UART_MSR_DCD)
- /* if B-Channel is up */
- isdn_tty_modem_result(5, info);
- else
- isdn_tty_modem_result(3, info);
- return;
- case 'Q':
- /* Q - Turn Emulator messages on/off */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[12] |= 1;
- break;
- case 1:
- m->mdmreg[12] &= ~1;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'S':
- /* S - Set/Get Register */
- p++;
- if (isdn_tty_cmd_ATS(&p, info))
- return;
- break;
- case 'V':
- /* V - Numeric or ASCII Emulator-messages */
- p++;
- switch (isdn_getnum(&p)) {
- case 0:
- m->mdmreg[12] |= 2;
- break;
- case 1:
- m->mdmreg[12] &= ~2;
- break;
- default:
- PARSE_ERROR;
- }
- break;
- case 'Z':
- /* Z - Load Registers from Profile */
- p++;
- isdn_tty_modem_reset_regs(info, 1);
- break;
+ printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
+#endif
+ for (p = &m->mdmcmd[2]; *p;) {
+ switch (*p) {
+ case 'A':
+ /* A - Accept incoming call */
+ p++;
+ isdn_tty_cmd_ATA(info);
+ return;
+ break;
+ case 'D':
+ /* D - Dial */
+ isdn_tty_getdial(++p, ds);
+ p += strlen(p);
+ if (!strlen(m->msn))
+ isdn_tty_modem_result(10, info);
+ else if (strlen(ds))
+ isdn_tty_dial(ds, info, m);
+ else
+ PARSE_ERROR;
+ return;
+ case 'E':
+ /* E - Turn Echo on/off */
+ p++;
+ switch (isdn_getnum(&p)) {
+ case 0:
+ m->mdmreg[12] &= ~4;
+ break;
+ case 1:
+ m->mdmreg[12] |= 4;
+ break;
+ default:
+ PARSE_ERROR;
+ }
+ break;
+ case 'H':
+ /* H - On/Off-hook */
+ p++;
+ switch (*p) {
+ case '0':
+ p++;
+ isdn_tty_on_hook(info);
+ break;
+ case '1':
+ p++;
+ isdn_tty_off_hook();
+ break;
+ default:
+ isdn_tty_on_hook(info);
+ break;
+ }
+ break;
+ case 'I':
+ /* I - Information */
+ p++;
+ isdn_tty_at_cout("\r\nLinux ISDN", info);
+ switch (*p) {
+ case '0':
+ case '1':
+ p++;
+ break;
+ case '2':
+ p++;
+ isdn_tty_report(info);
+ break;
+ default:
+ }
+ break;
+ case 'O':
+ /* O - Go online */
+ p++;
+ if (info->msr & UART_MSR_DCD)
+ /* if B-Channel is up */
+ isdn_tty_modem_result(5, info);
+ else
+ isdn_tty_modem_result(3, info);
+ return;
+ case 'Q':
+ /* Q - Turn Emulator messages on/off */
+ p++;
+ switch (isdn_getnum(&p)) {
+ case 0:
+ m->mdmreg[12] |= 1;
+ break;
+ case 1:
+ m->mdmreg[12] &= ~1;
+ break;
+ default:
+ PARSE_ERROR;
+ }
+ break;
+ case 'S':
+ /* S - Set/Get Register */
+ p++;
+ if (isdn_tty_cmd_ATS(&p, info))
+ return;
+ break;
+ case 'V':
+ /* V - Numeric or ASCII Emulator-messages */
+ p++;
+ switch (isdn_getnum(&p)) {
+ case 0:
+ m->mdmreg[12] |= 2;
+ break;
+ case 1:
+ m->mdmreg[12] &= ~2;
+ break;
+ default:
+ PARSE_ERROR;
+ }
+ break;
+ case 'Z':
+ /* Z - Load Registers from Profile */
+ p++;
+ isdn_tty_modem_reset_regs(info, 1);
+ break;
+#ifdef CONFIG_ISDN_AUDIO
+ case '+':
+ p++;
+ switch (*p) {
+ case 'F':
+ p++;
+ if (isdn_tty_cmd_PLUSF(&p, info))
+ return;
+ break;
+ case 'V':
+ if (!(m->mdmreg[18] & 1))
+ PARSE_ERROR;
+ p++;
+ if (isdn_tty_cmd_PLUSV(&p, info))
+ return;
+ break;
+ default:
+ PARSE_ERROR;
+ }
+ break;
+#endif /* CONFIG_ISDN_AUDIO */
+ case '&':
+ p++;
+ if (isdn_tty_cmd_ATand(&p, info))
+ return;
+ break;
+ default:
+ PARSE_ERROR;
+ }
+ }
#ifdef CONFIG_ISDN_AUDIO
- case '+':
- p++;
- switch (*p) {
- case 'F':
- p++;
- if (isdn_tty_cmd_PLUSF(&p, info))
- return;
- break;
- case 'V':
- if (!(m->mdmreg[18] & 1))
- PARSE_ERROR;
- p++;
- if (isdn_tty_cmd_PLUSV(&p, info))
- return;
- break;
- }
- break;
-#endif /* CONFIG_ISDN_AUDIO */
- case '&':
- p++;
- if (isdn_tty_cmd_ATand(&p, info))
- return;
- break;
- default:
- isdn_tty_modem_result(4, info);
- return;
- }
- }
- isdn_tty_modem_result(0, info);
+ if (!info->vonline)
+#endif
+ isdn_tty_modem_result(0, info);
}
/* Need own toupper() because standard-toupper is not available
* channel index to line (minor-device)
* user flag: buffer is in userspace
*/
-static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
+static int
+isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
{
atemu *m = &info->emu;
int total = 0;
if (m->mdmcmdl < 255) {
c = my_toupper(c);
switch (m->mdmcmdl) {
- case 0:
- if (c == 'A')
- m->mdmcmd[m->mdmcmdl++] = c;
- break;
- case 1:
- if (c == 'T')
- m->mdmcmd[m->mdmcmdl++] = c;
- break;
- default:
- m->mdmcmd[m->mdmcmdl++] = c;
+ case 0:
+ if (c == 'A')
+ m->mdmcmd[m->mdmcmdl++] = c;
+ break;
+ case 1:
+ if (c == 'T')
+ m->mdmcmd[m->mdmcmdl++] = c;
+ break;
+ default:
+ m->mdmcmd[m->mdmcmdl++] = c;
}
}
}
/*
* Switch all modem-channels who are online and got a valid
* escape-sequence 1.5 seconds ago, to command-mode.
- * This function is called every second via timer-interrupt from within
+ * This function is called every second via timer-interrupt from within
* timer-dispatcher isdn_timer_function()
*/
-void isdn_tty_modem_escape(void)
+void
+isdn_tty_modem_escape(void)
{
int ton = 0;
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (USG_MODEM(dev->usage[i]))
if ((midx = dev->m_idx[i]) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
+ modem_info *info = &dev->mdm.info[midx];
if (info->online) {
ton = 1;
if ((info->emu.pluscount == 3) &&
isdn_tty_modem_result(0, info);
}
}
- }
+ }
isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
}
/*
* Put a RING-message to all modem-channels who have the RI-bit set.
- * This function is called every second via timer-interrupt from within
+ * This function is called every second via timer-interrupt from within
* timer-dispatcher isdn_timer_function()
*/
-void isdn_tty_modem_ring(void)
+void
+isdn_tty_modem_ring(void)
{
int ton = 0;
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->msr & UART_MSR_RI) {
- ton = 1;
- isdn_tty_modem_result(2, info);
- }
- }
+ modem_info *info = &dev->mdm.info[i];
+ if (info->msr & UART_MSR_RI) {
+ ton = 1;
+ isdn_tty_modem_result(2, info);
+ }
+ }
isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
}
* For all online tty's, try sending data to
* the lower levels.
*/
-void isdn_tty_modem_xmit(void)
+void
+isdn_tty_modem_xmit(void)
{
int ton = 1;
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->online) {
- ton = 1;
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- }
+ modem_info *info = &dev->mdm.info[i];
+ if (info->online) {
+ ton = 1;
+ isdn_tty_senddown(info);
+ isdn_tty_tint(info);
+ }
+ }
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
}
-
-/*
- * A packet has been output successfully.
- * Search the tty-devices for an appropriate device, decrement its
- * counter for outstanding packets, and set CTS.
- */
-void isdn_tty_bsent(int drv, int chan)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if ((info->isdn_driver == drv) &&
- (info->isdn_channel == chan) ) {
- info->msr |= UART_MSR_CTS;
- if (info->send_outstanding)
- if (!(--info->send_outstanding))
- info->lsr |= UART_LSR_TEMT;
- isdn_tty_tint(info);
- }
- }
- return;
-}
-/* $Id: isdn_tty.h,v 1.5 1996/05/17 03:52:31 fritz Exp $
- *
+/* $Id: isdn_tty.h,v 1.10 1997/03/02 14:29:26 fritz Exp $
+
* header for Linux ISDN subsystem, tty related functions (linklevel).
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- *
+ *
* 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)
*
* 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.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.h,v $
+ * Revision 1.10 1997/03/02 14:29:26 fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.9 1997/02/28 02:32:49 fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ * to isdn_tty.c
+ * Bugfix: Bisync protocol did not behave like documented.
+ *
+ * Revision 1.8 1997/02/10 20:12:50 fritz
+ * Changed interface for reporting incoming calls.
+ *
+ * Revision 1.7 1997/02/03 23:06:10 fritz
+ * Reformatted according CodingStyle
+ *
+ * Revision 1.6 1997/01/14 01:35:19 fritz
+ * Changed prototype of isdn_tty_modem_hup.
+ *
* Revision 1.5 1996/05/17 03:52:31 fritz
* Changed DLE handling for audio receive.
*
*
*/
-extern void isdn_tty_modem_result(int, modem_info *);
-extern void isdn_tty_modem_escape(void);
-extern void isdn_tty_modem_ring(void);
-extern void isdn_tty_modem_xmit(void);
-extern void isdn_tty_modem_hup(modem_info *);
-extern int isdn_tty_modem_init(void);
-extern void isdn_tty_readmodem(void);
-extern int isdn_tty_try_read(modem_info *, struct sk_buff *);
-extern int isdn_tty_find_icall(int, int, char *);
-extern int isdn_tty_countDLE(unsigned char *, int);
-extern void isdn_tty_bsent(int, int);
-extern void isdn_tty_cleanup_xmit(modem_info *);
+extern void isdn_tty_modem_escape(void);
+extern void isdn_tty_modem_ring(void);
+extern void isdn_tty_modem_xmit(void);
+extern int isdn_tty_modem_init(void);
+extern void isdn_tty_readmodem(void);
+extern int isdn_tty_find_icall(int, int, setup_parm);
+extern void isdn_tty_cleanup_xmit(modem_info *);
+extern int isdn_tty_stat_callback(int, isdn_ctrl *);
+extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
* ictl.num >= strlen() + strlen() + 5
*/
- if (cbdata->data.setup.CalledPN)
- sprintf(ictl.num, "%s,%d,%d,%s",
- cbdata->data.setup.CallingPN,
- 7, 0,
- cbdata->data.setup.CalledPN);
-
- else
- sprintf(ictl.num, "%s,%d,%d,%s",
- cbdata->data.setup.CallingPN,
- 7, 0,
- "0");
-
+ strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN);
+ strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN);
+ ictl.parm.setup.si1 = 7;
+ ictl.parm.setup.si2 = 0;
+ ictl.parm.setup.plan = 0;
+ ictl.parm.setup.screen = 0;
#ifdef DEBUG
printk(KERN_DEBUG "statstr: %s\n", ictl.num);
return -1;
}
- (*skb)->free = 1;
+ SET_SKB_FREE((*skb));
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
return -1;
}
- (*skb)->free = 1;
+ SET_SKB_FREE((*skb));
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
return -1;
}
- (*skb)->free = 1;
+ SET_SKB_FREE((*skb));
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
return -1;
}
- (*skb)->free = 1;
+ SET_SKB_FREE((*skb));
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
return -1;
}
- (*skb)->free = 1;
+ SET_SKB_FREE((*skb));
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
return -1;
}
- (*skb)->free = 1;
+ SET_SKB_FREE((*skb));
*((ushort*) skb_put(*skb, 2) ) = chan->callref;
return -1;
}
- (*skb)->free = 1;
+ SET_SKB_FREE((*skb));
*((ushort*) skb_put(*skb, 2) ) = callref;
return -1;
}
- (*skb)->free = 1;
+ SET_SKB_FREE((*skb));
*((ushort*) skb_put(*skb, 2)) = chan->callref;
struct pcbit_dev *dev;
struct pcbit_chan *chan;
struct callb_data info;
- char *cp;
dev = finddev(ctl->driver);
break;
case ISDN_CMD_DIAL:
info.type = EV_USR_SETUP_REQ;
- info.data.setup.CalledPN = (char *) &ctl->num;
- cp = strchr(info.data.setup.CalledPN, ',');
- if (cp)
- *cp = 0;
- else {
- printk(KERN_DEBUG "DIAL: error in CalledPN\n");
- return -1;
- }
+ info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone;
pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info);
break;
case ISDN_CMD_ACCEPTD:
pcbit_clear_msn(dev);
break;
case ISDN_CMD_SETEAZ:
- pcbit_set_msn(dev, ctl->num);
+ pcbit_set_msn(dev, ctl->parm.num);
break;
case ISDN_CMD_SETL3:
if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS)
for (i=0; i < len; i++)
{
for(j=0; j < LOAD_RETRY; j++)
- {
- __volatile__ unsigned char * ptr;
-
- ptr = dev->sh_mem + dev->loadptr;
- if (*ptr == 0)
+ if (!(readb(dev->sh_mem + dev->loadptr)))
break;
- }
-
if (j == LOAD_RETRY)
{
errstat = -ETIME;
#endif
}
- skb->free = 1;
+ SET_SKB_FREE(skb);
kfree_skb(skb, FREE_READ);
return -ENODEV;
}
- cmd = (struct pcbit_ioctl *) ctl->num;
+ cmd = (struct pcbit_ioctl *) ctl->parm.num;
switch(ctl->arg) {
case PCBIT_IOCTL_GETSTAT:
/*
* Copyright (C) 1996 Universidade de Lisboa
- *
+ *
* Written by Pedro Roque Marques (roque@di.fc.ul.pt)
*
- * This software may be used and distributed according to the terms of
+ * This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
-/*
+/*
* PCBIT-D low-layer interface
*/
/*
* TODO: better handling of errors
* re-write/remove debug printks
- */
+ */
#define __NO_VERSION__
/*
* task queue struct
- */
+ */
* drv.c
*/
-extern void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg,
- struct sk_buff * skb,
+extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg,
+ struct sk_buff *skb,
ushort hdr_len, ushort refnum);
/*
* Prototypes
*/
-void pcbit_deliver(void * data);
-static void pcbit_transmit(struct pcbit_dev * dev);
+void pcbit_deliver(void *data);
+static void pcbit_transmit(struct pcbit_dev *dev);
static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
static void pcbit_l2_err_recover(unsigned long data);
-static void pcbit_firmware_bug(struct pcbit_dev * dev);
+static void pcbit_firmware_bug(struct pcbit_dev *dev);
-static __inline__ void pcbit_sched_delivery(struct pcbit_dev *dev)
+static __inline__ void
+pcbit_sched_delivery(struct pcbit_dev *dev)
{
queue_task(&dev->qdelivery, &tq_immediate);
mark_bh(IMMEDIATE_BH);
* Called from layer3
*/
-int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum,
- struct sk_buff *skb, unsigned short hdr_len)
-
+int
+pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
+ struct sk_buff *skb, unsigned short hdr_len)
{
- struct frame_buf * frame, * ptr;
- unsigned long flags;
+ struct frame_buf *frame,
+ *ptr;
+ unsigned long flags;
- if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
- dev_kfree_skb(skb, FREE_WRITE);
- return -1;
- }
-
- if ( (frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf),
- GFP_ATOMIC)) == NULL ) {
- printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n");
+ if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
+ dev_kfree_skb(skb, FREE_WRITE);
+ return -1;
+ }
+ if ((frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf),
+ GFP_ATOMIC)) == NULL) {
+ printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n");
dev_kfree_skb(skb, FREE_WRITE);
- return -1;
- }
+ return -1;
+ }
+ frame->msg = msg;
+ frame->refnum = refnum;
+ frame->copied = 0;
+ frame->hdr_len = hdr_len;
- frame->msg = msg;
- frame->refnum = refnum;
- frame->copied = 0;
- frame->hdr_len = hdr_len;
+ if (skb)
+ frame->dt_len = skb->len - hdr_len;
+ else
+ frame->dt_len = 0;
- if (skb) {
- frame->dt_len = skb->len - hdr_len;
- if (frame->dt_len == 0)
- skb->lock++;
- }
- else
- frame->dt_len = 0;
+ frame->skb = skb;
- frame->skb = skb;
+ frame->next = NULL;
- frame->next = NULL;
+ save_flags(flags);
+ cli();
- save_flags(flags);
- cli();
+ if (dev->write_queue == NULL) {
+ dev->write_queue = frame;
+ restore_flags(flags);
+ pcbit_transmit(dev);
+ } else {
+ for (ptr = dev->write_queue; ptr->next; ptr = ptr->next);
+ ptr->next = frame;
- if (dev->write_queue == NULL) {
- dev->write_queue = frame;
restore_flags(flags);
- pcbit_transmit(dev);
- }
- else {
- for(ptr=dev->write_queue; ptr->next; ptr=ptr->next);
- ptr->next = frame;
-
- restore_flags(flags);
- }
- return 0;
+ }
+ return 0;
}
-static __inline__ void pcbit_tx_update(struct pcbit_dev *dev, ushort len)
+static __inline__ void
+pcbit_tx_update(struct pcbit_dev *dev, ushort len)
{
- u_char info;
+ u_char info;
- dev->send_seq = (dev->send_seq + 1) % 8;
+ dev->send_seq = (dev->send_seq + 1) % 8;
- dev->fsize[dev->send_seq] = len;
- info = 0;
- info |= dev->rcv_seq << 3;
- info |= dev->send_seq;
+ dev->fsize[dev->send_seq] = len;
+ info = 0;
+ info |= dev->rcv_seq << 3;
+ info |= dev->send_seq;
- writeb(info, dev->sh_mem + BANK4);
+ writeb(info, dev->sh_mem + BANK4);
}
* called by interrupt service routine or by write_2
*/
-static void pcbit_transmit(struct pcbit_dev * dev)
+static void
+pcbit_transmit(struct pcbit_dev *dev)
{
- struct frame_buf * frame = NULL;
- unsigned char unacked;
- int flen; /* fragment frame length including all headers */
- int totlen; /* non-fragmented frame length */
- int free;
- int count, cp_len;
- unsigned long flags;
+ struct frame_buf *frame = NULL;
+ unsigned char unacked;
+ int flen; /* fragment frame length including all headers */
+ int totlen; /* non-fragmented frame length */
+ int free;
+ int count,
+ cp_len;
+ unsigned long flags;
unsigned short tt;
- if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
- return;
+ if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
+ return;
- unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07;
+ unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
save_flags(flags);
cli();
- if (dev->free > 16 && dev->write_queue && unacked < 7) {
+ if (dev->free > 16 && dev->write_queue && unacked < 7) {
- if (!dev->w_busy)
- dev->w_busy = 1;
- else
- {
- restore_flags(flags);
- return;
- }
+ if (!dev->w_busy)
+ dev->w_busy = 1;
+ else {
+ restore_flags(flags);
+ return;
+ }
- frame = dev->write_queue;
- free = dev->free;
+ frame = dev->write_queue;
+ free = dev->free;
- restore_flags(flags);
+ restore_flags(flags);
if (frame->copied == 0) {
- /* Type 0 frame */
+ /* Type 0 frame */
- struct msg_fmt * msg;
+ struct msg_fmt *msg;
if (frame->skb)
totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
flen = MIN(totlen, free);
- msg = (struct msg_fmt *) &(frame->msg);
+ msg = (struct msg_fmt *) &(frame->msg);
+
+ /*
+ * Board level 2 header
+ */
+
+ pcbit_writew(dev, flen - FRAME_HDR_LEN);
- /*
- * Board level 2 header
- */
+ pcbit_writeb(dev, msg->cpu);
- pcbit_writew(dev, flen - FRAME_HDR_LEN);
+ pcbit_writeb(dev, msg->proc);
- pcbit_writeb(dev, msg->cpu);
+ /* TH */
+ pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
- pcbit_writeb(dev, msg->proc);
+ /* TD */
+ pcbit_writew(dev, frame->dt_len);
- /* TH */
- pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
- /* TD */
- pcbit_writew(dev, frame->dt_len);
+ /*
+ * Board level 3 fixed-header
+ */
+ /* LEN = TH */
+ pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
- /*
- * Board level 3 fixed-header
- */
-
- /* LEN = TH */
- pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
-
- /* XX */
- pcbit_writew(dev, 0);
+ /* XX */
+ pcbit_writew(dev, 0);
- /* C + S */
- pcbit_writeb(dev, msg->cmd);
- pcbit_writeb(dev, msg->scmd);
+ /* C + S */
+ pcbit_writeb(dev, msg->cmd);
+ pcbit_writeb(dev, msg->scmd);
+
+ /* NUM */
+ pcbit_writew(dev, frame->refnum);
- /* NUM */
- pcbit_writew(dev, frame->refnum);
-
count = FRAME_HDR_LEN + PREHDR_LEN;
- }
- else {
+ } else {
/* Type 1 frame */
- totlen = 2 + (frame->skb->len - frame->copied);
-
+ totlen = 2 + (frame->skb->len - frame->copied);
+
flen = MIN(totlen, free);
- /* TT */
- tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */
- pcbit_writew(dev, tt);
+ /* TT */
+ tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */
+ pcbit_writew(dev, tt);
count = 2;
}
if (frame->skb) {
- cp_len = MIN(frame->skb->len - frame->copied,
- flen - count);
-
- memcpy_topcbit(dev, frame->skb->data + frame->copied,
- cp_len);
+ cp_len = MIN(frame->skb->len - frame->copied,
+ flen - count);
+
+ memcpy_topcbit(dev, frame->skb->data + frame->copied,
+ cp_len);
frame->copied += cp_len;
}
-
/* bookkeeping */
dev->free -= flen;
pcbit_tx_update(dev, flen);
cli();
- if (frame->skb == NULL || frame->copied == frame->skb->len) {
-
- dev->write_queue = frame->next;
-
- if (frame->skb != NULL) {
- /* free frame */
- dev_kfree_skb(frame->skb, FREE_WRITE);
- }
+ if (frame->skb == NULL || frame->copied == frame->skb->len) {
- kfree(frame);
- }
+ dev->write_queue = frame->next;
+ if (frame->skb != NULL) {
+ /* free frame */
+ dev_kfree_skb(frame->skb, FREE_WRITE);
+ }
+ kfree(frame);
+ }
dev->w_busy = 0;
- restore_flags(flags);
- }
- else
- {
restore_flags(flags);
-#ifdef DEBUG
- printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
- unacked, dev->free, dev->write_queue ? "not empty" :
- "empty");
+ } else {
+ restore_flags(flags);
+#ifdef DEBUG
+ printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
+ unacked, dev->free, dev->write_queue ? "not empty" :
+ "empty");
#endif
}
}
* deliver a queued frame to the upper layer
*/
-void pcbit_deliver(void * data)
-{
- struct frame_buf *frame;
- unsigned long flags;
+void
+pcbit_deliver(void *data)
+{
+ struct frame_buf *frame;
+ unsigned long flags;
struct msg_fmt msg;
- struct pcbit_dev *dev = (struct pcbit_dev *) data;
+ struct pcbit_dev *dev = (struct pcbit_dev *) data;
save_flags(flags);
- cli();
+ cli();
- while((frame=dev->read_queue))
- {
+ while ((frame = dev->read_queue)) {
dev->read_queue = frame->next;
restore_flags(flags);
msg.cmd = frame->skb->data[2];
msg.scmd = frame->skb->data[3];
- frame->refnum = *((ushort*) frame->skb->data + 4);
- frame->msg = *((ulong*) &msg);
-
+ frame->refnum = *((ushort *) frame->skb->data + 4);
+ frame->msg = *((ulong *) & msg);
+
skb_pull(frame->skb, 6);
- pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
+ pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
frame->refnum);
kfree(frame);
}
/*
- * Reads BANK 2 & Reassembles
+ * Reads BANK 2 & Reassembles
*/
-static void pcbit_receive(struct pcbit_dev * dev)
+static void
+pcbit_receive(struct pcbit_dev *dev)
{
- unsigned short tt;
- u_char cpu, proc;
- struct frame_buf * frame = NULL;
- unsigned long flags;
- u_char type1;
+ unsigned short tt;
+ u_char cpu,
+ proc;
+ struct frame_buf *frame = NULL;
+ unsigned long flags;
+ u_char type1;
- if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
- return;
+ if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
+ return;
- tt = pcbit_readw(dev);
+ tt = pcbit_readw(dev);
- if ((tt & 0x7fffU) > 511) {
- printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
+ if ((tt & 0x7fffU) > 511) {
+ printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
tt);
- pcbit_l2_error(dev);
- return;
- }
-
- if (!(tt & 0x8000U))
- { /* Type 0 */
- type1 = 0;
+ pcbit_l2_error(dev);
+ return;
+ }
+ if (!(tt & 0x8000U)) { /* Type 0 */
+ type1 = 0;
- if (dev->read_frame) {
- printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
+ if (dev->read_frame) {
+ printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
#if 0
- pcbit_l2_error(dev);
- return;
+ pcbit_l2_error(dev);
+ return;
#else
/* discard previous queued frame */
if (dev->read_frame->skb) {
- dev->read_frame->skb->free = 1;
+ SET_SKB_FREE(dev->read_frame->skb);
kfree_skb(dev->read_frame->skb, FREE_READ);
}
kfree(dev->read_frame);
dev->read_frame = NULL;
#endif
- }
-
- frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
-
- if (frame == NULL) {
- printk(KERN_WARNING "kmalloc failed\n");
- return;
- }
- memset(frame, 0, sizeof(struct frame_buf));
-
- cpu = pcbit_readb(dev);
- proc = pcbit_readb(dev);
-
-
- if (cpu != 0x06 && cpu != 0x02)
- {
- printk (KERN_DEBUG "pcbit: invalid cpu value\n");
+ }
+ frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
+
+ if (frame == NULL) {
+ printk(KERN_WARNING "kmalloc failed\n");
+ return;
+ }
+ memset(frame, 0, sizeof(struct frame_buf));
+
+ cpu = pcbit_readb(dev);
+ proc = pcbit_readb(dev);
+
+
+ if (cpu != 0x06 && cpu != 0x02) {
+ printk(KERN_DEBUG "pcbit: invalid cpu value\n");
kfree(frame);
pcbit_l2_error(dev);
- return;
- }
-
- /*
- * we discard cpu & proc on receiving
- * but we read it to update the pointer
- */
-
- frame->hdr_len = pcbit_readw(dev);
- frame->dt_len = pcbit_readw(dev);
-
- /*
- * 0 sized packet
- * I don't know if they are an error or not...
- * But they are very frequent
- * Not documented
- */
+ return;
+ }
+ /*
+ * we discard cpu & proc on receiving
+ * but we read it to update the pointer
+ */
+
+ frame->hdr_len = pcbit_readw(dev);
+ frame->dt_len = pcbit_readw(dev);
+
+ /*
+ * 0 sized packet
+ * I don't know if they are an error or not...
+ * But they are very frequent
+ * Not documented
+ */
if (frame->hdr_len == 0) {
- kfree(frame);
+ kfree(frame);
#ifdef DEBUG
- printk(KERN_DEBUG "0 sized frame\n");
+ printk(KERN_DEBUG "0 sized frame\n");
#endif
pcbit_firmware_bug(dev);
- return;
+ return;
}
-
- /* sanity check the length values */
- if (frame->hdr_len > 1024 || frame->dt_len > 2048)
- {
+ /* sanity check the length values */
+ if (frame->hdr_len > 1024 || frame->dt_len > 2048) {
#ifdef DEBUG
- printk(KERN_DEBUG "length problem: ");
- printk(KERN_DEBUG "TH=%04x TD=%04x\n",
- frame->hdr_len,
- frame->dt_len);
+ printk(KERN_DEBUG "length problem: ");
+ printk(KERN_DEBUG "TH=%04x TD=%04x\n",
+ frame->hdr_len,
+ frame->dt_len);
#endif
pcbit_l2_error(dev);
kfree(frame);
- return;
- }
-
- /* minimum frame read */
+ return;
+ }
+ /* minimum frame read */
- frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
+ frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
((frame->hdr_len + 15) & ~15));
if (!frame->skb) {
kfree(frame);
return;
}
-
- /* 16 byte alignment for IP */
+ /* 16 byte alignment for IP */
if (frame->dt_len)
- skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
+ skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
- }
- else {
+ } else {
/* Type 1 */
- type1 = 1;
- tt &= 0x7fffU;
+ type1 = 1;
+ tt &= 0x7fffU;
- if (!(frame = dev->read_frame)) {
- printk("Type 1 frame and no frame queued\n");
+ if (!(frame = dev->read_frame)) {
+ printk("Type 1 frame and no frame queued\n");
#if 1
/* usually after an error: toss frame */
dev->readptr += tt;
if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
dev->readptr -= BANKLEN;
#else
- pcbit_l2_error(dev);
+ pcbit_l2_error(dev);
#endif
- return;
+ return;
- }
- }
+ }
+ }
memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
frame->copied += tt;
- if (frame->copied == frame->hdr_len + frame->dt_len) {
-
- save_flags(flags);
- cli();
-
- if (type1) {
- dev->read_frame = NULL;
- }
-
- if (dev->read_queue) {
- struct frame_buf *ptr;
- for(ptr=dev->read_queue;ptr->next;ptr=ptr->next);
- ptr->next = frame;
- }
- else
- dev->read_queue = frame;
-
- restore_flags(flags);
-
- }
- else {
- save_flags(flags);
- cli();
- dev->read_frame = frame;
- restore_flags(flags);
- }
+ if (frame->copied == frame->hdr_len + frame->dt_len) {
+
+ save_flags(flags);
+ cli();
+
+ if (type1) {
+ dev->read_frame = NULL;
+ }
+ if (dev->read_queue) {
+ struct frame_buf *ptr;
+ for (ptr = dev->read_queue; ptr->next; ptr = ptr->next);
+ ptr->next = frame;
+ } else
+ dev->read_queue = frame;
+
+ restore_flags(flags);
+
+ } else {
+ save_flags(flags);
+ cli();
+ dev->read_frame = frame;
+ restore_flags(flags);
+ }
}
/*
* gotta send a fake acknowledgment to the upper layer somehow
*/
-static __inline__ void pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan * chan)
+static __inline__ void
+pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan)
{
- isdn_ctrl ictl;
-
- if (chan->queued) {
- chan->queued--;
-
- ictl.driver = dev->id;
- ictl.command = ISDN_STAT_BSENT;
- ictl.arg = chan->id;
- dev->dev_if->statcallb(&ictl);
- }
+ isdn_ctrl ictl;
+
+ if (chan->queued) {
+ chan->queued--;
+
+ ictl.driver = dev->id;
+ ictl.command = ISDN_STAT_BSENT;
+ ictl.arg = chan->id;
+ dev->dev_if->statcallb(&ictl);
+ }
}
-static void pcbit_firmware_bug(struct pcbit_dev * dev)
+static void
+pcbit_firmware_bug(struct pcbit_dev *dev)
{
- struct pcbit_chan *chan;
-
- chan = dev->b1;
+ struct pcbit_chan *chan;
- if (chan->fsm_state == ST_ACTIVE) {
- pcbit_fake_conf(dev, chan);
- }
+ chan = dev->b1;
- chan = dev->b2;
+ if (chan->fsm_state == ST_ACTIVE) {
+ pcbit_fake_conf(dev, chan);
+ }
+ chan = dev->b2;
- if (chan->fsm_state == ST_ACTIVE) {
- pcbit_fake_conf(dev, chan);
- }
-
+ if (chan->fsm_state == ST_ACTIVE) {
+ pcbit_fake_conf(dev, chan);
+ }
}
-void pcbit_irq_handler(int interrupt, void * devptr, struct pt_regs *regs)
+void
+pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs)
{
- struct pcbit_dev * dev;
- u_char info, ack_seq, read_seq;
+ struct pcbit_dev *dev;
+ u_char info,
+ ack_seq,
+ read_seq;
dev = (struct pcbit_dev *) devptr;
- if (!dev)
- {
- printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
- return;
- }
-
+ if (!dev) {
+ printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
+ return;
+ }
if (dev->interrupt) {
- printk(KERN_DEBUG "pcbit: reentering interrupt hander\n");
+ printk(KERN_DEBUG "pcbit: reentering interrupt hander\n");
return;
}
-
dev->interrupt = 1;
- info = readb(dev->sh_mem + BANK3);
+ info = readb(dev->sh_mem + BANK3);
- if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR)
- {
- pcbit_l2_active_conf(dev, info);
+ if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) {
+ pcbit_l2_active_conf(dev, info);
dev->interrupt = 0;
- return;
- }
-
- if (info & 0x40U) /* E bit set */
- {
+ return;
+ }
+ if (info & 0x40U) { /* E bit set */
#ifdef DEBUG
printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n");
#endif
- pcbit_l2_error(dev);
+ pcbit_l2_error(dev);
dev->interrupt = 0;
- return;
- }
-
- if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
- {
- dev->interrupt = 0;
- return;
+ return;
}
+ if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
+ dev->interrupt = 0;
+ return;
+ }
+ ack_seq = (info >> 3) & 0x07U;
+ read_seq = (info & 0x07U);
- ack_seq = (info >> 3) & 0x07U;
- read_seq = (info & 0x07U);
-
dev->interrupt = 0;
- if (read_seq != dev->rcv_seq)
- {
- while (read_seq != dev->rcv_seq)
- {
+ if (read_seq != dev->rcv_seq) {
+ while (read_seq != dev->rcv_seq) {
pcbit_receive(dev);
dev->rcv_seq = (dev->rcv_seq + 1) % 8;
}
pcbit_sched_delivery(dev);
- }
-
- if (ack_seq != dev->unack_seq)
- {
- pcbit_recv_ack(dev, ack_seq);
- }
-
-
+ }
+ if (ack_seq != dev->unack_seq) {
+ pcbit_recv_ack(dev, ack_seq);
+ }
info = dev->rcv_seq << 3;
info |= dev->send_seq;
-
- writeb(info, dev->sh_mem + BANK4);
+
+ writeb(info, dev->sh_mem + BANK4);
}
-static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
+static void
+pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
{
- u_char state;
+ u_char state;
- state = dev->l2_state;
+ state = dev->l2_state;
#ifdef DEBUG
- printk(KERN_DEBUG "layer2_active_confirm\n");
+ printk(KERN_DEBUG "layer2_active_confirm\n");
#endif
-
-
- if (info & 0x80U ) {
- dev->rcv_seq = info & 0x07U;
- dev->l2_state = L2_RUNNING;
- }
- else
- dev->l2_state = L2_DOWN;
-
- if (state == L2_STARTING)
- wake_up_interruptible(&dev->set_running_wq);
- if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
- pcbit_transmit(dev);
- }
+ if (info & 0x80U) {
+ dev->rcv_seq = info & 0x07U;
+ dev->l2_state = L2_RUNNING;
+ } else
+ dev->l2_state = L2_DOWN;
+
+ if (state == L2_STARTING)
+ wake_up_interruptible(&dev->set_running_wq);
+
+ if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
+ pcbit_transmit(dev);
+ }
}
-static void pcbit_l2_err_recover(unsigned long data)
+static void
+pcbit_l2_err_recover(unsigned long data)
{
- struct pcbit_dev * dev;
- struct frame_buf *frame;
+ struct pcbit_dev *dev;
+ struct frame_buf *frame;
- dev = (struct pcbit_dev *) data;
+ dev = (struct pcbit_dev *) data;
- del_timer(&dev->error_recover_timer);
- if (dev->w_busy || dev->r_busy)
- {
+ del_timer(&dev->error_recover_timer);
+ if (dev->w_busy || dev->r_busy) {
init_timer(&dev->error_recover_timer);
dev->error_recover_timer.expires = jiffies + ERRTIME;
add_timer(&dev->error_recover_timer);
return;
}
-
dev->w_busy = dev->r_busy = 1;
- if (dev->read_frame)
- {
- if (dev->read_frame->skb)
- {
- dev->read_frame->skb->free = 1;
- kfree_skb(dev->read_frame->skb, FREE_READ);
+ if (dev->read_frame) {
+ if (dev->read_frame->skb) {
+ SET_SKB_FREE(dev->read_frame->skb);
+ kfree_skb(dev->read_frame->skb, FREE_READ);
}
- kfree(dev->read_frame);
- dev->read_frame = NULL;
- }
-
-
- if (dev->write_queue)
- {
- frame = dev->write_queue;
+ kfree(dev->read_frame);
+ dev->read_frame = NULL;
+ }
+ if (dev->write_queue) {
+ frame = dev->write_queue;
#ifdef FREE_ON_ERROR
- dev->write_queue = dev->write_queue->next;
+ dev->write_queue = dev->write_queue->next;
if (frame->skb) {
- dev_kfree_skb(frame->skb, FREE_WRITE);
+ dev_kfree_skb(frame->skb, FREE_WRITE);
}
-
- kfree(frame);
-#else
- frame->copied = 0;
+ kfree(frame);
+#else
+ frame->copied = 0;
#endif
- }
-
- dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
- dev->free = 511;
- dev->l2_state = L2_ERROR;
+ }
+ dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
+ dev->free = 511;
+ dev->l2_state = L2_ERROR;
/* this is an hack... */
pcbit_firmware_bug(dev);
- dev->writeptr = dev->sh_mem;
- dev->readptr = dev->sh_mem + BANK2;
+ dev->writeptr = dev->sh_mem;
+ dev->readptr = dev->sh_mem + BANK2;
writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
dev->sh_mem + BANK4);
}
-static void pcbit_l2_error(struct pcbit_dev *dev)
+static void
+pcbit_l2_error(struct pcbit_dev *dev)
{
- if (dev->l2_state == L2_RUNNING) {
+ if (dev->l2_state == L2_RUNNING) {
- printk(KERN_INFO "pcbit: layer 2 error\n");
+ printk(KERN_INFO "pcbit: layer 2 error\n");
#ifdef DEBUG
- log_state(dev);
+ log_state(dev);
#endif
-
- dev->l2_state = L2_DOWN;
-
- init_timer(&dev->error_recover_timer);
- dev->error_recover_timer.function = &pcbit_l2_err_recover;
- dev->error_recover_timer.data = (ulong) dev;
- dev->error_recover_timer.expires = jiffies + ERRTIME;
- add_timer(&dev->error_recover_timer);
- }
+
+ dev->l2_state = L2_DOWN;
+
+ init_timer(&dev->error_recover_timer);
+ dev->error_recover_timer.function = &pcbit_l2_err_recover;
+ dev->error_recover_timer.data = (ulong) dev;
+ dev->error_recover_timer.expires = jiffies + ERRTIME;
+ add_timer(&dev->error_recover_timer);
+ }
}
/*
* call pcbit_transmit to write possible queued frames
*/
-static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
+static void
+pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
{
- int i, count;
- int unacked;
+ int i,
+ count;
+ int unacked;
- unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07;
+ unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
- /* dev->unack_seq < ack <= dev->send_seq; */
+ /* dev->unack_seq < ack <= dev->send_seq; */
- if (unacked)
- {
+ if (unacked) {
if (dev->send_seq > dev->unack_seq)
- if (ack <= dev->unack_seq || ack > dev->send_seq)
- {
- printk(KERN_DEBUG
- "layer 2 ack unacceptable - dev %d",
+ if (ack <= dev->unack_seq || ack > dev->send_seq) {
+ printk(KERN_DEBUG
+ "layer 2 ack unacceptable - dev %d",
dev->id);
- pcbit_l2_error(dev);
- }
- else
- if (ack > dev->send_seq && ack <= dev->unack_seq)
- {
- printk(KERN_DEBUG
- "layer 2 ack unacceptable - dev %d",
- dev->id);
- pcbit_l2_error(dev);
- }
-
- /* ack is acceptable */
+ pcbit_l2_error(dev);
+ } else if (ack > dev->send_seq && ack <= dev->unack_seq) {
+ printk(KERN_DEBUG
+ "layer 2 ack unacceptable - dev %d",
+ dev->id);
+ pcbit_l2_error(dev);
+ }
+ /* ack is acceptable */
- i = dev->unack_seq;
+ i = dev->unack_seq;
- do {
- dev->unack_seq = i = (i + 1) % 8;
- dev->free += dev->fsize[i];
- } while (i != ack);
+ do {
+ dev->unack_seq = i = (i + 1) % 8;
+ dev->free += dev->fsize[i];
+ } while (i != ack);
- count = 0;
- while (count < 7 && dev->write_queue)
- {
+ count = 0;
+ while (count < 7 && dev->write_queue) {
u8 lsend_seq = dev->send_seq;
- pcbit_transmit(dev);
+ pcbit_transmit(dev);
if (dev->send_seq == lsend_seq)
break;
- count++;
- }
- }
- else
- printk(KERN_DEBUG "recv_ack: unacked = 0\n");
+ count++;
+ }
+ } else
+ printk(KERN_DEBUG "recv_ack: unacked = 0\n");
}
#include <linux/isdnif.h>
#include "pcbit.h"
-int mem[MAX_PCBIT_CARDS] = {0, };
-int irq[MAX_PCBIT_CARDS] = {0, };
+static int mem[MAX_PCBIT_CARDS] = {0, };
+static int irq[MAX_PCBIT_CARDS] = {0, };
int num_boards;
struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0};
extern int pcbit_init_dev(int board, int mem_base, int irq);
#ifdef MODULE
+#if (LINUX_VERSION_CODE > 0x020111)
+MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
+#endif
#define pcbit_init init_module
#endif
}
/* No symbols to export, hide all symbols */
+#if (LINUX_VERSION_CODE < 0x020111)
register_symtab(NULL);
+#else
+ EXPORT_NO_SYMBOLS;
+#endif
return 0;
}
--- /dev/null
+#
+# $Id: Makefile,v 1.1 1997/03/22 02:01:22 fritz Exp $
+# Copyright (C) 1996 SpellCaster Telecommunications Inc.
+#
+# 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.
+#
+# For more information, please contact gpl-info@spellcast.com or write:
+#
+# SpellCaster Telecommunications Inc.
+# 5621 Finch Avenue East, Unit #3
+# Scarborough, Ontario Canada
+# M1B 2T9
+# +1 (416) 297-8565
+# +1 (416) 297-6433 Facsimile
+#
+
+L_OBJS :=
+M_OBJS :=
+O_OBJS := shmem.o init.o debug.o packet.o command.o event.o \
+ ioctl.o interrupt.o message.o timer.o
+
+O_TARGET :=
+ifeq ($(CONFIG_ISDN_DRV_SC),y)
+ O_TARGET += sc.o
+else
+ ifeq ($(CONFIG_ISDN_DRV_SC),m)
+ O_TARGET += sc.o
+ M_OBJS += sc.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * $Id: card.h,v 1.1 1996/11/07 13:07:40 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * card.h - Driver parameters for SpellCaster ISA ISDN adapters
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#ifndef CARD_H
+#define CARD_H
+
+/*
+ * We need these if they're not already included
+ */
+#include <linux/timer.h>
+#include <linux/isdnif.h>
+#include "message.h"
+
+/*
+ * Amount of time to wait for a reset to complete
+ */
+#define CHECKRESET_TIME milliseconds(4000)
+
+/*
+ * Amount of time between line status checks
+ */
+#define CHECKSTAT_TIME milliseconds(8000)
+
+/*
+ * The maximum amount of time to wait for a message response
+ * to arrive. Use exclusively by send_and_receive
+ */
+#define SAR_TIMEOUT milliseconds(10000)
+
+/*
+ * Macro to determine is a card id is valid
+ */
+#define IS_VALID_CARD(x) ((x >= 0) && (x <= cinst))
+
+/*
+ * Per channel status and configuration
+ */
+typedef struct {
+ int l2_proto;
+ int l3_proto;
+ char dn[50];
+ unsigned long first_sendbuf; /* Offset of first send buffer */
+ unsigned int num_sendbufs; /* Number of send buffers */
+ unsigned int free_sendbufs; /* Number of free sendbufs */
+ unsigned int next_sendbuf; /* Next sequential buffer */
+ char eazlist[50]; /* Set with SETEAZ */
+ char sillist[50]; /* Set with SETSIL */
+ int eazclear; /* Don't accept calls if TRUE */
+} bchan;
+
+/*
+ * Everything you want to know about the adapter ...
+ */
+typedef struct {
+ int model;
+ int driverId; /* LL Id */
+ char devicename[20]; /* The device name */
+ isdn_if *card; /* ISDN4Linux structure */
+ bchan *channel; /* status of the B channels */
+ char nChannels; /* Number of channels */
+ unsigned int interrupt; /* Interrupt number */
+ int iobase; /* I/O Base address */
+ int ioport[MAX_IO_REGS]; /* Index to I/O ports */
+ int shmem_pgport; /* port for the exp mem page reg. */
+ int shmem_magic; /* adapter magic number */
+ unsigned int rambase; /* Shared RAM base address */
+ unsigned int ramsize; /* Size of shared memory */
+ RspMessage async_msg; /* Async response message */
+ int want_async_messages; /* Snoop the Q ? */
+ unsigned char seq_no; /* Next send seq. number */
+ struct timer_list reset_timer; /* Check reset timer */
+ struct timer_list stat_timer; /* Check startproc timer */
+ unsigned char nphystat; /* Latest PhyStat info */
+ unsigned char phystat; /* Last PhyStat info */
+ HWConfig_pl hwconfig; /* Hardware config info */
+ char load_ver[11]; /* CommManage Version string */
+ char proc_ver[11]; /* CommEngine Version */
+ int StartOnReset; /* Indicates startproc after reset */
+ int EngineUp; /* Indicates CommEngine Up */
+ int trace_mode; /* Indicate if tracing is on */
+} board;
+
+#endif /* CARD_H */
--- /dev/null
+/*
+ * $Id: command.c,v 1.4 1997/03/30 16:51:34 calle Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h" /* This must be first */
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+#include "scioc.h"
+
+int dial(int card, unsigned long channel, setup_parm setup);
+int hangup(int card, unsigned long channel);
+int answer(int card, unsigned long channel);
+int clreaz(int card, unsigned long channel);
+int seteaz(int card, unsigned long channel, char *);
+int geteaz(int card, unsigned long channel, char *);
+int setsil(int card, unsigned long channel, char *);
+int getsil(int card, unsigned long channel, char *);
+int setl2(int card, unsigned long arg);
+int getl2(int card, unsigned long arg);
+int setl3(int card, unsigned long arg);
+int getl3(int card, unsigned long arg);
+int lock(void);
+int unlock(void);
+int acceptb(int card, unsigned long channel);
+
+extern int cinst;
+extern board *adapter[];
+
+extern int sc_ioctl(int, scs_ioctl *);
+extern int setup_buffers(int, int, unsigned int);
+extern int indicate_status(int, int,ulong,char*);
+extern void check_reset(unsigned long);
+extern int send_and_receive(int, unsigned int, unsigned char, unsigned char,
+ unsigned char, unsigned char, unsigned char, unsigned char *,
+ RspMessage *, int);
+extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int, unsigned int *);
+extern inline void pullphone(char *, char *);
+
+#ifdef DEBUG
+/*
+ * Translate command codes to strings
+ */
+static char *commands[] = { "ISDN_CMD_IOCTL",
+ "ISDN_CMD_DIAL",
+ "ISDN_CMD_ACCEPTB",
+ "ISDN_CMD_ACCEPTB",
+ "ISDN_CMD_HANGUP",
+ "ISDN_CMD_CLREAZ",
+ "ISDN_CMD_SETEAZ",
+ "ISDN_CMD_GETEAZ",
+ "ISDN_CMD_SETSIL",
+ "ISDN_CMD_GETSIL",
+ "ISDN_CMD_SETL2",
+ "ISDN_CMD_GETL2",
+ "ISDN_CMD_SETL3",
+ "ISDN_CMD_GETL3",
+ "ISDN_CMD_LOCK",
+ "ISDN_CMD_UNLOCK",
+ "ISDN_CMD_SUSPEND",
+ "ISDN_CMD_RESUME" };
+
+/*
+ * Translates ISDN4Linux protocol codes to strings for debug messages
+ */
+static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" };
+static char *l2protos[] = { "ISDN_PROTO_L2_X75I",
+ "ISDN_PROTO_L2_X75UI",
+ "ISDN_PROTO_L2_X75BUI",
+ "ISDN_PROTO_L2_HDLC",
+ "ISDN_PROTO_L2_TRANS" };
+#endif
+
+int get_card_from_id(int driver)
+{
+ int i;
+
+ for(i = 0 ; i < cinst ; i++) {
+ if(adapter[i]->driverId == driver)
+ return i;
+ }
+ return -NODEV;
+}
+
+/*
+ * command
+ */
+
+int command(isdn_ctrl *cmd)
+{
+ int card;
+
+ card = get_card_from_id(cmd->driver);
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ pr_debug("%s: Received %s command from Link Layer\n",
+ adapter[card]->devicename, commands[cmd->command]);
+
+ /*
+ * Dispatch the command
+ */
+ switch(cmd->command) {
+ case ISDN_CMD_IOCTL:
+ {
+ unsigned long cmdptr;
+ scs_ioctl ioc;
+ int err;
+
+ memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long));
+ if((err = copy_from_user(&ioc, (scs_ioctl *) cmdptr,
+ sizeof(scs_ioctl)))) {
+ pr_debug("%s: Failed to verify user space 0x%x\n",
+ adapter[card]->devicename, cmdptr);
+ return err;
+ }
+ return sc_ioctl(card, &ioc);
+ }
+ case ISDN_CMD_DIAL:
+ return dial(card, cmd->arg, cmd->parm.setup);
+ case ISDN_CMD_HANGUP:
+ return hangup(card, cmd->arg);
+ case ISDN_CMD_ACCEPTD:
+ return answer(card, cmd->arg);
+ case ISDN_CMD_ACCEPTB:
+ return acceptb(card, cmd->arg);
+ case ISDN_CMD_CLREAZ:
+ return clreaz(card, cmd->arg);
+ case ISDN_CMD_SETEAZ:
+ return seteaz(card, cmd->arg, cmd->parm.num);
+ case ISDN_CMD_GETEAZ:
+ return geteaz(card, cmd->arg, cmd->parm.num);
+ case ISDN_CMD_SETSIL:
+ return setsil(card, cmd->arg, cmd->parm.num);
+ case ISDN_CMD_GETSIL:
+ return getsil(card, cmd->arg, cmd->parm.num);
+ case ISDN_CMD_SETL2:
+ return setl2(card, cmd->arg);
+ case ISDN_CMD_GETL2:
+ return getl2(card, cmd->arg);
+ case ISDN_CMD_SETL3:
+ return setl3(card, cmd->arg);
+ case ISDN_CMD_GETL3:
+ return getl3(card, cmd->arg);
+ case ISDN_CMD_LOCK:
+ return lock();
+ case ISDN_CMD_UNLOCK:
+ return unlock();
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Confirm our ability to communicate with the board. This test assumes no
+ * other message activity is present
+ */
+int loopback(int card)
+{
+
+ int status;
+ static char testmsg[] = "Test Message";
+ RspMessage rspmsg;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ pr_debug("%s: Sending loopback message\n", adapter[card]->devicename);
+
+
+ /*
+ * Send the loopback message to confirm that memory transfer is
+ * operational
+ */
+ status = send_and_receive(card, CMPID, cmReqType1,
+ cmReqClass0,
+ cmReqMsgLpbk,
+ 0,
+ (unsigned char) strlen(testmsg),
+ (unsigned char *)testmsg,
+ &rspmsg, SAR_TIMEOUT);
+
+
+ if (!status) {
+ pr_debug("%s: Loopback message successfully sent\n",
+ adapter[card]->devicename);
+ if(strcmp(rspmsg.msg_data.byte_array, testmsg)) {
+ pr_debug("%s: Loopback return != sent\n",
+ adapter[card]->devicename);
+ return -EIO;
+ }
+ return 0;
+ }
+ else {
+ pr_debug("%s: Send loopback message failed\n",
+ adapter[card]->devicename);
+ return -EIO;
+ }
+
+}
+
+/*
+ * start the onboard firmware
+ */
+int startproc(int card)
+{
+ int status;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ /*
+ * send start msg
+ */
+ status = sendmessage(card, CMPID,cmReqType2,
+ cmReqClass0,
+ cmReqStartProc,
+ 0,0,0);
+ pr_debug("%s: Sent startProc\n", adapter[card]->devicename);
+
+ return status;
+}
+
+
+int loadproc(int card, char *data)
+{
+ return -1;
+}
+
+
+/*
+ * Dials the number passed in
+ */
+int dial(int card, unsigned long channel, setup_parm setup)
+{
+ int status;
+ char Phone[48];
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ /*extract ISDN number to dial from eaz/msn string*/
+ strcpy(Phone,setup.phone);
+
+ /*send the connection message*/
+ status = sendmessage(card, CEPID,ceReqTypePhy,
+ ceReqClass1,
+ ceReqPhyConnect,
+ (unsigned char) channel+1,
+ strlen(Phone),
+ (unsigned int *) Phone);
+
+ pr_debug("%s: Dialing %s on channel %d\n",
+ adapter[card]->devicename, Phone, channel+1);
+
+ return status;
+}
+
+/*
+ * Answer an incoming call
+ */
+int answer(int card, unsigned long channel)
+{
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ if(setup_buffers(card, channel+1, BUFFER_SIZE)) {
+ hangup(card, channel+1);
+ return -ENOBUFS;
+ }
+
+ indicate_status(card, ISDN_STAT_BCONN,channel,NULL);
+ pr_debug("%s: Answered incoming call on channel %s\n",
+ adapter[card]->devicename, channel+1);
+ return 0;
+}
+
+/*
+ * Hangup up the call on specified channel
+ */
+int hangup(int card, unsigned long channel)
+{
+ int status;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ status = sendmessage(card, CEPID, ceReqTypePhy,
+ ceReqClass1,
+ ceReqPhyDisconnect,
+ (unsigned char) channel+1,
+ 0,
+ NULL);
+ pr_debug("%s: Sent HANGUP message to channel %d\n",
+ adapter[card]->devicename, channel+1);
+ return status;
+}
+
+/*
+ * Set the layer 2 protocol (X.25, HDLC, Raw)
+ */
+int setl2(int card, unsigned long arg)
+{
+ int status =0;
+ int protocol,channel;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+ protocol = arg >> 8;
+ channel = arg & 0xff;
+ adapter[card]->channel[channel].l2_proto = protocol;
+ pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n",
+ adapter[card]->devicename, channel+1,l2protos[adapter[card]->channel[channel].l2_proto],protocol);
+
+ /*
+ * check that the adapter is also set to the correct protocol
+ */
+ pr_debug("%s: Sending GetFrameFormat for channel %d\n",
+ adapter[card]->devicename, channel+1);
+ status = sendmessage(card, CEPID, ceReqTypeCall,
+ ceReqClass0,
+ ceReqCallGetFrameFormat,
+ (unsigned char)channel+1,
+ 1,
+ (unsigned int *) protocol);
+ if(status)
+ return status;
+ return 0;
+}
+
+/*
+ * Get the layer 2 protocol
+ */
+int getl2(int card, unsigned long channel) {
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ pr_debug("%s: Level 2 protocol for channel %d reported as %s\n",
+ adapter[card]->devicename, channel+1,
+ l2protos[adapter[card]->channel[channel].l2_proto]);
+
+ return adapter[card]->channel[channel].l2_proto;
+}
+
+/*
+ * Set the layer 3 protocol
+ */
+int setl3(int card, unsigned long channel)
+{
+ int protocol = channel >> 8;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ adapter[card]->channel[channel].l3_proto = protocol;
+ pr_debug("%s: Level 3 protocol for channel %d set to %s\n",
+ adapter[card]->devicename, channel+1, l3protos[protocol]);
+ return 0;
+}
+
+/*
+ * Get the layer 3 protocol
+ */
+int getl3(int card, unsigned long arg)
+{
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ pr_debug("%s: Level 3 protocol for channel %d reported as %s\n",
+ adapter[card]->devicename, arg+1,
+ l3protos[adapter[card]->channel[arg].l3_proto]);
+ return adapter[card]->channel[arg].l3_proto;
+}
+
+
+int acceptb(int card, unsigned long channel)
+{
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ if(setup_buffers(card, channel+1, BUFFER_SIZE))
+ {
+ hangup(card, channel+1);
+ return -ENOBUFS;
+ }
+
+ pr_debug("%s: B-Channel connection accepted on channel %d\n",
+ adapter[card]->devicename, channel+1);
+ indicate_status(card, ISDN_STAT_BCONN, channel, NULL);
+ return 0;
+}
+
+int clreaz(int card, unsigned long arg)
+{
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ strcpy(adapter[card]->channel[arg].eazlist, "");
+ adapter[card]->channel[arg].eazclear = 1;
+ pr_debug("%s: EAZ List cleared for channel %d\n",
+ adapter[card]->devicename, arg+1);
+ return 0;
+}
+
+int seteaz(int card, unsigned long arg, char *num)
+{
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ strcpy(adapter[card]->channel[arg].eazlist, num);
+ adapter[card]->channel[arg].eazclear = 0;
+ pr_debug("%s: EAZ list for channel %d set to: %s\n",
+ adapter[card]->devicename, arg+1,
+ adapter[card]->channel[arg].eazlist);
+ return 0;
+}
+
+int geteaz(int card, unsigned long arg, char *num)
+{
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ strcpy(num, adapter[card]->channel[arg].eazlist);
+ pr_debug("%s: EAZ List for channel %d reported: %s\n",
+ adapter[card]->devicename, arg+1,
+ adapter[card]->channel[arg].eazlist);
+ return 0;
+}
+
+int setsil(int card, unsigned long arg, char *num)
+{
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ strcpy(adapter[card]->channel[arg].sillist, num);
+ pr_debug("%s: Service Indicators for channel %d set: %s\n",
+ adapter[card]->devicename, arg+1,
+ adapter[card]->channel[arg].sillist);
+ return 0;
+}
+
+int getsil(int card, unsigned long arg, char *num)
+{
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ strcpy(num, adapter[card]->channel[arg].sillist);
+ pr_debug("%s: SIL for channel %d reported: %s\n",
+ adapter[card]->devicename, arg+1,
+ adapter[card]->channel[arg].sillist);
+ return 0;
+}
+
+
+int lock()
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+int unlock()
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+int reset(int card)
+{
+ unsigned long flags;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ indicate_status(card, ISDN_STAT_STOP, 0, NULL);
+
+ if(adapter[card]->EngineUp) {
+ del_timer(&adapter[card]->stat_timer);
+ }
+
+ adapter[card]->EngineUp = 0;
+
+ save_flags(flags);
+ cli();
+ init_timer(&adapter[card]->reset_timer);
+ adapter[card]->reset_timer.function = check_reset;
+ adapter[card]->reset_timer.data = card;
+ adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
+ add_timer(&adapter[card]->reset_timer);
+ restore_flags(flags);
+
+ outb(0x1,adapter[card]->ioport[SFT_RESET]);
+
+ pr_debug("%s: Adapter Reset\n", adapter[card]->devicename);
+ return 0;
+}
+
+void flushreadfifo (int card)
+{
+ while(inb(adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA)
+ inb(adapter[card]->ioport[FIFO_READ]);
+}
--- /dev/null
+/*
+ * $Id: debug.c,v 1.2 1996/11/20 17:49:50 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+#include <linux/kernel.h>
+
+#define NULL 0x0
+
+#if LINUX_VERSION_CODE < 66363 /* Linux 1.3.59 there was a change to interrupts */
+ #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d)
+ #define FREE_IRQ(a,b) free_irq(a)
+#else
+ #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
+ #define FREE_IRQ(a,b) free_irq(a,b)
+#endif
+
+inline char *strcpy(char *, const char *);
+
+int dbg_level = 0;
+static char dbg_funcname[255];
+
+void dbg_endfunc(void)
+{
+ if (dbg_level) {
+ printk("<-- Leaving function %s\n", dbg_funcname);
+ strcpy(dbg_funcname, "");
+ }
+}
+
+void dbg_func(char *func)
+{
+ strcpy(dbg_funcname, func);
+ if(dbg_level)
+ printk("--> Entering function %s\n", dbg_funcname);
+}
+
+inline char *strcpy(char *dest, const char *src)
+{
+ char *i = dest;
+ char *j = (char *) src;
+
+ while(*j) {
+ *i = *j;
+ i++; j++;
+ }
+ *(++i) = NULL;
+ return dest;
+}
+
+inline void pullphone(char *dn, char *str)
+{
+ int i = 0;
+
+ while(dn[i] != ',')
+ str[i] = dn[i++];
+ str[i] = 0x0;
+}
--- /dev/null
+/*
+ * $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#if LINUX_VERSION_CODE < 131072
+ #error You cant use this driver on kernels older than 2.0
+#else
+ #define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
+ #define FREE_IRQ(a,b) free_irq(a,b)
+#endif
+
--- /dev/null
+/*
+ * $Id: event.c,v 1.3 1997/02/11 22:53:41 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern int cinst;
+extern board *adapter[];
+
+#ifdef DEBUG
+static char *events[] = { "ISDN_STAT_STAVAIL",
+ "ISDN_STAT_ICALL",
+ "ISDN_STAT_RUN",
+ "ISDN_STAT_STOP",
+ "ISDN_STAT_DCONN",
+ "ISDN_STAT_BCONN",
+ "ISDN_STAT_DHUP",
+ "ISDN_STAT_BHUP",
+ "ISDN_STAT_CINF",
+ "ISDN_STAT_LOAD",
+ "ISDN_STAT_UNLOAD",
+ "ISDN_STAT_BSENT",
+ "ISDN_STAT_NODCH",
+ "ISDN_STAT_ADDCH",
+ "ISDN_STAT_CAUSE" };
+#endif
+
+int indicate_status(int card, int event,ulong Channel,char *Data)
+{
+ isdn_ctrl cmd;
+
+ pr_debug("%s: Indicating event %s on Channel %d\n",
+ adapter[card]->devicename, events[event-256], Channel);
+ if (Data != NULL){
+ pr_debug("%s: Event data: %s\n", adapter[card]->devicename,
+ Data);
+ if (event == ISDN_STAT_ICALL)
+ memcpy(&cmd.parm.setup, Data, sizeof(cmd.parm.setup));
+ else
+ strcpy(cmd.parm.num, Data);
+ }
+
+ cmd.command = event;
+ cmd.driver = adapter[card]->driverId;
+ cmd.arg = Channel;
+ return adapter[card]->card->statcallb(&cmd);
+}
--- /dev/null
+/*
+ * Hardware specific macros, defines and structures
+ */
+
+#ifndef HARDWARE_H
+#define HARDWARE_H
+
+#include <asm/param.h> /* For HZ */
+
+/*
+ * General hardware parameters common to all ISA adapters
+ */
+
+#define MAX_CARDS 4 /* The maximum number of cards to
+ control or probe for. If you change
+ this, you must also change the number
+ of elements in io, irq, and ram to
+ match. Initialized in init.c */
+/*
+extern unsigned int io[];
+extern unsigned char irq[];
+extern unsigned long ram[];
+*/
+
+#define SIGNATURE 0x87654321 /* Board reset signature */
+#define SIG_OFFSET 0x1004 /* Where to find signature in shared RAM */
+#define TRACE_OFFSET 0x1008 /* Trace enable word offset in shared RAM */
+#define BUFFER_OFFSET 0x1800 /* Beginning of buffers */
+
+/* I/O Port parameters */
+#define IOBASE_MIN 0x180 /* Lowest I/O port address */
+#define IOBASE_MAX 0x3C0 /* Highest I/O port address */
+#define IOBASE_OFFSET 0x20 /* Inter-board I/O port gap used during
+ probing */
+#define FIFORD_OFFSET 0x0
+#define FIFOWR_OFFSET 0x400
+#define FIFOSTAT_OFFSET 0x1000
+#define RESET_OFFSET 0x2800
+#define PG0_OFFSET 0x3000 /* Offset from I/O Base for Page 0 register */
+#define PG1_OFFSET 0x3400 /* Offset from I/O Base for Page 1 register */
+#define PG2_OFFSET 0x3800 /* Offset from I/O Base for Page 2 register */
+#define PG3_OFFSET 0x3C00 /* Offset from I/O Base for Page 3 register */
+
+#define FIFO_READ 0 /* FIFO Read register */
+#define FIFO_WRITE 1 /* FIFO Write rgister */
+#define LO_ADDR_PTR 2 /* Extended RAM Low Addr Pointer */
+#define HI_ADDR_PTR 3 /* Extended RAM High Addr Pointer */
+#define NOT_USED_1 4
+#define FIFO_STATUS 5 /* FIFO Status Register */
+#define NOT_USED_2 6
+#define MEM_OFFSET 7
+#define SFT_RESET 10 /* Reset Register */
+#define EXP_BASE 11 /* Shared RAM Base address */
+#define EXP_PAGE0 12 /* Shared RAM Page0 register */
+#define EXP_PAGE1 13 /* Shared RAM Page1 register */
+#define EXP_PAGE2 14 /* Shared RAM Page2 register */
+#define EXP_PAGE3 15 /* Shared RAM Page3 register */
+#define IRQ_SELECT 16 /* IRQ selection register */
+#define MAX_IO_REGS 17 /* Total number of I/O ports */
+
+/* FIFO register values */
+#define RF_HAS_DATA 0x01 /* fifo has data */
+#define RF_QUART_FULL 0x02 /* fifo quarter full */
+#define RF_HALF_FULL 0x04 /* fifo half full */
+#define RF_NOT_FULL 0x08 /* fifo not full */
+#define WF_HAS_DATA 0x10 /* fifo has data */
+#define WF_QUART_FULL 0x20 /* fifo quarter full */
+#define WF_HALF_FULL 0x40 /* fifo half full */
+#define WF_NOT_FULL 0x80 /* fifo not full */
+
+/* Shared RAM parameters */
+#define SRAM_MIN 0xC0000 /* Lowest host shared RAM address */
+#define SRAM_MAX 0xEFFFF /* Highest host shared RAM address */
+#define SRAM_PAGESIZE 0x4000 /* Size of one RAM page (16K) */
+
+/* Shared RAM buffer parameters */
+#define BUFFER_SIZE 0x800 /* The size of a buffer in bytes */
+#define BUFFER_BASE BUFFER_OFFSET /* Offset from start of shared RAM
+ where buffer start */
+#define BUFFERS_MAX 16 /* Maximum number of send/receive
+ buffers per channel */
+#define HDLC_PROTO 0x01 /* Frame Format for Layer 2 */
+
+#define BRI_BOARD 0
+#define POTS_BOARD 1
+#define PRI_BOARD 2
+
+/*
+ * Specific hardware parameters for the DataCommute/BRI
+ */
+#define BRI_CHANNELS 2 /* Number of B channels */
+#define BRI_BASEPG_VAL 0x98
+#define BRI_MAGIC 0x60000 /* Magic Number */
+#define BRI_MEMSIZE 0x10000 /* Ammount of RAM (64K) */
+#define BRI_PARTNO "72-029"
+#define BRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
+/*
+ * Specific hardware parameters for the DataCommute/PRI
+ */
+#define PRI_CHANNELS 23 /* Number of B channels */
+#define PRI_BASEPG_VAL 0x88
+#define PRI_MAGIC 0x20000 /* Magic Number */
+#define PRI_MEMSIZE 0x100000 /* Amount of RAM (1M) */
+#define PRI_PARTNO "72-030"
+#define PRI_FEATURES ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L3_TRANS;
+
+/*
+ * Some handy macros
+ */
+
+/* Return the number of jiffies in a given number of msecs */
+#define milliseconds(x) (x/(1000/HZ))
+
+/* Determine if a channel number is valid for the adapter */
+#define IS_VALID_CHANNEL(y,x) ((x>0) && (x <= adapter[y]->channels))
+
+#endif
--- /dev/null
+#include <linux/module.h>
+#include <linux/version.h>
+#include <stdio.h>
+#include <linux/errno.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/isdnif.h>
+#include "debug.h"
--- /dev/null
+#include "includes.h"
+#include "hardware.h"
+#include "card.h"
+
+board *adapter[MAX_CARDS];
+int cinst;
+
+static char devname[] = "scX";
+const char version[] = "2.0b1";
+
+const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" };
+
+/* insmod set parameters */
+unsigned int io[] = {0,0,0,0};
+unsigned char irq[] = {0,0,0,0};
+unsigned long ram[] = {0,0,0,0};
+int do_reset = 0;
+
+static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 };
+#define MAX_IRQS 10
+
+extern void interrupt_handler(int, void *, struct pt_regs *);
+extern int sndpkt(int, int, struct sk_buff *);
+extern int command(isdn_ctrl *);
+extern int indicate_status(int, int, ulong, char*);
+extern int reset(int);
+
+int identify_board(unsigned long, unsigned int);
+
+int irq_supported(int irq_x)
+{
+ int i;
+ for(i=0 ; i < MAX_IRQS ; i++) {
+ if(sup_irq[i] == irq_x)
+ return 1;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE > 0x020111)
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(irq, "1-4i");
+MODULE_PARM(ram, "1-4i");
+MODULE_PARM(do_reset, "i");
+#endif
+#define init_sc init_module
+#else
+/*
+Initialization code for non-module version to be included
+
+void sc_setup(char *str, int *ints)
+{
+}
+*/
+#endif
+
+int init_sc(void)
+{
+ int b = -1;
+ int i, j;
+ int status = -ENODEV;
+
+ unsigned long memsize = 0;
+ unsigned long features = 0;
+ isdn_if *interface;
+ unsigned char channels;
+ unsigned char pgport;
+ unsigned long magic;
+ int model;
+ int last_base = IOBASE_MIN;
+ int probe_exhasted = 0;
+
+#ifdef MODULE
+ pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s Loaded\n", version);
+#else
+ pr_info("SpellCaster ISA ISDN Adapter Driver rev. %s\n", version);
+#endif
+ pr_info("Copyright (C) 1996 SpellCaster Telecommunications Inc.\n");
+
+ while(b++ < MAX_CARDS - 1) {
+ pr_debug("Probing for adapter #%d\n", b);
+ /*
+ * Initialize reusable variables
+ */
+ model = -1;
+ magic = 0;
+ channels = 0;
+ pgport = 0;
+
+ /*
+ * See if we should probe for IO base
+ */
+ pr_debug("I/O Base for board %d is 0x%x, %s probe\n", b, io[b],
+ io[b] == 0 ? "will" : "won't");
+ if(io[b]) {
+ /*
+ * No, I/O Base has been provided
+ */
+ for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
+ if(check_region(io[b] + i * 0x400, 1)) {
+ pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400);
+ io[b] = 0;
+ break;
+ }
+ }
+
+ /*
+ * Confirm the I/O Address with a test
+ */
+ if(io[b] == 0) {
+ pr_debug("I/O Address 0x%x is in use.\n");
+ continue;
+ }
+
+ outb(0x18, io[b] + 0x400 * EXP_PAGE0);
+ if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
+ pr_debug("I/O Base 0x%x fails test\n");
+ continue;
+ }
+ }
+ else {
+ /*
+ * Yes, probe for I/O Base
+ */
+ if(probe_exhasted) {
+ pr_debug("All probe addresses exhasted, skipping\n");
+ continue;
+ }
+ pr_debug("Probing for I/O...\n");
+ for (i = last_base ; i <= IOBASE_MAX ; i += IOBASE_OFFSET) {
+ int found_io = 1;
+ if (i == IOBASE_MAX) {
+ probe_exhasted = 1; /* No more addresses to probe */
+ pr_debug("End of Probes\n");
+ }
+ last_base = i + IOBASE_OFFSET;
+ pr_debug(" checking 0x%x...", i);
+ for ( j = 0 ; j < MAX_IO_REGS - 1 ; j++) {
+ if(check_region(i + j * 0x400, 1)) {
+ pr_debug("Failed\n");
+ found_io = 0;
+ break;
+ }
+ }
+
+ if(found_io) {
+ io[b] = i;
+ outb(0x18, io[b] + 0x400 * EXP_PAGE0);
+ if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
+ pr_debug("Failed by test\n");
+ continue;
+ }
+ pr_debug("Passed\n");
+ break;
+ }
+ }
+ if(probe_exhasted) {
+ continue;
+ }
+ }
+
+ /*
+ * See if we should probe for shared RAM
+ */
+ if(do_reset) {
+ pr_debug("Doing a SAFE probe reset\n");
+ outb(0xFF, io[b] + RESET_OFFSET);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + milliseconds(10000);
+ schedule();
+ }
+ pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
+ ram[b] == 0 ? "will" : "won't");
+
+ if(ram[b]) {
+ /*
+ * No, the RAM base has been provided
+ * Just look for a signature and ID the
+ * board model
+ */
+ if(!check_region(ram[b], SRAM_PAGESIZE)) {
+ pr_debug("check_region for RAM base 0x%x succeeded\n", ram[b]);
+ model = identify_board(ram[b], io[b]);
+ }
+ }
+ else {
+ /*
+ * Yes, probe for free RAM and look for
+ * a signature and id the board model
+ */
+ for (i = SRAM_MIN ; i < SRAM_MAX ; i += SRAM_PAGESIZE) {
+ pr_debug("Checking RAM address 0x%x...\n", i);
+ if(!check_region(i, SRAM_PAGESIZE)) {
+ pr_debug(" check_region succeeded\n");
+ model = identify_board(i, io[b]);
+ if (model >= 0) {
+ pr_debug(" Identified a %s\n",
+ boardname[model]);
+ ram[b] = i;
+ break;
+ }
+ pr_debug(" Unidentifed or inaccessible\n");
+ continue;
+ }
+ pr_debug(" check_region failed\n");
+ }
+ }
+ /*
+ * See if we found free RAM and the board model
+ */
+ if(!ram[b] || model < 0) {
+ /*
+ * Nope, there was no place in RAM for the
+ * board, or it couldn't be identified
+ */
+ pr_debug("Failed to find an adapter at 0x%x\n", ram[b]);
+ continue;
+ }
+
+ /*
+ * Set the board's magic number, memory size and page register
+ */
+ switch(model) {
+ case PRI_BOARD:
+ channels = 23;
+ magic = 0x20000;
+ memsize = 0x100000;
+ features = PRI_FEATURES;
+ break;
+
+ case BRI_BOARD:
+ case POTS_BOARD:
+ channels = 2;
+ magic = 0x60000;
+ memsize = 0x10000;
+ features = BRI_FEATURES;
+ break;
+ }
+ switch(ram[b] >> 12 & 0x0F) {
+ case 0x0:
+ pr_debug("RAM Page register set to EXP_PAGE0\n");
+ pgport = EXP_PAGE0;
+ break;
+
+ case 0x4:
+ pr_debug("RAM Page register set to EXP_PAGE1\n");
+ pgport = EXP_PAGE1;
+ break;
+
+ case 0x8:
+ pr_debug("RAM Page register set to EXP_PAGE2\n");
+ pgport = EXP_PAGE2;
+ break;
+
+ case 0xC:
+ pr_debug("RAM Page register set to EXP_PAGE3\n");
+ pgport = EXP_PAGE3;
+ break;
+
+ default:
+ pr_debug("RAM base address doesn't fall on 16K boundary\n");
+ continue;
+ }
+
+ pr_debug("current IRQ: %d b: %d\n",irq[b],b);
+ /*
+ * See if we should probe for an irq
+ */
+ if(irq[b]) {
+ /*
+ * No we were given one
+ * See that it is supported and free
+ */
+ pr_debug("Trying for IRQ: %d\n",irq[b]);
+ if (irq_supported(irq[b])) {
+ if(REQUEST_IRQ(irq[b], interrupt_handler,
+ SA_PROBE, "sc_probe", NULL)) {
+ pr_debug("IRQ %d is already in use\n",
+ irq[b]);
+ continue;
+ }
+ FREE_IRQ(irq[b], NULL);
+ }
+ }
+ else {
+ /*
+ * Yes, we need to probe for an IRQ
+ */
+ pr_debug("Probing for IRQ...\n");
+ for (i = 0; i < MAX_IRQS ; i++) {
+ if(!REQUEST_IRQ(sup_irq[i], interrupt_handler, SA_PROBE, "sc_probe", NULL)) {
+ pr_debug("Probed for and found IRQ %d\n", sup_irq[i]);
+ FREE_IRQ(sup_irq[i], NULL);
+ irq[b] = sup_irq[i];
+ break;
+ }
+ }
+ }
+
+ /*
+ * Make sure we got an IRQ
+ */
+ if(!irq[b]) {
+ /*
+ * No interrupt could be used
+ */
+ pr_debug("Failed to aquire an IRQ line\n");
+ continue;
+ }
+
+ /*
+ * Horray! We found a board, Make sure we can register
+ * it with ISDN4Linux
+ */
+ interface = kmalloc(sizeof(isdn_if), GFP_KERNEL);
+ if (interface == NULL) {
+ /*
+ * Oops, can't malloc isdn_if
+ */
+ continue;
+ }
+ memset(interface, 0, sizeof(isdn_if));
+
+ interface->hl_hdrlen = 0;
+ interface->channels = channels;
+ interface->maxbufsize = BUFFER_SIZE;
+ interface->features = features;
+ interface->writebuf_skb = sndpkt;
+ interface->writecmd = NULL;
+ interface->command = command;
+ strcpy(interface->id, devname);
+ interface->id[2] = '0' + cinst;
+
+ /*
+ * Allocate the board structure
+ */
+ adapter[cinst] = kmalloc(sizeof(board), GFP_KERNEL);
+ if (adapter[cinst] == NULL) {
+ /*
+ * Oops, can't alloc memory for the board
+ */
+ kfree(interface);
+ continue;
+ }
+ memset(adapter[cinst], 0, sizeof(board));
+
+ if(!register_isdn(interface)) {
+ /*
+ * Oops, couldn't register for some reason
+ */
+ kfree(interface);
+ kfree(adapter[cinst]);
+ continue;
+ }
+
+ adapter[cinst]->card = interface;
+ adapter[cinst]->driverId = interface->channels;
+ strcpy(adapter[cinst]->devicename, interface->id);
+ adapter[cinst]->nChannels = channels;
+ adapter[cinst]->ramsize = memsize;
+ adapter[cinst]->shmem_magic = magic;
+ adapter[cinst]->shmem_pgport = pgport;
+ adapter[cinst]->StartOnReset = 1;
+
+ /*
+ * Allocate channels status structures
+ */
+ adapter[cinst]->channel = kmalloc(sizeof(bchan) * channels, GFP_KERNEL);
+ if (adapter[cinst]->channel == NULL) {
+ /*
+ * Oops, can't alloc memory for the channels
+ */
+ indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */
+ kfree(interface);
+ kfree(adapter[cinst]);
+ continue;
+ }
+ memset(adapter[cinst]->channel, 0, sizeof(bchan) * channels);
+
+ /*
+ * Lock down the hardware resources
+ */
+ adapter[cinst]->interrupt = irq[b];
+ REQUEST_IRQ(adapter[cinst]->interrupt, interrupt_handler, SA_INTERRUPT,
+ interface->id, NULL);
+ adapter[cinst]->iobase = io[b];
+ for(i = 0 ; i < MAX_IO_REGS - 1 ; i++) {
+ adapter[cinst]->ioport[i] = io[b] + i * 0x400;
+ request_region(adapter[cinst]->ioport[i], 1, interface->id);
+ pr_debug("Requesting I/O Port %#x\n", adapter[cinst]->ioport[i]);
+ }
+ adapter[cinst]->ioport[IRQ_SELECT] = io[b] + 0x2;
+ request_region(adapter[cinst]->ioport[IRQ_SELECT], 1, interface->id);
+ pr_debug("Requesting I/O Port %#x\n", adapter[cinst]->ioport[IRQ_SELECT]);
+ adapter[cinst]->rambase = ram[b];
+ request_region(adapter[cinst]->rambase, SRAM_PAGESIZE, interface->id);
+
+ pr_info(" %s (%d) - %s %d channels IRQ %d, I/O Base 0x%x, RAM Base 0x%lx\n",
+ adapter[cinst]->devicename, adapter[cinst]->driverId,
+ boardname[model], channels, irq[b], io[b], ram[b]);
+
+ /*
+ * reset the adapter to put things in motion
+ */
+ reset(cinst);
+
+ cinst++;
+ status = 0;
+ }
+ if (status)
+ pr_info("Failed to find any adapters, driver unloaded\n");
+ return status;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ int i, j;
+
+ for(i = 0 ; i < cinst ; i++) {
+ pr_debug("Cleaning up after adapter %d\n", i);
+ /*
+ * kill the timers
+ */
+ del_timer(&(adapter[i]->reset_timer));
+ del_timer(&(adapter[i]->stat_timer));
+
+ /*
+ * Tell I4L we're toast
+ */
+ indicate_status(i, ISDN_STAT_STOP, 0, NULL);
+ indicate_status(i, ISDN_STAT_UNLOAD, 0, NULL);
+
+ /*
+ * Release shared RAM
+ */
+ release_region(adapter[i]->rambase, SRAM_PAGESIZE);
+
+ /*
+ * Release the IRQ
+ */
+ FREE_IRQ(adapter[i]->interrupt, NULL);
+
+ /*
+ * Reset for a clean start
+ */
+ outb(0xFF, adapter[i]->ioport[SFT_RESET]);
+
+ /*
+ * Release the I/O Port regions
+ */
+ for(j = 0 ; j < MAX_IO_REGS - 1; j++) {
+ release_region(adapter[i]->ioport[j], 1);
+ pr_debug("Releasing I/O Port %#x\n", adapter[i]->ioport[j]);
+ }
+ release_region(adapter[i]->ioport[IRQ_SELECT], 1);
+ pr_debug("Releasing I/O Port %#x\n", adapter[i]->ioport[IRQ_SELECT]);
+
+ /*
+ * Release any memory we alloced
+ */
+ kfree(adapter[i]->channel);
+ kfree(adapter[i]->card);
+ kfree(adapter[i]);
+ }
+ pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
+}
+#endif
+
+int identify_board(unsigned long rambase, unsigned int iobase)
+{
+ unsigned int pgport;
+ unsigned long sig;
+ DualPortMemory *dpm;
+ RspMessage rcvmsg;
+ ReqMessage sndmsg;
+ HWConfig_pl hwci;
+ int x;
+
+ pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n",
+ rambase, iobase);
+
+ /*
+ * Enable the base pointer
+ */
+ outb(rambase >> 12, iobase + 0x2c00);
+
+ switch(rambase >> 12 & 0x0F) {
+ case 0x0:
+ pgport = iobase + PG0_OFFSET;
+ pr_debug("Page Register offset is 0x%x\n", PG0_OFFSET);
+ break;
+
+ case 0x4:
+ pgport = iobase + PG1_OFFSET;
+ pr_debug("Page Register offset is 0x%x\n", PG1_OFFSET);
+ break;
+
+ case 0x8:
+ pgport = iobase + PG2_OFFSET;
+ pr_debug("Page Register offset is 0x%x\n", PG2_OFFSET);
+ break;
+
+ case 0xC:
+ pgport = iobase + PG3_OFFSET;
+ pr_debug("Page Register offset is 0x%x\n", PG3_OFFSET);
+ break;
+ default:
+ pr_debug("Invalid rambase 0x%lx\n", rambase);
+ return -1;
+ }
+
+ /*
+ * Try to identify a PRI card
+ */
+ outb(PRI_BASEPG_VAL, pgport);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ;
+ schedule();
+ sig = readl(rambase + SIG_OFFSET);
+ pr_debug("Looking for a signature, got 0x%x\n", sig);
+#if 0
+/*
+ * For Gary:
+ * If it's a timing problem, it should be gone with the above schedule()
+ * Another possible reason may be the missing volatile in the original
+ * code. readl() does this for us.
+ */
+ printk(""); /* Hack! Doesn't work without this !!!??? */
+#endif
+ if(sig == SIGNATURE)
+ return PRI_BOARD;
+
+ /*
+ * Try to identify a PRI card
+ */
+ outb(BRI_BASEPG_VAL, pgport);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ;
+ schedule();
+ sig = readl(rambase + SIG_OFFSET);
+ pr_debug("Looking for a signature, got 0x%x\n", sig);
+#if 0
+ printk(""); /* Hack! Doesn't work without this !!!??? */
+#endif
+ if(sig == SIGNATURE)
+ return BRI_BOARD;
+
+ return -1;
+
+ /*
+ * Try to spot a card
+ */
+ sig = readl(rambase + SIG_OFFSET);
+ pr_debug("Looking for a signature, got 0x%x\n", sig);
+ if(sig != SIGNATURE)
+ return -1;
+
+ dpm = (DualPortMemory *) rambase;
+
+ memset(&sndmsg, 0, MSG_LEN);
+ sndmsg.msg_byte_cnt = 3;
+ sndmsg.type = cmReqType1;
+ sndmsg.class = cmReqClass0;
+ sndmsg.code = cmReqHWConfig;
+ memcpy_toio(&(dpm->req_queue[dpm->req_head++]), &sndmsg, MSG_LEN);
+ outb(0, iobase + 0x400);
+ pr_debug("Sent HWConfig message\n");
+ /*
+ * Wait for the response
+ */
+ x = 0;
+ while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ x++;
+ }
+ if(x == 100) {
+ pr_debug("Timeout waiting for response\n");
+ return -1;
+ }
+
+ memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN);
+ pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status);
+ memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl));
+ pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n"
+ " Part: %s, Rev: %s\n",
+ hwci.st_u_sense ? "S/T" : "U", hwci.ram_size,
+ hwci.serial_no, hwci.part_no, hwci.rev_no);
+
+ if(!strncmp(PRI_PARTNO, hwci.part_no, 6))
+ return PRI_BOARD;
+ if(!strncmp(BRI_PARTNO, hwci.part_no, 6))
+ return BRI_BOARD;
+
+ return -1;
+}
--- /dev/null
+/*
+ * $Id: interrupt.c,v 1.3 1997/02/11 22:53:43 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern indicate_status(int, int, ulong, char *);
+extern void check_phystat(unsigned long);
+extern void dump_messages(int);
+extern int receivemessage(int, RspMessage *);
+extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int, unsigned int *);
+extern void rcvpkt(int, RspMessage *);
+
+extern int cinst;
+extern board *adapter[];
+
+int get_card_from_irq(int irq)
+{
+ int i;
+
+ for(i = 0 ; i < cinst ; i++) {
+ if(adapter[i]->interrupt == irq)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ *
+ */
+void interrupt_handler(int interrupt, void * cardptr, struct pt_regs *regs ) {
+
+ RspMessage rcvmsg;
+ int channel;
+ int card;
+
+ card = get_card_from_irq(interrupt);
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return;
+ }
+
+ pr_debug("%s: Entered Interrupt handler\n", adapter[card]->devicename);
+
+ /*
+ * Pull all of the waiting messages off the response queue
+ */
+ while (!receivemessage(card, &rcvmsg)) {
+ /*
+ * Push the message to the adapter structure for
+ * send_and_receive to snoop
+ */
+ if(adapter[card]->want_async_messages)
+ memcpy(&(adapter[card]->async_msg), &rcvmsg, sizeof(RspMessage));
+
+ channel = (unsigned int) rcvmsg.phy_link_no;
+
+ /*
+ * Trap Invalid request messages
+ */
+ if(IS_CM_MESSAGE(rcvmsg, 0, 0, Invalid)) {
+ pr_debug("%s: Invalid request Message, rsp_status = %d\n",
+ adapter[card]->devicename, rcvmsg.rsp_status);
+ break;
+ }
+
+ /*
+ * Check for a linkRead message
+ */
+ if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read))
+ {
+ pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n",
+ adapter[card]->devicename,
+ rcvmsg.msg_data.response.msg_len,
+ rcvmsg.msg_data.response.buff_offset);
+ rcvpkt(card, &rcvmsg);
+ continue;
+
+ }
+
+ /*
+ * Handle a write acknoledgement
+ */
+ if(IS_CE_MESSAGE(rcvmsg, Lnk, 1, Write)) {
+ pr_debug("%s: Packet Send ACK on channel %d\n", adapter[card]->devicename,
+ rcvmsg.phy_link_no);
+ adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++;
+ continue;
+ }
+
+ /*
+ * Handle a connection message
+ */
+ if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Connect))
+ {
+ unsigned int callid;
+ setup_parm setup;
+ pr_debug("%s: Connect message: line %d: status %d: cause 0x%x\n",
+ adapter[card]->devicename,
+ rcvmsg.phy_link_no,
+ rcvmsg.rsp_status,
+ rcvmsg.msg_data.byte_array[2]);
+
+ memcpy(&callid,rcvmsg.msg_data.byte_array,sizeof(int));
+ if(callid>=0x8000 && callid<=0xFFFF)
+ {
+ pr_debug("%s: Got Dial-Out Rsp\n", adapter[card]->devicename);
+ indicate_status(card, ISDN_STAT_DCONN,
+ (unsigned long)rcvmsg.phy_link_no-1,NULL);
+
+ }
+ else if(callid>=0x0000 && callid<=0x7FFF)
+ {
+ pr_debug("%s: Got Incomming Call\n", adapter[card]->devicename);
+ strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4]));
+ strcpy(setup.eazmsn,adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
+ setup.si1 = 7;
+ setup.si2 = 0;
+ setup.plan = 0;
+ setup.screen = 0;
+
+ indicate_status(card, ISDN_STAT_ICALL,(unsigned long)rcvmsg.phy_link_no-1,(char *)&setup);
+ indicate_status(card, ISDN_STAT_DCONN,(unsigned long)rcvmsg.phy_link_no-1,NULL);
+ }
+ continue;
+ }
+
+ /*
+ * Handle a disconnection message
+ */
+ if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Disconnect))
+ {
+ pr_debug("%s: disconnect message: line %d: status %d: cause 0x%x\n",
+ adapter[card]->devicename,
+ rcvmsg.phy_link_no,
+ rcvmsg.rsp_status,
+ rcvmsg.msg_data.byte_array[2]);
+
+ indicate_status(card, ISDN_STAT_BHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
+ indicate_status(card, ISDN_STAT_DHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
+ continue;
+
+ }
+
+ /*
+ * Handle a startProc engine up message
+ */
+ if (IS_CM_MESSAGE(rcvmsg, 5, 0, MiscEngineUp)) {
+ pr_debug("%s: Received EngineUp message\n", adapter[card]->devicename);
+ adapter[card]->EngineUp = 1;
+ sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,1,0,NULL);
+ sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,2,0,NULL);
+ init_timer(&adapter[card]->stat_timer);
+ adapter[card]->stat_timer.function = check_phystat;
+ adapter[card]->stat_timer.data = card;
+ adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
+ add_timer(&adapter[card]->stat_timer);
+ continue;
+ }
+
+ /*
+ * Start proc response
+ */
+ if (IS_CM_MESSAGE(rcvmsg, 2, 0, StartProc)) {
+ pr_debug("%s: StartProc Response Status %d\n", adapter[card]->devicename,
+ rcvmsg.rsp_status);
+ continue;
+ }
+
+ /*
+ * Handle a GetMyNumber Rsp
+ */
+ if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){
+ strcpy(adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array);
+ continue;
+ }
+
+ /*
+ * PhyStatus response
+ */
+ if(IS_CE_MESSAGE(rcvmsg, Phy, 2, Status)) {
+ unsigned int b1stat, b2stat;
+
+ /*
+ * Covert the message data to the adapter->phystat code
+ */
+ b1stat = (unsigned int) rcvmsg.msg_data.byte_array[0];
+ b2stat = (unsigned int) rcvmsg.msg_data.byte_array[1];
+
+ adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */
+ pr_debug("%s: PhyStat is 0x%2x\n", adapter[card]->devicename,
+ adapter[card]->nphystat);
+ continue;
+ }
+
+
+ /*
+ * Handle a GetFramFormat
+ */
+ if(IS_CE_MESSAGE(rcvmsg, Call, 0, GetFrameFormat)) {
+ if(rcvmsg.msg_data.byte_array[0] != HDLC_PROTO) {
+ unsigned int proto = HDLC_PROTO;
+ /*
+ * Set board format to HDLC if it wasn't already
+ */
+ pr_debug("%s: current frame format: 0x%x, will change to HDLC\n",
+ adapter[card]->devicename,
+ rcvmsg.msg_data.byte_array[0]);
+ sendmessage(card, CEPID, ceReqTypeCall,
+ ceReqClass0,
+ ceReqCallSetFrameFormat,
+ (unsigned char) channel +1,
+ 1,&proto);
+ }
+ continue;
+ }
+
+ /*
+ * Hmm...
+ */
+ pr_debug("%s: Received unhandled message (%d,%d,%d) link %d\n",
+ adapter[card]->devicename, rcvmsg.type, rcvmsg.class, rcvmsg.code,
+ rcvmsg.phy_link_no);
+
+ } /* while */
+
+ pr_debug("%s: Exiting Interrupt Handler\n", adapter[card]->devicename);
+}
--- /dev/null
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+#include "scioc.h"
+
+extern int indicate_status(int, int, unsigned long, char *);
+extern int startproc(int);
+extern int loadproc(int, char *record);
+extern int reset(int);
+extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
+ unsigned char,unsigned char,
+ unsigned char, unsigned char *, RspMessage *, int);
+
+extern board *adapter[];
+
+#if 0
+static char *ChannelStates[] = { "Idle", "Ready", "Connecting", "Connected", "Disconnecting" };
+#endif
+
+int GetStatus(int card, boardInfo *);
+
+/*
+ * Process private IOCTL messages (typically from scctrl)
+ */
+int sc_ioctl(int card, scs_ioctl *data)
+{
+ switch(data->command) {
+ case SCIOCRESET: /* Perform a hard reset of the adapter */
+ {
+ pr_debug("%s: SCIOCRESET: ioctl received\n", adapter[card]->devicename);
+ adapter[card]->StartOnReset = 0;
+ return (reset(card));
+ }
+
+ case SCIOCLOAD:
+ {
+ RspMessage rcvmsg;
+ char srec[SCIOC_SRECSIZE];
+ int status, err;
+
+ pr_debug("%s: SCIOLOAD: ioctl received\n", adapter[card]->devicename);
+ if(adapter[card]->EngineUp) {
+ pr_debug("%s: SCIOCLOAD: Command Failed, LoadProc while engine running.\n",
+ adapter[card]->devicename);
+ return -1;
+ }
+
+ /*
+ * Get the SRec from user space
+ */
+ if ((err = copy_from_user(srec, (char *) data->dataptr, sizeof(srec))))
+ return err;
+
+ status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc,
+ 0, sizeof(srec), srec, &rcvmsg, SAR_TIMEOUT);
+ if(status) {
+ pr_debug("%s: SCIOCLOAD: Command Failed, status = %d\n",
+ adapter[card]->devicename, status);
+ return -1;
+ }
+ else {
+ pr_debug("%s: SCIOCLOAD: Command Sucessful\n", adapter[card]->devicename);
+ return 0;
+ }
+ }
+
+ case SCIOCSTART:
+ {
+ pr_debug("%s: SCIOSTART: ioctl received\n", adapter[card]->devicename);
+ if(adapter[card]->EngineUp) {
+ pr_debug("%s: SCIOCSTART: Command Failed, Engine already running.\n",
+ adapter[card]->devicename);
+ return -1;
+ }
+
+ adapter[card]->StartOnReset = 1;
+ startproc(card);
+ return 0;
+ }
+
+ case SCIOCSETSWITCH:
+ {
+ RspMessage rcvmsg;
+ char switchtype;
+ int status, err;
+
+ pr_debug("%s: SCIOSETSWITCH: ioctl received\n", adapter[card]->devicename);
+
+ /*
+ * Get the switch type from user space
+ */
+ if ((err = copy_from_user(&switchtype, (char *) data->dataptr, sizeof(char))))
+ return err;
+
+ pr_debug("%s: SCIOCSETSWITCH: Setting switch type to %d\n", adapter[card]->devicename,
+ switchtype);
+ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallSetSwitchType,
+ 0, sizeof(char),&switchtype,&rcvmsg, SAR_TIMEOUT);
+ if(!status && !rcvmsg.rsp_status) {
+ pr_debug("%s: SCIOCSETSWITCH: Command Successful\n", adapter[card]->devicename);
+ return 0;
+ }
+ else {
+ pr_debug("%s: SCIOCSETSWITCH: Command Failed (status = %d)\n",
+ adapter[card]->devicename, status);
+ return status;
+ }
+ }
+
+ case SCIOCGETSWITCH:
+ {
+ RspMessage rcvmsg;
+ char switchtype;
+ int status, err;
+
+ pr_debug("%s: SCIOGETSWITCH: ioctl received\n", adapter[card]->devicename);
+
+ /*
+ * Get the switch type from the board
+ */
+ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
+ ceReqCallGetSwitchType, 0, 0, 0, &rcvmsg, SAR_TIMEOUT);
+ if (!status && !rcvmsg.rsp_status) {
+ pr_debug("%s: SCIOCGETSWITCH: Command Sucessful\n", adapter[card]->devicename);
+ }
+ else {
+ pr_debug("%s: SCIOCGETSWITCH: Command Failed (status = %d)\n",
+ adapter[card]->devicename, status);
+ return status;
+ }
+
+ switchtype = rcvmsg.msg_data.byte_array[0];
+
+ /*
+ * Package the switch type and send to user space
+ */
+ if ((err = copy_to_user((char *) data->dataptr, &switchtype, sizeof(char))))
+ return err;
+
+ return 0;
+ }
+
+ case SCIOCGETSPID:
+ {
+ RspMessage rcvmsg;
+ char spid[SCIOC_SPIDSIZE];
+ int status, err;
+
+ pr_debug("%s: SCIOGETSPID: ioctl received\n", adapter[card]->devicename);
+
+ /*
+ * Get the spid from the board
+ */
+ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID,
+ data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
+ if (!status) {
+ pr_debug("%s: SCIOCGETSPID: Command Sucessful\n", adapter[card]->devicename);
+ }
+ else {
+ pr_debug("%s: SCIOCGETSPID: Command Failed (status = %d)\n",
+ adapter[card]->devicename, status);
+ return status;
+ }
+ strcpy(spid, rcvmsg.msg_data.byte_array);
+
+ /*
+ * Package the switch type and send to user space
+ */
+ if ((err = copy_to_user((char *) data->dataptr, spid, sizeof(spid))))
+ return err;
+
+ return 0;
+ }
+
+ case SCIOCSETSPID:
+ {
+ RspMessage rcvmsg;
+ char spid[SCIOC_SPIDSIZE];
+ int status, err;
+
+ pr_debug("%s: DCBIOSETSPID: ioctl received\n", adapter[card]->devicename);
+
+ /*
+ * Get the spid from user space
+ */
+ if ((err = copy_from_user(spid, (char *) data->dataptr, sizeof(spid))))
+ return err;
+
+ pr_debug("%s: SCIOCSETSPID: Setting channel %d spid to %s\n",
+ adapter[card]->devicename, data->channel, spid);
+ status = send_and_receive(card, CEPID, ceReqTypeCall,
+ ceReqClass0, ceReqCallSetSPID, data->channel,
+ strlen(spid), spid, &rcvmsg, SAR_TIMEOUT);
+ if(!status && !rcvmsg.rsp_status) {
+ pr_debug("%s: SCIOCSETSPID: Command Successful\n",
+ adapter[card]->devicename);
+ return 0;
+ }
+ else {
+ pr_debug("%s: SCIOCSETSPID: Command Failed (status = %d)\n",
+ adapter[card]->devicename, status);
+ return status;
+ }
+ }
+
+ case SCIOCGETDN:
+ {
+ RspMessage rcvmsg;
+ char dn[SCIOC_DNSIZE];
+ int status, err;
+
+ pr_debug("%s: SCIOGETDN: ioctl received\n", adapter[card]->devicename);
+
+ /*
+ * Get the dn from the board
+ */
+ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber,
+ data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
+ if (!status) {
+ pr_debug("%s: SCIOCGETDN: Command Sucessful\n", adapter[card]->devicename);
+ }
+ else {
+ pr_debug("%s: SCIOCGETDN: Command Failed (status = %d)\n",
+ adapter[card]->devicename, status);
+ return status;
+ }
+
+ strcpy(dn, rcvmsg.msg_data.byte_array);
+
+ /*
+ * Package the dn and send to user space
+ */
+ if ((err = copy_to_user((char *) data->dataptr, dn, sizeof(dn))))
+ return err;
+
+ return 0;
+ }
+
+ case SCIOCSETDN:
+ {
+ RspMessage rcvmsg;
+ char dn[SCIOC_DNSIZE];
+ int status, err;
+
+ pr_debug("%s: SCIOSETDN: ioctl received\n", adapter[card]->devicename);
+
+ /*
+ * Get the spid from user space
+ */
+ if ((err = copy_from_user(dn, (char *) data->dataptr, sizeof(dn))))
+ return err;
+
+ pr_debug("%s: SCIOCSETDN: Setting channel %d dn to %s\n",
+ adapter[card]->devicename, data->channel, dn);
+ status = send_and_receive(card, CEPID, ceReqTypeCall,
+ ceReqClass0, ceReqCallSetMyNumber, data->channel,
+ strlen(dn),dn,&rcvmsg, SAR_TIMEOUT);
+ if(!status && !rcvmsg.rsp_status) {
+ pr_debug("%s: SCIOCSETDN: Command Successful\n",
+ adapter[card]->devicename);
+ return 0;
+ }
+ else {
+ pr_debug("%s: SCIOCSETDN: Command Failed (status = %d)\n",
+ adapter[card]->devicename, status);
+ return status;
+ }
+ }
+
+ case SCIOCTRACE:
+
+ pr_debug("%s: SCIOTRACE: ioctl received\n", adapter[card]->devicename);
+/* adapter[card]->trace = !adapter[card]->trace;
+ pr_debug("%s: SCIOCTRACE: Tracing turned %s\n", adapter[card]->devicename,
+ adapter[card]->trace ? "ON" : "OFF"); */
+ break;
+
+ case SCIOCSTAT:
+ {
+ boardInfo bi;
+ int err;
+
+ pr_debug("%s: SCIOSTAT: ioctl received\n", adapter[card]->devicename);
+ GetStatus(card, &bi);
+
+ if ((err = copy_to_user((boardInfo *) data->dataptr, &bi, sizeof(boardInfo))))
+ return err;
+
+ return 0;
+ }
+
+ case SCIOCGETSPEED:
+ {
+ RspMessage rcvmsg;
+ char speed;
+ int status, err;
+
+ pr_debug("%s: SCIOGETSPEED: ioctl received\n", adapter[card]->devicename);
+
+ /*
+ * Get the speed from the board
+ */
+ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
+ ceReqCallGetCallType, data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT);
+ if (!status && !rcvmsg.rsp_status) {
+ pr_debug("%s: SCIOCGETSPEED: Command Sucessful\n",
+ adapter[card]->devicename);
+ }
+ else {
+ pr_debug("%s: SCIOCGETSPEED: Command Failed (status = %d)\n",
+ adapter[card]->devicename, status);
+ return status;
+ }
+
+ speed = rcvmsg.msg_data.byte_array[0];
+
+ /*
+ * Package the switch type and send to user space
+ */
+ if ((err = copy_to_user((char *) data->dataptr, &speed, sizeof(char))))
+ return err;
+
+ return 0;
+ }
+
+ case SCIOCSETSPEED:
+ pr_debug("%s: SCIOCSETSPEED: ioctl received\n", adapter[card]->devicename);
+ break;
+
+ case SCIOCLOOPTST:
+ pr_debug("%s: SCIOCLOOPTST: ioctl received\n", adapter[card]->devicename);
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int GetStatus(int card, boardInfo *bi)
+{
+ RspMessage rcvmsg;
+ int i, status;
+
+ /*
+ * Fill in some of the basic info about the board
+ */
+ bi->modelid = adapter[card]->model;
+ strcpy(bi->serial_no, adapter[card]->hwconfig.serial_no);
+ strcpy(bi->part_no, adapter[card]->hwconfig.part_no);
+ bi->iobase = adapter[card]->iobase;
+ bi->rambase = adapter[card]->rambase;
+ bi->irq = adapter[card]->interrupt;
+ bi->ramsize = adapter[card]->hwconfig.ram_size;
+ bi->interface = adapter[card]->hwconfig.st_u_sense;
+ strcpy(bi->load_ver, adapter[card]->load_ver);
+ strcpy(bi->proc_ver, adapter[card]->proc_ver);
+
+ /*
+ * Get the current PhyStats and LnkStats
+ */
+ status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2,
+ ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if(!status) {
+ if(adapter[card]->model < PRI_BOARD) {
+ bi->l1_status = rcvmsg.msg_data.byte_array[2];
+ for(i = 0 ; i < BRI_CHANNELS ; i++)
+ bi->status.bristats[i].phy_stat =
+ rcvmsg.msg_data.byte_array[i];
+ }
+ else {
+ bi->l1_status = rcvmsg.msg_data.byte_array[0];
+ bi->l2_status = rcvmsg.msg_data.byte_array[1];
+ for(i = 0 ; i < PRI_CHANNELS ; i++)
+ bi->status.pristats[i].phy_stat =
+ rcvmsg.msg_data.byte_array[i+2];
+ }
+ }
+
+ /*
+ * Get the call types for each channel
+ */
+ for (i = 0 ; i < adapter[card]->nChannels ; i++) {
+ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
+ ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if(!status) {
+ if (adapter[card]->model == PRI_BOARD) {
+ bi->status.pristats[i].call_type =
+ rcvmsg.msg_data.byte_array[0];
+ }
+ else {
+ bi->status.bristats[i].call_type =
+ rcvmsg.msg_data.byte_array[0];
+ }
+ }
+ }
+
+ /*
+ * If PRI, get the call states and service states for each channel
+ */
+ if (adapter[card]->model == PRI_BOARD) {
+ /*
+ * Get the call states
+ */
+ status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
+ ceReqPhyChCallState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if(!status) {
+ for( i = 0 ; i < PRI_CHANNELS ; i++ )
+ bi->status.pristats[i].call_state =
+ rcvmsg.msg_data.byte_array[i];
+ }
+
+ /*
+ * Get the service states
+ */
+ status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2,
+ ceReqPhyChServState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if(!status) {
+ for( i = 0 ; i < PRI_CHANNELS ; i++ )
+ bi->status.pristats[i].serv_state =
+ rcvmsg.msg_data.byte_array[i];
+ }
+
+ /*
+ * Get the link stats for the channels
+ */
+ for (i = 1 ; i <= PRI_CHANNELS ; i++) {
+ status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
+ ceReqLnkGetStats, i, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if (!status) {
+ bi->status.pristats[i-1].link_stats.tx_good =
+ (unsigned long)rcvmsg.msg_data.byte_array[0];
+ bi->status.pristats[i-1].link_stats.tx_bad =
+ (unsigned long)rcvmsg.msg_data.byte_array[4];
+ bi->status.pristats[i-1].link_stats.rx_good =
+ (unsigned long)rcvmsg.msg_data.byte_array[8];
+ bi->status.pristats[i-1].link_stats.rx_bad =
+ (unsigned long)rcvmsg.msg_data.byte_array[12];
+ }
+ }
+
+ /*
+ * Link stats for the D channel
+ */
+ status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
+ ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if (!status) {
+ bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
+ bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
+ bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
+ bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
+ }
+
+ return 0;
+ }
+
+ /*
+ * If BRI or POTS, Get SPID, DN and call types for each channel
+ */
+
+ /*
+ * Get the link stats for the channels
+ */
+ status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0,
+ ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if (!status) {
+ bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0];
+ bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4];
+ bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8];
+ bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12];
+ bi->status.bristats[0].link_stats.tx_good =
+ (unsigned long)rcvmsg.msg_data.byte_array[16];
+ bi->status.bristats[0].link_stats.tx_bad =
+ (unsigned long)rcvmsg.msg_data.byte_array[20];
+ bi->status.bristats[0].link_stats.rx_good =
+ (unsigned long)rcvmsg.msg_data.byte_array[24];
+ bi->status.bristats[0].link_stats.rx_bad =
+ (unsigned long)rcvmsg.msg_data.byte_array[28];
+ bi->status.bristats[1].link_stats.tx_good =
+ (unsigned long)rcvmsg.msg_data.byte_array[32];
+ bi->status.bristats[1].link_stats.tx_bad =
+ (unsigned long)rcvmsg.msg_data.byte_array[36];
+ bi->status.bristats[1].link_stats.rx_good =
+ (unsigned long)rcvmsg.msg_data.byte_array[40];
+ bi->status.bristats[1].link_stats.rx_bad =
+ (unsigned long)rcvmsg.msg_data.byte_array[44];
+ }
+
+ /*
+ * Get the SPIDs
+ */
+ for (i = 0 ; i < BRI_CHANNELS ; i++) {
+ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
+ ceReqCallGetSPID, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if (!status)
+ strcpy(bi->status.bristats[i].spid, rcvmsg.msg_data.byte_array);
+ }
+
+ /*
+ * Get the DNs
+ */
+ for (i = 0 ; i < BRI_CHANNELS ; i++) {
+ status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0,
+ ceReqCallGetMyNumber, i+1, 0, NULL, &rcvmsg, SAR_TIMEOUT);
+ if (!status)
+ strcpy(bi->status.bristats[i].dn, rcvmsg.msg_data.byte_array);
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * $Id: message.c,v 1.2 1996/11/20 17:49:54 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * message.c - functions for sending and receiving control messages
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern board *adapter[];
+extern unsigned int cinst;
+
+/*
+ * Obligitory function prototypes
+ */
+extern int indicate_status(int,ulong,char*);
+extern int scm_command(isdn_ctrl *);
+extern void *memcpy_fromshmem(int, void *, const void *, size_t);
+
+/*
+ * Dump message queue in shared memory to screen
+ */
+void dump_messages(int card)
+{
+ DualPortMemory dpm;
+ unsigned long flags;
+
+ int i =0;
+
+ if (!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ }
+
+ save_flags(flags);
+ cli();
+ outb(adapter[card]->ioport[adapter[card]->shmem_pgport],
+ (adapter[card]->shmem_magic >> 14) | 0x80);
+ memcpy_fromshmem(card, &dpm, 0, sizeof(dpm));
+ restore_flags(flags);
+
+ pr_debug("%s: Dumping Request Queue\n", adapter[card]->devicename);
+ for (i = 0; i < dpm.req_head; i++) {
+ pr_debug("%s: Message #%d: (%d,%d,%d), link: %d\n",
+ adapter[card]->devicename, i,
+ dpm.req_queue[i].type,
+ dpm.req_queue[i].class,
+ dpm.req_queue[i].code,
+ dpm.req_queue[i].phy_link_no);
+ }
+
+ pr_debug("%s: Dumping Response Queue\n", adapter[card]->devicename);
+ for (i = 0; i < dpm.rsp_head; i++) {
+ pr_debug("%s: Message #%d: (%d,%d,%d), link: %d, status: %d\n",
+ adapter[card]->devicename, i,
+ dpm.rsp_queue[i].type,
+ dpm.rsp_queue[i].class,
+ dpm.rsp_queue[i].code,
+ dpm.rsp_queue[i].phy_link_no,
+ dpm.rsp_queue[i].rsp_status);
+ }
+
+}
+
+/*
+ * receive a message from the board
+ */
+int receivemessage(int card, RspMessage *rspmsg)
+{
+ DualPortMemory *dpm;
+ unsigned long flags;
+
+ if (!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: Entered receivemessage\n",adapter[card]->devicename);
+
+ /*
+ * See if there are messages waiting
+ */
+ if (inb(adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) {
+ /*
+ * Map in the DPM to the base page and copy the message
+ */
+ save_flags(flags);
+ cli();
+ outb((adapter[card]->shmem_magic >> 14) | 0x80,
+ adapter[card]->ioport[adapter[card]->shmem_pgport]);
+ dpm = (DualPortMemory *) adapter[card]->rambase;
+ memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]),
+ MSG_LEN);
+ dpm->rsp_tail = (dpm->rsp_tail+1) % MAX_MESSAGES;
+ inb(adapter[card]->ioport[FIFO_READ]);
+ restore_flags(flags);
+
+ /*
+ * Tell the board that the message is received
+ */
+ pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d "
+ "cnt:%d (type,class,code):(%d,%d,%d) "
+ "link:%d stat:0x%x\n",
+ adapter[card]->devicename,
+ rspmsg->sequence_no,
+ rspmsg->process_id,
+ rspmsg->time_stamp,
+ rspmsg->cmd_sequence_no,
+ rspmsg->msg_byte_cnt,
+ rspmsg->type,
+ rspmsg->class,
+ rspmsg->code,
+ rspmsg->phy_link_no,
+ rspmsg->rsp_status);
+
+ return 0;
+ }
+ return -ENOMSG;
+}
+
+/*
+ * send a message to the board
+ */
+int sendmessage(int card,
+ unsigned int procid,
+ unsigned int type,
+ unsigned int class,
+ unsigned int code,
+ unsigned int link,
+ unsigned int data_len,
+ unsigned int *data)
+{
+ DualPortMemory *dpm;
+ ReqMessage sndmsg;
+ unsigned long flags;
+
+ if (!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -EINVAL;
+ }
+
+ /*
+ * Make sure we only send CEPID messages when the engine is up
+ * and CMPID messages when it is down
+ */
+ if(adapter[card]->EngineUp && procid == CMPID) {
+ pr_debug("%s: Attempt to send CM message with engine up\n",
+ adapter[card]->devicename);
+ return -ESRCH;
+ }
+
+ if(!adapter[card]->EngineUp && procid == CEPID) {
+ pr_debug("%s: Attempt to send CE message with engine down\n",
+ adapter[card]->devicename);
+ return -ESRCH;
+ }
+
+ memset(&sndmsg, 0, MSG_LEN);
+ sndmsg.msg_byte_cnt = 4;
+ sndmsg.type = type;
+ sndmsg.class = class;
+ sndmsg.code = code;
+ sndmsg.phy_link_no = link;
+
+ if (data_len > 0) {
+ if (data_len > MSG_DATA_LEN)
+ data_len = MSG_DATA_LEN;
+ memcpy(&(sndmsg.msg_data), data, data_len);
+ sndmsg.msg_byte_cnt = data_len + 8;
+ }
+
+ sndmsg.process_id = procid;
+ sndmsg.sequence_no = adapter[card]->seq_no++ % 256;
+
+ /*
+ * wait for an empty slot in the queue
+ */
+ while (!(inb(adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
+ SLOW_DOWN_IO;
+
+ /*
+ * Disable interrupts and map in shared memory
+ */
+ save_flags(flags);
+ cli();
+ outb((adapter[card]->shmem_magic >> 14) | 0x80,
+ adapter[card]->ioport[adapter[card]->shmem_pgport]);
+ dpm = (DualPortMemory *) adapter[card]->rambase; /* Fix me */
+ memcpy_toio(&(dpm->req_queue[dpm->req_head]),&sndmsg,MSG_LEN);
+ dpm->req_head = (dpm->req_head+1) % MAX_MESSAGES;
+ outb(sndmsg.sequence_no, adapter[card]->ioport[FIFO_WRITE]);
+ restore_flags(flags);
+
+ pr_debug("%s: Sent Message seq:%d pid:%d time:%d "
+ "cnt:%d (type,class,code):(%d,%d,%d) "
+ "link:%d\n ",
+ adapter[card]->devicename,
+ sndmsg.sequence_no,
+ sndmsg.process_id,
+ sndmsg.time_stamp,
+ sndmsg.msg_byte_cnt,
+ sndmsg.type,
+ sndmsg.class,
+ sndmsg.code,
+ sndmsg.phy_link_no);
+
+ return 0;
+}
+
+int send_and_receive(int card,
+ unsigned int procid,
+ unsigned char type,
+ unsigned char class,
+ unsigned char code,
+ unsigned char link,
+ unsigned char data_len,
+ unsigned char *data,
+ RspMessage *mesgdata,
+ int timeout)
+{
+ int retval;
+ int tries;
+
+ if (!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -EINVAL;
+ }
+
+ adapter[card]->want_async_messages = 1;
+ retval = sendmessage(card, procid, type, class, code, link,
+ data_len, (unsigned int *) data);
+
+ if (retval) {
+ pr_debug("%s: SendMessage failed in SAR\n",
+ adapter[card]->devicename);
+ adapter[card]->want_async_messages = 0;
+ return -EIO;
+ }
+
+ tries = 0;
+ /* wait for the response */
+ while (tries < timeout) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+
+ pr_debug("SAR waiting..\n");
+
+ /*
+ * See if we got our message back
+ */
+ if ((adapter[card]->async_msg.type == type) &&
+ (adapter[card]->async_msg.class == class) &&
+ (adapter[card]->async_msg.code == code) &&
+ (adapter[card]->async_msg.phy_link_no == link)) {
+
+ /*
+ * Got it!
+ */
+ pr_debug("%s: Got ASYNC message\n",
+ adapter[card]->devicename);
+ memcpy(mesgdata, &(adapter[card]->async_msg),
+ sizeof(RspMessage));
+ adapter[card]->want_async_messages = 0;
+ return 0;
+ }
+
+ tries++;
+ }
+
+ pr_debug("%s: SAR message timeout\n", adapter[card]->devicename);
+ adapter[card]->want_async_messages = 0;
+ return -ETIME;
+}
--- /dev/null
+/*
+ * $Id: message.h,v 1.1 1996/11/07 13:07:47 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * message.h - structures, macros and defines useful for sending
+ * messages to the adapter
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+/*
+ * Board message macros, defines and structures
+ */
+
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#define MAX_MESSAGES 32 /* Maximum messages that can be
+ queued */
+#define MSG_DATA_LEN 48 /* Maximum size of message payload */
+#define MSG_LEN 64 /* Size of a message */
+#define CMPID 0 /* Loader message process ID */
+#define CEPID 64 /* Firmware message process ID */
+
+/*
+ * Macro to determine if a message is a loader message
+ */
+#define IS_CM_MESSAGE(mesg, tx, cx, dx) \
+ ((mesg.type == cmRspType##tx) \
+ &&(mesg.class == cmRspClass##cx) \
+ &&(mesg.code == cmRsp##dx))
+
+/*
+ * Macro to determine if a message is a firmware message
+ */
+#define IS_CE_MESSAGE(mesg, tx, cx, dx) \
+ ((mesg.type == ceRspType##tx) \
+ &&(mesg.class == ceRspClass##cx) \
+ &&(mesg.code == ceRsp##tx##dx))
+
+/*
+ * Loader Request and Response Messages
+ */
+
+/* message types */
+#define cmReqType1 1
+#define cmReqType2 2
+#define cmRspType0 0
+#define cmRspType1 1
+#define cmRspType2 2
+#define cmRspType5 5
+
+/* message classes */
+#define cmReqClass0 0
+#define cmRspClass0 0
+
+/* message codes */
+#define cmReqHWConfig 1 /* 1,0,1 */
+#define cmReqMsgLpbk 2 /* 1,0,2 */
+#define cmReqVersion 3 /* 1,0,3 */
+#define cmReqLoadProc 1 /* 2,0,1 */
+#define cmReqStartProc 2 /* 2,0,2 */
+#define cmReqReadMem 6 /* 2,0,6 */
+#define cmRspHWConfig cmReqHWConfig
+#define cmRspMsgLpbk cmReqMsgLpbk
+#define cmRspVersion cmReqVersion
+#define cmRspLoadProc cmReqLoadProc
+#define cmRspStartProc cmReqStartProc
+#define cmRspReadMem cmReqReadMem
+#define cmRspMiscEngineUp 1 /* 5,0,1 */
+#define cmRspInvalid 0 /* 0,0,0 */
+
+
+/*
+ * Firmware Request and Response Messages
+ */
+
+/* message types */
+#define ceReqTypePhy 1
+#define ceReqTypeLnk 2
+#define ceReqTypeCall 3
+#define ceReqTypeStat 1
+#define ceRspTypeErr 0
+#define ceRspTypePhy ceReqTypePhy
+#define ceRspTypeLnk ceReqTypeLnk
+#define ceRspTypeCall ceReqTypeCall
+#define ceRspTypeStat ceReqTypeStat
+
+/* message classes */
+#define ceReqClass0 0
+#define ceReqClass1 1
+#define ceReqClass2 2
+#define ceReqClass3 3
+#define ceRspClass0 ceReqClass0
+#define ceRspClass1 ceReqClass1
+#define ceRspClass2 ceReqClass2
+#define ceRspClass3 ceReqClass3
+
+/* message codes (B) = BRI only, (P) = PRI only, (V) = POTS only */
+#define ceReqPhyProcInfo 1 /* 1,0,1 */
+#define ceReqPhyConnect 1 /* 1,1,1 */
+#define ceReqPhyDisconnect 2 /* 1,1,2 */
+#define ceReqPhySetParams 3 /* 1,1,3 (P) */
+#define ceReqPhyGetParams 4 /* 1,1,4 (P) */
+#define ceReqPhyStatus 1 /* 1,2,1 */
+#define ceReqPhyAcfaStatus 2 /* 1,2,2 (P) */
+#define ceReqPhyChCallState 3 /* 1,2,3 (P) */
+#define ceReqPhyChServState 4 /* 1,2,4 (P) */
+#define ceReqPhyRLoopBack 1 /* 1,3,1 */
+#define ceRspPhyProcInfo ceReqPhyProcInfo
+#define ceRspPhyConnect ceReqPhyConnect
+#define ceRspPhyDisconnect ceReqPhyDisconnect
+#define ceRspPhySetParams ceReqPhySetParams
+#define ceRspPhyGetParams ceReqPhyGetParams
+#define ceRspPhyStatus ceReqPhyStatus
+#define ceRspPhyAcfaStatus ceReqPhyAcfaStatus
+#define ceRspPhyChCallState ceReqPhyChCallState
+#define ceRspPhyChServState ceReqPhyChServState
+#define ceRspPhyRLoopBack ceReqphyRLoopBack
+#define ceReqLnkSetParam 1 /* 2,0,1 */
+#define ceReqLnkGetParam 2 /* 2,0,2 */
+#define ceReqLnkGetStats 3 /* 2,0,3 */
+#define ceReqLnkWrite 1 /* 2,1,1 */
+#define ceReqLnkRead 2 /* 2,1,2 */
+#define ceReqLnkFlush 3 /* 2,1,3 */
+#define ceReqLnkWrBufTrc 4 /* 2,1,4 */
+#define ceReqLnkRdBufTrc 5 /* 2,1,5 */
+#define ceRspLnkSetParam ceReqLnkSetParam
+#define ceRspLnkGetParam ceReqLnkGetParam
+#define ceRspLnkGetStats ceReqLnkGetStats
+#define ceRspLnkWrite ceReqLnkWrite
+#define ceRspLnkRead ceReqLnkRead
+#define ceRspLnkFlush ceReqLnkFlush
+#define ceRspLnkWrBufTrc ceReqLnkWrBufTrc
+#define ceRspLnkRdBufTrc ceReqLnkRdBufTrc
+#define ceReqCallSetSwitchType 1 /* 3,0,1 */
+#define ceReqCallGetSwitchType 2 /* 3,0,2 */
+#define ceReqCallSetFrameFormat 3 /* 3,0,3 */
+#define ceReqCallGetFrameFormat 4 /* 3,0,4 */
+#define ceReqCallSetCallType 5 /* 3,0,5 */
+#define ceReqCallGetCallType 6 /* 3,0,6 */
+#define ceReqCallSetSPID 7 /* 3,0,7 (!P) */
+#define ceReqCallGetSPID 8 /* 3,0,8 (!P) */
+#define ceReqCallSetMyNumber 9 /* 3,0,9 (!P) */
+#define ceReqCallGetMyNumber 10 /* 3,0,10 (!P) */
+#define ceRspCallSetSwitchType ceReqCallSetSwitchType
+#define ceRspCallGetSwitchType ceReqCallSetSwitchType
+#define ceRspCallSetFrameFormat ceReqCallSetFrameFormat
+#define ceRspCallGetFrameFormat ceReqCallGetFrameFormat
+#define ceRspCallSetCallType ceReqCallSetCallType
+#define ceRspCallGetCallType ceReqCallGetCallType
+#define ceRspCallSetSPID ceReqCallSetSPID
+#define ceRspCallGetSPID ceReqCallGetSPID
+#define ceRspCallSetMyNumber ceReqCallSetMyNumber
+#define ceRspCallGetMyNumber ceReqCallGetMyNumber
+#define ceRspStatAcfaStatus 2
+#define ceRspStat
+#define ceRspErrError 0 /* 0,0,0 */
+
+/*
+ * Call Types
+ */
+#define CALLTYPE_64K 0
+#define CALLTYPE_56K 1
+#define CALLTYPE_SPEECH 2
+#define CALLTYPE_31KHZ 3
+
+/*
+ * Link Level data contains a pointer to and the length of
+ * a buffer in shared RAM. Used by LnkRead and LnkWrite message
+ * types. Part of RspMsgStruct and ReqMsgStruct.
+ */
+typedef struct {
+ unsigned long buff_offset;
+ unsigned short msg_len;
+} LLData;
+
+
+/*
+ * Message payload template for an HWConfig message
+ */
+typedef struct {
+ char st_u_sense;
+ char powr_sense;
+ char sply_sense;
+ unsigned char asic_id;
+ long ram_size;
+ char serial_no[13];
+ char part_no[13];
+ char rev_no[2];
+} HWConfig_pl;
+
+/*
+ * A Message
+ */
+struct message {
+ unsigned char sequence_no;
+ unsigned char process_id;
+ unsigned char time_stamp;
+ unsigned char cmd_sequence_no; /* Rsp messages only */
+ unsigned char reserved1[3];
+ unsigned char msg_byte_cnt;
+ unsigned char type;
+ unsigned char class;
+ unsigned char code;
+ unsigned char phy_link_no;
+ unsigned char rsp_status; /* Rsp messages only */
+ unsigned char reseved2[3];
+ union {
+ unsigned char byte_array[MSG_DATA_LEN];
+ LLData response;
+ HWConfig_pl HWCresponse;
+ } msg_data;
+};
+
+typedef struct message ReqMessage; /* Request message */
+typedef struct message RspMessage; /* Response message */
+
+/*
+ * The first 5010 bytes of shared memory contain the message queues,
+ * indexes and other data. This structure is its template
+ */
+typedef struct {
+ volatile ReqMessage req_queue[MAX_MESSAGES];
+ volatile RspMessage rsp_queue[MAX_MESSAGES];
+ volatile unsigned char req_head;
+ volatile unsigned char req_tail;
+ volatile unsigned char rsp_head;
+ volatile unsigned char rsp_tail;
+ volatile unsigned long signature;
+ volatile unsigned long trace_enable;
+ volatile unsigned char reserved[4];
+} DualPortMemory;
+
+#endif
--- /dev/null
+/*
+ * $Id: packet.c,v 1.2 1996/11/20 17:49:55 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern board *adapter[];
+extern unsigned int cinst;
+
+extern int get_card_from_id(int);
+extern int indicate_status(int, int,ulong,char*);
+extern void *memcpy_toshmem(int, void *, const void *, size_t);
+extern void *memcpy_fromshmem(int, void *, const void *, size_t);
+extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int, unsigned int *);
+
+int sndpkt(int devId, int channel, struct sk_buff *data)
+{
+ LLData ReqLnkWrite;
+ int status;
+ int card;
+
+ card = get_card_from_id(devId);
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ pr_debug("%s: Send Packet: frst = 0x%x nxt = %d f = %d n = %d\n",
+ adapter[card]->devicename,
+ adapter[card]->channel[channel].first_sendbuf,
+ adapter[card]->channel[channel].next_sendbuf,
+ adapter[card]->channel[channel].free_sendbufs,
+ adapter[card]->channel[channel].num_sendbufs);
+
+ if(!adapter[card]->channel[channel].free_sendbufs) {
+ pr_debug("%s: Out out TX buffers\n", adapter[card]->devicename);
+ return -EINVAL;
+ }
+
+ if(data->len > BUFFER_SIZE) {
+ pr_debug("%s: Data overflows buffer size (data > buffer)\n", adapter[card]->devicename);
+ return -EINVAL;
+ }
+
+ ReqLnkWrite.buff_offset = adapter[card]->channel[channel].next_sendbuf *
+ BUFFER_SIZE + adapter[card]->channel[channel].first_sendbuf;
+ ReqLnkWrite.msg_len = data->len; /* sk_buff size */
+ pr_debug("%s: Writing %d bytes to buffer offset 0x%x\n", adapter[card]->devicename,
+ ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset);
+ memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len);
+
+ /*
+ * sendmessage
+ */
+ pr_debug("%s: Send Packet size=%d, buf_offset=0x%x buf_indx=%d\n",
+ adapter[card]->devicename,
+ ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset,
+ adapter[card]->channel[channel].next_sendbuf);
+
+ status = sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkWrite,
+ channel+1, sizeof(LLData), (unsigned int*)&ReqLnkWrite);
+ if(status) {
+ pr_debug("%s: Failed to send packet, status = %d\n", adapter[card]->devicename, status);
+ return -1;
+ }
+ else {
+ adapter[card]->channel[channel].free_sendbufs--;
+ adapter[card]->channel[channel].next_sendbuf =
+ ++adapter[card]->channel[channel].next_sendbuf ==
+ adapter[card]->channel[channel].num_sendbufs ? 0 :
+ adapter[card]->channel[channel].next_sendbuf;
+ pr_debug("%s: Packet sent successfully\n", adapter[card]->devicename);
+ dev_kfree_skb(data, FREE_WRITE);
+ indicate_status(card,ISDN_STAT_BSENT,channel,NULL);
+ }
+ return data->len;
+}
+
+void rcvpkt(int card, RspMessage *rcvmsg)
+{
+ LLData newll;
+ struct sk_buff *skb;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return;
+ }
+
+ switch(rcvmsg->rsp_status){
+ case 0x01:
+ case 0x02:
+ case 0x70:
+ pr_debug("%s: Error status code: 0x%x\n", adapter[card]->devicename, rcvmsg->rsp_status);
+ return;
+ case 0x00:
+ if (!(skb = dev_alloc_skb(rcvmsg->msg_data.response.msg_len))) {
+ printk(KERN_WARNING "%s: rcvpkt out of memory, dropping packet\n",
+ adapter[card]->devicename);
+ return;
+ }
+ skb_put(skb, rcvmsg->msg_data.response.msg_len);
+ pr_debug("%s: getting data from offset: 0x%x\n",
+ adapter[card]->devicename,rcvmsg->msg_data.response.buff_offset);
+ memcpy_fromshmem(card,
+ skb_put(skb, rcvmsg->msg_data.response.msg_len),
+ (char *)rcvmsg->msg_data.response.buff_offset,
+ rcvmsg->msg_data.response.msg_len);
+ adapter[card]->card->rcvcallb_skb(adapter[card]->driverId,
+ rcvmsg->phy_link_no-1, skb);
+
+ case 0x03:
+ /*
+ * Recycle the buffer
+ */
+ pr_debug("%s: Buffer size : %d\n", adapter[card]->devicename, BUFFER_SIZE);
+/* memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */
+ newll.buff_offset = rcvmsg->msg_data.response.buff_offset;
+ newll.msg_len = BUFFER_SIZE;
+ pr_debug("%s: recycled buffer at offset 0x%x size %d\n", adapter[card]->devicename,
+ newll.buff_offset, newll.msg_len);
+ sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
+ rcvmsg->phy_link_no, sizeof(LLData), (unsigned int *)&newll);
+ }
+
+}
+
+int setup_buffers(int card, int c)
+{
+ unsigned int nBuffers, i, cBase;
+ unsigned int buffer_size;
+ LLData RcvBuffOffset;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return -ENODEV;
+ }
+
+ /*
+ * Calculate the buffer offsets (send/recv/send/recv)
+ */
+ pr_debug("%s: Seting up channel buffer space in shared RAM\n", adapter[card]->devicename);
+ buffer_size = BUFFER_SIZE;
+ nBuffers = ((adapter[card]->ramsize - BUFFER_BASE) / buffer_size) / 2;
+ nBuffers = nBuffers > BUFFERS_MAX ? BUFFERS_MAX : nBuffers;
+ pr_debug("%s: Calculating buffer space: %d buffers, %d big\n", adapter[card]->devicename,
+ nBuffers, buffer_size);
+ if(nBuffers < 2) {
+ pr_debug("%s: Not enough buffer space\n", adapter[card]->devicename);
+ return -1;
+ }
+ cBase = (nBuffers * buffer_size) * (c - 1);
+ pr_debug("%s: Channel buffer offset from Shared RAM: 0x%x\n", adapter[card]->devicename, cBase);
+ adapter[card]->channel[c-1].first_sendbuf = BUFFER_BASE + cBase;
+ adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2;
+ adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2;
+ adapter[card]->channel[c-1].next_sendbuf = 0;
+ pr_debug("%s: Send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n",
+ adapter[card]->devicename,
+ adapter[card]->channel[c-1].first_sendbuf,
+ adapter[card]->channel[c-1].num_sendbufs,
+ adapter[card]->channel[c-1].free_sendbufs,
+ adapter[card]->channel[c-1].next_sendbuf);
+
+ /*
+ * Prep the receive buffers
+ */
+ pr_debug("%s: Adding %d RecvBuffers:\n", adapter[card]->devicename, nBuffers /2);
+ for (i = 0 ; i < nBuffers / 2; i++) {
+ RcvBuffOffset.buff_offset =
+ ((adapter[card]->channel[c-1].first_sendbuf +
+ (nBuffers / 2) * buffer_size) + (buffer_size * i));
+ RcvBuffOffset.msg_len = buffer_size;
+ pr_debug("%s: Adding RcvBuffer #%d offset=0x%x sz=%d buffsz:%d\n",
+ adapter[card]->devicename,
+ i + 1, RcvBuffOffset.buff_offset,
+ RcvBuffOffset.msg_len,buffer_size);
+ sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
+ c, sizeof(LLData), (unsigned int *)&RcvBuffOffset);
+ }
+ return 0;
+}
+
+int print_skb(int card,char *skb_p, int len){
+ int i,data;
+ pr_debug("%s: data at 0x%x len: 0x%x\n",adapter[card]->devicename,
+ skb_p,len);
+ for(i=1;i<=len;i++,skb_p++){
+ data = (int) (0xff & (*skb_p));
+ pr_debug("%s: data = 0x%x",adapter[card]->devicename,data);
+ if(!(i%4))
+ pr_debug(" ");
+ if(!(i%32))
+ pr_debug("\n");
+ }
+ pr_debug("\n");
+ return 0;
+}
+
--- /dev/null
+
+/*
+ * IOCTL Command Codes
+ */
+#define SCIOCLOAD 0x01 /* Load a firmware record */
+#define SCIOCRESET 0x02 /* Perform hard reset */
+#define SCIOCDEBUG 0x03 /* Set debug level */
+#define SCIOCREV 0x04 /* Get driver revision(s) */
+#define SCIOCSTART 0x05 /* Start the firmware */
+#define SCIOCGETSWITCH 0x06 /* Get switch type */
+#define SCIOCSETSWITCH 0x07 /* Set switch type */
+#define SCIOCGETSPID 0x08 /* Get channel SPID */
+#define SCIOCSETSPID 0x09 /* Set channel SPID */
+#define SCIOCGETDN 0x0A /* Get channel DN */
+#define SCIOCSETDN 0x0B /* Set channel DN */
+#define SCIOCTRACE 0x0C /* Toggle trace mode */
+#define SCIOCSTAT 0x0D /* Get line status */
+#define SCIOCGETSPEED 0x0E /* Set channel speed */
+#define SCIOCSETSPEED 0x0F /* Set channel speed */
+#define SCIOCLOOPTST 0x10 /* Perform loopback test */
+
+typedef struct {
+ int device;
+ int channel;
+ unsigned long command;
+ void *dataptr;
+} scs_ioctl;
+
+/* Size of strings */
+#define SCIOC_SPIDSIZE 49
+#define SCIOC_DNSIZE SCIOC_SPIDSIZE
+#define SCIOC_REVSIZE SCIOC_SPIDSIZE
+#define SCIOC_SRECSIZE 49
+
+typedef struct {
+ unsigned long tx_good;
+ unsigned long tx_bad;
+ unsigned long rx_good;
+ unsigned long rx_bad;
+} ChLinkStats;
+
+typedef struct {
+ char spid[49];
+ char dn[49];
+ char call_type;
+ char phy_stat;
+ ChLinkStats link_stats;
+} BRIStat;
+
+typedef BRIStat POTStat;
+
+typedef struct {
+ char call_type;
+ char call_state;
+ char serv_state;
+ char phy_stat;
+ ChLinkStats link_stats;
+} PRIStat;
+
+typedef char PRIInfo;
+typedef char BRIInfo;
+typedef char POTInfo;
+
+
+typedef struct {
+ char acfa_nos;
+ char acfa_ais;
+ char acfa_los;
+ char acfa_rra;
+ char acfa_slpp;
+ char acfa_slpn;
+ char acfa_fsrf;
+} ACFAStat;
+
+typedef struct {
+ unsigned char modelid;
+ char serial_no[13];
+ char part_no[13];
+ char load_ver[11];
+ char proc_ver[11];
+ int iobase;
+ long rambase;
+ char irq;
+ long ramsize;
+ char interface;
+ char switch_type;
+ char l1_status;
+ char l2_status;
+ ChLinkStats dch_stats;
+ ACFAStat AcfaStats;
+ union {
+ PRIStat pristats[23];
+ BRIStat bristats[2];
+ POTStat potsstats[2];
+ } status;
+ union {
+ PRIInfo priinfo;
+ BRIInfo briinfo;
+ POTInfo potsinfo;
+ } info;
+} boardInfo;
--- /dev/null
+/*
+ * $Id: shmem.c,v 1.2 1996/11/20 17:49:56 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * card.c - Card functions implementing ISDN4Linux functionality
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h" /* This must be first */
+#include "hardware.h"
+#include "card.h"
+
+/*
+ * Main adapter array
+ */
+extern board *adapter[];
+extern int cinst;
+
+/*
+ *
+ */
+void *memcpy_toshmem(int card, void *dest, const void *src, size_t n)
+{
+ unsigned long flags;
+ void *ret;
+ unsigned char ch;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return NULL;
+ }
+
+ if(n > SRAM_PAGESIZE) {
+ return NULL;
+ }
+
+ /*
+ * determine the page to load from the address
+ */
+ ch = (unsigned long) dest / SRAM_PAGESIZE;
+ pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+ /*
+ * Block interrupts and load the page
+ */
+ save_flags(flags);
+ cli();
+
+ outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+ adapter[card]->ioport[adapter[card]->shmem_pgport]);
+ pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
+ ((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+ ret = memcpy_toio(adapter[card]->rambase +
+ ((unsigned long) dest % 0x4000), src, n);
+ pr_debug("%s: copying %d bytes from %#x to %#x\n",adapter[card]->devicename, n,
+ (unsigned long) src, adapter[card]->rambase + ((unsigned long) dest %0x4000));
+ restore_flags(flags);
+
+ return ret;
+}
+
+/*
+ * Reverse of above
+ */
+void *memcpy_fromshmem(int card, void *dest, const void *src, size_t n)
+{
+ unsigned long flags;
+ void *ret;
+ unsigned char ch;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return NULL;
+ }
+
+ if(n > SRAM_PAGESIZE) {
+ return NULL;
+ }
+
+ /*
+ * determine the page to load from the address
+ */
+ ch = (unsigned long) src / SRAM_PAGESIZE;
+ pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+
+
+ /*
+ * Block interrupts and load the page
+ */
+ save_flags(flags);
+ cli();
+
+ outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+ adapter[card]->ioport[adapter[card]->shmem_pgport]);
+ pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
+ ((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+ ret = memcpy_fromio(dest,(void *)(adapter[card]->rambase +
+ ((unsigned long) src % 0x4000)), n);
+/* pr_debug("%s: copying %d bytes from %#x to %#x\n",
+ adapter[card]->devicename, n,
+ adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */
+ restore_flags(flags);
+
+ return ret;
+}
+
+void *memset_shmem(int card, void *dest, int c, size_t n)
+{
+ unsigned long flags;
+ unsigned char ch;
+ void *ret;
+
+ if(!IS_VALID_CARD(card)) {
+ pr_debug("Invalid param: %d is not a valid card id\n", card);
+ return NULL;
+ }
+
+ if(n > SRAM_PAGESIZE) {
+ return NULL;
+ }
+
+ /*
+ * determine the page to load from the address
+ */
+ ch = (unsigned long) dest / SRAM_PAGESIZE;
+ pr_debug("%s: loaded page %d\n",adapter[card]->devicename,ch);
+
+ /*
+ * Block interrupts and load the page
+ */
+ save_flags(flags);
+ cli();
+
+ outb(((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
+ adapter[card]->ioport[adapter[card]->shmem_pgport]);
+ pr_debug("%s: set page to %#x\n",adapter[card]->devicename,
+ ((adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
+ ret = memset_io(adapter[card]->rambase +
+ ((unsigned long) dest % 0x4000), c, n);
+ restore_flags(flags);
+
+ return ret;
+}
--- /dev/null
+/*
+ * $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+ * 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.
+ *
+ * For more information, please contact gpl-info@spellcast.com or write:
+ *
+ * SpellCaster Telecommunications Inc.
+ * 5621 Finch Avenue East, Unit #3
+ * Scarborough, Ontario Canada
+ * M1B 2T9
+ * +1 (416) 297-8565
+ * +1 (416) 297-6433 Facsimile
+ */
+
+#define __NO_VERSION__
+#include "includes.h"
+#include "hardware.h"
+#include "message.h"
+#include "card.h"
+
+extern board *adapter[];
+
+extern void flushreadfifo(int);
+extern int startproc(int);
+extern int indicate_status(int, int, unsigned long, char *);
+extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int, unsigned int *);
+
+
+/*
+ * Write the proper values into the I/O ports following a reset
+ */
+void setup_ports(int card)
+{
+
+ outb((adapter[card]->rambase >> 12), adapter[card]->ioport[EXP_BASE]);
+
+ /* And the IRQ */
+ outb((adapter[card]->interrupt | 0x80),
+ adapter[card]->ioport[IRQ_SELECT]);
+}
+
+/*
+ * Timed function to check the status of a previous reset
+ * Must be very fast as this function runs in the context of
+ * an interrupt handler.
+ *
+ * Setup the ioports for the board that were cleared by the reset.
+ * Then, check to see if the signate has been set. Next, set the
+ * signature to a known value and issue a startproc if needed.
+ */
+void check_reset(unsigned long data)
+{
+ unsigned long flags;
+ unsigned long sig;
+ int card = (unsigned int) data;
+
+ pr_debug("%s: check_timer timer called\n", adapter[card]->devicename);
+
+ /* Setup the io ports */
+ setup_ports(card);
+
+ save_flags(flags);
+ cli();
+ outb(adapter[card]->ioport[adapter[card]->shmem_pgport],
+ (adapter[card]->shmem_magic>>14) | 0x80);
+ sig = (unsigned long) *((unsigned long *)(adapter[card]->rambase + SIG_OFFSET));
+
+ /* check the signature */
+ if(sig == SIGNATURE) {
+ flushreadfifo(card);
+ restore_flags(flags);
+ /* See if we need to do a startproc */
+ if (adapter[card]->StartOnReset)
+ startproc(card);
+ }
+ else {
+ pr_debug("%s: No signature yet, waiting another %d jiffies.\n",
+ adapter[card]->devicename, CHECKRESET_TIME);
+ del_timer(&adapter[card]->reset_timer);
+ adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
+ add_timer(&adapter[card]->reset_timer);
+ }
+ restore_flags(flags);
+
+}
+
+/*
+ * Timed function to check the status of a previous reset
+ * Must be very fast as this function runs in the context of
+ * an interrupt handler.
+ *
+ * Send check adapter->phystat to see if the channels are up
+ * If they are, tell ISDN4Linux that the board is up. If not,
+ * tell IADN4Linux that it is up. Always reset the timer to
+ * fire again (endless loop).
+ */
+void check_phystat(unsigned long data)
+{
+ unsigned long flags;
+ int card = (unsigned int) data;
+
+ pr_debug("%s: Checking status...\n", adapter[card]->devicename);
+ /*
+ * check the results of the last PhyStat and change only if
+ * has changed drastically
+ */
+ if (adapter[card]->nphystat && !adapter[card]->phystat) { /* All is well */
+ pr_debug("PhyStat transition to RUN\n");
+ pr_info("%s: Switch contacted, transmitter enabled\n",
+ adapter[card]->devicename);
+ indicate_status(card, ISDN_STAT_RUN, 0, NULL);
+ }
+ else if (!adapter[card]->nphystat && adapter[card]->phystat) { /* All is not well */
+ pr_debug("PhyStat transition to STOP\n");
+ pr_info("%s: Switch connection lost, transmitter disabled\n",
+ adapter[card]->devicename);
+
+ indicate_status(card, ISDN_STAT_STOP, 0, NULL);
+ }
+
+ adapter[card]->phystat = adapter[card]->nphystat;
+
+ /* Reinitialize the timer */
+ save_flags(flags);
+ cli();
+ del_timer(&adapter[card]->stat_timer);
+ adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
+ add_timer(&adapter[card]->stat_timer);
+ restore_flags(flags);
+
+ /* Send a new cePhyStatus message */
+ sendmessage(card, CEPID,ceReqTypePhy,ceReqClass2,
+ ceReqPhyStatus,0,0,NULL);
+}
+
+/*
+ * When in trace mode, this callback is used to swap the working shared
+ * RAM page to the trace page(s) and process all received messages. It
+ * must be called often enough to get all of the messages out of RAM before
+ * it loops around.
+ * Trace messages are \n terminated strings.
+ * We output the messages in 64 byte chunks through readstat. Each chunk
+ * is scanned for a \n followed by a time stamp. If the timerstamp is older
+ * than the current time, scanning stops and the page and offset are recorded
+ * as the starting point the next time the trace timer is called. The final
+ * step is to restore the working page and reset the timer.
+ */
+void trace_timer(unsigned long data)
+{
+ unsigned long flags;
+
+ /*
+ * Disable interrupts and swap the first page
+ */
+ save_flags(flags);
+ cli();
+}
+++ /dev/null
-L_OBJS :=
-M_OBJS :=
-O_OBJS := mod.o card.o config.o buffers.o tei.o isdnl2.o isdnl3.o \
-llglue.o q931.o callc.o fsm.o
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_TELES),y)
- O_TARGET += teles.o
-else
- ifeq ($(CONFIG_ISDN_DRV_TELES),m)
- O_TARGET += teles.o
- M_OBJS += teles.o
- endif
-endif
-
-include $(TOPDIR)/Rules.make
-
+++ /dev/null
-/* $Id: buffers.c,v 1.3 1996/05/31 00:56:53 fritz Exp $
- *
- * $Log: buffers.c,v $
- * Revision 1.3 1996/05/31 00:56:53 fritz
- * removed cli() from BufPoolAdd, since it is called
- * with interrupts off anyway.
- *
- * Revision 1.2 1996/04/29 22:48:14 fritz
- * Removed compatibility-macros. No longer needed.
- *
- * Revision 1.1 1996/04/13 10:19:28 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/mm.h>
-#include <linux/malloc.h>
-
-
-void
-BufPoolInit(struct BufPool *bp, int order, int bpps,
- int maxpages)
-{
-#ifdef DEBUG_MAGIC
- generateerror
- bp->magic = 010167;
-#endif
-
-#if 0
- printk(KERN_DEBUG "BufPoolInit bp %x\n", bp);
-#endif
-
- bp->freelist = NULL;
- bp->pageslist = NULL;
- bp->pageorder = order;
- bp->pagescount = 0;
- bp->bpps = bpps;
- bp->bufsize = BUFFER_SIZE(order, bpps);
- bp->maxpages = maxpages;
-}
-
-int
-BufPoolAdd(struct BufPool *bp, int priority)
-{
- struct Pages *ptr;
- byte *bptr;
- int i;
- struct BufHeader *bh = NULL, *prev, *first;
-
-#if 0
- printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
-#endif
-
- ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0);
- if (!ptr) {
- printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
- return (-1);
- }
-#if 0
- printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr);
-#endif
-
- ptr->next = bp->pageslist;
- bp->pageslist = ptr;
- bp->pagescount++;
-
- bptr = (byte *) ptr + sizeof(struct Pages *);
-
- i = bp->bpps;
- first = (struct BufHeader *) bptr;
- prev = NULL;
- while (i--) {
- bh = (struct BufHeader *) bptr;
-#ifdef DEBUG_MAGIC
- bh->magic = 020167;
-#endif
- bh->next = prev;
- prev = bh;
- bh->bp = bp;
- bptr += PART_SIZE(bp->pageorder, bp->bpps);
- }
-
- first->next = bp->freelist;
- bp->freelist = bh;
- return (0);
-}
-
-void
-BufPoolFree(struct BufPool *bp)
-{
- struct Pages *p;
-
-#if 0
- printk(KERN_DEBUG "BufPoolFree bp %x\n", bp);
-#endif
-
- while (bp->pagescount--) {
- p = bp->pageslist->next;
- free_pages((unsigned long) bp->pageslist, bp->pageorder);
-#if 0
- printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder);
-#endif
- bp->pageslist = p;
- }
-}
-
-int
-BufPoolGet(struct BufHeader **bh,
- struct BufPool *bp, int priority, void *heldby, int where)
-{
- long flags;
- int i;
-
-#ifdef DEBUG_MAGIC
- if (bp->magic != 010167) {
- printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n");
- return (-1);
- }
-#endif
-
- save_flags(flags);
- cli();
- i = 0;
- while (!0) {
- if (bp->freelist) {
- *bh = bp->freelist;
- bp->freelist = bp->freelist->next;
- (*bh)->heldby = heldby;
- (*bh)->where = where;
- restore_flags(flags);
- return (0);
- }
- if ((i == 0) && (bp->pagescount < bp->maxpages)) {
- if (BufPoolAdd(bp, priority)) {
- restore_flags(flags);
- return -1;
- }
- i++;
- } else {
- *bh = NULL;
- restore_flags(flags);
- return (-1);
- }
- }
-
-}
-
-void
-BufPoolRelease(struct BufHeader *bh)
-{
- struct BufPool *bp;
- long flags;
-
-#ifdef DEBUG_MAGIC
- if (bh->magic != 020167) {
- printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n");
- printk(KERN_DEBUG "called from %x\n", __builtin_return_address(0));
- return;
- }
-#endif
-
- bp = bh->bp;
-
-#ifdef DEBUG_MAGIC
- if (bp->magic != 010167) {
- printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n");
- return;
- }
-#endif
-
- save_flags(flags);
- cli();
- bh->next = bp->freelist;
- bp->freelist = bh;
- restore_flags(flags);
-}
-
-void
-BufQueueLink(struct BufQueue *bq,
- struct BufHeader *bh)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- if (!bq->head)
- bq->head = bh;
- if (bq->tail)
- bq->tail->next = bh;
- bq->tail = bh;
- bh->next = NULL;
- restore_flags(flags);
-}
-
-void
-BufQueueLinkFront(struct BufQueue *bq,
- struct BufHeader *bh)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- bh->next = bq->head;
- bq->head = bh;
- if (!bq->tail)
- bq->tail = bh;
- restore_flags(flags);
-}
-
-int
-BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq)
-{
- long flags;
-
- save_flags(flags);
- cli();
-
- if (bq->head) {
- if (bq->tail == bq->head)
- bq->tail = NULL;
- *bh = bq->head;
- bq->head = (*bh)->next;
- restore_flags(flags);
- return (0);
- } else {
- restore_flags(flags);
- return (-1);
- }
-}
-
-void
-BufQueueInit(struct BufQueue *bq)
-{
-#ifdef DEBUG_MAGIC
- bq->magic = 030167;
-#endif
- bq->head = NULL;
- bq->tail = NULL;
-}
-
-void
-BufQueueRelease(struct BufQueue *bq)
-{
- struct BufHeader *bh;
-
- while (bq->head) {
- BufQueueUnlink(&bh, bq);
- BufPoolRelease(bh);
- }
-}
-
-int
-BufQueueLength(struct BufQueue *bq)
-{
- int i = 0;
- struct BufHeader *bh;
-
- bh = bq->head;
- while (bh) {
- i++;
- bh = bh->next;
- }
- return (i);
-}
-
-void
-BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
- int releasetoo)
-{
- long flags;
- struct BufHeader *sp;
-
- save_flags(flags);
- cli();
-
- while (!0) {
- sp = q->head;
- if (!sp)
- break;
- if ((sp->primitive == pr) && (sp->heldby == heldby)) {
- q->head = sp->next;
- if (q->tail == sp)
- q->tail = NULL;
- if (releasetoo)
- BufPoolRelease(sp);
- } else
- break;
- }
-
- sp = q->head;
- if (sp)
- while (sp->next) {
- if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) {
- if (q->tail == sp->next)
- q->tail = sp;
- if (releasetoo)
- BufPoolRelease(sp->next);
- sp->next = sp->next->next;
- } else
- sp = sp->next;
- }
- restore_flags(flags);
-}
-
-void
-Sfree(byte * ptr)
-{
-#if 0
- printk(KERN_DEBUG "Sfree %x\n", ptr);
-#endif
- kfree(ptr);
-}
-
-byte *
-Smalloc(int size, int pr, char *why)
-{
- byte *p;
-
- p = (byte *) kmalloc(size, pr);
-#if 0
- printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, p);
-#endif
- return (p);
-}
+++ /dev/null
-/* $Id: callc.c,v 1.14 1996/10/22 23:14:14 fritz Exp $
- *
- * $Log: callc.c,v $
- * Revision 1.14 1996/10/22 23:14:14 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.13 1996/06/24 17:15:55 fritz
- * corrected return code of teles_writebuf()
- *
- * Revision 1.12 1996/06/12 16:15:33 fritz
- * Extended user-configurable debugging flags.
- *
- * Revision 1.11 1996/06/07 12:32:20 fritz
- * More changes to support suspend/resume.
- *
- * Revision 1.10 1996/06/06 21:24:21 fritz
- * Started adding support for suspend/resume.
- *
- * Revision 1.9 1996/05/31 12:23:57 jdenoud
- * Jan: added channel open check to teles_writebuf
- *
- * Revision 1.8 1996/05/31 01:00:38 fritz
- * Changed return code of teles_writebuf, when out of memory.
- *
- * Revision 1.7 1996/05/17 03:40:37 fritz
- * General cleanup.
- *
- * Revision 1.6 1996/05/10 22:42:07 fritz
- * Added entry for EV_RELEASE_CNF in ST_OUT (if no D-Channel avail.)
- *
- * Revision 1.5 1996/05/06 10:16:15 fritz
- * Added voice stuff.
- *
- * Revision 1.4 1996/04/30 22:04:05 isdn4dev
- * improved callback Karsten Keil
- *
- * Revision 1.3 1996/04/30 10:04:19 fritz
- * Started voice support.
- * Added printk() to debug-switcher for easier
- * synchronization between printk()'s and output
- * of /dev/isdnctrl.
- *
- * Revision 1.2 1996/04/20 16:42:29 fritz
- * Changed statemachine to allow reject of incoming calls.
- *
- * Revision 1.1 1996/04/13 10:20:59 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int nrcards;
-extern int drid;
-extern isdn_if iif;
-extern void teles_mod_dec_use_count(void);
-extern void teles_mod_inc_use_count(void);
-
-static int init_ds(int chan, int incoming);
-static void release_ds(int chan);
-static char *strcpyupto(char *dest, char *src, char upto);
-
-static struct Fsm callcfsm =
-{NULL, 0, 0}, lcfsm =
-{NULL, 0, 0};
-
-struct Channel *chanlist;
-static int chancount = 0;
-unsigned int debugflags = 0;
-
-#define TMR_DCHAN_EST 2000
-
-static void
-stat_debug(struct Channel *chanp, char *s)
-{
- char tmp[100], tm[32];
-
- jiftime(tm, jiffies);
- sprintf(tmp, "%s Channel %d HL->LL %s\n", tm, chanp->chan, s);
- teles_putstatus(tmp);
-}
-
-enum {
- ST_NULL, /* 0 inactive */
- ST_OUT, /* 1 outgoing, awaiting SETUP confirm */
- ST_CLEAR, /* 2 call release, awaiting RELEASE confirm */
- ST_OUT_W, /* 3 outgoing, awaiting d-channel establishment */
- ST_REL_W, /* 4 awaiting d-channel release */
- ST_IN_W, /* 5 incoming, awaiting d-channel establishment */
- ST_IN, /* 6 incoming call received */
- ST_IN_SETUP, /* 7 incoming, SETUP response sent */
- ST_IN_DACT, /* 8 incoming connected, no b-channel prot. */
- ST_OUT_ESTB, /* 10 outgoing connected, awaiting b-channel prot. estbl. */
- ST_ACTIVE, /* 11 active, b channel prot. established */
- ST_BC_HANGUP, /* 12 call clear. (initiator), awaiting b channel prot. rel. */
- ST_PRO_W, /* 13 call clear. (initiator), DISCONNECT req. sent */
- ST_ANT_W, /* 14 call clear. (receiver), awaiting DISCONNECT ind. */
- ST_DISC_BC_HANGUP, /* d channel gone, wait for b channel deactivation */
- ST_OUT_W_HANGUP, /* Outgoing waiting for D-Channel hangup received */
- ST_D_ERR, /* d channel released while active */
-};
-
-#define STATE_COUNT (ST_D_ERR+1)
-
-static char *strState[] =
-{
- "ST_NULL",
- "ST_OUT",
- "ST_CLEAR",
- "ST_OUT_W",
- "ST_REL_W",
- "ST_IN_W",
- "ST_IN",
- "ST_IN_SETUP",
- "ST_IN_DACT",
- "ST_OUT_ESTB",
- "ST_ACTIVE",
- "ST_BC_HANGUP",
- "ST_PRO_W",
- "ST_ANT_W",
- "ST_DISC_BC_HANGUP",
- "ST_OUT_W_HANGUP",
- "ST_D_ERR",
-};
-
-enum {
- EV_DIAL, /* 0 */
- EV_SETUP_CNF, /* 1 */
- EV_ACCEPTB, /* 2 */
- EV_DISCONNECT_CNF, /* 5 */
- EV_DISCONNECT_IND, /* 6 */
- EV_RELEASE_CNF, /* 7 */
- EV_DLEST, /* 8 */
- EV_DLRL, /* 9 */
- EV_SETUP_IND, /* 10 */
- EV_RELEASE_IND, /* 11 */
- EV_ACCEPTD, /* 12 */
- EV_SETUP_CMPL_IND, /* 13 */
- EV_BC_EST, /* 14 */
- EV_WRITEBUF, /* 15 */
- EV_DATAIN, /* 16 */
- EV_HANGUP, /* 17 */
- EV_BC_REL, /* 18 */
- EV_CINF, /* 19 */
- EV_SUSPEND, /* 20 */
- EV_RESUME, /* 21 */
-};
-
-#define EVENT_COUNT (EV_CINF+1)
-
-static char *strEvent[] =
-{
- "EV_DIAL",
- "EV_SETUP_CNF",
- "EV_ACCEPTB",
- "EV_DISCONNECT_CNF",
- "EV_DISCONNECT_IND",
- "EV_RELEASE_CNF",
- "EV_DLEST",
- "EV_DLRL",
- "EV_SETUP_IND",
- "EV_RELEASE_IND",
- "EV_ACCEPTD",
- "EV_SETUP_CMPL_IND",
- "EV_BC_EST",
- "EV_WRITEBUF",
- "EV_DATAIN",
- "EV_HANGUP",
- "EV_BC_REL",
- "EV_CINF",
- "EV_SUSPEND",
- "EV_RESUME",
-};
-
-enum {
- ST_LC_NULL,
- ST_LC_ACTIVATE_WAIT,
- ST_LC_DELAY,
- ST_LC_ESTABLISH_WAIT,
- ST_LC_CONNECTED,
- ST_LC_RELEASE_WAIT,
-};
-
-#define LC_STATE_COUNT (ST_LC_RELEASE_WAIT+1)
-
-static char *strLcState[] =
-{
- "ST_LC_NULL",
- "ST_LC_ACTIVATE_WAIT",
- "ST_LC_DELAY",
- "ST_LC_ESTABLISH_WAIT",
- "ST_LC_CONNECTED",
- "ST_LC_RELEASE_WAIT",
-};
-
-enum {
- EV_LC_ESTABLISH,
- EV_LC_PH_ACTIVATE,
- EV_LC_PH_DEACTIVATE,
- EV_LC_DL_ESTABLISH,
- EV_LC_TIMER,
- EV_LC_DL_RELEASE,
- EV_LC_RELEASE,
-};
-
-#define LC_EVENT_COUNT (EV_LC_RELEASE+1)
-
-static char *strLcEvent[] =
-{
- "EV_LC_ESTABLISH",
- "EV_LC_PH_ACTIVATE",
- "EV_LC_PH_DEACTIVATE",
- "EV_LC_DL_ESTABLISH",
- "EV_LC_TIMER",
- "EV_LC_DL_RELEASE",
- "EV_LC_RELEASE",
-};
-
-#define LC_D 0
-#define LC_B 1
-
-static int
-my_atoi(char *s)
-{
- int i, n;
-
- n = 0;
- if (!s)
- return -1;
- for (i = 0; *s >= '0' && *s <= '9'; i++, s++)
- n = 10 * n + (*s - '0');
- return n;
-}
-
-/*
- * Dial out
- */
-static void
-r1(struct FsmInst *fi, int event, void *arg)
-{
- isdn_ctrl *ic = arg;
- struct Channel *chanp = fi->userdata;
- char *ptr;
- char sis[3];
-
- /* Destination Phone-Number */
- ptr = strcpyupto(chanp->para.called, ic->num, ',');
- /* Source Phone-Number */
- ptr = strcpyupto(chanp->para.calling, ptr + 1, ',');
- if (!strcmp(chanp->para.calling, "0"))
- chanp->para.calling[0] = '\0';
-
- /* Service-Indicator 1 */
- ptr = strcpyupto(sis, ptr + 1, ',');
- chanp->para.info = my_atoi(sis);
-
- /* Service-Indicator 2 */
- ptr = strcpyupto(sis, ptr + 1, '\0');
- chanp->para.info2 = my_atoi(sis);
-
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = 0;
- chanp->lc_b.l2_start = !0;
-
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- chanp->lc_b.l2_establish = !0;
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- chanp->lc_b.l2_establish = 0;
- break;
- default:
- printk(KERN_WARNING "r1 unknown protocol\n");
- break;
- }
-
- FsmChangeState(fi, ST_OUT_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-ll_hangup(struct Channel *chanp, int bchantoo)
-{
- isdn_ctrl ic;
-
- if (bchantoo) {
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_BHUP");
- ic.driver = drid;
- ic.command = ISDN_STAT_BHUP;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
- }
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_DHUP");
- ic.driver = drid;
- ic.command = ISDN_STAT_DHUP;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static void
-r2(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- FsmChangeState(fi, ST_CLEAR);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r2_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-
- FsmChangeState(fi, ST_OUT_W_HANGUP);
-}
-
-
-static void
-r2_2(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_REL_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r3(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
-}
-
-
-static void
-r3_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r4(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp=fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
- FsmChangeState(fi, ST_NULL);
-}
-
-static void
-r5(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->para.callref = chanp->outcallref;
-
- chanp->outcallref++;
- if (chanp->outcallref == 128)
- chanp->outcallref = 64;
-
- chanp->is.l4.l4l3(&chanp->is, CC_SETUP_REQ, NULL);
-
- FsmChangeState(fi, ST_OUT);
-}
-
-static void
-r6(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r7(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- /*
- * Report incoming calls only once to linklevel, use octet 3 of
- * channel identification information element. (it's value
- * is copied to chanp->para.bchannel in l3s12(), file isdnl3.c)
- */
- if (((chanp->chan & 1) + 1) & chanp->para.bchannel) {
- chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL);
- FsmChangeState(fi, ST_IN);
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_ICALL");
- ic.driver = drid;
- ic.command = ISDN_STAT_ICALL;
- ic.arg = chanp->chan;
- /*
- * No need to return "unknown" for calls without OAD,
- * cause that's handled in linklevel now (replaced by '0')
- */
- sprintf(ic.num, "%s,%d,0,%s", chanp->para.calling, chanp->para.info,
- chanp->para.called);
- iif.statcallb(&ic);
- } else {
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
- FsmChangeState(fi, ST_REL_W);
- }
-}
-
-static void
-r8(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_SETUP);
- chanp->is.l4.l4l3(&chanp->is, CC_SETUP_RSP, NULL);
-
-}
-
-static void
-r9(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_IN_DACT);
-
- chanp->l2_active_protocol = chanp->l2_protocol;
- chanp->incoming = !0;
- chanp->lc_b.l2_start = 0;
-
- switch (chanp->l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- chanp->lc_b.l2_establish = !0;
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- chanp->lc_b.l2_establish = 0;
- break;
- default:
- printk(KERN_WARNING "r9 unknown protocol\n");
- break;
- }
-
- init_ds(chanp->chan, !0);
-
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-}
-
-static void
-r10(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_OUT_ESTB);
-
- init_ds(chanp->chan, 0);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_ESTABLISH, NULL);
-
-}
-
-static void
-r12(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
- FsmChangeState(fi, ST_ACTIVE);
- chanp->data_open = !0;
-
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_DCONN");
- ic.driver = drid;
- ic.command = ISDN_STAT_DCONN;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-
- if (chanp->debug & 1)
- stat_debug(chanp, "STAT_BCONN");
- ic.driver = drid;
- ic.command = ISDN_STAT_BCONN;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static void
-r15(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_BC_HANGUP);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r16(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_PRO_W);
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r17(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_ANT_W);
-}
-
-
-static void
-r17_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- release_ds(chanp->chan);
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp,!0);
-}
-
-static void
-r18(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_REL_W);
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r19(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- FsmChangeState(fi, ST_CLEAR);
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r20(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp, 0);
-}
-
-
-static void
-r21(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_DISC_BC_HANGUP);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r22(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_CLEAR);
-
- chanp->is.l4.l4l3(&chanp->is, CC_RELEASE_REQ, NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r23(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_PRO_W);
- chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
-}
-
-static void
-r23_1(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- chanp->is.l4.l4l3(&chanp->is, CC_DLRL,NULL);
-
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE,NULL);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp,!0);
-}
-
-static void
-r24(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- chanp->data_open = 0;
- FsmChangeState(fi, ST_D_ERR);
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_RELEASE, NULL);
-}
-
-static void
-r25(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
-
- release_ds(chanp->chan);
-
- FsmChangeState(fi, ST_NULL);
-
- ll_hangup(chanp, !0);
-}
-
-static void
-r26(struct FsmInst *fi, int event, void *arg)
-{
- struct Channel *chanp = fi->userdata;
- isdn_ctrl ic;
-
-
- ic.driver = drid;
- ic.command = ISDN_STAT_CINF;
- ic.arg = chanp->chan;
- sprintf(ic.num, "%d", chanp->para.chargeinfo);
- iif.statcallb(&ic);
-}
-
-
-
-static struct FsmNode fnlist[] =
-{
- {ST_NULL, EV_DIAL, r1},
- {ST_OUT_W, EV_DLEST, r5},
- {ST_OUT_W, EV_DLRL, r20},
- {ST_OUT_W, EV_RELEASE_CNF, r2_2 },
- {ST_OUT, EV_DISCONNECT_IND, r2},
- {ST_OUT, EV_SETUP_CNF, r10},
- {ST_OUT, EV_HANGUP, r2_1},
- {ST_OUT, EV_RELEASE_IND, r20},
- {ST_OUT, EV_RELEASE_CNF, r20},
- {ST_OUT, EV_DLRL, r2_2},
- {ST_OUT_W_HANGUP, EV_RELEASE_IND, r2_2},
- {ST_OUT_W_HANGUP, EV_DLRL, r20},
- {ST_CLEAR, EV_RELEASE_CNF, r3},
- {ST_CLEAR, EV_DLRL, r20},
- {ST_REL_W, EV_DLRL, r4},
- {ST_NULL, EV_SETUP_IND, r6},
- {ST_IN_W, EV_DLEST, r7},
- {ST_IN_W, EV_DLRL, r3_1},
- {ST_IN, EV_DLRL, r3_1},
- {ST_IN, EV_HANGUP, r2_1},
- {ST_IN, EV_RELEASE_IND, r2_2},
- {ST_IN, EV_RELEASE_CNF, r2_2},
- {ST_IN, EV_ACCEPTD, r8},
- {ST_IN_SETUP, EV_HANGUP, r2_1},
- {ST_IN_SETUP, EV_SETUP_CMPL_IND, r9},
- {ST_IN_SETUP, EV_RELEASE_IND, r2_2},
- {ST_IN_SETUP, EV_DISCONNECT_IND, r2},
- {ST_IN_SETUP, EV_DLRL, r20},
- {ST_OUT_ESTB, EV_BC_EST, r12},
- {ST_OUT_ESTB, EV_BC_REL, r23},
- {ST_OUT_ESTB, EV_DLRL, r23_1},
- {ST_IN_DACT, EV_BC_EST, r12},
- {ST_IN_DACT, EV_BC_REL, r17},
- {ST_IN_DACT, EV_DLRL, r17_1},
- {ST_ACTIVE, EV_HANGUP, r15},
- {ST_ACTIVE, EV_BC_REL, r17},
- {ST_ACTIVE, EV_DISCONNECT_IND, r21},
- {ST_ACTIVE, EV_DLRL, r24},
- {ST_ACTIVE, EV_CINF, r26},
- {ST_ACTIVE, EV_RELEASE_IND, r17},
- {ST_BC_HANGUP, EV_BC_REL, r16},
- {ST_BC_HANGUP, EV_DISCONNECT_IND, r21},
- {ST_PRO_W, EV_RELEASE_IND, r18},
- {ST_ANT_W, EV_DISCONNECT_IND, r19},
- {ST_DISC_BC_HANGUP, EV_BC_REL, r22},
- {ST_D_ERR, EV_BC_REL, r25},
-};
-
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
-
-static void
-lc_r1(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_ACTIVATE_WAIT);
- FsmAddTimer(&lf->act_timer, 1000, EV_LC_TIMER, NULL, 50);
- lf->st->ma.manl1(lf->st, PH_ACTIVATE, NULL);
-
-}
-
-static void
-lc_r6(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmDelTimer(&lf->act_timer, 50);
- FsmChangeState(fi, ST_LC_DELAY);
- FsmAddTimer(&lf->act_timer, 40, EV_LC_TIMER, NULL, 51);
-}
-
-static void
-lc_r2(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- if (lf->l2_establish) {
- FsmChangeState(fi, ST_LC_ESTABLISH_WAIT);
- if (lf->l2_start)
- lf->st->ma.manl2(lf->st, DL_ESTABLISH, NULL);
- } else {
- FsmChangeState(fi, ST_LC_CONNECTED);
- lf->lccall(lf, LC_ESTABLISH, NULL);
- }
-}
-
-static void
-lc_r3(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_CONNECTED);
- lf->lccall(lf, LC_ESTABLISH, NULL);
-}
-
-static void
-lc_r4(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- if (lf->l2_establish) {
- FsmChangeState(fi, ST_LC_RELEASE_WAIT);
- lf->st->ma.manl2(lf->st, DL_RELEASE, NULL);
- } else {
- FsmChangeState(fi, ST_LC_NULL);
- lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
- lf->lccall(lf, LC_RELEASE, NULL);
- }
-}
-
-static void
-lc_r5(struct FsmInst *fi, int event, void *arg)
-{
- struct LcFsm *lf = fi->userdata;
-
- FsmChangeState(fi, ST_LC_NULL);
- lf->st->ma.manl1(lf->st, PH_DEACTIVATE, NULL);
- lf->lccall(lf, LC_RELEASE, NULL);
-}
-
-static struct FsmNode LcFnList[] =
-{
- {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1},
- {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6},
- {ST_LC_DELAY, EV_LC_TIMER, lc_r2},
- {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3},
- {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4},
- {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5},
- {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5},
- {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5},
- {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5},
-};
-
-#define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode))
-
-void
-CallcNew(void)
-{
- callcfsm.state_count = STATE_COUNT;
- callcfsm.event_count = EVENT_COUNT;
- callcfsm.strEvent = strEvent;
- callcfsm.strState = strState;
- FsmNew(&callcfsm, fnlist, FNCOUNT);
-
- lcfsm.state_count = LC_STATE_COUNT;
- lcfsm.event_count = LC_EVENT_COUNT;
- lcfsm.strEvent = strLcEvent;
- lcfsm.strState = strLcState;
- FsmNew(&lcfsm, LcFnList, LC_FN_COUNT);
-}
-
-void
-CallcFree(void)
-{
- FsmFree(&lcfsm);
- FsmFree(&callcfsm);
-}
-
-static void
-release_ds(int chan)
-{
- struct PStack *st = &chanlist[chan].ds;
- struct IsdnCardState *sp;
- struct HscxState *hsp;
-
- sp = st->l1.hardware;
- hsp = sp->hs + chanlist[chan].hscx;
-
- close_hscxstate(hsp);
-
- switch (chanlist[chan].l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- releasestack_isdnl2(st);
- break;
- case (ISDN_PROTO_L2_HDLC):
- case (ISDN_PROTO_L2_TRANS):
- releasestack_transl2(st);
- break;
- }
-}
-
-static void
-cc_l1man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (PH_ACTIVATE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_PH_DEACTIVATE, NULL);
- break;
- }
-}
-
-static void
-cc_l2man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_ESTABLISH, NULL);
- break;
- case (DL_RELEASE):
- FsmEvent(&chanp->lc_d.lcfi, EV_LC_DL_RELEASE, NULL);
- break;
- }
-}
-
-static void
-dcc_l1man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (PH_ACTIVATE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_PH_DEACTIVATE, NULL);
- break;
- }
-}
-
-static void
-dcc_l2man(struct PStack *st, int pr, void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_ESTABLISH, NULL);
- break;
- case (DL_RELEASE):
- FsmEvent(&chanp->lc_b.lcfi, EV_LC_DL_RELEASE, NULL);
- break;
- }
-}
-
-static void
-ll_handler(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
-
- switch (pr) {
- case (CC_DISCONNECT_IND):
- FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
- break;
- case (CC_RELEASE_CNF):
- FsmEvent(&chanp->fi, EV_RELEASE_CNF, NULL);
- break;
- case (CC_SETUP_IND):
- FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
- break;
- case (CC_RELEASE_IND):
- FsmEvent(&chanp->fi, EV_RELEASE_IND, NULL);
- break;
- case (CC_SETUP_COMPLETE_IND):
- FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL);
- break;
- case (CC_SETUP_CNF):
- FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL);
- break;
- case (CC_INFO_CHARGE):
- FsmEvent(&chanp->fi, EV_CINF, NULL);
- break;
- }
-}
-
-static void
-init_is(int chan, unsigned int ces)
-{
- struct PStack *st = &(chanlist[chan].is);
- struct IsdnCardState *sp = chanlist[chan].sp;
- char tmp[128];
-
- setstack_teles(st, sp);
-
- st->l2.sap = 0;
-
- st->l2.tei = 255;
-
- st->l2.ces = ces;
- st->l2.extended = !0;
- st->l2.laptype = LAPD;
- st->l2.window = 1;
- st->l2.orig = !0;
- st->l2.t200 = 1000; /* 1000 milliseconds */
- if (st->protocol == ISDN_PTYPE_1TR6) {
- st->l2.n200 = 3; /* try 3 times */
- st->l2.t203 = 10000; /* 10000 milliseconds */
- } else {
- st->l2.n200 = 4; /* try 4 times */
- st->l2.t203 = 5000; /* 5000 milliseconds */
- }
-
- sprintf(tmp, "Channel %d q.921", chan);
- setstack_isdnl2(st, tmp);
- setstack_isdnl3(st);
- st->l2.debug = 2;
- st->l3.debug = 2;
- st->l2.debug = 0xff;
- st->l3.debug = 0xff;
- st->l4.userdata = chanlist + chan;
- st->l4.l2writewakeup = NULL;
-
- st->l3.l3l4 = ll_handler;
- st->l1.l1man = cc_l1man;
- st->l2.l2man = cc_l2man;
-
- st->pa = &chanlist[chan].para;
- teles_addlist(sp, st);
-}
-
-static void
-callc_debug(struct FsmInst *fi, char *s)
-{
- char str[80], tm[32];
- struct Channel *chanp = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d callc %s\n", tm, chanp->chan, s);
- teles_putstatus(str);
-}
-
-static void
-lc_debug(struct FsmInst *fi, char *s)
-{
- char str[256], tm[32];
- struct LcFsm *lf = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d lc %s\n", tm, lf->ch->chan, s);
- teles_putstatus(str);
-}
-
-static void
-dlc_debug(struct FsmInst *fi, char *s)
-{
- char str[256], tm[32];
- struct LcFsm *lf = fi->userdata;
-
- jiftime(tm, jiffies);
- sprintf(str, "%s Channel %d dlc %s\n", tm, lf->ch->chan, s);
- teles_putstatus(str);
-}
-
-static void
-lccall_d(struct LcFsm *lf, int pr, void *arg)
-{
- struct Channel *chanp = lf->ch;
-
- switch (pr) {
- case (LC_ESTABLISH):
- FsmEvent(&chanp->fi, EV_DLEST, NULL);
- break;
- case (LC_RELEASE):
- FsmEvent(&chanp->fi, EV_DLRL, NULL);
- break;
- }
-}
-
-static void
-lccall_b(struct LcFsm *lf, int pr, void *arg)
-{
- struct Channel *chanp = lf->ch;
-
- switch (pr) {
- case (LC_ESTABLISH):
- FsmEvent(&chanp->fi, EV_BC_EST, NULL);
- break;
- case (LC_RELEASE):
- FsmEvent(&chanp->fi, EV_BC_REL, NULL);
- break;
- }
-}
-
-static void
-init_chan(int chan, int cardnr, int hscx,
- unsigned int ces)
-{
- struct IsdnCard *card = cards + cardnr;
- struct Channel *chanp = chanlist + chan;
-
- chanp->sp = card->sp;
- chanp->hscx = hscx;
- chanp->chan = chan;
- chanp->incoming = 0;
- chanp->debug = 0;
- init_is(chan, ces);
-
- chanp->fi.fsm = &callcfsm;
- chanp->fi.state = ST_NULL;
- chanp->fi.debug = 0;
- chanp->fi.userdata = chanp;
- chanp->fi.printdebug = callc_debug;
-
- chanp->lc_d.lcfi.fsm = &lcfsm;
- chanp->lc_d.lcfi.state = ST_LC_NULL;
- chanp->lc_d.lcfi.debug = 0;
- chanp->lc_d.lcfi.userdata = &chanp->lc_d;
- chanp->lc_d.lcfi.printdebug = lc_debug;
- chanp->lc_d.type = LC_D;
- chanp->lc_d.ch = chanp;
- chanp->lc_d.st = &chanp->is;
- chanp->lc_d.l2_establish = !0;
- chanp->lc_d.l2_start = !0;
- chanp->lc_d.lccall = lccall_d;
- FsmInitTimer(&chanp->lc_d.lcfi, &chanp->lc_d.act_timer);
-
- chanp->lc_b.lcfi.fsm = &lcfsm;
- chanp->lc_b.lcfi.state = ST_LC_NULL;
- chanp->lc_b.lcfi.debug = 0;
- chanp->lc_b.lcfi.userdata = &chanp->lc_b;
- chanp->lc_b.lcfi.printdebug = dlc_debug;
- chanp->lc_b.type = LC_B;
- chanp->lc_b.ch = chanp;
- chanp->lc_b.st = &chanp->ds;
- chanp->lc_b.l2_establish = !0;
- chanp->lc_b.l2_start = !0;
- chanp->lc_b.lccall = lccall_b;
- FsmInitTimer(&chanp->lc_b.lcfi, &chanp->lc_b.act_timer);
-
- chanp->outcallref = 64;
- chanp->data_open = 0;
-}
-
-int
-CallcNewChan(void)
-{
- int i, ces, c;
-
- chancount = 0;
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- chancount += 2;
-
- chanlist = (struct Channel *) Smalloc(sizeof(struct Channel) *
- chancount, GFP_KERNEL, "chanlist");
-
- c = 0;
- ces = randomces();
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- init_chan(c++, i, 1, ces++);
- ces %= 0xffff;
- init_chan(c++, i, 0, ces++);
- ces %= 0xffff;
- }
- printk(KERN_INFO "channels %d\n", chancount);
- return (chancount);
-
-}
-
-static void
-release_is(int chan)
-{
- struct PStack *st = &chanlist[chan].is;
-
- releasestack_isdnl2(st);
- teles_rmlist(st->l1.hardware, st);
- BufQueueRelease(&st->l2.i_queue);
-}
-
-void
-CallcFreeChan(void)
-{
- int i;
-
- for (i = 0; i < chancount; i++)
- release_is(i);
- Sfree((void *) chanlist);
-}
-
-static void
-lldata_handler(struct PStack *st, int pr,
- void *arg)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
- byte *ptr;
- int size;
- struct BufHeader *ibh = arg;
-
- switch (pr) {
- case (DL_DATA):
- if (chanp->data_open) {
- ptr = DATAPTR(ibh);
- ptr += chanp->ds.l2.ihsize;
- size = ibh->datasize - chanp->ds.l2.ihsize;
- iif.rcvcallb(drid, chanp->chan, ptr, size);
- }
- BufPoolRelease(ibh);
- break;
- default:
- printk(KERN_WARNING "lldata_handler unknown primitive\n");
- break;
- }
-}
-
-static void
-lltrans_handler(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct Channel *chanp = (struct Channel *) st->l4.userdata;
- byte *ptr;
-
- switch (pr) {
- case (PH_DATA):
- if (chanp->data_open) {
- ptr = DATAPTR(ibh);
- iif.rcvcallb(drid, chanp->chan, ptr, ibh->datasize);
- }
- BufPoolRelease(ibh);
- break;
- default:
- printk(KERN_WARNING "lltrans_handler unknown primitive\n");
- break;
- }
-}
-
-static void
-ll_writewakeup(struct PStack *st)
-{
- struct Channel *chanp = st->l4.userdata;
- isdn_ctrl ic;
-
- ic.driver = drid;
- ic.command = ISDN_STAT_BSENT;
- ic.arg = chanp->chan;
- iif.statcallb(&ic);
-}
-
-static int
-init_ds(int chan, int incoming)
-{
- struct PStack *st = &(chanlist[chan].ds);
- struct IsdnCardState *sp = (struct IsdnCardState *)
- chanlist[chan].is.l1.hardware;
- struct HscxState *hsp = sp->hs + chanlist[chan].hscx;
- char tmp[128];
-
- st->l1.hardware = sp;
-
- hsp->mode = 2;
- hsp->transbufsize = 4000;
-
- if (setstack_hscx(st, hsp))
- return (-1);
-
- st->l2.extended = 0;
- st->l2.laptype = LAPB;
- st->l2.orig = !incoming;
- st->l2.t200 = 1000; /* 1000 milliseconds */
- st->l2.window = 3;
- st->l2.n200 = 4; /* try 4 times */
- st->l2.t203 = 5000; /* 5000 milliseconds */
-
- st->l2.debug = 0xff;
- st->l3.debug = 0xff;
- switch (chanlist[chan].l2_active_protocol) {
- case (ISDN_PROTO_L2_X75I):
- sprintf(tmp, "Channel %d x.75", chan);
- setstack_isdnl2(st, tmp);
- st->l2.l2l3 = lldata_handler;
- st->l1.l1man = dcc_l1man;
- st->l2.l2man = dcc_l2man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = NULL;
- st->l4.l2writewakeup = ll_writewakeup;
- st->l2.l2m.debug = debugflags & 16;
- st->ma.manl2(st, MDL_NOTEIPROC, NULL);
- st->l1.hscxmode = 2; /* Packet-Mode ? */
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- case (ISDN_PROTO_L2_HDLC):
- st->l1.l1l2 = lltrans_handler;
- st->l1.l1man = dcc_l1man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = ll_writewakeup;
- st->l1.hscxmode = 2;
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- case (ISDN_PROTO_L2_TRANS):
- st->l1.l1l2 = lltrans_handler;
- st->l1.l1man = dcc_l1man;
- st->l4.userdata = chanlist + chan;
- st->l4.l1writewakeup = ll_writewakeup;
- st->l1.hscxmode = 1;
- st->l1.hscxchannel = chanlist[chan].para.bchannel - 1;
- break;
- }
-
- return (0);
-
-}
-
-static void
-channel_report(int i)
-{
-}
-
-static void
-command_debug(struct Channel *chanp, char *s)
-{
- char tmp[64], tm[32];
-
- jiftime(tm, jiffies);
- sprintf(tmp, "%s Channel %d LL->HL %s\n", tm, chanp->chan, s);
- teles_putstatus(tmp);
-}
-
-static void
-distr_debug(void)
-{
- int i;
-
- for (i = 0; i < chancount; i++) {
- chanlist[i].debug = debugflags & 1;
- chanlist[i].fi.debug = debugflags & 2;
- chanlist[i].is.l2.l2m.debug = debugflags & 8;
- chanlist[i].ds.l2.l2m.debug = debugflags & 16;
- }
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- cards[i].sp->dlogflag = debugflags & 4;
- cards[i].sp->debug = debugflags & 32;
- }
-}
-
-int
-teles_command(isdn_ctrl * ic)
-{
- struct Channel *chanp;
- char tmp[64];
- int i;
- unsigned int num;
-
- switch (ic->command) {
- case (ISDN_CMD_SETEAZ):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "SETEAZ");
- return (0);
- case (ISDN_CMD_DIAL):
- chanp = chanlist + (ic->arg & 0xff);
- if (chanp->debug & 1) {
- sprintf(tmp, "DIAL %s", ic->num);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_DIAL, ic);
- return (0);
- case (ISDN_CMD_ACCEPTB):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "ACCEPTB");
- FsmEvent(&chanp->fi, EV_ACCEPTB, NULL);
- break;
- case (ISDN_CMD_ACCEPTD):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "ACCEPTD");
- FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
- break;
- case (ISDN_CMD_HANGUP):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1)
- command_debug(chanp, "HANGUP");
- FsmEvent(&chanp->fi, EV_HANGUP, NULL);
- break;
- case (ISDN_CMD_SUSPEND):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1) {
- sprintf(tmp, "SUSPEND %s", ic->num);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_SUSPEND, ic);
- break;
- case (ISDN_CMD_RESUME):
- chanp = chanlist + ic->arg;
- if (chanp->debug & 1) {
- sprintf(tmp, "RESUME %s", ic->num);
- command_debug(chanp, tmp);
- }
- FsmEvent(&chanp->fi, EV_RESUME, ic);
- break;
- case (ISDN_CMD_LOCK):
- teles_mod_inc_use_count();
- break;
- case (ISDN_CMD_UNLOCK):
- teles_mod_dec_use_count();
- break;
- case (ISDN_CMD_IOCTL):
- switch (ic->arg) {
- case (0):
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- teles_reportcard(i);
- for (i = 0; i < chancount; i++)
- channel_report(i);
- break;
- case (1):
- debugflags = *(unsigned int *) ic->num;
- distr_debug();
- sprintf(tmp, "debugging flags set to %x\n", debugflags);
- teles_putstatus(tmp);
- printk(KERN_DEBUG "%s", tmp);
- break;
- case (2):
- num = *(unsigned int *) ic->num;
- i = num >> 8;
- if (i >= chancount)
- break;
- chanp = chanlist + i;
- chanp->impair = num & 0xff;
- if (chanp->debug & 1) {
- sprintf(tmp, "IMPAIR %x", chanp->impair);
- command_debug(chanp, tmp);
- }
- break;
- }
- break;
- case (ISDN_CMD_SETL2):
- chanp = chanlist + (ic->arg & 0xff);
- if (chanp->debug & 1) {
- sprintf(tmp, "SETL2 %ld", ic->arg >> 8);
- command_debug(chanp, tmp);
- }
- chanp->l2_protocol = ic->arg >> 8;
- break;
- default:
- break;
- }
-
- return (0);
-}
-
-int
-teles_writebuf(int id, int chan, const u_char * buf, int count, int user)
-{
- struct Channel *chanp = chanlist + chan;
- struct PStack *st = &chanp->ds;
- struct BufHeader *ibh;
- int err, i;
- byte *ptr;
-
- if (!chanp->data_open) {
- printk(KERN_DEBUG "teles_writebuf: channel not open\n");
- return -EIO;
- }
-
- err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21);
- if (err)
- /* Must return 0 here, since this is not an error
- * but a temporary lack of resources.
- */
- return 0;
-
- ptr = DATAPTR(ibh);
- if (chanp->lc_b.l2_establish)
- i = st->l2.ihsize;
- else
- i = 0;
-
- if ((count+i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) {
- printk(KERN_WARNING "teles_writebuf: packet too large!\n");
- return (-EINVAL);
- }
-
- ptr += i;
-
- if (user)
- copy_from_user(ptr, buf, count);
- else
- memcpy(ptr, buf, count);
- ibh->datasize = count + i;
-
- if (chanp->data_open) {
- if (chanp->lc_b.l2_establish)
- chanp->ds.l3.l3l2(&chanp->ds, DL_DATA, ibh);
- else
- chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, ibh);
- return (count);
- } else {
- BufPoolRelease(ibh);
- return (0);
- }
-
-}
-
-static char *
-strcpyupto(char *dest, char *src, char upto)
-{
- while (*src && (*src != upto) && (*src != '\0'))
- *dest++ = *src++;
- *dest = '\0';
- return (src);
-}
+++ /dev/null
-/* $Id: card.c,v 1.16 1996/10/22 23:14:16 fritz Exp $
- *
- * card.c low level stuff for the Teles S0 isdn card
- *
- * Author Jan den Ouden
- *
- * Beat Doebeli log all D channel traffic
- *
- * $Log: card.c,v $
- * Revision 1.16 1996/10/22 23:14:16 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.15 1996/09/29 19:41:56 fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.14 1996/09/23 01:53:49 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.13 1996/07/18 11:21:24 jdenoud
- * Use small buffers for incoming audio data
- *
- * Revision 1.12 1996/06/24 17:16:52 fritz
- * Added check for misconfigured membase.
- *
- * Revision 1.11 1996/06/14 03:30:37 fritz
- * Added recovery from EXIR 40 interrupt.
- * Some cleanup.
- *
- * Revision 1.10 1996/06/11 14:57:20 hipp
- * minor changes to ensure, that SKBs are sent in the right order
- *
- * Revision 1.9 1996/06/06 14:42:09 fritz
- * Bugfix: forgot hsp-> in last change.
- *
- * Revision 1.7 1996/05/31 01:02:21 fritz
- * Cosmetic changes.
- *
- * Revision 1.6 1996/05/26 14:58:10 fritz
- * Bugfix: Did not show port correctly, when no card found.
- *
- * Revision 1.5 1996/05/17 03:45:02 fritz
- * Made error messages more clearly.
- * Bugfix: Only 31 bytes of 32-byte audio frames
- * have been transfered to upper layers.
- *
- * Revision 1.4 1996/05/06 10:17:57 fritz
- * Added voice-send stuff
- * (Not reporting EXIR when in voice-mode, since it's normal).
- *
- * Revision 1.3 1996/04/30 22:02:40 isdn4dev
- * Bugfixes for 16.3
- * -improved IO allocation
- * -fix second B channel problem
- * -correct ph_command patch
- *
- * Revision 1.2 1996/04/30 10:00:59 fritz
- * Bugfix: Added ph_command(8) for 16.3.
- * Bugfix: Ports did not get registered correctly
- * when using a 16.3.
- * Started voice support.
- * Some experimental changes of waitforXFW().
- *
- * Revision 1.1 1996/04/13 10:22:42 fritz
- * Initial revision
- *
- *
- */
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-
-#define INCLUDE_INLINE_FUNCS
-#include <linux/tqueue.h>
-#include <linux/interrupt.h>
-
-#undef DCHAN_VERBOSE
-
-extern void tei_handler(struct PStack *st, byte pr,
- struct BufHeader *ibh);
-extern struct IsdnCard cards[];
-extern int nrcards;
-
-#define byteout(addr,val) outb_p(val,addr)
-#define bytein(addr) inb_p(addr)
-
-static inline byte
-readisac_0(byte * cardm, byte offset)
-{
- return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline byte
-readisac_3(int iobase, byte offset)
-{
- return (bytein(iobase - 0x420 + offset));
-}
-
-#define READISAC(mbase,ibase,ofs) \
- ((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs))
-
-static inline void
-writeisac_0(byte * cardm, byte offset, byte value)
-{
- writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
-}
-
-static inline void
-writeisac_3(int iobase, byte offset, byte value)
-{
- byteout(iobase - 0x420 + offset, value);
-}
-
-#define WRITEISAC(mbase,ibase,ofs,val) \
- ((mbase)?writeisac_0(mbase,ofs,val):writeisac_3(ibase,ofs,val))
-
-static inline void
-readisac_s(int iobase, byte offset, byte * dest, int count)
-{
- insb(iobase - 0x420 + offset, dest, count);
-}
-
-static inline void
-writeisac_s(int iobase, byte offset, byte * src, int count)
-{
- outsb(iobase - 0x420 + offset, src, count);
-}
-
-static inline byte
-readhscx_0(byte * base, byte hscx, byte offset)
-{
- return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
- ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline byte
-readhscx_3(int iobase, byte hscx, byte offset)
-{
- return (bytein(iobase - (hscx ? 0x820 : 0xc20) + offset));
-}
-
-#define READHSCX(mbase,ibase,hscx,ofs) \
- ((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs))
-
-static inline void
-writehscx_0(byte * base, byte hscx, byte offset, byte data)
-{
- writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
- ((hscx & 1) ? 0x40 : 0) + offset);
-}
-
-static inline void
-writehscx_3(int iobase, byte hscx, byte offset, byte data)
-{
- byteout(iobase - (hscx ? 0x820 : 0xc20) + offset, data);
-}
-
-static inline void
-readhscx_s(int iobase, byte hscx, byte offset, byte * dest, int count)
-{
- insb(iobase - (hscx ? 0x820 : 0xc20) + offset, dest, count);
-}
-
-static inline void
-writehscx_s(int iobase, byte hscx, byte offset, byte * src, int count)
-{
- outsb(iobase - (hscx ? 0x820 : 0xc20) + offset, src, count);
-}
-
-#define ISAC_MASK 0x20
-#define ISAC_ISTA 0x20
-#define ISAC_STAR 0x21
-#define ISAC_CMDR 0x21
-#define ISAC_EXIR 0x24
-
-#define ISAC_RBCH 0x2a
-
-#define ISAC_ADF2 0x39
-#define ISAC_SPCR 0x30
-#define ISAC_ADF1 0x38
-#define ISAC_CIX0 0x31
-#define ISAC_STCR 0x37
-#define ISAC_MODE 0x22
-#define ISAC_RSTA 0x27
-#define ISAC_RBCL 0x25
-#define ISAC_TIMR 0x23
-#define ISAC_SQXR 0x3b
-
-#define HSCX_ISTA 0x20
-#define HSCX_CCR1 0x2f
-#define HSCX_CCR2 0x2c
-#define HSCX_TSAR 0x31
-#define HSCX_TSAX 0x30
-#define HSCX_XCCR 0x32
-#define HSCX_RCCR 0x33
-#define HSCX_MODE 0x22
-#define HSCX_CMDR 0x21
-#define HSCX_EXIR 0x24
-#define HSCX_XAD1 0x24
-#define HSCX_XAD2 0x25
-#define HSCX_RAH2 0x27
-#define HSCX_RSTA 0x27
-#define HSCX_TIMR 0x23
-#define HSCX_STAR 0x21
-#define HSCX_RBCL 0x25
-#define HSCX_XBCH 0x2d
-#define HSCX_VSTR 0x2e
-#define HSCX_RLCR 0x2e
-#define HSCX_MASK 0x20
-
-static inline void
-waitforCEC_0(byte * base, byte hscx)
-{
- long to = 10;
-
- while ((readhscx_0(base, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforCEC_3(int iobase, byte hscx)
-{
- long to = 10;
-
- while ((readhscx_3(iobase, hscx, HSCX_STAR) & 0x04) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforCEC timeout\n");
-}
-
-static inline void
-waitforXFW_0(byte * base, byte hscx)
-{
- long to = 20;
-
- while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-waitforXFW_3(int iobase, byte hscx)
-{
- long to = 20;
-
- while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
- udelay(5);
- to--;
- }
- if (!to)
- printk(KERN_WARNING "waitforXFW timeout\n");
-}
-
-static inline void
-writehscxCMDR_0(byte * base, byte hscx, byte data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC_0(base, hscx);
- writehscx_0(base, hscx, HSCX_CMDR, data);
- restore_flags(flags);
-}
-
-static inline void
-writehscxCMDR_3(int iobase, byte hscx, byte data)
-{
- long flags;
-
- save_flags(flags);
- cli();
- waitforCEC_3(iobase, hscx);
- writehscx_3(iobase, hscx, HSCX_CMDR, data);
- restore_flags(flags);
-}
-
-#define WRITEHSCX_CMDR(mbase,ibase,hscx,data) \
- ((mbase)?writehscxCMDR_0(mbase,hscx,data):writehscxCMDR_3(ibase,hscx,data))
-
-/*
- * fast interrupt here
- */
-
-#define ISAC_RCVBUFREADY 0
-#define ISAC_XMTBUFREADY 1
-#define ISAC_PHCHANGE 2
-
-#define HSCX_RCVBUFREADY 0
-#define HSCX_XMTBUFREADY 1
-
-void
-teles_hscxreport(struct IsdnCardState *sp, int hscx)
-{
- printk(KERN_DEBUG "HSCX %d\n", hscx);
- if (sp->membase) {
- printk(KERN_DEBUG " ISTA %x\n", readhscx_0(sp->membase,
- hscx, HSCX_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readhscx_0(sp->membase,
- hscx, HSCX_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readhscx_0(sp->membase,
- hscx, HSCX_EXIR));
- } else {
- printk(KERN_DEBUG " ISTA %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readhscx_3(sp->iobase,
- hscx, HSCX_EXIR));
- }
-}
-
-void
-teles_report(struct IsdnCardState *sp)
-{
- printk(KERN_DEBUG "ISAC\n");
- if (sp->membase) {
- printk(KERN_DEBUG " ISTA %x\n", readisac_0(sp->membase,
- ISAC_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readisac_0(sp->membase,
- ISAC_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readisac_0(sp->membase,
- ISAC_EXIR));
- } else {
- printk(KERN_DEBUG " ISTA %x\n", readisac_3(sp->iobase,
- ISAC_ISTA));
- printk(KERN_DEBUG " STAR %x\n", readisac_3(sp->iobase,
- ISAC_STAR));
- printk(KERN_DEBUG " EXIR %x\n", readisac_3(sp->iobase,
- ISAC_EXIR));
- }
- teles_hscxreport(sp, 0);
- teles_hscxreport(sp, 1);
-}
-
-/*
- * HSCX stuff goes here
- */
-
-static void
-hscx_sched_event(struct HscxState *hsp, int event)
-{
- hsp->event |= 1 << event;
- queue_task_irq_off(&hsp->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-static void
-hscx_empty_fifo(struct HscxState *hsp, int count)
-{
- byte *ptr;
- struct BufHeader *ibh = hsp->rcvibh;
-
- if (hsp->sp->debug)
- printk(KERN_DEBUG "hscx_empty_fifo\n");
-
- if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
- HSCX_RBUF_BPPS)) {
- printk(KERN_WARNING
- "hscx_empty_fifo: incoming packet too large\n");
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, 0x80);
- return;
- }
- ptr = DATAPTR(ibh);
- ptr += hsp->rcvptr;
-
- hsp->rcvptr += count;
- if (hsp->membase) {
- while (count--)
- *ptr++ = readhscx_0(hsp->membase, hsp->hscx, 0x0);
- writehscxCMDR_0(hsp->membase, hsp->hscx, 0x80);
- } else {
- readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
- writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80);
- }
-}
-
-static void
-hscx_fill_fifo(struct HscxState *hsp)
-{
- struct BufHeader *ibh;
- int more, count;
- byte *ptr;
-
- if (hsp->sp->debug)
- printk(KERN_DEBUG "hscx_fill_fifo\n");
-
- ibh = hsp->xmtibh;
- if (!ibh)
- return;
-
- count = ibh->datasize - hsp->sendptr;
- if (count <= 0)
- return;
-
- more = (hsp->mode == 1)?1:0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- ptr = DATAPTR(ibh);
- ptr += hsp->sendptr;
- hsp->sendptr += count;
-
-#ifdef BCHAN_VERBOSE
- {
- int i;
- printk(KERN_DEBUG "hscx_fill_fifo ");
- for (i = 0; i < count; i++)
- printk(" %2x", ptr[i]);
- printk("\n");
- }
-#endif
- if (hsp->membase) {
- waitforXFW_0(hsp->membase, hsp->hscx);
- while (count--)
- writehscx_0(hsp->membase, hsp->hscx, 0x0, *ptr++);
- writehscxCMDR_0(hsp->membase, hsp->hscx, more ? 0x8 : 0xa);
- } else {
- waitforXFW_3(hsp->iobase, hsp->hscx);
- writehscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
- writehscxCMDR_3(hsp->iobase, hsp->hscx, more ? 0x8 : 0xa);
- }
-}
-
-static inline void
-hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
-{
- byte r;
- struct HscxState *hsp = sp->hs + hscx;
- int count, err;
-
- if (!hsp->init)
- return;
-
- if (val & 0x80) { /* RME */
-
- r = READHSCX(hsp->membase, sp->iobase, hsp->hscx, HSCX_RSTA);
- if ((r & 0xf0) != 0xa0) {
- if (!r & 0x80)
- printk(KERN_WARNING
- "Teles: HSCX invalid frame\n");
- if ((r & 0x40) && hsp->mode)
- printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode);
- if (!r & 0x20)
- printk(KERN_WARNING "Teles: HSCX CRC error\n");
- if (hsp->rcvibh)
- BufPoolRelease(hsp->rcvibh);
- hsp->rcvibh = NULL;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx,
- 0x80);
- goto afterRME;
- }
- if (!hsp->rcvibh)
- if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
- GFP_ATOMIC, (void *) 1, 1)) {
- printk(KERN_WARNING
- "HSCX RME out of buffers at %ld\n",
- jiffies);
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x80);
- goto afterRME;
- } else
- hsp->rcvptr = 0;
-
- count = READHSCX(hsp->membase, sp->iobase, hsp->hscx,
- HSCX_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- hscx_empty_fifo(hsp, count);
- hsp->rcvibh->datasize = hsp->rcvptr - 1;
- BufQueueLink(&hsp->rq, hsp->rcvibh);
- hsp->rcvibh = NULL;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
- afterRME:
- if (val & 0x40) { /* RPF */
- if (!hsp->rcvibh) {
- if (hsp->mode == 1)
- err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
- GFP_ATOMIC, (void *)1, 2);
- else
- err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
- GFP_ATOMIC, (void *)1, 2);
-
- if (err) {
- printk(KERN_WARNING
- "HSCX RPF out of buffers at %ld\n",
- jiffies);
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x80);
- goto afterRPF;
- } else
- hsp->rcvptr = 0;
- }
-
- hscx_empty_fifo(hsp, 32);
- if (hsp->mode == 1) {
- /* receive audio data */
- hsp->rcvibh->datasize = hsp->rcvptr;
- BufQueueLink(&hsp->rq, hsp->rcvibh);
- hsp->rcvibh = NULL;
- hscx_sched_event(hsp, HSCX_RCVBUFREADY);
- }
-
- }
- afterRPF:
- if (val & 0x10) { /* XPR */
- if (hsp->xmtibh)
- if (hsp->xmtibh->datasize > hsp->sendptr) {
- hscx_fill_fifo(hsp);
- goto afterXPR;
- } else {
- if (hsp->releasebuf)
- BufPoolRelease(hsp->xmtibh);
- hsp->sendptr = 0;
- if (hsp->st->l4.l1writewakeup)
- hsp->st->l4.l1writewakeup(hsp->st);
- hsp->xmtibh = NULL;
- }
- if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
- hsp->releasebuf = !0;
- hscx_fill_fifo(hsp);
- } else
- hscx_sched_event(hsp, HSCX_XMTBUFREADY);
- }
- afterXPR:
-}
-
-/*
- * ISAC stuff goes here
- */
-
-static void
-isac_sched_event(struct IsdnCardState *sp, int event)
-{
- sp->event |= 1 << event;
- queue_task_irq_off(&sp->tqueue, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-static void
-empty_fifo(struct IsdnCardState *sp, int count)
-{
- byte *ptr;
- struct BufHeader *ibh = sp->rcvibh;
-
- if (sp->debug)
- printk(KERN_DEBUG "empty_fifo\n");
-
- if (sp->rcvptr >= 3072) {
- printk(KERN_WARNING "empty_fifo rcvptr %d\n", sp->rcvptr);
- return;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->rcvptr;
- sp->rcvptr += count;
-
- if (sp->membase) {
-#ifdef DCHAN_VERBOSE
- printk(KERN_DEBUG "empty_fifo ");
- while (count--) {
- *ptr = readisac_0(sp->membase, 0x0);
- printk("%2x ", *ptr);
- ptr++;
- }
- printk("\n");
-#else
- while (count--)
- *ptr++ = readisac_0(sp->membase, 0x0);
-#endif
- writeisac_0(sp->membase, ISAC_CMDR, 0x80);
- } else {
-#ifdef DCHAN_VERBOSE
- int i;
- printk(KERN_DEBUG "empty_fifo ");
- readisac_s(sp->iobase, 0x3e, ptr, count);
- for (i = 0; i < count; i++)
- printk("%2x ", ptr[i]);
- printk("\n");
-#else
- readisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
- writeisac_3(sp->iobase, ISAC_CMDR, 0x80);
- }
-}
-
-static void
-fill_fifo(struct IsdnCardState *sp)
-{
- struct BufHeader *ibh;
- int count, more;
- byte *ptr;
-
- if (sp->debug)
- printk(KERN_DEBUG "fill_fifo\n");
-
- ibh = sp->xmtibh;
- if (!ibh)
- return;
-
- count = ibh->datasize - sp->sendptr;
- if (count <= 0)
- return;
- if (count >= 3072)
- return;
-
- more = 0;
- if (count > 32) {
- more = !0;
- count = 32;
- }
- ptr = DATAPTR(ibh);
- ptr += sp->sendptr;
- sp->sendptr += count;
-
- if (sp->membase) {
-#ifdef DCHAN_VERBOSE
- printk(KERN_DEBUG "fill_fifo ");
- while (count--) {
- writeisac_0(sp->membase, 0x0, *ptr);
- printk("%2x ", *ptr);
- ptr++;
- }
- printk("\n");
-#else
- while (count--)
- writeisac_0(sp->membase, 0x0, *ptr++);
-#endif
- writeisac_0(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
- } else {
-#ifdef DCHAN_VERBOSE
- int i;
- writeisac_s(sp->iobase, 0x3e, ptr, count);
- printk(KERN_DEBUG "fill_fifo ");
- for (i = 0; i < count; i++)
- printk("%2x ", ptr[i]);
- printk("\n");
-#else
- writeisac_s(sp->iobase, 0x3e, ptr, count);
-#endif
- writeisac_3(sp->iobase, ISAC_CMDR, more ? 0x8 : 0xa);
- }
-}
-
-static int
-act_wanted(struct IsdnCardState *sp)
-{
- struct PStack *st;
-
- st = sp->stlist;
- while (st)
- if (st->l1.act_state)
- return (!0);
- else
- st = st->next;
- return (0);
-}
-
-static void
-ph_command(struct IsdnCardState *sp, unsigned int command)
-{
- printk(KERN_DEBUG "ph_command %d\n", command);
- WRITEISAC(sp->membase, sp->iobase, ISAC_CIX0, (command << 2) | 3);
-}
-
-static void
-isac_new_ph(struct IsdnCardState *sp)
-{
- int enq;
-
- enq = act_wanted(sp);
-
- switch (sp->ph_state) {
- case (0):
- case (6):
- if (enq)
- ph_command(sp, 0);
- else
- ph_command(sp, 15);
- break;
- case (7):
- if (enq)
- ph_command(sp, 9);
- break;
- case (12):
- ph_command(sp, 8);
- sp->ph_active = 5;
- isac_sched_event(sp, ISAC_PHCHANGE);
- if (!sp->xmtibh)
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
- sp->sendptr = 0;
- if (sp->xmtibh)
- fill_fifo(sp);
- break;
- case (13):
- ph_command(sp, 9);
- sp->ph_active = 5;
- isac_sched_event(sp, ISAC_PHCHANGE);
- if (!sp->xmtibh)
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
- sp->sendptr = 0;
- if (sp->xmtibh)
- fill_fifo(sp);
- break;
- case (4):
- case (8):
- break;
- default:
- sp->ph_active = 0;
- break;
- }
-}
-
-static void
-teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
-{
- byte val, r, exval;
- struct IsdnCardState *sp;
- unsigned int count;
- struct HscxState *hsp;
-
- sp = (struct IsdnCardState *) irq2dev_map[intno];
-
- if (!sp) {
- printk(KERN_WARNING "Teles: Spurious interrupt!\n");
- return;
- }
- val = READHSCX(sp->membase, sp->iobase, 1, HSCX_ISTA);
-
- if (val & 0x01) {
- hsp = sp->hs + 1;
- exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- hsp->sendptr = 0;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x01);
- printk(KERN_DEBUG "HSCX B EXIR %x\n", exval);
- }
- } else
- printk(KERN_WARNING "HSCX B EXIR %x\n", exval);
- }
- if (val & 0xf8) {
- if (sp->debug)
- printk(KERN_DEBUG "HSCX B interrupt %x\n", val);
- hscx_interrupt(sp, val, 1);
- }
- if (val & 0x02) {
- hsp = sp->hs;
- exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR);
- if (exval == 0x40) {
- if (hsp->mode == 1)
- hscx_fill_fifo(hsp);
- else {
- /* Here we lost an TX interrupt, so
- * restart transmitting the whole frame.
- */
- hsp->sendptr = 0;
- WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
- hsp->hscx, 0x01);
- printk(KERN_DEBUG "HSCX A EXIR %x\n", exval);
- }
- } else
- printk(KERN_WARNING "HSCX A EXIR %x\n", exval);
- }
- if (val & 0x04) {
- val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA);
- if (sp->debug)
- printk(KERN_DEBUG "HSCX A interrupt %x\n",
- val);
- hscx_interrupt(sp, val, 0);
- }
-
- val = READISAC(sp->membase, sp->iobase, ISAC_ISTA);
-
- if (sp->debug)
- printk(KERN_DEBUG "ISAC interrupt %x\n", val);
-
- if (val & 0x80) { /* RME */
-
- r = READISAC(sp->membase, sp->iobase, ISAC_RSTA);
- if ((r & 0x70) != 0x20) {
- if (r & 0x40)
- printk(KERN_WARNING "Teles: ISAC RDO\n");
- if (!r & 0x20)
- printk(KERN_WARNING "Teles: ISAC CRC error\n");
- if (sp->rcvibh)
- BufPoolRelease(sp->rcvibh);
- sp->rcvibh = NULL;
- WRITEISAC(sp->membase, sp->iobase, ISAC_CMDR, 0x80);
- goto afterRME;
- }
- if (!sp->rcvibh)
- if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
- GFP_ATOMIC,
- (void *) 1, 3)) {
- printk(KERN_WARNING
- "ISAC RME out of buffers!\n");
- WRITEISAC(sp->membase, sp->iobase,
- ISAC_CMDR, 0x80);
- goto afterRME;
- } else
- sp->rcvptr = 0;
-
- count = READISAC(sp->membase, sp->iobase, ISAC_RBCL) & 0x1f;
- if (count == 0)
- count = 32;
- empty_fifo(sp, count);
- sp->rcvibh->datasize = sp->rcvptr;
- BufQueueLink(&(sp->rq), sp->rcvibh);
- sp->rcvibh = NULL;
- isac_sched_event(sp, ISAC_RCVBUFREADY);
- }
- afterRME:
- if (val & 0x40) { /* RPF */
- if (!sp->rcvibh)
- if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
- GFP_ATOMIC,
- (void *) 1, 4)) {
- printk(KERN_WARNING
- "ISAC RME out of buffers!\n");
- WRITEISAC(sp->membase, sp->iobase,
- ISAC_CMDR, 0x80);
- goto afterRPF;
- } else
- sp->rcvptr = 0;
- empty_fifo(sp, 32);
- }
- afterRPF:
- if (val & 0x20) {
- }
- if (val & 0x10) { /* XPR */
- if (sp->xmtibh)
- if (sp->xmtibh->datasize > sp->sendptr) {
- fill_fifo(sp);
- goto afterXPR;
- } else {
- if (sp->releasebuf)
- BufPoolRelease(sp->xmtibh);
- sp->xmtibh = NULL;
- sp->sendptr = 0;
- }
- if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
- sp->releasebuf = !0;
- fill_fifo(sp);
- } else
- isac_sched_event(sp, ISAC_XMTBUFREADY);
- }
- afterXPR:
- if (val & 0x04) { /* CISQ */
- sp->ph_state = (READISAC(sp->membase, sp->iobase, ISAC_CIX0)
- >> 2) & 0xf;
- printk(KERN_DEBUG "l1state %d\n", sp->ph_state);
- isac_new_ph(sp);
- }
- if (sp->membase) {
- writeisac_0(sp->membase, ISAC_MASK, 0xFF);
- writehscx_0(sp->membase, 0, HSCX_MASK, 0xFF);
- writehscx_0(sp->membase, 1, HSCX_MASK, 0xFF);
- writeisac_0(sp->membase, ISAC_MASK, 0x0);
- writehscx_0(sp->membase, 0, HSCX_MASK, 0x0);
- writehscx_0(sp->membase, 1, HSCX_MASK, 0x0);
- } else {
- writeisac_3(sp->iobase, ISAC_MASK, 0xFF);
- writehscx_3(sp->iobase, 0, HSCX_MASK, 0xFF);
- writehscx_3(sp->iobase, 1, HSCX_MASK, 0xFF);
- writeisac_3(sp->iobase, ISAC_MASK, 0x0);
- writehscx_3(sp->iobase, 0, HSCX_MASK, 0x0);
- writehscx_3(sp->iobase, 1, HSCX_MASK, 0x0);
- }
-}
-
-/*
- * soft interrupt
- */
-
-static void
-act_ivated(struct IsdnCardState *sp)
-{
- struct PStack *st;
-
- st = sp->stlist;
- while (st) {
- if (st->l1.act_state == 1) {
- st->l1.act_state = 2;
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- }
- st = st->next;
- }
-}
-
-static void
-process_new_ph(struct IsdnCardState *sp)
-{
- if (sp->ph_active == 5)
- act_ivated(sp);
-}
-
-static void
-process_xmt(struct IsdnCardState *sp)
-{
- struct PStack *stptr;
-
- if (sp->xmtibh)
- return;
-
- stptr = sp->stlist;
- while (stptr != NULL)
- if (stptr->l1.requestpull) {
- stptr->l1.requestpull = 0;
- stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
- break;
- } else
- stptr = stptr->next;
-}
-
-static void
-process_rcv(struct IsdnCardState *sp)
-{
- struct BufHeader *ibh, *cibh;
- struct PStack *stptr;
- byte *ptr;
- int found, broadc;
- char tmp[64];
-
- while (!BufQueueUnlink(&ibh, &sp->rq)) {
- stptr = sp->stlist;
- ptr = DATAPTR(ibh);
- broadc = (ptr[1] >> 1) == 127;
-
- if (broadc && sp->dlogflag && (!(ptr[0] >> 2)))
- dlogframe(sp, ptr + 3, ibh->datasize - 3,
- "Q.931 frame network->user broadcast");
-
- if (broadc) {
- while (stptr != NULL) {
- if ((ptr[0] >> 2) == stptr->l2.sap)
- if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC,
- (void *) 1, 5)) {
- memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize);
- cibh->datasize = ibh->datasize;
- stptr->l1.l1l2(stptr, PH_DATA, cibh);
- } else
- printk(KERN_WARNING "isdn broadcast buffer shortage\n");
- stptr = stptr->next;
- }
- BufPoolRelease(ibh);
- } else {
- found = 0;
- while (stptr != NULL)
- if (((ptr[0] >> 2) == stptr->l2.sap) &&
- ((ptr[1] >> 1) == stptr->l2.tei)) {
- stptr->l1.l1l2(stptr, PH_DATA, ibh);
- found = !0;
- break;
- } else
- stptr = stptr->next;
- if (!found) {
- /* BD 10.10.95
- * Print out D-Channel msg not processed
- * by isdn4linux
- */
-
- if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) {
- sprintf(tmp, "Q.931 frame network->user with tei %d (not for us)", ptr[1] >> 1);
- dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp);
- }
- BufPoolRelease(ibh);
- }
- }
-
- }
-
-}
-
-static void
-isac_bh(struct IsdnCardState *sp)
-{
- if (!sp)
- return;
-
- if (clear_bit(ISAC_PHCHANGE, &sp->event))
- process_new_ph(sp);
- if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
- process_rcv(sp);
- if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
- process_xmt(sp);
-}
-
-
-static void
-hscx_process_xmt(struct HscxState *hsp)
-{
- struct PStack *st = hsp->st;
-
- if (hsp->xmtibh)
- return;
-
- if (st->l1.requestpull) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- }
- if (!hsp->active)
- if ((!hsp->xmtibh) && (!hsp->sq.head))
- modehscx(hsp, 0, 0);
-}
-
-static void
-hscx_process_rcv(struct HscxState *hsp)
-{
- struct BufHeader *ibh;
-
-#ifdef DEBUG_MAGIC
- if (hsp->magic != 301270) {
- printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
- return;
- }
-#endif
- while (!BufQueueUnlink(&ibh, &hsp->rq)) {
- hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh);
- }
-}
-
-static void
-hscx_bh(struct HscxState *hsp)
-{
-
- if (!hsp)
- return;
-
- if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
- hscx_process_rcv(hsp);
- if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
- hscx_process_xmt(hsp);
-
-}
-
-/*
- * interrupt stuff ends here
- */
-
-static void
-restart_ph(struct IsdnCardState *sp)
-{
- switch (sp->ph_active) {
- case (0):
- if (sp->ph_state == 6)
- ph_command(sp, 0);
- else
- ph_command(sp, 1);
- sp->ph_active = 1;
- break;
- }
-}
-
-static void
-initisac(byte * cardmem, int iobase)
-{
- if (cardmem) {
- writeisac_0(cardmem, ISAC_MASK, 0xff);
- writeisac_0(cardmem, ISAC_ADF2, 0x0);
- writeisac_0(cardmem, ISAC_SPCR, 0xa);
- writeisac_0(cardmem, ISAC_ADF1, 0x2);
- writeisac_0(cardmem, ISAC_STCR, 0x70);
- writeisac_0(cardmem, ISAC_MODE, 0xc9);
- writeisac_0(cardmem, ISAC_CMDR, 0x41);
- writeisac_0(cardmem, ISAC_CIX0, (1 << 2) | 3);
- } else {
- writeisac_3(iobase, ISAC_MASK, 0xff);
- writeisac_3(iobase, ISAC_ADF2, 0x80);
- writeisac_3(iobase, ISAC_SQXR, 0x2f);
- writeisac_3(iobase, ISAC_SPCR, 0x00);
- writeisac_3(iobase, ISAC_ADF1, 0x02);
- writeisac_3(iobase, ISAC_STCR, 0x70);
- writeisac_3(iobase, ISAC_MODE, 0xc9);
- writeisac_3(iobase, ISAC_TIMR, 0x00);
- writeisac_3(iobase, ISAC_ADF1, 0x00);
- writeisac_3(iobase, ISAC_CMDR, 0x41);
- writeisac_3(iobase, ISAC_CIX0, (1 << 2) | 3);
- }
-}
-
-static int
-checkcard(int cardnr)
-{
- int timout;
- byte cfval, val;
- struct IsdnCard *card = cards + cardnr;
-
- if (card->membase)
- if ((unsigned long)card->membase < 0x10000) {
- (unsigned long)card->membase <<= 4;
- printk(KERN_INFO
- "Teles membase configured DOSish, assuming 0x%lx\n",
- (unsigned long)card->membase);
- }
- if (!card->iobase) {
- if (card->membase) {
- printk(KERN_NOTICE
- "Teles 8 assumed, mem: %lx irq: %d proto: %s\n",
- (long) card->membase, card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- printk(KERN_INFO "HSCX version A:%x B:%x\n",
- readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf,
- readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf);
- }
- } else {
- switch (card->iobase) {
- case 0x180:
- case 0x280:
- case 0x380:
- card->iobase |= 0xc00;
- break;
- }
- if (card->membase) { /* 16.0 */
- if (check_region(card->iobase, 8)) {
- printk(KERN_WARNING
- "teles: ports %x-%x already in use\n",
- card->iobase,
- card->iobase + 8 );
- return -1;
- }
- } else { /* 16.3 */
- if (check_region(card->iobase, 16)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase,
- card->iobase + 16 );
- return -1;
- }
- if (check_region((card->iobase - 0xc00) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0xc00,
- card->iobase - 0xc00 + 32);
- return -1;
- }
- if (check_region((card->iobase - 0x800) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0x800,
- card->iobase - 0x800 + 32);
- return -1;
- }
- if (check_region((card->iobase - 0x400) , 32)) {
- printk(KERN_WARNING
- "teles: 16.3 ports %x-%x already in use\n",
- card->iobase - 0x400,
- card->iobase - 0x400 + 32);
- return -1;
- }
- }
- switch (card->interrupt) {
- case 2:
- cfval = 0x00;
- break;
- case 3:
- cfval = 0x02;
- break;
- case 4:
- cfval = 0x04;
- break;
- case 5:
- cfval = 0x06;
- break;
- case 10:
- cfval = 0x08;
- break;
- case 11:
- cfval = 0x0A;
- break;
- case 12:
- cfval = 0x0C;
- break;
- case 15:
- cfval = 0x0E;
- break;
- default:
- cfval = 0x00;
- break;
- }
- if (card->membase) {
- cfval |= (((unsigned int) card->membase >> 9) & 0xF0);
- }
- if (bytein(card->iobase + 0) != 0x51) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 0,
- bytein(card->iobase + 0));
- return -2;
- }
- if (bytein(card->iobase + 1) != 0x93) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 1,
- bytein(card->iobase + 1));
- return -2;
- }
- val = bytein(card->iobase + 2); /* 0x1e=without AB
- * 0x1f=with AB
- * 0x1c 16.3 ???
- */
- if (val != 0x1c && val != 0x1e && val != 0x1f) {
- printk(KERN_INFO "XXX Byte at %x is %x\n",
- card->iobase + 2,
- bytein(card->iobase + 2));
- return -2;
- }
- if (card->membase) { /* 16.0 */
- request_region(card->iobase, 8, "teles 16.0");
- } else {
- request_region(card->iobase, 16, "teles 16.3");
- request_region(card->iobase - 0xC00, 32, "teles HSCX0");
- request_region(card->iobase - 0x800, 32, "teles HSCX1");
- request_region(card->iobase - 0x400, 32, "teles ISAC");
- }
- cli();
- timout = jiffies + (HZ / 10) + 1;
- byteout(card->iobase + 4, cfval);
- sti();
- while (jiffies <= timout);
-
- cli();
- timout = jiffies + (HZ / 10) + 1;
- byteout(card->iobase + 4, cfval | 1);
- sti();
- while (jiffies <= timout);
-
- if (card->membase)
- printk(KERN_NOTICE
- "Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n",
- card->iobase, (long) card->membase,
- card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- else
- printk(KERN_NOTICE
- "Teles 16.3 found, io: %x irq: %d proto: %s\n",
- card->iobase, card->interrupt,
- (card->protocol == ISDN_PTYPE_1TR6) ?
- "1TR6" : "EDSS1");
- printk(KERN_INFO "HSCX version A:%x B:%x\n",
- READHSCX(card->membase, card->iobase, 0,
- HSCX_VSTR) & 0xf,
- READHSCX(card->membase, card->iobase, 1,
- HSCX_VSTR) & 0xf);
-
- }
- if (card->membase) {
- cli();
- timout = jiffies + (HZ / 5) + 1;
- writeb(0, card->membase + 0x80);
- sti();
- while (jiffies <= timout);
-
- cli();
- writeb(1, card->membase + 0x80);
- timout = jiffies + (HZ / 5) + 1;
- sti();
- while (jiffies <= timout);
- }
- return (0);
-}
-
-void
-modehscx(struct HscxState *hs, int mode,
- int ichan)
-{
- struct IsdnCardState *sp = hs->sp;
- int hscx = hs->hscx;
-
- printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n",
- hscx, mode, ichan);
-
- hs->mode = mode;
- if (sp->membase) {
- /* What's that ??? KKeil */
- if (hscx == 0)
- ichan = 1 - ichan; /* raar maar waar... */
- writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85);
- writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_RAH2, 0xFF);
- writehscx_0(sp->membase, hscx, HSCX_XBCH, 0x0);
-
- switch (mode) {
- case (0):
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0xff);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0xff);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- }
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0xe4);
- writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
- writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
- writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
- writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
- }
- writehscx_0(sp->membase, hscx, HSCX_MODE, 0x8c);
- writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
- break;
- }
- writehscx_0(sp->membase, hscx, HSCX_ISTA, 0x00);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR1, 0x85);
- writehscx_3(sp->iobase, hscx, HSCX_XAD1, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_XAD2, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_RAH2, 0xFF);
- writehscx_3(sp->iobase, hscx, HSCX_XBCH, 0x00);
- writehscx_3(sp->iobase, hscx, HSCX_RLCR, 0x00);
-
- switch (mode) {
- case (0):
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0xff);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0xff);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x84);
- break;
- case (1):
- if (ichan == 0) {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- }
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0xe4);
- writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
- break;
- case (2):
- if (ichan == 0) {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- } else {
- writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
- writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
- writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
- writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
- }
- writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x8c);
- writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
- break;
- }
- writehscx_3(sp->iobase, hscx, HSCX_ISTA, 0x00);
- }
-}
-
-void
-teles_addlist(struct IsdnCardState *sp,
- struct PStack *st)
-{
- st->next = sp->stlist;
- sp->stlist = st;
-}
-
-void
-teles_rmlist(struct IsdnCardState *sp,
- struct PStack *st)
-{
- struct PStack *p;
-
- if (sp->stlist == st)
- sp->stlist = st->next;
- else {
- p = sp->stlist;
- while (p)
- if (p->next == st) {
- p->next = st->next;
- return;
- } else
- p = p->next;
- }
-}
-
-
-static void
-teles_l2l1(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
-
-
- switch (pr) {
- case (PH_DATA):
- if (sp->xmtibh)
- BufQueueLink(&sp->sq, ibh);
- else {
- sp->xmtibh = ibh;
- sp->sendptr = 0;
- sp->releasebuf = !0;
- fill_fifo(sp);
- }
- break;
- case (PH_DATA_PULLED):
- if (sp->xmtibh) {
- printk(KERN_DEBUG "teles_l2l1: this shouldn't happen\n");
- break;
- }
- sp->xmtibh = ibh;
- sp->sendptr = 0;
- sp->releasebuf = 0;
- fill_fifo(sp);
- break;
- case (PH_REQUEST_PULL):
- if (!sp->xmtibh) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- } else
- st->l1.requestpull = !0;
- break;
- }
-}
-
-static void
-check_ph_act(struct IsdnCardState *sp)
-{
- struct PStack *st = sp->stlist;
-
- while (st) {
- if (st->l1.act_state)
- return;
- st = st->next;
- }
- sp->ph_active = 0;
-}
-
-static void
-teles_manl1(struct PStack *st, int pr,
- void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- long flags;
-
- switch (pr) {
- case (PH_ACTIVATE):
- save_flags(flags);
- cli();
- if (sp->ph_active == 5) {
- st->l1.act_state = 2;
- restore_flags(flags);
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- } else {
- st->l1.act_state = 1;
- if (sp->ph_active == 0)
- restart_ph(sp);
- restore_flags(flags);
- }
- break;
- case (PH_DEACTIVATE):
- st->l1.act_state = 0;
- check_ph_act(sp);
- break;
- }
-}
-
-static void
-teles_l2l1discardq(struct PStack *st, int pr,
- void *heldby, int releasetoo)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
-
-#ifdef DEBUG_MAGIC
- if (sp->magic != 301271) {
- printk(KERN_DEBUG "isac_discardq magic not 301271\n");
- return;
- }
-#endif
-
- BufQueueDiscard(&sp->sq, pr, heldby, releasetoo);
-}
-
-void
-setstack_teles(struct PStack *st, struct IsdnCardState *sp)
-{
- st->l1.hardware = sp;
- st->l1.sbufpool = &(sp->sbufpool);
- st->l1.rbufpool = &(sp->rbufpool);
- st->l1.smallpool = &(sp->smallpool);
- st->protocol = sp->teistack->protocol;
-
- setstack_tei(st);
-
- st->l1.stlistp = &(sp->stlist);
- st->l1.act_state = 0;
- st->l2.l2l1 = teles_l2l1;
- st->l2.l2l1discardq = teles_l2l1discardq;
- st->ma.manl1 = teles_manl1;
- st->l1.requestpull = 0;
-}
-
-void
-init_hscxstate(struct IsdnCardState *sp,
- int hscx)
-{
- struct HscxState *hsp = sp->hs + hscx;
-
- hsp->sp = sp;
- hsp->hscx = hscx;
- hsp->membase = sp->membase;
- hsp->iobase = sp->iobase;
-
- hsp->tqueue.next = 0;
- hsp->tqueue.sync = 0;
- hsp->tqueue.routine = (void *) (void *) hscx_bh;
- hsp->tqueue.data = hsp;
-
- hsp->inuse = 0;
- hsp->init = 0;
- hsp->active = 0;
-
-#ifdef DEBUG_MAGIC
- hsp->magic = 301270;
-#endif
-}
-
-void
-initcard(int cardnr)
-{
- struct IsdnCardState *sp;
- struct IsdnCard *card = cards + cardnr;
-
- sp = (struct IsdnCardState *)
- Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL,
- "struct IsdnCardState");
-
- sp->membase = card->membase;
- sp->iobase = card->iobase;
- sp->cardnr = cardnr;
-
- BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS,
- ISAC_SBUF_MAXPAGES);
- BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS,
- ISAC_RBUF_MAXPAGES);
- BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS,
- ISAC_SMALLBUF_MAXPAGES);
-
- sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace");
-
- initisac(card->membase, card->iobase);
-
- sp->rcvibh = NULL;
- sp->rcvptr = 0;
- sp->xmtibh = NULL;
- sp->sendptr = 0;
- sp->event = 0;
- sp->tqueue.next = 0;
- sp->tqueue.sync = 0;
- sp->tqueue.routine = (void *) (void *) isac_bh;
- sp->tqueue.data = sp;
-
- BufQueueInit(&sp->rq);
- BufQueueInit(&sp->sq);
-
- sp->stlist = NULL;
-
- sp->ph_active = 0;
-
- sp->dlogflag = 0;
- sp->debug = 0;
-
- sp->releasebuf = 0;
-#ifdef DEBUG_MAGIC
- sp->magic = 301271;
-#endif
-
- cards[sp->cardnr].sp = sp;
-
- init_hscxstate(sp, 0);
- init_hscxstate(sp, 1);
-
- modehscx(sp->hs, 0, 0);
- modehscx(sp->hs + 1, 0, 0);
-
- WRITEISAC(sp->membase, sp->iobase, ISAC_MASK, 0x0);
-}
-
-static int
-get_irq(int cardnr)
-{
- struct IsdnCard *card = cards + cardnr;
- long flags;
-
- save_flags(flags);
- cli();
- if (request_irq(card->interrupt, &teles_interrupt,
- SA_INTERRUPT, "teles", NULL)) {
- printk(KERN_WARNING "Teles couldn't get interrupt %d\n",
- card->interrupt);
- restore_flags(flags);
- return (!0);
- }
- irq2dev_map[card->interrupt] = (void *) card->sp;
- restore_flags(flags);
- return (0);
-}
-
-static void
-release_irq(int cardnr)
-{
- struct IsdnCard *card = cards + cardnr;
-
- irq2dev_map[card->interrupt] = NULL;
- free_irq(card->interrupt, NULL);
-}
-
-void
-close_hscxstate(struct HscxState *hs)
-{
- modehscx(hs, 0, 0);
- hs->inuse = 0;
-
- if (hs->init) {
- BufPoolFree(&hs->smallpool);
- BufPoolFree(&hs->rbufpool);
- BufPoolFree(&hs->sbufpool);
- }
- hs->init = 0;
-}
-
-void
-closecard(int cardnr)
-{
- struct IsdnCardState *sp = cards[cardnr].sp;
-
- cards[cardnr].sp = NULL;
-
- Sfree(sp->dlogspace);
-
- BufPoolFree(&sp->smallpool);
- BufPoolFree(&sp->rbufpool);
- BufPoolFree(&sp->sbufpool);
-
- close_hscxstate(sp->hs + 1);
- close_hscxstate(sp->hs);
-
- if (cards[cardnr].iobase)
- if (cards[cardnr].membase) { /* 16.0 */
- release_region(cards[cardnr].iobase, 8);
- } else {
- release_region(cards[cardnr].iobase, 16);
- release_region(cards[cardnr].iobase - 0xC00, 32);
- release_region(cards[cardnr].iobase - 0x800, 32);
- release_region(cards[cardnr].iobase - 0x400, 32);
- }
-
- Sfree((void *) sp);
-}
-
-void
-teles_shiftcards(int idx)
-{
- int i;
-
- for (i = idx; i < 15; i++)
- memcpy(&cards[i],&cards[i+1],sizeof(cards[i]));
-}
-
-int
-teles_inithardware(void)
-{
- int foundcards = 0;
- int i = 0;
-
- while (i < nrcards) {
- if (!cards[i].protocol)
- break;
- switch (checkcard(i)) {
- case (0):
- initcard(i);
- if (get_irq(i)) {
- closecard(i);
- teles_shiftcards(i);
- } else {
- foundcards++;
- i++;
- }
- break;
- case (-1):
- teles_shiftcards(i);
- break;
- case (-2):
- release_region(cards[i].iobase, 8);
- printk(KERN_WARNING "NO Teles card found at 0x%x!\n", cards[i].iobase);
- teles_shiftcards(i);
- break;
- }
- }
- return foundcards;
-}
-
-void
-teles_closehardware(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp) {
- release_irq(i);
- closecard(i);
- }
-}
-
-static void
-hscx_l2l1(struct PStack *st, int pr,
- struct BufHeader *ibh)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
- long flags;
-
- switch (pr) {
- case (PH_DATA):
- save_flags(flags);
- cli();
- if (hsp->xmtibh) {
- BufQueueLink(&hsp->sq, ibh);
- restore_flags(flags);
- }
- else {
- restore_flags(flags);
- hsp->xmtibh = ibh;
- hsp->sendptr = 0;
- hsp->releasebuf = !0;
- hscx_fill_fifo(hsp);
- }
- break;
- case (PH_DATA_PULLED):
- if (hsp->xmtibh) {
- printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n");
- break;
- }
- hsp->xmtibh = ibh;
- hsp->sendptr = 0;
- hsp->releasebuf = 0;
- hscx_fill_fifo(hsp);
- break;
- case (PH_REQUEST_PULL):
- if (!hsp->xmtibh) {
- st->l1.requestpull = 0;
- st->l1.l1l2(st, PH_PULL_ACK, NULL);
- } else
- st->l1.requestpull = !0;
- break;
- }
-
-}
-
-extern struct IsdnBuffers *tracebuf;
-
-static void
-hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
- int releasetoo)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
-
-#ifdef DEBUG_MAGIC
- if (hsp->magic != 301270) {
- printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
- return;
- }
-#endif
-
- BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo);
-}
-
-static int
-open_hscxstate(struct IsdnCardState *sp,
- int hscx)
-{
- struct HscxState *hsp = sp->hs + hscx;
-
- if (!hsp->init) {
- BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS,
- HSCX_SBUF_MAXPAGES);
- BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS,
- HSCX_RBUF_MAXPAGES);
- BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS,
- HSCX_SMALLBUF_MAXPAGES);
- }
- hsp->init = !0;
-
- BufQueueInit(&hsp->rq);
- BufQueueInit(&hsp->sq);
-
- hsp->releasebuf = 0;
- hsp->rcvibh = NULL;
- hsp->xmtibh = NULL;
- hsp->rcvptr = 0;
- hsp->sendptr = 0;
- hsp->event = 0;
- return (0);
-}
-
-static void
-hscx_manl1(struct PStack *st, int pr,
- void *arg)
-{
- struct IsdnCardState *sp = (struct IsdnCardState *)
- st->l1.hardware;
- struct HscxState *hsp = sp->hs + st->l1.hscx;
-
- switch (pr) {
- case (PH_ACTIVATE):
- hsp->active = !0;
- modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
- st->l1.l1man(st, PH_ACTIVATE, NULL);
- break;
- case (PH_DEACTIVATE):
- if (!hsp->xmtibh)
- modehscx(hsp, 0, 0);
-
- hsp->active = 0;
- break;
- }
-}
-
-int
-setstack_hscx(struct PStack *st, struct HscxState *hs)
-{
- if (open_hscxstate(st->l1.hardware, hs->hscx))
- return (-1);
-
- st->l1.hscx = hs->hscx;
- st->l2.l2l1 = hscx_l2l1;
- st->ma.manl1 = hscx_manl1;
- st->l2.l2l1discardq = hscx_l2l1discardq;
-
- st->l1.sbufpool = &hs->sbufpool;
- st->l1.rbufpool = &hs->rbufpool;
- st->l1.smallpool = &hs->smallpool;
- st->l1.act_state = 0;
- st->l1.requestpull = 0;
-
- hs->st = st;
- return (0);
-}
-
-void
-teles_reportcard(int cardnr)
-{
- printk(KERN_DEBUG "teles_reportcard\n");
-}
+++ /dev/null
-/* $Id: config.c,v 1.1 1996/04/13 10:23:11 fritz Exp $
- *
- * $Log: config.c,v $
- * Revision 1.1 1996/04/13 10:23:11 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include "teles.h"
-
-/*
- * This structure array contains one entry per card. An entry looks
- * like this:
- *
- * { membase,irq,portbase,protocol,NULL }
- *
- * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6
- *
- * Cards which don't have an io port (Teles 8 bit cards for
- * example) can be entered with io port 0x0
- *
- * For the Teles 16.3, membase has to be set to 0.
- *
- */
-
-struct IsdnCard cards[] =
-{
- {(byte *) 0xd0000, 15, 0xd80, ISDN_PTYPE_EURO, NULL}, /* example */
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
- {NULL, 0, 0, 0, NULL},
-};
+++ /dev/null
-/* $Id: fsm.c,v 1.2 1996/04/29 22:49:57 fritz Exp $
- *
- * $Log: fsm.c,v $
- * Revision 1.2 1996/04/29 22:49:57 fritz
- * Removed compatibility-macros.
- *
- * Revision 1.1 1996/04/13 10:23:41 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-void
-FsmNew(struct Fsm *fsm,
- struct FsmNode *fnlist, int fncount)
-{
- int i;
-
- fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count,
- GFP_KERNEL, "Fsm jumpmatrix");
- memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
-
- for (i = 0; i < fncount; i++)
- fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
- fnlist[i].state] = (int) fnlist[i].routine;
-}
-
-void
-FsmFree(struct Fsm *fsm)
-{
- Sfree((void *) fsm->jumpmatrix);
-}
-
-int
-FsmEvent(struct FsmInst *fi, int event, void *arg)
-{
- void (*r) (struct FsmInst *, int, void *);
- char str[80];
-
- r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
- if (r) {
- if (fi->debug) {
- sprintf(str, "State %s Event %s",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- fi->printdebug(fi, str);
- }
- r(fi, event, arg);
- return (0);
- } else {
- if (fi->debug) {
- sprintf(str, "State %s Event %s no routine",
- fi->fsm->strState[fi->state],
- fi->fsm->strEvent[event]);
- fi->printdebug(fi, str);
- }
- return (!0);
- }
-}
-
-void
-FsmChangeState(struct FsmInst *fi, int newstate)
-{
- char str[80];
-
- fi->state = newstate;
- if (fi->debug) {
- sprintf(str, "ChangeState %s",
- fi->fsm->strState[newstate]);
- fi->printdebug(fi, str);
- }
-}
-
-static void
-FsmExpireTimer(struct FsmTimer *ft)
-{
- FsmEvent(ft->fi, ft->event, ft->arg);
-}
-
-void
-FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
-{
- ft->fi = fi;
- ft->tl.function = (void *) FsmExpireTimer;
- ft->tl.data = (long) ft;
- init_timer(&ft->tl);
-}
-
-void
-FsmDelTimer(struct FsmTimer *ft, int where)
-{
- long flags;
-
-#if 0
- if (ft->fi->debug) {
- sprintf(str, "FsmDelTimer %lx %d", ft, where);
- ft->fi->printdebug(ft->fi, str);
- }
-#endif
-
- save_flags(flags);
- cli();
- if (ft->tl.next)
- del_timer(&ft->tl);
- restore_flags(flags);
-}
-
-int
-FsmAddTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where)
-{
-
-#if 0
- if (ft->fi->debug) {
- sprintf(str, "FsmAddTimer %lx %d %d", ft, millisec, where);
- ft->fi->printdebug(ft->fi, str);
- }
-#endif
-
- if (ft->tl.next) {
- printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
- return -1;
- }
- init_timer(&ft->tl);
- ft->event = event;
- ft->arg = arg;
- ft->tl.expires = jiffies + (millisec * HZ) / 1000;
- add_timer(&ft->tl);
- return 0;
-}
-
-int
-FsmTimerRunning(struct FsmTimer *ft)
-{
- return (ft->tl.next != NULL);
-}
-
-void
-jiftime(char *s, long mark)
-{
- s += 8;
-
- *s-- = '\0';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = '.';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 6 + '0';
- mark /= 6;
- *s-- = ':';
- *s-- = mark % 10 + '0';
- mark /= 10;
- *s-- = mark % 10 + '0';
-}
+++ /dev/null
-/* $Id: isdnl2.c,v 1.2 1996/05/17 03:46:15 fritz Exp $
- *
- * $Log: isdnl2.c,v $
- * Revision 1.2 1996/05/17 03:46:15 fritz
- * General cleanup.
- *
- * Revision 1.1 1996/04/13 10:24:16 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-#define TIMER_1 2000
-
-static void l2m_debug(struct FsmInst *fi, char *s);
-
-struct Fsm l2fsm =
-{NULL, 0, 0};
-
-enum {
- ST_L2_1,
- ST_L2_3,
- ST_L2_4,
- ST_L2_5,
- ST_L2_6,
- ST_L2_7,
- ST_L2_8,
-};
-
-#define L2_STATE_COUNT (ST_L2_8+1)
-
-static char *strL2State[] =
-{
- "ST_L2_1",
- "ST_L2_3",
- "ST_L2_4",
- "ST_L2_5",
- "ST_L2_6",
- "ST_L2_7",
- "ST_L2_8",
-};
-
-enum {
- EV_L2_UI,
- EV_L2_SABMX,
- EV_L2_UA,
- EV_L2_DISC,
- EV_L2_I,
- EV_L2_RR,
- EV_L2_REJ,
- EV_L2_FRMR,
- EV_L2_DL_DATA,
- EV_L2_DL_ESTABLISH,
- EV_L2_MDL_ASSIGN,
- EV_L2_DL_UNIT_DATA,
- EV_L2_DL_RELEASE,
- EV_L2_MDL_NOTEIPROC,
- EV_L2_T200,
- EV_L2_ACK_PULL,
- EV_L2_T203,
- EV_L2_RNR,
-};
-
-#define L2_EVENT_COUNT (EV_L2_RNR+1)
-
-static char *strL2Event[] =
-{
- "EV_L2_UI",
- "EV_L2_SABMX",
- "EV_L2_UA",
- "EV_L2_DISC",
- "EV_L2_I",
- "EV_L2_RR",
- "EV_L2_REJ",
- "EV_L2_FRMR",
- "EV_L2_DL_DATA",
- "EV_L2_DL_ESTABLISH",
- "EV_L2_MDL_ASSIGN",
- "EV_L2_DL_UNIT_DATA",
- "EV_L2_DL_RELEASE",
- "EV_L2_MDL_NOTEIPROC",
- "EV_L2_T200",
- "EV_L2_ACK_PULL",
- "EV_L2_T203",
- "EV_L2_RNR",
-};
-
-int errcount = 0;
-
-static int l2addrsize(struct Layer2 *tsp);
-
-static int
-cansend(struct PStack *st)
-{
- int p1;
-
- p1 = (st->l2.va + st->l2.window) % (st->l2.extended ? 128 : 8);
- return (st->l2.vs != p1);
-}
-
-static void
-discard_i_queue(struct PStack *st)
-{
- struct BufHeader *ibh;
-
- while (!BufQueueUnlink(&ibh, &st->l2.i_queue))
- BufPoolRelease(ibh);
-}
-
-int
-l2headersize(struct Layer2 *tsp, int UI)
-{
- return ((tsp->extended && (!UI) ? 2 : 1) + (tsp->laptype == LAPD ? 2 : 1));
-}
-
-int
-l2addrsize(struct Layer2 *tsp)
-{
- return (tsp->laptype == LAPD ? 2 : 1);
-}
-
-static int
-sethdraddr(struct Layer2 *tsp,
- struct BufHeader *ibh, int rsp)
-{
- byte *ptr = DATAPTR(ibh);
- int crbit;
-
- if (tsp->laptype == LAPD) {
- crbit = rsp;
- if (!tsp->orig)
- crbit = !crbit;
- *ptr++ = (tsp->sap << 2) | (crbit ? 2 : 0);
- *ptr++ = (tsp->tei << 1) | 1;
- return (2);
- } else {
- crbit = rsp;
- if (tsp->orig)
- crbit = !crbit;
- if (crbit)
- *ptr++ = 1;
- else
- *ptr++ = 3;
- return (1);
- }
-}
-
-static void
-enqueue_ui(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static void
-enqueue_super(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l2.l2l1(st, PH_DATA, ibh);
-}
-
-static int
-legalnr(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
- int lnr, lvs;
-
- lvs = (l2->vs >= l2->va) ? l2->vs : (l2->vs + l2->extended ? 128 : 8);
- lnr = (nr >= l2->va) ? nr : (nr + l2->extended ? 128 : 8);
- return (lnr <= lvs);
-}
-
-static void
-setva(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
-
- if (l2->va != nr) {
- while (l2->va != nr) {
- l2->va = (l2->va + 1) % (l2->extended ? 128 : 8);
- BufPoolRelease(l2->windowar[l2->sow]);
- l2->sow = (l2->sow + 1) % l2->window;
- }
- if (st->l4.l2writewakeup)
- st->l4.l2writewakeup(st);
- }
-}
-
-static void
-l2s1(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.l2tei(st, MDL_ASSIGN, (void *)st->l2.ces);
- FsmChangeState(fi, ST_L2_3);
-}
-
-static void
-l2s2(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
-
- byte *ptr;
- int i;
-
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x3;
-
- enqueue_ui(st, ibh);
-}
-
-static void
-l2s3(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
-
- st->l2.l2l3(st, DL_UNIT_DATA, ibh);
-}
-
-static void
-establishlink(struct FsmInst *fi)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh;
- int i;
- byte *ptr;
-
- FsmChangeState(fi, ST_L2_5);
- st->l2.rc = 0;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 1))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 1");
-
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- if (st->l2.extended)
- *ptr = 0x7f;
- else
- *ptr = 0x3f;
- ibh->datasize = i + 1;
-
- enqueue_super(st, ibh);
-}
-
-static void
-l2s11(struct FsmInst *fi, int event, void *arg)
-{
- establishlink(fi);
-}
-
-static void
-l2s13(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- byte *ptr;
- struct BufHeader *ibh;
- int i;
-
- FsmChangeState(fi, ST_L2_6);
-
- FsmDelTimer(&st->l2.t203_timer, 1);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 2);
- st->l2.t200_running = 0;
- }
- st->l2.rc = 0;
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 2))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 2");
-
-
- if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
- goto nodisc;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 9))
- return;
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x53;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- nodisc:
- discard_i_queue(st);
-}
-
-static void
-l2s12(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- int i;
-
- BufPoolRelease(ibh);
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 3");
-
- st->l2.l2man(st, DL_ESTABLISH, NULL);
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
- return;
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x73;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
-}
-
-static void
-l2s14(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- struct Channel *chanp = st->l4.userdata;
- byte *ptr;
- int i, p;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&(st->l2));
- p = (*ptr) & 0x10;
- BufPoolRelease(ibh);
-
- FsmChangeState(fi, ST_L2_4);
-
- FsmDelTimer(&st->l2.t203_timer, 3);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 4);
- st->l2.t200_running = 0;
- }
- if ((chanp->impair == 1) && (st->l2.laptype == LAPB))
- goto noresponse;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 11))
- return;
- i = sethdraddr(&(st->l2), ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x63 | (p ? 0x10 : 0x0);
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- noresponse:
- st->l2.l2man(st, DL_RELEASE, NULL);
-
-}
-
-static void
-l2s5(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int f;
- byte *data;
-
- data = DATAPTR(ibh);
- data += l2addrsize(&(st->l2));
-
- f = *data & 0x10;
- BufPoolRelease(ibh);
-
- if (f) {
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
- FsmChangeState(fi, ST_L2_7);
-
- FsmDelTimer(&st->l2.t200_timer, 5);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 4))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 4");
-
-
- st->l2.l2man(st, DL_ESTABLISH, NULL);
- }
-}
-
-static void
-l2s15(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int f;
- byte *data;
-
- data = DATAPTR(ibh);
- data += l2addrsize(&st->l2);
-
- f = *data & 0x10;
- BufPoolRelease(ibh);
-
- if (f) {
- FsmDelTimer(&st->l2.t200_timer, 6);
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- }
-}
-
-static void
-l2s6(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- struct BufHeader *ibh = arg;
- int p, i, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if ((chanp->impair == 4) && (st->l2.laptype == LAPB))
- goto noresp;
-
- if ((!rsp) && p) {
- if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
- i = sethdraddr(l2, ibh, !0);
- ptr = DATAPTR(ibh);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh->datasize = i;
- enqueue_super(st, ibh);
- }
- }
- noresp:
- if (legalnr(st, seq))
- if (seq == st->l2.vs) {
- setva(st, seq);
- FsmDelTimer(&st->l2.t200_timer, 7);
- st->l2.t200_running = 0;
- FsmDelTimer(&st->l2.t203_timer, 8);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 5))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 5");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else if (st->l2.va != seq) {
- setva(st, seq);
- FsmDelTimer(&st->l2.t200_timer, 9);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 6))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 6");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
-}
-
-static void
-l2s7(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int i;
- byte *ptr;
- struct IsdnCardState *sp = st->l1.hardware;
- char str[64];
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
-
- if (st->l2.laptype == LAPD)
- if (sp->dlogflag) {
- sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
- dlogframe(sp, ptr + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- str);
- }
- BufQueueLink(&st->l2.i_queue, ibh);
-
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-}
-
-static void
-l2s8(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- struct BufHeader *ibh2;
- struct IsdnCardState *sp = st->l1.hardware;
- struct Layer2 *l2 = &(st->l2);
- int i, p, seq, nr, wasok;
- char str[64];
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(l2);
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[0] >> 1;
- nr = (ptr[1] >> 1) & 0x7f;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 1) & 0x7;
- nr = (ptr[0] >> 5) & 0x7;
- }
-
- if (l2->vr == seq) {
- wasok = !0;
-
- l2->vr = (l2->vr + 1) % (l2->extended ? 128 : 8);
- l2->rejexp = 0;
-
- ptr = DATAPTR(ibh);
- if (st->l2.laptype == LAPD)
- if (sp->dlogflag) {
- sprintf(str, "Q.931 frame network->user tei %d", st->l2.tei);
- dlogframe(st->l1.hardware, ptr + l2->ihsize,
- ibh->datasize - l2->ihsize, str);
- }
- label8_1:
- if ((chanp->impair == 3) && (st->l2.laptype == LAPB))
- goto noRR;
-
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 13)) {
- i = sethdraddr(&(st->l2), ibh2, p);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- noRR:
- }
- } else {
- /* n(s)!=v(r) */
- wasok = 0;
- BufPoolRelease(ibh);
- if (st->l2.rejexp) {
- if (p)
- goto label8_1;
- } else {
- st->l2.rejexp = !0;
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 14)) {
- i = sethdraddr(&(st->l2), ibh2, p);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x9;
- *ptr++ = (l2->vr << 1) | (p ? 1 : 0);
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x9 | (p ? 0x10 : 0x0);
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- }
- }
- }
-
- if (legalnr(st, nr))
- if (nr == st->l2.vs) {
- setva(st, nr);
- FsmDelTimer(&st->l2.t200_timer, 10);
- st->l2.t200_running = 0;
- FsmDelTimer(&st->l2.t203_timer, 11);
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 7))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 5");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- } else if (nr != st->l2.va) {
- setva(st, nr);
- FsmDelTimer(&st->l2.t200_timer, 12);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 8))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 6");
-
- if (st->l2.i_queue.head)
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
- if (wasok)
- st->l2.l2l3(st, DL_DATA, ibh);
-
-}
-
-static void
-l2s17(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.tei = (int) arg;
- establishlink(fi);
-}
-
-static void
-enquiry_response(struct PStack *st)
-{
- struct BufHeader *ibh2;
- int i;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- if (!BufPoolGet(&ibh2, st->l1.smallpool, GFP_ATOMIC, (void *) st, 16)) {
- i = sethdraddr(&(st->l2), ibh2, !0);
- ptr = DATAPTR(ibh2);
- ptr += i;
-
- if (l2->extended) {
- *ptr++ = 0x1;
- *ptr++ = (l2->vr << 1) | 0x1;
- i += 2;
- } else {
- *ptr++ = (l2->vr << 5) | 0x1 | 0x10;
- i += 1;
- }
- ibh2->datasize = i;
- enqueue_super(st, ibh2);
- }
-}
-
-static void
-invoke_retransmission(struct PStack *st, int nr)
-{
- struct Layer2 *l2 = &st->l2;
- int p1;
-
- if (l2->vs != nr) {
- while (l2->vs != nr) {
-
- l2->vs = l2->vs - 1;
- if (l2->vs < 0)
- l2->vs += l2->extended ? 128 : 8;
-
- p1 = l2->vs - l2->va;
- if (p1 < 0)
- p1 += l2->extended ? 128 : 8;
- p1 = (p1 + l2->sow) % l2->window;
-
- BufQueueLinkFront(&l2->i_queue, l2->windowar[p1]);
- }
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
- }
-}
-
-static void
-l2s16(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int p, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &(st->l2);
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if ((!rsp) && p)
- enquiry_response(st);
-
- if (!legalnr(st, seq))
- return;
-
- setva(st, seq);
- invoke_retransmission(st, seq);
-
-}
-
-static void
-l2s19(struct FsmInst *fi, int event, void *arg)
-{
- FsmChangeState(fi, ST_L2_4);
-}
-
-static void
-l2s20(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- int i;
- struct BufHeader *ibh;
- byte *ptr;
-
- if (st->l2.rc == st->l2.n200) {
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- } else {
- st->l2.rc++;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 9))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 7");
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- if (st->l2.extended)
- *ptr = 0x7f;
- else
- *ptr = 0x3f;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
- }
-}
-
-static void
-l2s21(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct Channel *chanp = st->l4.userdata;
- int i;
- struct BufHeader *ibh;
- byte *ptr;
-
- if (st->l2.rc == st->l2.n200) {
- FsmChangeState(fi, ST_L2_4);
- st->l2.l2man(st, DL_RELEASE, NULL);
- } else {
- st->l2.rc++;
-
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 10))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 8");
-
-
- if ((chanp->impair == 2) && (st->l2.laptype == LAPB))
- goto nodisc;
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 15))
- return;
-
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x53;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
- nodisc:
-
- }
-}
-
-static void
-l2s22(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh;
- struct Layer2 *l2 = &st->l2;
- byte *ptr;
- int p1;
-
- if (!cansend(st))
- return;
-
- if (BufQueueUnlink(&ibh, &l2->i_queue))
- return;
-
-
- p1 = l2->vs - l2->va;
- if (p1 < 0)
- p1 += l2->extended ? 128 : 8;
- p1 = (p1 + l2->sow) % l2->window;
- l2->windowar[p1] = ibh;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- *ptr++ = l2->vs << 1;
- *ptr++ = (l2->vr << 1) | 0x1;
- l2->vs = (l2->vs + 1) % 128;
- } else {
- *ptr++ = (l2->vr << 5) | (l2->vs << 1) | 0x10;
- l2->vs = (l2->vs + 1) % 8;
- }
-
- st->l2.l2l1(st, PH_DATA_PULLED, ibh);
-
- if (!st->l2.t200_running) {
- FsmDelTimer(&st->l2.t203_timer, 13);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 11))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 9");
-
- st->l2.t200_running = !0;
- }
- if (l2->i_queue.head && cansend(st))
- st->l2.l2l1(st, PH_REQUEST_PULL, NULL);
-
-}
-
-static void
-transmit_enquiry(struct PStack *st)
-{
- struct BufHeader *ibh;
- byte *ptr;
-
- if (!BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 12)) {
- ptr = DATAPTR(ibh);
- ptr += sethdraddr(&st->l2, ibh, 0);
-
- if (st->l2.extended) {
- *ptr++ = 0x1;
- *ptr++ = (st->l2.vr << 1) | 1;
- } else {
- *ptr++ = (st->l2.vr << 5) | 0x11;
- }
- ibh->datasize = ptr - DATAPTR(ibh);
- enqueue_super(st, ibh);
- if (FsmAddTimer(&st->l2.t200_timer, st->l2.t200, EV_L2_T200, NULL, 12))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 10");
-
- st->l2.t200_running = !0;
- }
-}
-
-static void
-l2s23(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.t200_running = 0;
-
- st->l2.rc = 1;
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
-}
-
-static void
-l2s24(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- int p, seq, rsp;
- byte *ptr;
- struct Layer2 *l2;
-
- l2 = &st->l2;
- ptr = DATAPTR(ibh);
-
- if (l2->laptype == LAPD) {
- rsp = ptr[0] & 0x2;
- if (l2->orig)
- rsp = !rsp;
- } else {
- rsp = ptr[0] == 0x3;
- if (l2->orig)
- rsp = !rsp;
- }
-
-
- ptr += l2addrsize(l2);
-
- if (l2->extended) {
- p = (ptr[1] & 0x1) == 0x1;
- seq = ptr[1] >> 1;
- } else {
- p = (ptr[0] & 0x10);
- seq = (ptr[0] >> 5) & 0x7;
- }
- BufPoolRelease(ibh);
-
- if (rsp && p) {
- if (legalnr(st, seq)) {
- FsmChangeState(fi, ST_L2_7);
- setva(st, seq);
- if (st->l2.t200_running) {
- FsmDelTimer(&st->l2.t200_timer, 14);
- st->l2.t200_running = 0;
- }
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 13))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 11");
-
- invoke_retransmission(st, seq);
- }
- } else {
- if (!rsp && p)
- enquiry_response(st);
- if (legalnr(st, seq)) {
- setva(st, seq);
- }
- }
-}
-
-static void
-l2s25(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- st->l2.rc = 0;
- FsmChangeState(fi, ST_L2_8);
- transmit_enquiry(st);
-}
-
-static void
-l2s26(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
-
- if (st->l2.rc == st->l2.n200) {
- l2s13(fi, event, NULL);
- } else {
- st->l2.rc++;
- transmit_enquiry(st);
- }
-}
-
-static void
-l2s27(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- int i, p, est;
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&st->l2);
-
- if (st->l2.extended)
- p = ptr[1] & 0x1;
- else
- p = ptr[0] & 0x10;
-
- BufPoolRelease(ibh);
-
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 10))
- return;
- i = sethdraddr(&st->l2, ibh, 0);
- ptr = DATAPTR(ibh);
- ptr += i;
- *ptr = 0x63 | p;
- ibh->datasize = i + 1;
- enqueue_super(st, ibh);
-
- if (st->l2.vs != st->l2.va) {
- discard_i_queue(st);
- est = !0;
- } else
- est = 0;
-
- FsmDelTimer(&st->l2.t200_timer, 15);
- st->l2.t200_running = 0;
-
- if (FsmAddTimer(&st->l2.t203_timer, st->l2.t203, EV_L2_T203, NULL, 3))
- if (st->l2.l2m.debug)
- l2m_debug(&st->l2.l2m, "FAT 12");
-
- st->l2.vs = 0;
- st->l2.va = 0;
- st->l2.vr = 0;
- st->l2.sow = 0;
-
-
- if (est)
- st->l2.l2man(st, DL_ESTABLISH, NULL);
-
-}
-
-static void
-l2s28(struct FsmInst *fi, int event, void *arg)
-{
- struct PStack *st = fi->userdata;
- struct BufHeader *ibh = arg;
- byte *ptr;
- char tmp[64];
-
- ptr = DATAPTR(ibh);
- ptr += l2addrsize(&st->l2);
- ptr++;
-
- if (st->l2.l2m.debug) {
- if (st->l2.extended)
- sprintf(tmp, "FRMR information %2x %2x %2x %2x %2x",
- ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
- else
- sprintf(tmp, "FRMR information %2x %2x %2x",
- ptr[0], ptr[1], ptr[2]);
-
- l2m_debug(&st->l2.l2m, tmp);
- }
- BufPoolRelease(ibh);
-}
-
-static int
-IsUI(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x3);
-}
-
-static int
-IsUA(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x63);
-}
-
-static int
-IsDISC(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x43);
-}
-
-static int
-IsRR(byte * data, int ext)
-{
- if (ext)
- return (data[0] == 0x1);
- else
- return ((data[0] & 0xf) == 1);
-}
-
-static int
-IsI(byte * data, int ext)
-{
- return ((data[0] & 0x1) == 0x0);
-}
-
-static int
-IsSABMX(byte * data, int ext)
-{
- return (ext ? data[0] == 0x7f : data[0] == 0x3f);
-}
-
-static int
-IsREJ(byte * data, int ext)
-{
- return (ext ? data[0] == 0x9 : (data[0] & 0xf) == 0x9);
-}
-
-static int
-IsFRMR(byte * data, int ext)
-{
- return ((data[0] & 0xef) == 0x87);
-}
-
-static int
-IsRNR(byte * data, int ext)
-{
- if (ext)
- return (data[0] == 0x5);
- else
- return ((data[0] & 0xf) == 5);
-}
-
-static struct FsmNode L2FnList[] =
-{
- {ST_L2_1, EV_L2_DL_ESTABLISH, l2s1},
- {ST_L2_1, EV_L2_MDL_NOTEIPROC, l2s19},
- {ST_L2_3, EV_L2_MDL_ASSIGN, l2s17},
- {ST_L2_4, EV_L2_DL_UNIT_DATA, l2s2},
- {ST_L2_4, EV_L2_DL_ESTABLISH, l2s11},
- {ST_L2_7, EV_L2_DL_UNIT_DATA, l2s2},
- {ST_L2_7, EV_L2_DL_DATA, l2s7},
- {ST_L2_7, EV_L2_DL_RELEASE, l2s13},
- {ST_L2_7, EV_L2_ACK_PULL, l2s22},
- {ST_L2_8, EV_L2_DL_RELEASE, l2s13},
-
- {ST_L2_1, EV_L2_UI, l2s3},
- {ST_L2_4, EV_L2_UI, l2s3},
- {ST_L2_4, EV_L2_SABMX, l2s12},
- {ST_L2_5, EV_L2_UA, l2s5},
- {ST_L2_6, EV_L2_UA, l2s15},
- {ST_L2_7, EV_L2_UI, l2s3},
- {ST_L2_7, EV_L2_DISC, l2s14},
- {ST_L2_7, EV_L2_I, l2s8},
- {ST_L2_7, EV_L2_RR, l2s6},
- {ST_L2_7, EV_L2_REJ, l2s16},
- {ST_L2_7, EV_L2_SABMX, l2s27},
- {ST_L2_7, EV_L2_FRMR, l2s28},
- {ST_L2_8, EV_L2_RR, l2s24},
- {ST_L2_8, EV_L2_DISC, l2s14},
- {ST_L2_8, EV_L2_FRMR, l2s28},
-
- {ST_L2_5, EV_L2_T200, l2s20},
- {ST_L2_6, EV_L2_T200, l2s21},
- {ST_L2_7, EV_L2_T200, l2s23},
- {ST_L2_7, EV_L2_T203, l2s25},
- {ST_L2_8, EV_L2_T200, l2s26},
-};
-
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
-static void
-isdnl2_l1l2(struct PStack *st, int pr, struct BufHeader *arg)
-{
- struct BufHeader *ibh;
- byte *datap;
- int ret = !0;
-
- switch (pr) {
- case (PH_DATA):
-
- ibh = arg;
- datap = DATAPTR(ibh);
- datap += l2addrsize(&st->l2);
-
- if (IsI(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_I, ibh);
- else if (IsRR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_RR, ibh);
- else if (IsUI(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UI, ibh);
- else if (IsSABMX(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_SABMX, ibh);
- else if (IsUA(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_UA, ibh);
- else if (IsDISC(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, ibh);
- else if (IsREJ(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_REJ, ibh);
- else if (IsFRMR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, ibh);
- else if (IsRNR(datap, st->l2.extended))
- ret = FsmEvent(&st->l2.l2m, EV_L2_RNR, ibh);
-
- if (ret)
- BufPoolRelease(ibh);
-
- break;
- case (PH_PULL_ACK):
- FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
- break;
- }
-}
-
-static void
-isdnl2_l3l2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (DL_DATA):
- if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg))
- BufPoolRelease((struct BufHeader *) arg);
- break;
- case (DL_UNIT_DATA):
- if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg))
- BufPoolRelease((struct BufHeader *) arg);
- break;
- }
-}
-
-static void
-isdnl2_manl2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (DL_ESTABLISH):
- FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH, arg);
- break;
- case (DL_RELEASE):
- FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE, arg);
- break;
- case (MDL_NOTEIPROC):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_NOTEIPROC, NULL);
- break;
- }
-}
-
-static void
-isdnl2_teil2(struct PStack *st, int pr,
- void *arg)
-{
- switch (pr) {
- case (MDL_ASSIGN):
- FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg);
- break;
- }
-}
-
-void
-releasestack_isdnl2(struct PStack *st)
-{
- FsmDelTimer(&st->l2.t200_timer, 15);
- FsmDelTimer(&st->l2.t203_timer, 16);
-}
-
-static void
-l2m_debug(struct FsmInst *fi, char *s)
-{
- struct PStack *st = fi->userdata;
- char tm[32], str[256];
-
- jiftime(tm, jiffies);
- sprintf(str, "%s %s %s\n", tm, st->l2.debug_id, s);
- teles_putstatus(str);
-}
-
-
-void
-setstack_isdnl2(struct PStack *st, char *debug_id)
-{
- st->l1.l1l2 = isdnl2_l1l2;
- st->l3.l3l2 = isdnl2_l3l2;
- st->ma.manl2 = isdnl2_manl2;
- st->ma.teil2 = isdnl2_teil2;
-
- st->l2.uihsize = l2headersize(&st->l2, !0);
- st->l2.ihsize = l2headersize(&st->l2, 0);
- BufQueueInit(&(st->l2.i_queue));
- st->l2.rejexp = 0;
- st->l2.debug = 1;
-
- st->l2.l2m.fsm = &l2fsm;
- st->l2.l2m.state = ST_L2_1;
- st->l2.l2m.debug = 0;
- st->l2.l2m.userdata = st;
- st->l2.l2m.printdebug = l2m_debug;
- strcpy(st->l2.debug_id, debug_id);
-
- FsmInitTimer(&st->l2.l2m, &st->l2.t200_timer);
- FsmInitTimer(&st->l2.l2m, &st->l2.t203_timer);
- st->l2.t200_running = 0;
-}
-
-void
-setstack_transl2(struct PStack *st)
-{
-}
-
-void
-releasestack_transl2(struct PStack *st)
-{
-}
-
-void
-Isdnl2New(void)
-{
- l2fsm.state_count = L2_STATE_COUNT;
- l2fsm.event_count = L2_EVENT_COUNT;
- l2fsm.strEvent = strL2Event;
- l2fsm.strState = strL2State;
- FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
-}
-
-void
-Isdnl2Free(void)
-{
- FsmFree(&l2fsm);
-}
+++ /dev/null
-/* $Id: isdnl3.c,v 1.11 1996/09/29 19:41:58 fritz Exp $
- *
- * $Log: isdnl3.c,v $
- * Revision 1.11 1996/09/29 19:41:58 fritz
- * Bugfix: ignore unknown frames.
- *
- * Revision 1.10 1996/09/25 18:32:43 keil
- * response for STATUS_ENQ message added
- *
- * Revision 1.9 1996/06/06 14:22:27 fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.8 1996/06/03 20:35:04 fritz
- * Fixed typos.
- *
- * Revision 1.7 1996/06/03 20:03:39 fritz
- * Fixed typos.
- *
- * Revision 1.6 1996/05/21 11:33:50 keil
- * Adding SETUP_ACKNOWLEDGE as answer of a SETUP message.
- *
- * Revision 1.5 1996/05/18 01:37:16 fritz
- * Added spelling corrections and some minor changes
- * to stay in sync with kernel.
- *
- * Revision 1.4 1996/05/17 03:46:16 fritz
- * General cleanup.
- *
- * Revision 1.3 1996/04/30 21:57:53 isdn4dev
- * remove some debugging code, improve callback Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:45:05 fritz
- * Changed to report all incoming calls to Linklevel, not just those
- * with Service 7.
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:24:45 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#define P_1TR6
-#include "teles.h"
-#include "l3_1TR6.h"
-#define DEBUG_1TR6 0
-
-static void
-i_down(struct PStack *st,
- struct BufHeader *ibh)
-{
- st->l3.l3l2(st, DL_DATA, ibh);
-}
-
-static void
-newl3state(struct PStack *st, int state)
-{
- st->l3.state = state;
- if (DEBUG_1TR6 > 4)
- printk(KERN_INFO "isdnl3: bc:%d cr:%x new state %d\n",
- st->pa->bchannel, st->pa->callref, state);
-
-}
-
-static void
-l3_message(struct PStack *st, int mt)
-{
- struct BufHeader *dibh;
- byte *p;
- int size;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = mt;
- size += 4;
-
- dibh->datasize = size;
- i_down(st, dibh);
-}
-
-static void
-l3s3(struct PStack *st, byte pr, void *arg)
-{
- l3_message(st, MT_RELEASE);
- newl3state(st, 19);
-}
-
-static void
-l3s4(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s4_1(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 19);
- l3_message(st, MT_RELEASE);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3s5(struct PStack *st, byte pr,
- void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- char *teln;
-
- st->l3.callref = st->pa->callref;
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_SETUP;
- *p++ = 0xa1;
-
- /*
- * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
- */
- switch (st->pa->info) {
- case 1: /* Telephony */
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. national, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa3; /* A-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = 0x4; /* BC-IE-code */
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. nat., unrestr. dig. Inform. */
- *p++ = 0x90; /* Packet-Mode 64kbps */
- break;
- }
- /*
- * What about info2? Mapping to High-Layer-Compatibility?
- */
- if (st->pa->calling[0] != '\0') {
- *p++ = 0x6c;
- *p++ = strlen(st->pa->calling) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- teln = st->pa->calling;
- while (*teln)
- *p++ = *teln++ & 0x7f;
- }
- *p++ = 0x70;
- *p++ = strlen(st->pa->called) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-
- teln = st->pa->called;
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
-
- dibh->datasize = p - DATAPTR(dibh);
-
- newl3state(st, 1);
- i_down(st, dibh);
-
-}
-
-static void
-l3s6(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_WARNING "octect 3 not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 3);
- st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3s7(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 12);
- st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-static void
-l3s8(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_CNF, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3s11(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 4);
- st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3s12(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int bcfound = 0;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- p += st->l2.uihsize;
- st->pa->callref = getcallref(p);
- st->l3.callref = 0x80 + st->pa->callref;
-
- /*
- * Channel Identification
- */
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x18, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- bcfound++ ;
- } else
- printk(KERN_WARNING "l3s12: Channel ident not found\n");
-
- p = DATAPTR(ibh);
- if (st->protocol == ISDN_PTYPE_1TR6) {
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x01, 6))) {
- st->pa->info = p[2];
- st->pa->info2 = p[3];
- } else
- printk(KERN_WARNING "l3s12(1TR6): ServiceIndicator not found\n");
- } else {
- /*
- * Bearer Capabilities
- */
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) {
- switch (p[2] & 0x1f) {
- case 0x00:
- /* Speech */
- case 0x10:
- /* 3.1 Khz audio */
- st->pa->info = 1;
- break;
- case 0x08:
- /* Unrestricted digital information */
- st->pa->info = 7;
- break;
- case 0x09:
- /* Restricted digital information */
- st->pa->info = 2;
- break;
- case 0x11:
- /* Unrestr. digital information with tones/announcements */
- st->pa->info = 3;
- break;
- case 0x18:
- /* Video */
- st->pa->info = 4;
- break;
- default:
- st->pa->info = 0;
- }
- } else
- printk(KERN_WARNING "l3s12: Bearer capabilities not found\n");
- }
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x70, 0)))
- iecpy(st->pa->called, p, 1);
- else
- strcpy(st->pa->called, "");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- 0x6c, 0))) {
- if (st->protocol == ISDN_PTYPE_1TR6)
- iecpy(st->pa->calling, p, 1);
- else
- iecpy(st->pa->calling, p, 2);
- } else
- strcpy(st->pa->calling, "");
- BufPoolRelease(ibh);
-
- if (bcfound) {
- if (st->pa->info != 7) {
- printk(KERN_DEBUG "non-digital call: %s -> %s\n",
- st->pa->calling,
- st->pa->called);
- }
- newl3state(st, 6);
- st->l3.l3l4(st, CC_SETUP_IND, NULL);
- }
-}
-
-static void
-l3s13(struct PStack *st, byte pr, void *arg)
-{
- newl3state(st, 0);
-}
-
-static void
-l3s16(struct PStack *st, byte pr,
- void *arg)
-{
- st->l3.callref = 0x80 + st->pa->callref;
- l3_message(st, MT_CONNECT);
- newl3state(st, 8);
-}
-
-static void
-l3s17(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3s18(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- int size;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_DISCONNECT;
- size += 4;
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 0x90;
- size += 4;
-
- dibh->datasize = size;
- i_down(st, dibh);
-
- newl3state(st, 11);
-}
-
-static void
-l3s19(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- l3_message(st, MT_RELEASE_COMPLETE);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
-}
-
-static void
-l3s20(struct PStack *st, byte pr,
- void *arg)
-{
- l3_message(st, MT_ALERTING);
- newl3state(st, 7);
-}
-
-static void
-l3s21(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh=arg;
- byte *p;
- int size;
-
- BufPoolRelease(dibh);
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
- size = st->l2.ihsize;
-
- *p++ = 0x8;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_STATUS;
- size += 4;
-
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 0x9E; /* answer status enquire */
- size += 4;
-
- *p++ = 0x14; /* CallState */
- *p++ = 0x1;
- *p++ = st->l3.state & 0x3f; /* ISO L3 CallState */
- size += 3;
-
- dibh->datasize = size;
- i_down(st, dibh);
-
-}
-
-struct stateentry {
- int state;
- byte primitive;
- void (*rout) (struct PStack *, byte, void *);
-};
-
-static struct stateentry downstatelist[] =
-{
- {0,CC_SETUP_REQ,l3s5},
- {1,CC_DISCONNECT_REQ,l3s18},
- {1,CC_RELEASE_REQ,l3s3},
- {1,CC_DLRL,l3s13},
- {3,CC_DISCONNECT_REQ,l3s18},
- {3,CC_RELEASE_REQ,l3s3},
- {3,CC_DLRL,l3s13},
- {4,CC_RELEASE_REQ,l3s3},
- {4,CC_DISCONNECT_REQ,l3s18},
- {4,CC_DLRL,l3s13},
- {6,CC_RELEASE_REQ,l3s3},
- {6,CC_DISCONNECT_REQ,l3s18},
- {6,CC_ALERTING_REQ,l3s20},
- {6,CC_DLRL,l3s13},
- {7,CC_RELEASE_REQ,l3s3},
- {7,CC_SETUP_RSP,l3s16},
- {7,CC_DLRL,l3s13},
- {8,CC_RELEASE_REQ,l3s3},
- {8,CC_DISCONNECT_REQ,l3s18},
- {8,CC_DLRL,l3s13},
- {10,CC_DISCONNECT_REQ,l3s18},
- {10,CC_RELEASE_REQ,l3s3},
- {10,CC_DLRL,l3s13},
- {11,CC_RELEASE_REQ,l3s3},
- {12,CC_RELEASE_REQ,l3s3},
- {19,CC_DLRL,l3s13},
-};
-
-static int downsllen = sizeof(downstatelist) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist[] =
-{
- {0,MT_STATUS_ENQUIRY,l3s21},
- {0,MT_SETUP,l3s12},
- {1,MT_STATUS_ENQUIRY,l3s21},
- {1,MT_CALL_PROCEEDING,l3s6},
- {1,MT_SETUP_ACKNOWLEDGE,l3s6},
- {1,MT_RELEASE_COMPLETE,l3s4},
- {1,MT_RELEASE,l3s19},
- {1,MT_DISCONNECT,l3s7},
- {3,MT_STATUS_ENQUIRY,l3s21},
- {3,MT_DISCONNECT,l3s7},
- {3,MT_CONNECT,l3s8},
- {3,MT_ALERTING,l3s11},
- {3,MT_RELEASE,l3s19},
- {3,MT_RELEASE_COMPLETE,l3s4},
- {4,MT_STATUS_ENQUIRY,l3s21},
- {4,MT_CONNECT,l3s8},
- {4,MT_DISCONNECT,l3s7},
- {4,MT_RELEASE,l3s19},
- {4,MT_RELEASE_COMPLETE,l3s4},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {6,MT_SETUP,l3s12},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {7,MT_RELEASE,l3s19},
- {7,MT_RELEASE_COMPLETE,l3s4_1},
- {7,MT_DISCONNECT,l3s7},
- {8,MT_STATUS_ENQUIRY,l3s21},
- {8,MT_RELEASE,l3s19},
- {8,MT_CONNECT_ACKNOWLEDGE,l3s17},
- {8,MT_DISCONNECT,l3s7},
- {8,MT_RELEASE_COMPLETE,l3s4_1},
- {10,MT_STATUS_ENQUIRY,l3s21},
- {10,MT_DISCONNECT,l3s7},
- {10,MT_RELEASE,l3s19},
- {10,MT_RELEASE_COMPLETE,l3s4_1},
- {11,MT_STATUS_ENQUIRY,l3s21},
- {11,MT_RELEASE,l3s19},
- {11,MT_RELEASE_COMPLETE,l3s4},
- {19,MT_STATUS_ENQUIRY,l3s21},
- {19,MT_RELEASE_COMPLETE,l3s4},
-};
-
-static int datasllen = sizeof(datastatelist) /
-sizeof(struct stateentry);
-
-#ifdef P_1TR6
-#include "l3_1TR6.c"
-#endif
-
-static void
-l3up(struct PStack *st,
- int pr, void *arg)
-{
- int i, mt, size;
- byte *ptr;
- struct BufHeader *ibh = arg;
-
- if (pr == DL_DATA) {
- ptr = DATAPTR(ibh);
- ptr += st->l2.ihsize;
- size = ibh->datasize - st->l2.ihsize;
- mt = ptr[3];
- switch (ptr[0]) {
-#ifdef P_1TR6
- case PROTO_DIS_N0:
- BufPoolRelease(ibh);
- break;
- case PROTO_DIS_N1:
- for (i = 0; i < datasl_1tr6t_len; i++)
- if ((st->l3.state == datastatelist_1tr6t[i].state) &&
- (mt == datastatelist_1tr6t[i].primitive))
- break;
- if (i == datasl_1tr6t_len) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- case PROTO_EURO: /* E-DSS1 */
- for (i = 0; i < datasllen; i++)
- if ((st->l3.state == datastatelist[i].state) &&
- (mt == datastatelist[i].primitive))
- break;
- if (i == datasllen) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist[i].rout(st, pr, ibh);
- break;
- default:
- BufPoolRelease(ibh);
- break;
- }
- } else if (pr == DL_UNIT_DATA) {
- ptr = DATAPTR(ibh);
- ptr += st->l2.uihsize;
- size = ibh->datasize - st->l2.uihsize;
- mt = ptr[3];
- switch (ptr[0]) {
-#ifdef P_1TR6
- case PROTO_DIS_N0:
- BufPoolRelease(ibh);
- break;
- case PROTO_DIS_N1:
- for (i = 0; i < datasl_1tr6t_len; i++)
- if ((st->l3.state == datastatelist_1tr6t[i].state) &&
- (mt == datastatelist_1tr6t[i].primitive))
- break;
- if (i == datasl_1tr6t_len) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3up unhandled 1tr6 state %d MT %x\n"
- ,st->l3.state, mt);
- }
- BufPoolRelease(ibh);
- } else
- datastatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- case PROTO_EURO: /* E-DSS1 */
- for (i = 0; i < datasllen; i++)
- if ((st->l3.state == datastatelist[i].state) &&
- (mt == datastatelist[i].primitive))
- break;
- if (i == datasllen) {
- BufPoolRelease(ibh);
- if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "isdnl3up unhandled E-DSS1 state %d MT %x\n",
- st->l3.state, mt);
- } else
- datastatelist[i].rout(st, pr, ibh);
- break;
- default:
- BufPoolRelease(ibh);
- break;
- }
- }
-}
-
-static void
-l3down(struct PStack *st,
- int pr, void *arg)
-{
- int i;
- struct BufHeader *ibh = arg;
-
- switch (st->protocol) {
-#ifdef P_1TR6
- case ISDN_PTYPE_1TR6:
- for (i = 0; i < downsl_1tr6t_len; i++)
- if ((st->l3.state == downstatelist_1tr6t[i].state) &&
- (pr == downstatelist_1tr6t[i].primitive))
- break;
- if (i == downsl_1tr6t_len) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3down unhandled 1tr6 state %d primitive %x\n", st->l3.state, pr);
- }
- } else
- downstatelist_1tr6t[i].rout(st, pr, ibh);
- break;
-#endif
- default:
- for (i = 0; i < downsllen; i++)
- if ((st->l3.state == downstatelist[i].state) &&
- (pr == downstatelist[i].primitive))
- break;
- if (i == downsllen) {
- if (DEBUG_1TR6 > 0) {
- printk(KERN_INFO "isdnl3down unhandled E-DSS1 state %d primitive %x\n", st->l3.state, pr);
- }
- } else
- downstatelist[i].rout(st, pr, ibh);
- }
-}
-
-void
-setstack_isdnl3(struct PStack *st)
-{
- st->l4.l4l3 = l3down;
- st->l2.l2l3 = l3up;
- st->l3.state = 0;
- st->l3.callref = 0;
- st->l3.debug = 0;
-}
+++ /dev/null
-/* $Id: l3_1TR6.c,v 1.6 1996/09/25 18:34:57 keil Exp $
- *
- * $Log: l3_1TR6.c,v $
- * Revision 1.6 1996/09/25 18:34:57 keil
- * missing states in 1TR6 Statemachine added
- *
- * Revision 1.5 1996/09/23 01:53:51 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.4 1996/06/06 14:22:28 fritz
- * Changed level of "non-digital call..." message, since
- * with audio support, this is quite normal.
- *
- * Revision 1.3 1996/04/30 21:54:42 isdn4dev
- * SPV, callback , remove some debugging code Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:47:23 fritz
- * Changed statemachine to allow reject of an incoming call.
- * Report all incoming calls, not just those with Service = 7.
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:25:16 fritz
- * Initial revision
- *
- *
- */
-
-#include "proto.h"
-
-static void
-l3_1TR6_message(struct PStack *st, int mt, int pd)
-{
- struct BufHeader *dibh;
- byte *p;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = pd;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = mt;
-
- dibh->datasize = p - DATAPTR(dibh);
- i_down(st, dibh);
-}
-
-static void
-l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- char *teln;
-
- st->l3.callref = st->pa->callref;
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_SETUP;
-
- if ('S' == (st->pa->called[0] & 0x5f)) { /* SPV ??? */
- /* NSF SPV */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_SPV; /* SPV */
- *p++ = st->pa->info; /* 0 for all Services */
- *p++ = st->pa->info2; /* 0 for all Services */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_Activate; /* aktiviere SPV (default) */
- *p++ = st->pa->info; /* 0 for all Services */
- *p++ = st->pa->info2; /* 0 for all Services */
- }
- if (st->pa->calling[0] != '\0') {
- *p++ = WE0_origAddr;
- *p++ = strlen(st->pa->calling) + 1;
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- teln = st->pa->calling;
- while (*teln)
- *p++ = *teln++ & 0x7f;
- }
- *p++ = WE0_destAddr;
- teln = st->pa->called;
- if ('S' != (st->pa->called[0] & 0x5f)) { /* Keine SPV ??? */
- *p++ = strlen(st->pa->called) + 1;
- st->pa->spv = 0;
- } else { /* SPV */
- *p++ = strlen(st->pa->called);
- teln++; /* skip S */
- st->pa->spv = 1;
- }
- /* Classify as AnyPref. */
- *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
- while (*teln)
- *p++ = *teln++ & 0x7f;
-
- *p++ = WE_Shift_F6;
- /* Codesatz 6 fuer Service */
- *p++ = WE6_serviceInd;
- *p++ = 2; /* len=2 info,info2 */
- *p++ = st->pa->info;
- *p++ = st->pa->info2;
-
- dibh->datasize = p - DATAPTR(dibh);
-
- newl3state(st, 1);
- i_down(st, dibh);
-
-}
-
-static void
-l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- p += st->l2.uihsize;
- st->pa->callref = getcallref(p);
- st->l3.callref = 0x80 + st->pa->callref;
-
- /* Channel Identification */
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "l3tu_setup: Channel ident not found\n");
-
- p = DATAPTR(ibh);
-
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) {
- st->pa->info = p[2];
- st->pa->info2 = p[3];
- } else
- printk(KERN_INFO "l3s12(1TR6): ServiceIndicator not found\n");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_destAddr, 0)))
- iecpy(st->pa->called, p, 1);
- else
- strcpy(st->pa->called, "");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_origAddr, 0))) {
- iecpy(st->pa->calling, p, 1);
- } else
- strcpy(st->pa->calling, "");
-
- p = DATAPTR(ibh);
- st->pa->spv = 0;
- if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
- WE0_netSpecFac, 0))) {
- if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
- st->pa->spv = 1;
- }
- BufPoolRelease(ibh);
-
- /* Signal all services, linklevel takes care of Service-Indicator */
- if (st->pa->info != 7) {
- printk(KERN_DEBUG "non-digital call: %s -> %s\n",
- st->pa->calling,
- st->pa->called);
- }
- newl3state(st, 6);
- st->l3.l3l4(st, CC_SETUP_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "octect 3 not found\n");
-
-
- BufPoolRelease(ibh);
- newl3state(st, 2);
-}
-
-static void
-l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_chanID, 0))) {
- st->pa->bchannel = p[2] & 0x3;
- } else
- printk(KERN_INFO "octect 3 not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 3);
- st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- struct BufHeader *ibh = arg;
-
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_statusCalled, 6))) {
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "status called %x\n", p[2]);
- } else if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "statusCalled not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 4);
- st->l3.l3l4(st, CC_ALERTING_IND, NULL);
-}
-
-static void
-l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int i,tmpcharge=0;
- char a_charge[8];
- struct BufHeader *ibh = arg;
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_chargingInfo, 6))) {
- iecpy(a_charge, p, 1);
- for (i = 0; i < strlen (a_charge); i++) {
- tmpcharge *= 10;
- tmpcharge += a_charge[i] & 0xf;
- }
- if (tmpcharge > st->pa->chargeinfo) {
- st->pa->chargeinfo = tmpcharge;
- st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
- }
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
- } else if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo not found\n");
-
- BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg)
-{
- byte *p;
- int i;
- struct BufHeader *ibh = arg;
-
- if (DEBUG_1TR6 > 4) {
- p = DATAPTR(ibh);
- for (i = 0; i < ibh->datasize; i++) {
- printk(KERN_INFO "Info DATA %x\n", p[i]);
- }
- }
- BufPoolRelease(ibh);
-}
-
-static void
-l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- st->pa->chargeinfo=0;
- BufPoolRelease(ibh);
- st->l3.l3l4(st, CC_SETUP_CNF, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
- st->l3.l3l4(st, CC_RELEASE_IND, NULL);
- newl3state(st, 0);
-}
-
-static void
-l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- newl3state(st, 0);
- st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
-}
-
-static void
-l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
- byte *p;
- int i,tmpcharge=0;
- char a_charge[8];
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE6_chargingInfo, 6))) {
- iecpy(a_charge, p, 1);
- for (i = 0; i < strlen (a_charge); i++) {
- tmpcharge *= 10;
- tmpcharge += a_charge[i] & 0xf;
- }
- if (tmpcharge > st->pa->chargeinfo) {
- st->pa->chargeinfo = tmpcharge;
- st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
- }
- if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo %d\n", st->pa->chargeinfo);
- } else if (DEBUG_1TR6 > 2)
- printk(KERN_INFO "chargingInfo not found\n");
-
- p = DATAPTR(ibh);
- if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
- WE0_cause, 0))) {
- if (p[1] > 0) {
- st->pa->cause = p[2];
- } else {
- st->pa->cause = 0;
- }
- if (DEBUG_1TR6 > 1)
- printk(KERN_INFO "Cause %x\n", st->pa->cause);
- } else if (DEBUG_1TR6 > 0)
- printk(KERN_INFO "Cause not found\n");
-
- BufPoolRelease(ibh);
- newl3state(st, 12);
- st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
-}
-
-
-static void
-l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *ibh = arg;
-
- BufPoolRelease(ibh);
- st->pa->chargeinfo = 0;
- st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
- newl3state(st, 10);
-}
-
-static void
-l3_1tr6_alert(struct PStack *st, byte pr,
- void *arg)
-{
- l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
- newl3state(st, 7);
-}
-
-static void
-l3_1tr6_conn(struct PStack *st, byte pr,
- void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
-
- st->l3.callref = 0x80 + st->pa->callref;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_CONN;
-
- if (st->pa->spv) { /* SPV ??? */
- /* NSF SPV */
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_SPV; /* SPV */
- *p++ = st->pa->info;
- *p++ = st->pa->info2;
- *p++ = WE0_netSpecFac;
- *p++ = 4; /* Laenge */
- *p++ = 0;
- *p++ = FAC_Activate; /* aktiviere SPV */
- *p++ = st->pa->info;
- *p++ = st->pa->info2;
- }
- dibh->datasize = p - DATAPTR(dibh);
-
- i_down(st, dibh);
-
- newl3state(st, 8);
-}
-
-static void
-l3_1tr6_reset(struct PStack *st, byte pr, void *arg)
-{
- newl3state(st, 0);
-}
-
-static void
-l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
-{
- struct BufHeader *dibh;
- byte *p;
- byte rejflg;
-
- BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
- p = DATAPTR(dibh);
- p += st->l2.ihsize;
-
- *p++ = PROTO_DIS_N1;
- *p++ = 0x1;
- *p++ = st->l3.callref;
- *p++ = MT_N1_DISC;
-
- if (st->l3.state == 7) {
- rejflg = 1;
- *p++ = WE0_cause; /* Anruf abweisen */
- *p++ = 0x01; /* Laenge = 1 */
- *p++ = CAUSE_CallRejected;
- } else {
- rejflg = 0;
- *p++ = WE0_cause;
- *p++ = 0x0; /* Laenge = 0 normales Ausloesen */
- }
-
- dibh->datasize = p - DATAPTR(dibh);
-
- i_down(st, dibh);
-
- newl3state(st, 11);
-}
-
-static void
-l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
-{
- l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
- newl3state(st, 19);
-}
-
-static struct stateentry downstatelist_1tr6t[] =
-{
- {0, CC_SETUP_REQ, l3_1tr6_setup},
- {1, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {1, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {1, CC_DLRL, l3_1tr6_reset},
- {2, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {2, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {2, CC_DLRL, l3_1tr6_reset},
- {3, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {3, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {3, CC_DLRL, l3_1tr6_reset},
- {4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {4, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {4, CC_DLRL, l3_1tr6_reset},
- {6, CC_REJECT_REQ, l3_1tr6_reset},
- {6, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {6, CC_SETUP_RSP, l3_1tr6_conn},
- {6, CC_ALERTING_REQ, l3_1tr6_alert},
- {6, CC_DLRL, l3_1tr6_reset},
- {7, CC_SETUP_RSP, l3_1tr6_conn},
- {7, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {7, CC_DLRL, l3_1tr6_reset},
- {8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {8, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {8, CC_DLRL, l3_1tr6_reset},
- {10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
- {10, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {10, CC_DLRL, l3_1tr6_reset},
- {12, CC_RELEASE_REQ, l3_1tr6_rel_req},
- {12, CC_DLRL, l3_1tr6_reset},
- {19, CC_DLRL, l3_1tr6_reset},
-};
-
-static int downsl_1tr6t_len = sizeof(downstatelist_1tr6t) /
-sizeof(struct stateentry);
-
-static struct stateentry datastatelist_1tr6t[] =
-{
- {0, MT_N1_SETUP, l3_1tr6_tu_setup},
- {0, MT_N1_REL, l3_1tr6_tu_rel},
- {1, MT_N1_SETUP_ACK, l3_1tr6_tu_setup_ack},
- {1, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
- {1, MT_N1_REL, l3_1tr6_tu_rel},
- {1, MT_N1_DISC, l3_1tr6_tu_disc},
- {2, MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
- {2, MT_N1_ALERT, l3_1tr6_tu_alert},
- {2, MT_N1_CONN, l3_1tr6_tu_connect},
- {2, MT_N1_REL, l3_1tr6_tu_rel},
- {2, MT_N1_DISC, l3_1tr6_tu_disc},
- {2, MT_N1_INFO, l3_1tr6_tu_info_s2},
- {3, MT_N1_ALERT, l3_1tr6_tu_alert},
- {3, MT_N1_CONN, l3_1tr6_tu_connect},
- {3, MT_N1_REL, l3_1tr6_tu_rel},
- {3, MT_N1_DISC, l3_1tr6_tu_disc},
- {4, MT_N1_ALERT, l3_1tr6_tu_alert},
- {4, MT_N1_CONN, l3_1tr6_tu_connect},
- {4, MT_N1_REL, l3_1tr6_tu_rel},
- {4, MT_N1_DISC, l3_1tr6_tu_disc},
- {7, MT_N1_REL, l3_1tr6_tu_rel},
- {7, MT_N1_DISC, l3_1tr6_tu_disc},
- {8, MT_N1_REL, l3_1tr6_tu_rel},
- {8, MT_N1_DISC, l3_1tr6_tu_disc},
- {8, MT_N1_CONN_ACK, l3_1tr6_tu_connect_ack},
- {10, MT_N1_REL, l3_1tr6_tu_rel},
- {10, MT_N1_DISC, l3_1tr6_tu_disc},
- {10, MT_N1_INFO, l3_1tr6_tu_info},
- {11, MT_N1_REL, l3_1tr6_tu_rel},
- {12, MT_N1_REL, l3_1tr6_tu_rel},
- {19, MT_N1_REL_ACK, l3_1tr6_tu_rel_ack}
-};
-
-static int datasl_1tr6t_len = sizeof(datastatelist_1tr6t) /
-sizeof(struct stateentry);
+++ /dev/null
-/* $Id: l3_1TR6.h,v 1.4 1996/09/23 01:53:52 fritz Exp $
- *
- * $Log: l3_1TR6.h,v $
- * Revision 1.4 1996/09/23 01:53:52 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.3 1996/04/30 21:53:48 isdn4dev
- * Bugs, SPV, Logging in q931.c Karsten Keil
- *
- * Revision 1.1 1996/04/13 10:25:42 fritz
- * Initial revision
- *
- *
- */
-#ifndef l3_1TR6
-#define l3_1TR6
-
-/*
- * MsgType N0
- */
-#define MT_N0_REG_IND 0x61
-#define MT_N0_CANC_IND 0x62
-#define MT_N0_FAC_STA 0x63
-#define MT_N0_STA_ACK 0x64
-#define MT_N0_STA_REJ 0x65
-#define MT_N0_FAC_INF 0x66
-#define MT_N0_INF_ACK 0x67
-#define MT_N0_INF_REJ 0x68
-#define MT_N0_CLOSE 0x75
-#define MT_N0_CLO_ACK 0x77
-
-
-/*
- * MsgType N1
- */
-
-#define MT_N1_ESC 0x00
-#define MT_N1_ALERT 0x01
-#define MT_N1_CALL_SENT 0x02
-#define MT_N1_CONN 0x07
-#define MT_N1_CONN_ACK 0x0F
-#define MT_N1_SETUP 0x05
-#define MT_N1_SETUP_ACK 0x0D
-#define MT_N1_RES 0x26
-#define MT_N1_RES_ACK 0x2E
-#define MT_N1_RES_REJ 0x22
-#define MT_N1_SUSP 0x25
-#define MT_N1_SUSP_ACK 0x2D
-#define MT_N1_SUSP_REJ 0x21
-#define MT_N1_USER_INFO 0x20
-#define MT_N1_DET 0x40
-#define MT_N1_DISC 0x45
-#define MT_N1_REL 0x4D
-#define MT_N1_REL_ACK 0x5A
-#define MT_N1_CANC_ACK 0x6E
-#define MT_N1_CANC_REJ 0x67
-#define MT_N1_CON_CON 0x69
-#define MT_N1_FAC 0x60
-#define MT_N1_FAC_ACK 0x68
-#define MT_N1_FAC_CAN 0x66
-#define MT_N1_FAC_REG 0x64
-#define MT_N1_FAC_REJ 0x65
-#define MT_N1_INFO 0x6D
-#define MT_N1_REG_ACK 0x6C
-#define MT_N1_REG_REJ 0x6F
-#define MT_N1_STAT 0x63
-
-
-
-/*
- * W Elemente
- */
-
-#define WE_Shift_F0 0x90
-#define WE_Shift_F6 0x96
-#define WE_Shift_OF0 0x98
-#define WE_Shift_OF6 0x9E
-
-#define WE0_cause 0x08
-#define WE0_connAddr 0x0C
-#define WE0_callID 0x10
-#define WE0_chanID 0x18
-#define WE0_netSpecFac 0x20
-#define WE0_display 0x28
-#define WE0_keypad 0x2C
-#define WE0_origAddr 0x6C
-#define WE0_destAddr 0x70
-#define WE0_userInfo 0x7E
-
-#define WE0_moreData 0xA0
-#define WE0_congestLevel 0xB0
-
-#define WE6_serviceInd 0x01
-#define WE6_chargingInfo 0x02
-#define WE6_date 0x03
-#define WE6_facSelect 0x05
-#define WE6_facStatus 0x06
-#define WE6_statusCalled 0x07
-#define WE6_addTransAttr 0x08
-
-/*
- * FacCodes
- */
-#define FAC_Sperre 0x01
-#define FAC_Sperre_All 0x02
-#define FAC_Sperre_Fern 0x03
-#define FAC_Sperre_Intl 0x04
-#define FAC_Sperre_Interk 0x05
-
-#define FAC_Forward1 0x02
-#define FAC_Forward2 0x03
-#define FAC_Konferenz 0x06
-#define FAC_GrabBchan 0x0F
-#define FAC_Reactivate 0x10
-#define FAC_Konferenz3 0x11
-#define FAC_Dienstwechsel1 0x12
-#define FAC_Dienstwechsel2 0x13
-#define FAC_NummernIdent 0x14
-#define FAC_GBG 0x15
-#define FAC_DisplayUebergeben 0x17
-#define FAC_DisplayUmgeleitet 0x1A
-#define FAC_Unterdruecke 0x1B
-#define FAC_Deactivate 0x1E
-#define FAC_Activate 0x1D
-#define FAC_SPV 0x1F
-#define FAC_Rueckwechsel 0x23
-#define FAC_Umleitung 0x24
-
-/*
- * Cause codes
- */
-#define CAUSE_InvCRef 0x01
-#define CAUSE_BearerNotImpl 0x03
-#define CAUSE_CIDunknown 0x07
-#define CAUSE_CIDinUse 0x08
-#define CAUSE_NoChans 0x0A
-#define CAUSE_FacNotImpl 0x10
-#define CAUSE_FacNotSubscr 0x11
-#define CAUSE_OutgoingBarred 0x20
-#define CAUSE_UserAccessBusy 0x21
-#define CAUSE_NegativeGBG 0x22
-#define CAUSE_UnknownGBG 0x23
-#define CAUSE_NoSPVknown 0x25
-#define CAUSE_DestNotObtain 0x35
-#define CAUSE_NumberChanged 0x38
-#define CAUSE_OutOfOrder 0x39
-#define CAUSE_NoUserResponse 0x3A
-#define CAUSE_UserBusy 0x3B
-#define CAUSE_IncomingBarred 0x3D
-#define CAUSE_CallRejected 0x3E
-#define CAUSE_NetworkCongestion 0x59
-#define CAUSE_RemoteUser 0x5A
-#define CAUSE_LocalProcErr 0x70
-#define CAUSE_RemoteProcErr 0x71
-#define CAUSE_RemoteUserSuspend 0x72
-#define CAUSE_RemoteUserResumed 0x73
-#define CAUSE_UserInfoDiscarded 0x7F
-
-
-#endif
+++ /dev/null
-/* $Id: llglue.c,v 1.7 1996/10/22 23:14:17 fritz Exp $
- *
- * $Log: llglue.c,v $
- * Revision 1.7 1996/10/22 23:14:17 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.6 1996/06/03 20:03:39 fritz
- * Fixed typos.
- *
- * Revision 1.5 1996/05/31 00:58:47 fritz
- * Errata: Reverted change from rev 1.4.
- *
- * Revision 1.4 1996/05/26 14:59:57 fritz
- * Bugfix: maxbufsize had been set without respect to possible X.75 header.
- *
- * Revision 1.3 1996/05/01 14:19:57 fritz
- * Added ISDN_FEATURE_L2_TRANS
- *
- * Revision 1.2 1996/04/29 23:01:46 fritz
- * Added driverId and channel to readstatus().
- *
- * Revision 1.1 1996/04/13 10:26:29 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-#include <linux/malloc.h>
-#include <linux/timer.h>
-
-
-extern struct Channel *chanlist;
-int drid;
-char *teles_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-
-isdn_if iif;
-
-#define TELES_STATUS_BUFSIZE 4096
-static byte *teles_status_buf = NULL;
-static byte *teles_status_read = NULL;
-static byte *teles_status_write = NULL;
-static byte *teles_status_end = NULL;
-
-int
-teles_readstatus(byte * buf, int len, int user, int id, int channel)
-{
- int count;
- byte *p;
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (user)
- put_user(*teles_status_read++, p);
- else
- *p++ = *teles_status_read++;
- if (teles_status_read > teles_status_end)
- teles_status_read = teles_status_buf;
- }
- return count;
-}
-
-void
-teles_putstatus(char *buf)
-{
- long flags;
- int len, count, i;
- byte *p;
- isdn_ctrl ic;
-
- save_flags(flags);
- cli();
- count = 0;
- len = strlen(buf);
- for (p = buf, i = len; i > 0; i--, p++) {
- *teles_status_write++ = *p;
- if (teles_status_write > teles_status_end)
- teles_status_write = teles_status_buf;
- count++;
- }
- restore_flags(flags);
- if (count) {
- ic.command = ISDN_STAT_STAVAIL;
- ic.driver = drid;
- ic.arg = count;
- iif.statcallb(&ic);
- }
-}
-
-
-int
-ll_init(void)
-{
- isdn_ctrl ic;
-
- teles_status_buf = Smalloc(TELES_STATUS_BUFSIZE,
- GFP_KERNEL, "teles_status_buf");
- if (!teles_status_buf) {
- printk(KERN_ERR "teles: Could not allocate status-buffer\n");
- return (-EIO);
- } else {
- teles_status_read = teles_status_buf;
- teles_status_write = teles_status_buf;
- teles_status_end = teles_status_buf + TELES_STATUS_BUFSIZE - 1;
- }
-
- iif.channels = CallcNewChan();
- iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS);
- iif.features =
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_1TR6 |
- ISDN_FEATURE_P_EURO;
-
- iif.command = teles_command;
- iif.writebuf = teles_writebuf;
- iif.writecmd = NULL;
- iif.readstat = teles_readstatus;
- strncpy(iif.id, teles_id, sizeof(iif.id) - 1);
-
- register_isdn(&iif);
- drid = iif.channels;
-
- ic.driver = drid;
- ic.command = ISDN_STAT_RUN;
- iif.statcallb(&ic);
- return 0;
-}
-
-void
-ll_stop(void)
-{
- isdn_ctrl ic;
-
- ic.command = ISDN_STAT_STOP;
- ic.driver = drid;
- iif.statcallb(&ic);
-
- CallcFreeChan();
-}
-
-void
-ll_unload(void)
-{
- isdn_ctrl ic;
-
- ic.command = ISDN_STAT_UNLOAD;
- ic.driver = drid;
- iif.statcallb(&ic);
-}
+++ /dev/null
-/* $Id: mod.c,v 1.1 1996/04/13 10:27:02 fritz Exp $
- *
- * $Log: mod.c,v $
- * Revision 1.1 1996/04/13 10:27:02 fritz
- * Initial revision
- *
- *
- */
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern char *teles_id;
-
-int nrcards;
-
-typedef struct {
- byte *membase;
- int interrupt;
- unsigned int iobase;
- unsigned int protocol;
-} io_type;
-
-io_type io[] =
-{
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
-};
-
-void
-teles_mod_dec_use_count(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-void
-teles_mod_inc_use_count(void)
-{
- MOD_INC_USE_COUNT;
-}
-
-#ifdef MODULE
-#define teles_init init_module
-#else
-void teles_setup(char *str, int *ints)
-{
- int i, j, argc;
- static char sid[20];
-
- argc = ints[0];
- i = 0;
- j = 1;
- while (argc && (i<16)) {
- if (argc) {
- io[i].iobase = ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].interrupt = ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].membase = (byte *)ints[j];
- j++; argc--;
- }
- if (argc) {
- io[i].protocol = ints[j];
- j++; argc--;
- }
- i++;
- }
- if (strlen(str)) {
- strcpy(sid,str);
- teles_id = sid;
- }
-}
-#endif
-
-int
-teles_init(void)
-{
- int i;
-
- nrcards = 0;
- for (i = 0; i < 16; i++) {
- if (io[i].protocol) {
- cards[i].membase = io[i].membase;
- cards[i].interrupt = io[i].interrupt;
- cards[i].iobase = io[i].iobase;
- cards[i].protocol = io[i].protocol;
- }
- }
- for (i = 0; i < 16; i++)
- if (cards[i].protocol)
- nrcards++;
- printk(KERN_DEBUG "teles: Total %d card%s defined\n",
- nrcards, (nrcards > 1) ? "s" : "");
- if (teles_inithardware()) {
- /* Install only, if at least one card found */
- Isdnl2New();
- TeiNew();
- CallcNew();
- ll_init();
-
- /* No symbols to export, hide all symbols */
- register_symtab(NULL);
-
-#ifdef MODULE
- printk(KERN_NOTICE "Teles module installed\n");
-#endif
- return (0);
- } else
- return -EIO;
-}
-
-#ifdef MODULE
-void
-cleanup_module(void)
-{
-
- ll_stop();
- TeiFree();
- Isdnl2Free();
- CallcFree();
- teles_closehardware();
- ll_unload();
- printk(KERN_NOTICE "Teles module removed\n");
-
-}
-#endif
+++ /dev/null
-/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $
- *
- * not much now - just the l3 proto discriminator
- *
- * $Log: proto.h,v $
- * Revision 1.1 1996/09/23 01:53:52 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- */
-
-#ifndef PROTO_H
-#define PROTO_H
-
-#define PROTO_EURO 0x08
-#define PROTO_DIS_N0 0x40
-#define PROTO_DIS_N1 0x41
-
-#endif
+++ /dev/null
-/* $Id: q931.c,v 1.6 1996/09/23 01:53:53 fritz Exp $
- *
- * q931.c code to decode ITU Q.931 call control messages
- *
- * Author Jan den Ouden
- *
- * Changelog
- *
- * Pauline Middelink general improvements
- *
- * Beat Doebeli cause texts, display information element
- *
- * Karsten Keil cause texts, display information element for 1TR6
- *
- *
- * $Log: q931.c,v $
- * Revision 1.6 1996/09/23 01:53:53 fritz
- * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
- *
- * Revision 1.5 1996/06/03 20:03:40 fritz
- * Fixed typos.
- *
- * Revision 1.4 1996/05/17 03:46:17 fritz
- * General cleanup.
- *
- * Revision 1.3 1996/04/30 22:06:50 isdn4dev
- * logging 1TR6 messages correctly Karsten Keil
- *
- * Revision 1.2 1996/04/20 16:48:19 fritz
- * Misc. typos
- *
- * Revision 1.1 1996/04/13 10:27:49 fritz
- * Initial revision
- *
- *
- */
-
-
-#define __NO_VERSION__
-#include "teles.h"
-#include "proto.h"
-#include "l3_1TR6.h"
-
-byte *
-findie(byte * p, int size, byte ie, int wanted_set)
-{
- int l, codeset, maincodeset;
- byte *pend = p + size;
-
- /* skip protocol discriminator, callref and message type */
- p++;
- l = (*p++) & 0xf;
- p += l;
- p++;
- codeset = 0;
- maincodeset = 0;
- /* while there are bytes left... */
- while (p < pend) {
- if ((*p & 0xf0) == 0x90) {
- codeset = *p & 0x07;
- if (!(*p & 0x08))
- maincodeset = codeset;
- }
- if (*p & 0x80)
- p++;
- else {
- if (codeset == wanted_set) {
- if (*p == ie)
- return (p);
- if (*p > ie)
- return (NULL);
- }
- p++;
- l = *p++;
- p += l;
- codeset = maincodeset;
- }
- }
- return (NULL);
-}
-
-void
-iecpy(byte * dest, byte * iestart, int ieoffset)
-{
- byte *p;
- int l;
-
- p = iestart + ieoffset + 2;
- l = iestart[1] - ieoffset;
- while (l--)
- *dest++ = *p++;
- *dest++ = '\0';
-}
-
-int
-getcallref(byte * p)
-{
- p++; /* prot discr */
- p++; /* callref length */
- return (*p); /* assuming one-byte callref */
-}
-
-/*
- * According to Table 4-2/Q.931
- */
-static
-struct MessageType {
- byte nr;
- char *descr;
-} mtlist[] = {
-
- {
- 0x1, "ALERTING"
- },
- {
- 0x2, "CALL PROCEEDING"
- },
- {
- 0x7, "CONNECT"
- },
- {
- 0xf, "CONNECT ACKNOWLEDGE"
- },
- {
- 0x3, "PROGRESS"
- },
- {
- 0x5, "SETUP"
- },
- {
- 0xd, "SETUP ACKNOWLEDGE"
- },
- {
- 0x26, "RESUME"
- },
- {
- 0x2e, "RESUME ACKNOWLEDGE"
- },
- {
- 0x22, "RESUME REJECT"
- },
- {
- 0x25, "SUSPEND"
- },
- {
- 0x2d, "SUSPEND ACKNOWLEDGE"
- },
- {
- 0x21, "SUSPEND REJECT"
- },
- {
- 0x20, "USER INFORMATION"
- },
- {
- 0x45, "DISCONNECT"
- },
- {
- 0x4d, "RELEASE"
- },
- {
- 0x5a, "RELEASE COMPLETE"
- },
- {
- 0x46, "RESTART"
- },
- {
- 0x4e, "RESTART ACKNOWLEDGE"
- },
- {
- 0x60, "SEGMENT"
- },
- {
- 0x79, "CONGESTION CONTROL"
- },
- {
- 0x7b, "INFORMATION"
- },
- {
- 0x62, "FACILITY"
- },
- {
- 0x6e, "NOTIFY"
- },
- {
- 0x7d, "STATUS"
- },
- {
- 0x75, "STATUS ENQUIRY"
- }
-};
-
-#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
-
-static
-struct MessageType mt_n0[] =
-{
- {MT_N0_REG_IND, "REGister INDication"},
- {MT_N0_CANC_IND, "CANCel INDication"},
- {MT_N0_FAC_STA, "FACility STAtus"},
- {MT_N0_STA_ACK, "STAtus ACKnowledge"},
- {MT_N0_STA_REJ, "STAtus REJect"},
- {MT_N0_FAC_INF, "FACility INFormation"},
- {MT_N0_INF_ACK, "INFormation ACKnowledge"},
- {MT_N0_INF_REJ, "INFormation REJect"},
- {MT_N0_CLOSE, "CLOSE"},
- {MT_N0_CLO_ACK, "CLOse ACKnowledge"}
-};
-
-int mt_n0_len = (sizeof(mt_n0) / sizeof(struct MessageType));
-
-static
-struct MessageType mt_n1[] =
-{
- {MT_N1_ESC, "ESCape"},
- {MT_N1_ALERT, "ALERT"},
- {MT_N1_CALL_SENT, "CALL SENT"},
- {MT_N1_CONN, "CONNect"},
- {MT_N1_CONN_ACK, "CONNect ACKnowledge"},
- {MT_N1_SETUP, "SETUP"},
- {MT_N1_SETUP_ACK, "SETUP ACKnowledge"},
- {MT_N1_RES, "RESume"},
- {MT_N1_RES_ACK, "RESume ACKnowledge"},
- {MT_N1_RES_REJ, "RESume REJect"},
- {MT_N1_SUSP, "SUSPend"},
- {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"},
- {MT_N1_SUSP_REJ, "SUSPend REJect"},
- {MT_N1_USER_INFO, "USER INFO"},
- {MT_N1_DET, "DETach"},
- {MT_N1_DISC, "DISConnect"},
- {MT_N1_REL, "RELease"},
- {MT_N1_REL_ACK, "RELease ACKnowledge"},
- {MT_N1_CANC_ACK, "CANCel ACKnowledge"},
- {MT_N1_CANC_REJ, "CANCel REJect"},
- {MT_N1_CON_CON, "CONgestion CONtrol"},
- {MT_N1_FAC, "FACility"},
- {MT_N1_FAC_ACK, "FACility ACKnowledge"},
- {MT_N1_FAC_CAN, "FACility CANcel"},
- {MT_N1_FAC_REG, "FACility REGister"},
- {MT_N1_FAC_REJ, "FACility REJect"},
- {MT_N1_INFO, "INFOrmation"},
- {MT_N1_REG_ACK, "REGister ACKnowledge"},
- {MT_N1_REG_REJ, "REGister REJect"},
- {MT_N1_STAT, "STATus"}
-};
-
-int mt_n1_len = (sizeof(mt_n1) / sizeof(struct MessageType));
-
-static struct MessageType fac_1tr6[] =
-{
- {FAC_Sperre, "Sperre"},
- {FAC_Forward1, "Forward 1"},
- {FAC_Forward2, "Forward 2"},
- {FAC_Konferenz, "Konferenz"},
- {FAC_GrabBchan, "Grab Bchannel"},
- {FAC_Reactivate, "Reactivate"},
- {FAC_Konferenz3, "Dreier Konferenz"},
- {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
- {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
- {FAC_NummernIdent, "Rufnummer-Identifizierung"},
- {FAC_GBG, "GBG"},
- {FAC_DisplayUebergeben, "Display Uebergeben"},
- {FAC_DisplayUmgeleitet, "Display Umgeleitet"},
- {FAC_Unterdruecke, "Unterdruecke Rufnummer"},
- {FAC_Deactivate, "Deactivate"},
- {FAC_Activate, "Activate"},
- {FAC_SPV, "SPV"},
- {FAC_Rueckwechsel, "Rueckwechsel"},
- {FAC_Umleitung, "Umleitung"}
-};
-int fac_1tr6_len = (sizeof(fac_1tr6) / sizeof(struct MessageType));
-
-
-
-static int
-prbits(char *dest, byte b, int start, int len)
-{
- char *dp = dest;
-
- b = b << (8 - start);
- while (len--) {
- if (b & 0x80)
- *dp++ = '1';
- else
- *dp++ = '0';
- b = b << 1;
- }
- return (dp - dest);
-}
-
-static
-byte *
-skipext(byte * p)
-{
- while (!(*p++ & 0x80));
- return (p);
-}
-
-/*
- * Cause Values According to Q.850
- * edescr: English description
- * ddescr: German description used by Swissnet II (Swiss Telecom
- * not yet written...
- */
-
-static
-struct CauseValue {
- byte nr;
- char *edescr;
- char *ddescr;
-} cvlist[] = {
-
- {
- 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt"
- },
- {
- 0x02, "No route to specified transit network", ""
- },
- {
- 0x03, "No route to destination", ""
- },
- {
- 0x04, "Send special information tone", ""
- },
- {
- 0x05, "Misdialled trunk prefix", ""
- },
- {
- 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar"
- },
- {
- 0x07, "Channel awarded and being delivered in an established channel", ""
- },
- {
- 0x08, "Preemption", ""
- },
- {
- 0x09, "Preemption - circuit reserved for reuse", ""
- },
- {
- 0x10, "Normal call clearing", "Normale Ausloesung"
- },
- {
- 0x11, "User busy", "TNB besetzt"
- },
- {
- 0x12, "No user responding", ""
- },
- {
- 0x13, "No answer from user (user alerted)", ""
- },
- {
- 0x14, "Subscriber absent", ""
- },
- {
- 0x15, "Call rejected", ""
- },
- {
- 0x16, "Number changed", ""
- },
- {
- 0x1a, "non-selected user clearing", ""
- },
- {
- 0x1b, "Destination out of order", ""
- },
- {
- 0x1c, "Invalid number format (address incomplete)", ""
- },
- {
- 0x1d, "Facility rejected", ""
- },
- {
- 0x1e, "Response to Status enquiry", ""
- },
- {
- 0x1f, "Normal, unspecified", ""
- },
- {
- 0x22, "No circuit/channel available", ""
- },
- {
- 0x26, "Network out of order", ""
- },
- {
- 0x27, "Permanent frame mode connection out-of-service", ""
- },
- {
- 0x28, "Permanent frame mode connection operational", ""
- },
- {
- 0x29, "Temporary failure", ""
- },
- {
- 0x2a, "Switching equipment congestion", ""
- },
- {
- 0x2b, "Access information discarded", ""
- },
- {
- 0x2c, "Requested circuit/channel not available", ""
- },
- {
- 0x2e, "Precedence call blocked", ""
- },
- {
- 0x2f, "Resource unavailable, unspecified", ""
- },
- {
- 0x31, "Quality of service unavailable", ""
- },
- {
- 0x32, "Requested facility not subscribed", ""
- },
- {
- 0x35, "Outgoing calls barred within CUG", ""
- },
- {
- 0x37, "Incoming calls barred within CUG", ""
- },
- {
- 0x39, "Bearer capability not authorized", ""
- },
- {
- 0x3a, "Bearer capability not presently available", ""
- },
- {
- 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " "
- },
- {
- 0x3f, "Service or option not available, unspecified", ""
- },
- {
- 0x41, "Bearer capability not implemented", ""
- },
- {
- 0x42, "Channel type not implemented", ""
- },
- {
- 0x43, "Requested facility not implemented", ""
- },
- {
- 0x44, "Only restricted digital information bearer capability is available", ""
- },
- {
- 0x4f, "Service or option not implemented", ""
- },
- {
- 0x51, "Invalid call reference value", ""
- },
- {
- 0x52, "Identified channel does not exist", ""
- },
- {
- 0x53, "A suspended call exists, but this call identity does not", ""
- },
- {
- 0x54, "Call identity in use", ""
- },
- {
- 0x55, "No call suspended", ""
- },
- {
- 0x56, "Call having the requested call identity has been cleared", ""
- },
- {
- 0x57, "User not member of CUG", ""
- },
- {
- 0x58, "Incompatible destination", ""
- },
- {
- 0x5a, "Non-existent CUG", ""
- },
- {
- 0x5b, "Invalid transit network selection", ""
- },
- {
- 0x5f, "Invalid message, unspecified", ""
- },
- {
- 0x60, "Mandatory information element is missing", ""
- },
- {
- 0x61, "Message type non-existent or not implemented", ""
- },
- {
- 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " "
- },
- {
- 0x63, "Information element/parameter non-existent or not implemented", ""
- },
- {
- 0x64, "Invalid information element contents", ""
- },
- {
- 0x65, "Message not compatible with call state", ""
- },
- {
- 0x66, "Recovery on timer expiry", ""
- },
- {
- 0x67, "Parameter non-existent or not implemented - passed on", ""
- },
- {
- 0x6e, "Message with unrecognized parameter discarded", ""
- },
- {
- 0x6f, "Protocol error, unspecified", ""
- },
- {
- 0x7f, "Interworking, unspecified", ""
- },
-};
-
-#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
-
-static
-int
-prcause(char *dest, byte * p)
-{
- byte *end;
- char *dp = dest;
- int i, cause;
-
- end = p + p[1] + 1;
- p += 2;
- dp += sprintf(dp, " coding ");
- dp += prbits(dp, *p, 7, 2);
- dp += sprintf(dp, " location ");
- dp += prbits(dp, *p, 4, 4);
- *dp++ = '\n';
- p = skipext(p);
-
- cause = 0x7f & *p++;
-
- /* locate cause value */
- for (i = 0; i < CVSIZE; i++)
- if (cvlist[i].nr == cause)
- break;
-
- /* display cause value if it exists */
- if (i == CVSIZE)
- dp += sprintf(dp, "Unknown cause type %x!\n", cause);
- else
- dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr);
-
- while (!0) {
- if (p > end)
- break;
- dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f);
- dp += sprintf(dp, " rej %d ", *p & 0x7f);
- if (*p & 0x80) {
- *dp++ = '\n';
- break;
- } else
- dp += sprintf(dp, " av %d\n", (*++p) & 0x7f);
- }
- return (dp - dest);
-
-}
-
-static
-struct MessageType cause_1tr6[] =
-{
- {CAUSE_InvCRef, "Invalid Call Reference"},
- {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"},
- {CAUSE_CIDunknown, "Caller Identity unknown"},
- {CAUSE_CIDinUse, "Caller Identity in Use"},
- {CAUSE_NoChans, "No Channels available"},
- {CAUSE_FacNotImpl, "Facility Not Implemented"},
- {CAUSE_FacNotSubscr, "Facility Not Subscribed"},
- {CAUSE_OutgoingBarred, "Outgoing calls barred"},
- {CAUSE_UserAccessBusy, "User Access Busy"},
- {CAUSE_NegativeGBG, "Negative GBG"},
- {CAUSE_UnknownGBG, "Unknown GBG"},
- {CAUSE_NoSPVknown, "No SPV known"},
- {CAUSE_DestNotObtain, "Destination not obtainable"},
- {CAUSE_NumberChanged, "Number changed"},
- {CAUSE_OutOfOrder, "Out Of Order"},
- {CAUSE_NoUserResponse, "No User Response"},
- {CAUSE_UserBusy, "User Busy"},
- {CAUSE_IncomingBarred, "Incoming Barred"},
- {CAUSE_CallRejected, "Call Rejected"},
- {CAUSE_NetworkCongestion, "Network Congestion"},
- {CAUSE_RemoteUser, "Remote User initiated"},
- {CAUSE_LocalProcErr, "Local Procedure Error"},
- {CAUSE_RemoteProcErr, "Remote Procedure Error"},
- {CAUSE_RemoteUserSuspend, "Remote User Suspend"},
- {CAUSE_RemoteUserResumed, "Remote User Resumed"},
- {CAUSE_UserInfoDiscarded, "User Info Discarded"}
-};
-
-int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
-
-static int
-prcause_1tr6(char *dest, byte * p)
-{
- char *dp = dest;
- int i, cause;
-
- p++;
- if (0 == *p) {
- dp += sprintf(dp, " OK (cause length=0)\n");
- return (dp - dest);
- } else if (*p > 1) {
- dp += sprintf(dp, " coding ");
- dp += prbits(dp, p[2], 7, 2);
- dp += sprintf(dp, " location ");
- dp += prbits(dp, p[2], 4, 4);
- *dp++ = '\n';
- }
- p++;
- cause = 0x7f & *p;
-
- /* locate cause value */
- for (i = 0; i < cause_1tr6_len; i++)
- if (cause_1tr6[i].nr == cause)
- break;
-
- /* display cause value if it exists */
- if (i == cause_1tr6_len)
- dp += sprintf(dp, "Unknown cause type %x!\n", cause);
- else
- dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr);
-
- return (dp - dest);
-
-}
-
-static int
-prchident(char *dest, byte * p) {
- char *dp = dest;
-
- p += 2;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static int
-prcalled(char *dest, byte * p) {
- int l;
- char *dp = dest;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- dp += sprintf(dp, " number digits ");
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-prcalling(char *dest, byte * p) {
- int l;
- char *dp = dest;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (!(*p & 0x80)) {
- dp += sprintf(dp, " octet 3a ");
- dp += prbits(dp, *++p, 8, 8);
- *dp++ = '\n';
- l--;
- };
- p++;
-
- dp += sprintf(dp, " number digits ");
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-
-static
-int
-prbearer(char *dest, byte * p)
-{
- char *dp = dest, ch;
-
- p += 2;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if ((*p++ & 0x1f) == 0x18) {
- dp += sprintf(dp, " octet 4.1 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- /* check for user information layer 1 */
- if ((*p & 0x60) == 0x20) {
- ch = ' ';
- do {
- dp += sprintf(dp, " octet 5%c ", ch);
- dp += prbits(dp, *p, 8, 8);
- *dp++ = '\n';
- if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- while (!(*p++ & 0x80));
- }
- /* check for user information layer 2 */
- if ((*p & 0x60) == 0x40) {
- dp += sprintf(dp, " octet 6 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- /* check for user information layer 3 */
- if ((*p & 0x60) == 0x60) {
- dp += sprintf(dp, " octet 7 ");
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
- }
- return (dp - dest);
-}
-
-static int
-general(char *dest, byte * p) {
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the information element */
- while (l--) {
- dp += sprintf(dp, " octet %d%c ", octet, ch);
- dp += prbits(dp, *p++, 8, 8);
- *dp++ = '\n';
-
- /* last octet in group? */
- if (*p & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
- else
- ch++;
- }
- return (dp - dest);
-}
-
-static int
-prcharge(char *dest, byte * p) {
- char *dp = dest;
- int l;
-
- p++;
- l = *p++ - 1;
- dp += sprintf(dp, " GEA ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, " Anzahl: ");
- /* Iterate over all octets in the * information element */
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-prtext(char *dest, byte * p) {
- char *dp = dest;
- int l;
-
- p++;
- l = *p++;
- dp += sprintf(dp, " ");
- /* Iterate over all octets in the * information element */
- while (l--)
- *dp++ = *p++;
- *dp++ = '\n';
- return (dp - dest);
-}
-static int
-display(char *dest, byte * p) {
- char *dp = dest;
- char ch = ' ';
- int l, octet = 3;
-
- p++;
- l = *p++;
- /* Iterate over all octets in the * display-information element */
- dp += sprintf(dp, " \"");
- while (l--) {
- dp += sprintf(dp, "%c", *p++);
-
- /* last octet in group? */
- if (*p & 0x80) {
- octet++;
- ch = ' ';
- } else if (ch == ' ')
- ch = 'a';
-
- else
- ch++;
- }
- *dp++ = '\"';
- *dp++ = '\n';
- return (dp - dest);
-}
-
-int
-prfacility(char *dest, byte * p)
-{
- char *dp = dest;
- int l, l2;
-
- p++;
- l = *p++;
- dp += sprintf(dp, " octet 3 ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, "\n");
- l -= 1;
-
- while (l > 0) {
- dp += sprintf(dp, " octet 4 ");
- dp += prbits(dp, *p++, 8, 8);
- dp += sprintf(dp, "\n");
- dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f);
- l -= 2;
- dp += sprintf(dp, " contents ");
- while (l2--) {
- dp += sprintf(dp, "%2x ", *p++);
- l--;
- }
- dp += sprintf(dp, "\n");
- }
-
- return (dp - dest);
-}
-
-static
-struct InformationElement {
- byte nr;
- char *descr;
- int (*f) (char *, byte *);
-} ielist[] = {
-
- {
- 0x00, "Segmented message", general
- },
- {
- 0x04, "Bearer capability", prbearer
- },
- {
- 0x08, "Cause", prcause
- },
- {
- 0x10, "Call identity", general
- },
- {
- 0x14, "Call state", general
- },
- {
- 0x18, "Channel identification", prchident
- },
- {
- 0x1c, "Facility", prfacility
- },
- {
- 0x1e, "Progress indicator", general
- },
- {
- 0x20, "Network-specific facilities", general
- },
- {
- 0x27, "Notification indicator", general
- },
- {
- 0x28, "Display", display
- },
- {
- 0x29, "Date/Time", general
- },
- {
- 0x2c, "Keypad facility", general
- },
- {
- 0x34, "Signal", general
- },
- {
- 0x40, "Information rate", general
- },
- {
- 0x42, "End-to-end delay", general
- },
- {
- 0x43, "Transit delay selection and indication", general
- },
- {
- 0x44, "Packet layer binary parameters", general
- },
- {
- 0x45, "Packet layer window size", general
- },
- {
- 0x46, "Packet size", general
- },
- {
- 0x47, "Closed user group", general
- },
- {
- 0x4a, "Reverse charge indication", general
- },
- {
- 0x6c, "Calling party number", prcalling
- },
- {
- 0x6d, "Calling party subaddress", general
- },
- {
- 0x70, "Called party number", prcalled
- },
- {
- 0x71, "Called party subaddress", general
- },
- {
- 0x74, "Redirecting number", general
- },
- {
- 0x78, "Transit network selection", general
- },
- {
- 0x79, "Restart indicator", general
- },
- {
- 0x7c, "Low layer compatibility", general
- },
- {
- 0x7d, "High layer compatibility", general
- },
- {
- 0x7e, "User-user", general
- },
- {
- 0x7f, "Escape for extension", general
- },
-};
-
-
-#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
-
-static struct InformationElement we_0[] =
-{
- {WE0_cause, "Cause", prcause_1tr6},
- {WE0_connAddr, "Connecting Address", prcalled},
- {WE0_callID, "Call IDentity", general},
- {WE0_chanID, "Channel IDentity", general},
- {WE0_netSpecFac, "Network Specific Facility", general},
- {WE0_display, "Display", general},
- {WE0_keypad, "Keypad", general},
- {WE0_origAddr, "Origination Address", prcalled},
- {WE0_destAddr, "Destination Address", prcalled},
- {WE0_userInfo, "User Info", general}
-};
-
-static int we_0_len = (sizeof(we_0) / sizeof(struct InformationElement));
-
-static struct InformationElement we_6[] =
-{
- {WE6_serviceInd, "Service Indicator", general},
- {WE6_chargingInfo, "Charging Information", prcharge},
- {WE6_date, "Date", prtext},
- {WE6_facSelect, "Facility Select", general},
- {WE6_facStatus, "Facility Status", general},
- {WE6_statusCalled, "Status Called", general},
- {WE6_addTransAttr, "Additional Transmission Attributes", general}
-};
-static int we_6_len = (sizeof(we_6) / sizeof(struct InformationElement));
-
-void
-dlogframe(struct IsdnCardState *sp, byte * buf, int size, char *comment) {
- byte *bend = buf + size;
- char *dp;
- int i, cs = 0, cs_old = 0, cs_fest = 0;
-
- /* display header */
- dp = sp->dlogspace;
- dp += sprintf(dp, "%s\n", comment);
-
- {
- byte *p = buf;
- dp += sprintf(dp, "hex: ");
- while (p < bend)
- dp += sprintf(dp, "%02x ", *p++);
- dp += sprintf(dp, "\n");
- teles_putstatus(sp->dlogspace);
- dp = sp->dlogspace;
- }
- if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */
- /* locate message type */
- if (buf[0] == PROTO_DIS_N0) { /* N0 */
- for (i = 0; i < mt_n0_len; i++)
- if (mt_n0[i].nr == buf[3])
- break;
- /* display message type iff it exists */
- if (i == mt_n0_len)
- dp += sprintf(dp, "Unknown message type N0 %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mt_n0[i].descr);
- } else { /* N1 */
- for (i = 0; i < mt_n1_len; i++)
- if (mt_n1[i].nr == buf[3])
- break;
- /* display message type iff it exists */
- if (i == mt_n1_len)
- dp += sprintf(dp, "Unknown message type N1 %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mt_n1[i].descr);
- }
-
- /* display each information element */
- buf += 4;
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- cs_old = cs;
- cs = *buf & 7;
- cs_fest = *buf & 8;
- break;
- case 3:
- dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
- break;
- case 2:
- if (*buf == 0xa0) {
- dp += sprintf(dp, " More data\n");
- break;
- }
- if (*buf == 0xa1) {
- dp += sprintf(dp, " Sending complete\n");
- }
- break;
- /* fall through */
- default:
- dp += sprintf(dp, " Reserved %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- if (cs == 0) {
- for (i = 0; i < we_0_len; i++)
- if (*buf == we_0[i].nr)
- break;
-
- /* When found, give appropriate msg */
- if (i != we_0_len) {
- dp += sprintf(dp, " %s\n", we_0[i].descr);
- dp += we_0[i].f(dp, buf);
- } else
- dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- } else if (cs == 6) {
- for (i = 0; i < we_6_len; i++)
- if (*buf == we_6[i].nr)
- break;
-
- /* When found, give appropriate msg */
- if (i != we_6_len) {
- dp += sprintf(dp, " %s\n", we_6[i].descr);
- dp += we_6[i].f(dp, buf);
- } else
- dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- } else
- dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cs, *buf, buf[1]);
- /* Skip to next element */
- if (cs_fest == 8) {
- cs = cs_old;
- cs_old = 0;
- cs_fest = 0;
- }
- buf += buf[1] + 2;
- }
- } else if (buf[0]==PROTO_EURO) { /* EURO */
- /* locate message type */
- for (i = 0; i < MTSIZE; i++)
- if (mtlist[i].nr == buf[3])
- break;
-
- /* display message type iff it exists */
- if (i == MTSIZE)
- dp += sprintf(dp, "Unknown message type %x!\n", buf[3]);
- else
- dp += sprintf(dp, "call reference %d size %d message type %s\n",
- buf[2], size, mtlist[i].descr);
-
- /* display each information element */
- buf += 4;
- while (buf < bend) {
- /* Is it a single octet information element? */
- if (*buf & 0x80) {
- switch ((*buf >> 4) & 7) {
- case 1:
- dp += sprintf(dp, " Shift %x\n", *buf & 0xf);
- break;
- case 3:
- dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf);
- break;
- case 5:
- dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf);
- break;
- case 2:
- if (*buf == 0xa0) {
- dp += sprintf(dp, " More data\n");
- break;
- }
- if (*buf == 0xa1) {
- dp += sprintf(dp, " Sending complete\n");
- }
- break;
- /* fall through */
- default:
- dp += sprintf(dp, " Reserved %x\n", *buf);
- break;
- }
- buf++;
- continue;
- }
- /* No, locate it in the table */
- for (i = 0; i < IESIZE; i++)
- if (*buf == ielist[i].nr)
- break;
-
- /* When not found, give appropriate msg */
- if (i != IESIZE) {
- dp += sprintf(dp, " %s\n", ielist[i].descr);
- dp += ielist[i].f(dp, buf);
- } else
- dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]);
-
- /* Skip to next element */
- buf += buf[1] + 2;
- }
- }
- else dp += sprintf(dp,"Unnown frame type %.2x, ignored\n",buf[0]);
-
- dp += sprintf(dp, "\n");
- teles_putstatus(sp->dlogspace);
-}
+++ /dev/null
-/* $Id: tei.c,v 1.1 1996/04/13 10:28:25 fritz Exp $
- *
- * $Log: tei.c,v $
- * Revision 1.1 1996/04/13 10:28:25 fritz
- * Initial revision
- *
- *
- */
-#define __NO_VERSION__
-#include "teles.h"
-
-extern struct IsdnCard cards[];
-extern int nrcards;
-
-static struct PStack *
-findces(struct PStack *st, int ces)
-{
- struct PStack *ptr = *(st->l1.stlistp);
-
- while (ptr)
- if (ptr->l2.ces == ces)
- return (ptr);
- else
- ptr = ptr->next;
- return (NULL);
-}
-
-static struct PStack *
-findtei(struct PStack *st, int tei)
-{
- struct PStack *ptr = *(st->l1.stlistp);
-
- if (tei == 127)
- return (NULL);
-
- while (ptr)
- if (ptr->l2.tei == tei)
- return (ptr);
- else
- ptr = ptr->next;
- return (NULL);
-}
-
-void
-tei_handler(struct PStack *st,
- byte pr, struct BufHeader *ibh)
-{
- byte *bp;
- unsigned int tces;
- struct PStack *otsp, *ptr;
- unsigned int data;
-
- if (st->l2.debug)
- printk(KERN_DEBUG "teihandler %d\n", pr);
-
- switch (pr) {
- case (MDL_ASSIGN):
- data = (unsigned int) ibh;
- BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 6);
- if (!ibh)
- return;
- bp = DATAPTR(ibh);
- bp += st->l2.uihsize;
- bp[0] = 0xf;
- bp[1] = data >> 8;
- bp[2] = data & 0xff;
- bp[3] = 0x1;
- bp[4] = 0xff;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- break;
- case (DL_UNIT_DATA):
- bp = DATAPTR(ibh);
- bp += 3;
- if (bp[0] != 0xf)
- break;
- switch (bp[3]) {
- case (2):
- tces = (bp[1] << 8) | bp[2];
- BufPoolRelease(ibh);
- if (st->l3.debug)
- printk(KERN_DEBUG "tei identity assigned for %d=%d\n", tces,
- bp[4] >> 1);
- if ((otsp = findces(st, tces)))
- otsp->ma.teil2(otsp, MDL_ASSIGN,
- (void *)(bp[4] >> 1));
- break;
- case (4):
- if (st->l3.debug)
- printk(KERN_DEBUG "checking identity for %d\n", bp[4] >> 1);
- if (bp[4] >> 1 == 0x7f) {
- BufPoolRelease(ibh);
- ptr = *(st->l1.stlistp);
- while (ptr) {
- if ((ptr->l2.tei & 0x7f) != 0x7f) {
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
- break;
- bp = DATAPTR(ibh);
- bp += 3;
- bp[0] = 0xf;
- bp[1] = ptr->l2.ces >> 8;
- bp[2] = ptr->l2.ces & 0xff;
- bp[3] = 0x5;
- bp[4] = (ptr->l2.tei << 1) | 1;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- }
- ptr = ptr->next;
- }
- } else {
- otsp = findtei(st, bp[4] >> 1);
- BufPoolRelease(ibh);
- if (!otsp)
- break;
- if (st->l3.debug)
- printk(KERN_DEBUG "ces is %d\n", otsp->l2.ces);
- if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
- break;
- bp = DATAPTR(ibh);
- bp += 3;
- bp[0] = 0xf;
- bp[1] = otsp->l2.ces >> 8;
- bp[2] = otsp->l2.ces & 0xff;
- bp[3] = 0x5;
- bp[4] = (otsp->l2.tei << 1) | 1;
- ibh->datasize = 8;
- st->l3.l3l2(st, DL_UNIT_DATA, ibh);
- }
- break;
- default:
- BufPoolRelease(ibh);
- if (st->l3.debug)
- printk(KERN_DEBUG "tei message unknown %d ai %d\n", bp[3], bp[4] >> 1);
- }
- break;
- default:
- printk(KERN_WARNING "tei handler unknown primitive %d\n", pr);
- break;
- }
-}
-
-unsigned int
-randomces(void)
-{
- int x = jiffies & 0xffff;
-
- return (x);
-}
-
-static void
-tei_man(struct PStack *sp, int i, void *v)
-{
- printk(KERN_DEBUG "tei_man\n");
-}
-
-static void
-tei_l2tei(struct PStack *st, int pr, void *arg)
-{
- struct IsdnCardState *sp = st->l1.hardware;
-
- tei_handler(sp->teistack, pr, arg);
-}
-
-void
-setstack_tei(struct PStack *st)
-{
- st->l2.l2tei = tei_l2tei;
-}
-
-static void
-init_tei(struct IsdnCardState *sp, int protocol)
-{
- struct PStack *st;
- char tmp[128];
-
-#define DIRTY_HACK_AGAINST_SIGSEGV
-
- st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL,
- "struct PStack");
-
-#ifdef DIRTY_HACK_AGAINST_SIGSEGV
- sp->teistack = st; /* struct is not initialized yet */
- sp->teistack->protocol = protocol; /* struct is not initialized yet */
-#endif /* DIRTY_HACK_AGAINST_SIGSEGV */
-
-
- setstack_teles(st, sp);
-
- st->l2.extended = !0;
- st->l2.laptype = LAPD;
- st->l2.window = 1;
- st->l2.orig = !0;
- st->protocol = protocol;
-
-/*
- * the following is not necessary for tei mng. (broadcast only)
- */
-
- st->l2.t200 = 500; /* 500 milliseconds */
- st->l2.n200 = 4; /* try 4 times */
-
- st->l2.sap = 63;
- st->l2.tei = 127;
-
- sprintf(tmp, "Card %d tei ", sp->cardnr);
- setstack_isdnl2(st, tmp);
- st->l2.debug = 0;
- st->l3.debug = 0;
-
- st->ma.manl2(st, MDL_NOTEIPROC, NULL);
-
- st->l2.l2l3 = (void *) tei_handler;
- st->l1.l1man = tei_man;
- st->l2.l2man = tei_man;
- st->l4.l2writewakeup = NULL;
-
- teles_addlist(sp, st);
- sp->teistack = st;
-}
-
-static void
-release_tei(struct IsdnCardState *sp)
-{
- struct PStack *st = sp->teistack;
-
- teles_rmlist(sp, st);
- Sfree((void *) st);
-}
-
-void
-TeiNew(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- init_tei(cards[i].sp, cards[i].protocol);
-}
-
-void
-TeiFree(void)
-{
- int i;
-
- for (i = 0; i < nrcards; i++)
- if (cards[i].sp)
- release_tei(cards[i].sp);
-}
+++ /dev/null
-/* $Id: teles.h,v 1.2 1996/04/30 21:52:04 isdn4dev Exp $
- *
- * $Log: teles.h,v $
- * Revision 1.2 1996/04/30 21:52:04 isdn4dev
- * SPV for 1TR6 - Karsten
- *
- * Revision 1.1 1996/04/13 10:29:00 fritz
- * Initial revision
- *
- *
- */
-#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/delay.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/isdnif.h>
-#include <linux/tty.h>
-
-#define PH_ACTIVATE 1
-#define PH_DATA 2
-#define PH_DEACTIVATE 3
-
-#define MDL_ASSIGN 4
-#define DL_UNIT_DATA 5
-#define SC_STARTUP 6
-#define CC_ESTABLISH 7
-#define DL_ESTABLISH 8
-#define DL_DATA 9
-#define CC_S_STATUS_ENQ 10
-
-#define CC_CONNECT 15
-#define CC_CONNECT_ACKNOWLEDGE 16
-#define CO_EOF 17
-#define SC_DISCONNECT 18
-#define CO_DTMF 19
-#define DL_RELEASE 20
-
-#define CO_ALARM 22
-#define CC_REJECT 23
-
-#define CC_SETUP_REQ 24
-#define CC_SETUP_CNF 25
-#define CC_SETUP_IND 26
-#define CC_SETUP_RSP 27
-#define CC_SETUP_COMPLETE_IND 28
-
-#define CC_DISCONNECT_REQ 29
-#define CC_DISCONNECT_IND 30
-
-#define CC_RELEASE_CNF 31
-#define CC_RELEASE_IND 32
-#define CC_RELEASE_REQ 33
-
-#define CC_REJECT_REQ 34
-
-#define CC_PROCEEDING_IND 35
-
-#define CC_DLRL 36
-#define CC_DLEST 37
-
-#define CC_ALERTING_REQ 38
-#define CC_ALERTING_IND 39
-
-#define DL_STOP 40
-#define DL_START 41
-
-#define MDL_NOTEIPROC 46
-
-#define LC_ESTABLISH 47
-#define LC_RELEASE 48
-
-#define PH_REQUEST_PULL 49
-#define PH_PULL_ACK 50
-#define PH_DATA_PULLED 51
-#define CC_INFO_CHARGE 52
-
-/*
- * Message-Types
- */
-
-#define MT_ALERTING 0x01
-#define MT_CALL_PROCEEDING 0x02
-#define MT_CONNECT 0x07
-#define MT_CONNECT_ACKNOWLEDGE 0x0f
-#define MT_PROGRESS 0x03
-#define MT_SETUP 0x05
-#define MT_SETUP_ACKNOWLEDGE 0x0d
-#define MT_RESUME 0x26
-#define MT_RESUME_ACKNOWLEDGE 0x2e
-#define MT_RESUME_REJECT 0x22
-#define MT_SUSPEND 0x25
-#define MT_SUSPEND_ACKNOWLEDGE 0x2d
-#define MT_SUSPEND_REJECT 0x21
-#define MT_USER_INFORMATION 0x20
-#define MT_DISCONNECT 0x45
-#define MT_RELEASE 0x4d
-#define MT_RELEASE_COMPLETE 0x5a
-#define MT_RESTART 0x46
-#define MT_RESTART_ACKNOWLEDGE 0x4e
-#define MT_SEGMENT 0x60
-#define MT_CONGESTION_CONTROL 0x79
-#define MT_INFORMATION 0x7b
-#define MT_FACILITY 0x62
-#define MT_NOTIFY 0x6e
-#define MT_STATUS 0x7d
-#define MT_STATUS_ENQUIRY 0x75
-
-#define IE_CAUSE 0x08
-
-struct HscxIoctlArg {
- int channel;
- int mode;
- int transbufsize;
-};
-
-#ifdef __KERNEL__
-
-#undef DEBUG_MAGIC
-
-#define HSCX_SBUF_ORDER 1
-#define HSCX_SBUF_BPPS 2
-#define HSCX_SBUF_MAXPAGES 3
-
-#define HSCX_RBUF_ORDER 1
-#define HSCX_RBUF_BPPS 2
-#define HSCX_RBUF_MAXPAGES 3
-
-#define HSCX_SMALLBUF_ORDER 0
-#define HSCX_SMALLBUF_BPPS 40
-#define HSCX_SMALLBUF_MAXPAGES 1
-
-#define ISAC_SBUF_ORDER 0
-#define ISAC_SBUF_BPPS 16
-#define ISAC_SBUF_MAXPAGES 1
-
-#define ISAC_RBUF_ORDER 0
-#define ISAC_RBUF_BPPS 16
-#define ISAC_RBUF_MAXPAGES 1
-
-#define ISAC_SMALLBUF_ORDER 0
-#define ISAC_SMALLBUF_BPPS 40
-#define ISAC_SMALLBUF_MAXPAGES 1
-
-#define byte unsigned char
-
-#define MAX_WINDOW 8
-
-byte *Smalloc(int size, int pr, char *why);
-void Sfree(byte * ptr);
-
-/*
- * Statemachine
- */
-struct Fsm {
- int *jumpmatrix;
- int state_count, event_count;
- char **strEvent, **strState;
-};
-
-struct FsmInst {
- struct Fsm *fsm;
- int state;
- int debug;
- void *userdata;
- int userint;
- void (*printdebug) (struct FsmInst *, char *);
-};
-
-struct FsmNode {
- int state, event;
- void (*routine) (struct FsmInst *, int, void *);
-};
-
-struct FsmTimer {
- struct FsmInst *fi;
- struct timer_list tl;
- int event;
- void *arg;
-};
-
-struct BufHeader {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *next;
- struct BufPool *bp;
- int datasize;
- byte primitive, where;
- void *heldby;
-};
-
-struct Pages {
- struct Pages *next;
-};
-
-struct BufPool {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *freelist;
- struct Pages *pageslist;
- int pageorder;
- int pagescount;
- int bpps;
- int bufsize;
- int maxpages;
-};
-
-struct BufQueue {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- struct BufHeader *head, *tail;
-};
-
-struct Layer1 {
- void *hardware;
- int hscx;
- struct BufPool *sbufpool, *rbufpool, *smallpool;
- struct PStack **stlistp;
- int act_state;
- void (*l1l2) (struct PStack *, int, struct BufHeader *);
- void (*l1man) (struct PStack *, int, void *);
- int hscxmode, hscxchannel, requestpull;
-};
-
-struct Layer2 {
- int sap, tei, ces;
- int extended, laptype;
- int uihsize, ihsize;
- int vs, va, vr;
- struct BufQueue i_queue;
- int window, orig;
- int rejexp;
- int debug;
- struct BufHeader *windowar[MAX_WINDOW];
- int sow;
- struct FsmInst l2m;
- void (*l2l1) (struct PStack *, int, struct BufHeader *);
- void (*l2l1discardq) (struct PStack *, int, void *, int);
- void (*l2man) (struct PStack *, int, void *);
- void (*l2l3) (struct PStack *, int, void *);
- void (*l2tei) (struct PStack *, int, void *);
- struct FsmTimer t200_timer, t203_timer;
- int t200, n200, t203;
- int rc, t200_running;
- char debug_id[32];
-};
-
-struct Layer3 {
- void (*l3l4) (struct PStack *, int, struct BufHeader *);
- void (*l3l2) (struct PStack *, int, void *);
- int state, callref;
- int debug;
-};
-
-struct Layer4 {
- void (*l4l3) (struct PStack *, int, void *);
- void *userdata;
- void (*l1writewakeup) (struct PStack *);
- void (*l2writewakeup) (struct PStack *);
-};
-
-struct Management {
- void (*manl1) (struct PStack *, int, void *);
- void (*manl2) (struct PStack *, int, void *);
- void (*teil2) (struct PStack *, int, void *);
-};
-
-struct Param {
- int cause;
- int bchannel;
- int callref; /* TEI-Number */
- int itc;
- int info; /* Service-Indicator */
- int info2; /* Service-Indicator, second octet */
- char calling[40]; /* Called Id */
- char called[40]; /* Caller Id */
- int chargeinfo; /* Charge Info - only for 1tr6 in
- * the moment
- */
- int spv; /* SPV Flag */
-};
-
-struct PStack {
- struct PStack *next;
- struct Layer1 l1;
- struct Layer2 l2;
- struct Layer3 l3;
- struct Layer4 l4;
- struct Management ma;
- struct Param *pa;
- int protocol; /* EDSS1 or 1TR6 */
-};
-
-struct HscxState {
- byte *membase;
- int iobase;
- int inuse, init, active;
- struct BufPool sbufpool, rbufpool, smallpool;
- struct IsdnCardState *sp;
- int hscx, mode;
- int transbufsize, receive;
- struct BufHeader *rcvibh, *xmtibh;
- int rcvptr, sendptr;
- struct PStack *st;
- struct tq_struct tqueue;
- int event;
- struct BufQueue rq, sq;
- int releasebuf;
-#ifdef DEBUG_MAGIC
- int magic; /* 301270 */
-#endif
-};
-
-struct IsdnCardState {
-#ifdef DEBUG_MAGIC
- int magic;
-#endif
- byte *membase;
- int iobase;
- struct BufPool sbufpool, rbufpool, smallpool;
- struct PStack *stlist;
- struct BufHeader *xmtibh, *rcvibh;
- int rcvptr, sendptr;
- int event;
- struct tq_struct tqueue;
- int ph_active;
- struct BufQueue rq, sq;
-
- int cardnr, ph_state;
- struct PStack *teistack;
- struct HscxState hs[2];
-
- int dlogflag;
- char *dlogspace;
- int debug;
- int releasebuf;
-};
-
-struct IsdnCard {
- byte *membase;
- int interrupt;
- unsigned int iobase;
- int protocol; /* EDSS1 or 1TR6 */
- struct IsdnCardState *sp;
-};
-
-#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader))
-
-#define LAPD 0
-#define LAPB 1
-
-void BufPoolInit(struct BufPool *bp, int order, int bpps,
- int maxpages);
-int BufPoolAdd(struct BufPool *bp, int priority);
-void BufPoolFree(struct BufPool *bp);
-int BufPoolGet(struct BufHeader **bh,
- struct BufPool *bp, int priority, void *heldby, int where);
-void BufPoolRelease(struct BufHeader *bh);
-void BufQueueLink(struct BufQueue *bq,
- struct BufHeader *bh);
-int BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq);
-void BufQueueInit(struct BufQueue *bq);
-void BufQueueRelease(struct BufQueue *bq);
-void BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
- int releasetoo);
-int BufQueueLength(struct BufQueue *bq);
-void BufQueueLinkFront(struct BufQueue *bq,
- struct BufHeader *bh);
-
-void l2down(struct PStack *st,
- byte pr, struct BufHeader *ibh);
-void l2up(struct PStack *st,
- byte pr, struct BufHeader *ibh);
-void acceptph(struct PStack *st,
- struct BufHeader *ibh);
-void setstack_isdnl2(struct PStack *st, char *debug_id);
-int teles_inithardware(void);
-void teles_closehardware(void);
-
-void setstack_teles(struct PStack *st, struct IsdnCardState *sp);
-unsigned int randomces(void);
-void setstack_isdnl3(struct PStack *st);
-void teles_addlist(struct IsdnCardState *sp,
- struct PStack *st);
-void releasestack_isdnl2(struct PStack *st);
-void teles_rmlist(struct IsdnCardState *sp,
- struct PStack *st);
-void newcallref(struct PStack *st);
-
-int ll_init(void);
-void ll_stop(void), ll_unload(void);
-int setstack_hscx(struct PStack *st, struct HscxState *hs);
-void modehscx(struct HscxState *hs, int mode, int ichan);
-byte *findie(byte * p, int size, byte ie, int wanted_set);
-int getcallref(byte * p);
-
-void FsmNew(struct Fsm *fsm,
- struct FsmNode *fnlist, int fncount);
-void FsmFree(struct Fsm *fsm);
-int FsmEvent(struct FsmInst *fi,
- int event, void *arg);
-void FsmChangeState(struct FsmInst *fi,
- int newstate);
-void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
-int FsmAddTimer(struct FsmTimer *ft,
- int millisec, int event, void *arg, int where);
-void FsmDelTimer(struct FsmTimer *ft, int where);
-int FsmTimerRunning(struct FsmTimer *ft);
-void jiftime(char *s, long mark);
-
-void CallcNew(void);
-void CallcFree(void);
-int CallcNewChan(void);
-void CallcFreeChan(void);
-int teles_command(isdn_ctrl * ic);
-int teles_writebuf(int id, int chan, const u_char * buf, int count, int user);
-void teles_putstatus(char *buf);
-void teles_reportcard(int cardnr);
-int ListLength(struct BufHeader *ibh);
-void dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment);
-void iecpy(byte * dest, byte * iestart, int ieoffset);
-void setstack_transl2(struct PStack *st);
-void releasestack_transl2(struct PStack *st);
-void close_hscxstate(struct HscxState *);
-void setstack_tei(struct PStack *st);
-
-struct LcFsm {
- struct FsmInst lcfi;
- int type;
- struct Channel *ch;
- void (*lccall) (struct LcFsm *, int, void *);
- struct PStack *st;
- int l2_establish;
- int l2_start;
- struct FsmTimer act_timer;
- char debug_id[32];
-};
-
-struct Channel {
- struct PStack ds, is;
- struct IsdnCardState *sp;
- int hscx;
- int chan;
- int incoming;
- struct FsmInst fi;
- struct LcFsm lc_d, lc_b;
- struct Param para;
- int debug;
-#ifdef DEBUG_MAGIC
- int magic; /* 301272 */
-#endif
- int l2_protocol, l2_active_protocol;
- int l2_primitive, l2_headersize;
- int data_open;
- int outcallref;
- int impair;
-};
-
-#define PART_SIZE(order,bpps) (( (PAGE_SIZE<<order) -\
- sizeof(void *))/bpps)
-#define BUFFER_SIZE(order,bpps) (PART_SIZE(order,bpps)-\
- sizeof(struct BufHeader))
-
-#endif
-
-void Isdnl2New(void);
-void Isdnl2Free(void);
-void TeiNew(void);
-void TeiFree(void);
-
-
-
-
Paul Gortmaker : multiple card support for module users.
Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c
Paul Gortmaker : Allow users with bad cards to avoid full probe.
+ Paul Gortmaker : PCI probe changes, more PCI cards supported.
*/
/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
/* #define PACKETBUF_MEMSIZE 0x40 */
-/* ---- No user-serviceable parts below ---- */
-
/* A zero-terminated list of I/O addresses to be probed. */
static unsigned int netcard_portlist[] =
{ 0x300, 0x280, 0x320, 0x340, 0x360, 0};
+#ifdef CONFIG_PCI
+/* Ack! People are making PCI ne2000 clones! Oh the horror, the horror... */
+static struct { unsigned short vendor, dev_id;}
+pci_clone_list[] = {
+ {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029},
+ {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940},
+ {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000},
+ {0,}
+};
+#endif
+
#ifdef SUPPORT_NE_BAD_CLONES
/* A list of bad clones that we none-the-less recognize. */
static struct { const char *name8, *name16; unsigned char SAprefix[4];}
{"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}}, /* Outlaw 4-Dimension cards. */
{"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
{"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
+ {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
+ {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
{0,}
};
#endif
+/* ---- No user-serviceable parts below ---- */
+
#define NE_BASE (dev->base_addr)
#define NE_CMD 0x00
#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
static unsigned char pci_irq_line = 0;
int ne_probe(struct device *dev);
+static int ne_probe_pci(struct device *dev);
static int ne_probe1(struct device *dev, int ioaddr);
static int ne_open(struct device *dev);
else if (base_addr != 0) /* Don't probe at all. */
return ENXIO;
+#ifdef CONFIG_PCI
/* Then look for any installed PCI clones */
-#if defined(CONFIG_PCI)
- if (pcibios_present()) {
- int pci_index;
- for (pci_index = 0; pci_index < 8; pci_index++) {
- unsigned char pci_bus, pci_device_fn;
- unsigned int pci_ioaddr;
-
- /* Currently only Realtek are making PCI ne2k clones. */
- if (pcibios_find_device (PCI_VENDOR_ID_REALTEK,
- PCI_DEVICE_ID_REALTEK_8029, pci_index,
- &pci_bus, &pci_device_fn) != 0)
- break; /* OK, now try to probe for std. ISA card */
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
- /* Strip the I/O address out of the returned value */
- pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
- /* Avoid already found cards from previous ne_probe() calls */
- if (check_region(pci_ioaddr, NE_IO_EXTENT)) {
- pci_irq_line=0;
- continue;
- }
- printk("ne.c: PCI BIOS reports ne2000 clone at i/o %#x, irq %d.\n",
- pci_ioaddr, pci_irq_line);
- if (ne_probe1(dev, pci_ioaddr) != 0) { /* Shouldn't happen. */
- printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
- break; /* Hrmm, try to probe for ISA card... */
- }
- pci_irq_line = 0;
- return 0;
- }
- }
-#endif /* defined(CONFIG_PCI) */
+ if (pcibios_present() && (ne_probe_pci(dev) == 0))
+ return 0;
+#endif
+#ifndef MODULE
/* Last resort. The semi-risky ISA auto-probe. */
for (i = 0; netcard_portlist[i]; i++) {
int ioaddr = netcard_portlist[i];
if (ne_probe1(dev, ioaddr) == 0)
return 0;
}
+#endif
return ENODEV;
}
#endif
+#ifdef CONFIG_PCI
+static int ne_probe_pci(struct device *dev)
+{
+ int i;
+
+ for (i = 0; pci_clone_list[i].vendor != 0; i++) {
+ unsigned char pci_bus, pci_device_fn;
+ unsigned int pci_ioaddr;
+ int pci_index;
+
+ for (pci_index = 0; pci_index < 8; pci_index++) {
+ if (pcibios_find_device (pci_clone_list[i].vendor,
+ pci_clone_list[i].dev_id, pci_index,
+ &pci_bus, &pci_device_fn) != 0)
+ break; /* No more of these type of cards */
+ pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ /* Strip the I/O address out of the returned value */
+ pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
+ /* Avoid already found cards from previous calls */
+ if (check_region(pci_ioaddr, NE_IO_EXTENT))
+ continue;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ break; /* Beauty -- got a valid card. */
+ }
+ if (pci_irq_line == 0) continue; /* Try next PCI ID */
+ printk("ne.c: PCI BIOS reports NE 2000 clone at i/o %#x, irq %d.\n",
+ pci_ioaddr, pci_irq_line);
+ if (ne_probe1(dev, pci_ioaddr) != 0) { /* Shouldn't happen. */
+ printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
+ pci_irq_line = 0;
+ return -ENXIO;
+ }
+ pci_irq_line = 0;
+ return 0;
+ }
+ return -ENODEV;
+}
+#endif /* CONFIG_PCI */
+
static int ne_probe1(struct device *dev, int ioaddr)
{
int i;
for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i];
- if (pci_irq_line)
- wordlength = 2; /* Catch broken cards mentioned above. */
+ if (pci_irq_line || ioaddr >= 0x400)
+ wordlength = 2; /* Catch broken PCI cards mentioned above. */
if (wordlength == 2) {
/* We must set the 8390 for word mode. */
}
- if (pci_irq_line) {
+ if (pci_irq_line)
dev->irq = pci_irq_line;
- }
if (dev->irq < 2) {
autoirq_setup(0);
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
dev->init = ne_probe;
- if (io[this_dev] == 0) {
- if (this_dev != 0) break; /* only complain once */
- printk(KERN_NOTICE "ne.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
- return -EPERM;
- }
- if (register_netdev(dev) != 0) {
- printk(KERN_WARNING "ne.c: No NE*000 card found (i/o = 0x%x).\n", io[this_dev]);
- if (found != 0) return 0; /* Got at least one. */
- return -ENXIO;
+ if (register_netdev(dev) == 0) {
+ found++;
+ continue;
}
- found++;
+ if (found != 0) /* Got at least one. */
+ return 0;
+ if (io[this_dev] != 0)
+ printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
+ else
+ printk(KERN_NOTICE "ne.c: No PCI cards found. Use \"io=0xNNN\" value(s) for ISA cards.\n");
+ return -ENXIO;
}
return 0;
DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER, "MultiMaster"),
DEVICE( BUSLOGIC, BUSLOGIC_FLASHPOINT, "FlashPoint"),
DEVICE( OAK, OAK_OTI107, "OTI107"),
+ DEVICE( WINBOND2, WINBOND2_89C940,"NE2000-PCI"),
DEVICE( PROMISE, PROMISE_5300, "DC5030"),
DEVICE( N9, N9_I128, "Imagine 128"),
DEVICE( N9, N9_I128_2, "Imagine 128v2"),
DEVICE( ZEITNET, ZEITNET_1225, "1225"),
DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"),
DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"),
+ DEVICE( COMPEX, COMPEX_RL2000, "ReadyLink 2000"),
DEVICE( RP, RP8OCTA, "RocketPort 8 Oct"),
DEVICE( RP, RP8INTF, "RocketPort 8 Intf"),
DEVICE( RP, RP16INTF, "RocketPort 16 Intf"),
case PCI_VENDOR_ID_SGS: return "SGS Thomson";
case PCI_VENDOR_ID_BUSLOGIC: return "BusLogic";
case PCI_VENDOR_ID_OAK: return "OAK";
+ case PCI_VENDOR_ID_WINBOND2: return "Winbond";
case PCI_VENDOR_ID_PROMISE: return "Promise Technology";
case PCI_VENDOR_ID_N9: return "Number Nine";
case PCI_VENDOR_ID_UMC: return "UMC";
case PCI_VENDOR_ID_TOSHIBA: return "Toshiba";
case PCI_VENDOR_ID_ZEITNET: return "ZeitNet";
case PCI_VENDOR_ID_SPECIALIX: return "Specialix";
+ case PCI_VENDOR_ID_COMPEX: return "Compex";
case PCI_VENDOR_ID_RP: return "Comtrol";
case PCI_VENDOR_ID_CYCLADES: return "Cyclades";
case PCI_VENDOR_ID_SYMPHONY: return "Symphony";
int ' maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
fi
dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
+dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI
#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
endmenu
SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
AHA152X = -DDEBUG_AHA152X -DAUTOCONF
+GDTH = #-DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
.SUFFIXES:
.SUFFIXES: .c .o .h .a
endif
endif
+ifeq ($(CONFIG_SCSI_GDTH),y)
+L_OBJS += gdth.o
+else
+ ifeq ($(CONFIG_SCSI_GDTH),m)
+ M_OBJS += gdth.o
+ endif
+endif
+
ifeq ($(CONFIG_SCSI_DEBUG),y)
L_OBJS += scsi_debug.o
else
aha152x.o: aha152x.c
$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c
+gdth.o: gdth.c gdth.h gdth_proc.c gdth_proc.h
+ $(CC) $(CFLAGS) $(GDTH) -c gdth.c
+
aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
$(CC) $(CFLAGS) -c -o $@ aic7xxx.c
--- /dev/null
+/************************************************************************
+ * GDT ISA/EISA/PCI Disk Array Controller driver for Linux *
+ * *
+ * gdth.c *
+ * Copyright (C) 1995-97 ICP vortex Computersysteme GmbH, Achim Leubner *
+ * *
+ * <achim@vortex.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 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 kernel; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ * *
+ * Tested with Linux 1.2.13, ..., 2.0.29 *
+ * *
+ * $Log: gdth.c,v $
+ * Revision 1.8 1997/04/02 12:14:30 achim
+ * Version 1.00 (see gdth.h), tested with kernel 2.0.29
+ *
+ * Revision 1.7 1997/03/12 13:33:37 achim
+ * gdth_reset() changed, new async. events
+ *
+ * Revision 1.6 1997/03/04 14:01:11 achim
+ * Shutdown routine gdth_halt() implemented
+ *
+ * Revision 1.5 1997/02/21 09:08:36 achim
+ * New controller included (RP, RP1, RP2 series)
+ * IOCTL interface implemented
+ *
+ * Revision 1.4 1996/07/05 12:48:55 achim
+ * Function gdth_bios_param() implemented
+ * New constant GDTH_MAXC_P_L inserted
+ * GDT_WRITE_THR, GDT_EXT_INFO implemented
+ * Function gdth_reset() changed
+ *
+ * Revision 1.3 1996/05/10 09:04:41 achim
+ * Small changes for Linux 1.2.13
+ *
+ * Revision 1.2 1996/05/09 12:45:27 achim
+ * Loadable module support implemented
+ * /proc support corrections made
+ *
+ * Revision 1.1 1996/04/11 07:35:57 achim
+ * Initial revision
+ *
+ *
+ * $Id: gdth.c,v 1.8 1997/04/02 12:14:30 achim Exp $
+ ************************************************************************/
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/head.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/proc_fs.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#if LINUX_VERSION_CODE >= 0x010300
+#include <linux/blk.h>
+#else
+#include "../block/blk.h"
+#endif
+#include "scsi.h"
+#include "hosts.h"
+#include "sd.h"
+
+#include "gdth.h"
+
+#if LINUX_VERSION_CODE >= 0x010346
+static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+#else
+static void gdth_interrupt(int irq,struct pt_regs *regs);
+#endif
+static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
+static int gdth_async_event(int hanum,int service);
+
+static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
+static void gdth_next(int hanum);
+static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
+static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
+static gdth_evt_str *gdth_store_event(ushort source, ushort idx,
+ gdth_evt_data *evt);
+static int gdth_read_event(int handle, gdth_evt_str *estr);
+static void gdth_readapp_event(unchar application, gdth_evt_str *estr);
+static void gdth_clear_events(void);
+
+static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count);
+static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp,
+ unchar b,ulong *flags);
+static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
+
+static int gdth_search_eisa(ushort eisa_adr);
+static int gdth_search_isa(ulong bios_adr);
+static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr);
+static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime);
+static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime);
+static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime);
+
+static void gdth_enable_int(int hanum);
+static int gdth_get_status(unchar *pIStatus,int irq);
+static int gdth_test_busy(int hanum);
+static int gdth_get_cmd_index(int hanum);
+static void gdth_release_event(int hanum);
+static int gdth_wait(int hanum,int index,ulong time);
+static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
+ ulong p2,ulong p3);
+static int gdth_search_drives(int hanum,int firsttime);
+
+static const char *gdth_ctr_name(int hanum);
+void gdth_halt(void);
+
+#ifdef DEBUG_GDTH
+static unchar DebugState = DEBUG_GDTH;
+extern int sys_syslog(int,char*,int);
+#define LOGEN sys_syslog(7,NULL,0);
+#define WAITSEC(a) {ulong idx; for(idx=0;idx<a*1000L;++idx) udelay(1000);}
+
+#ifdef SLOWMOTION_GDTH
+#define SLOWM WAITSEC(2)
+#undef INIT_RETRIES
+#undef INIT_TIMEOUT
+#undef POLL_TIMEOUT
+#define INIT_RETRIES 15
+#define INIT_TIMEOUT 150
+#define POLL_TIMEOUT 150
+#else
+#define SLOWM
+#endif
+
+#ifdef __SERIAL__
+#define MAX_SERBUF 160
+static void ser_init(void);
+static void ser_puts(char *str);
+static void ser_putc(char c);
+static int ser_printk(const char *fmt, ...);
+static char strbuf[MAX_SERBUF+1];
+#ifdef __COM2__
+#define COM_BASE 0x2f8
+#else
+#define COM_BASE 0x3f8
+#endif
+static void ser_init()
+{
+ unsigned port=COM_BASE;
+
+ outb(0x80,port+3);
+ outb(0,port+1);
+ /* 19200 Baud, if 9600: outb(12,port) */
+ outb(6, port);
+ outb(3,port+3);
+ outb(0,port+1);
+ /*
+ ser_putc('I');
+ ser_putc(' ');
+ */
+}
+
+static void ser_puts(char *str)
+{
+ char *ptr;
+
+ ser_init();
+ for (ptr=str;*ptr;++ptr)
+ ser_putc(*ptr);
+}
+
+static void ser_putc(char c)
+{
+ unsigned port=COM_BASE;
+
+ while ((inb(port+5) & 0x20)==0);
+ outb(c,port);
+ if (c==0x0a)
+ {
+ while ((inb(port+5) & 0x20)==0);
+ outb(0x0d,port);
+ }
+}
+
+static int ser_printk(const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args,fmt);
+ i = vsprintf(strbuf,fmt,args);
+ ser_puts(strbuf);
+ va_end(args);
+ return i;
+}
+
+#define TRACE(a) {if (DebugState==1) {ser_printk a; SLOWM}}
+#define TRACE2(a) {if (DebugState==1 || DebugState==2) {ser_printk a; SLOWM}}
+#define TRACE3(a) {if (DebugState!=0) {ser_printk a; SLOWM}}
+
+#else /* !__SERIAL__ */
+#define TRACE(a) {if (DebugState==1) {LOGEN;printk a; SLOWM}}
+#define TRACE2(a) {if (DebugState==1 || DebugState==2) {LOGEN;printk a; SLOWM}}
+#define TRACE3(a) {if (DebugState!=0) {LOGEN;printk a; SLOWM}}
+#endif
+
+#else /* !DEBUG */
+#define TRACE(a)
+#define TRACE2(a)
+#define TRACE3(a)
+#endif
+
+
+#ifdef GDTH_STATISTICS
+static ulong max_rq=0, max_index=0, max_sg=0;
+static ulong act_ints=0, act_ios=0, act_stats=0, act_rq=0;
+#define GDTH_TIMER 31 /* see linux/timer.h ! */
+#endif
+
+#define PTR2USHORT(a) (ushort)(ulong)(a)
+#define JIFFYWAIT(a) {ulong gdtjf;gdtjf=jiffies+(a);while(gdtjf>jiffies);}
+#define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b)
+#define INDEX_OK(i,t) ((i)<sizeof(t)/sizeof((t)[0]))
+
+#define NUMDATA(a) ( (gdth_num_str *)((a)->hostdata))
+#define HADATA(a) (&((gdth_ext_str *)((a)->hostdata))->haext)
+#define CMDDATA(a) (&((gdth_ext_str *)((a)->hostdata))->cmdext)
+#define DMADATA(a) (&((gdth_ext_str *)((a)->hostdata))->dmaext)
+
+static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */
+static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */
+static unchar gdth_polling; /* polling if TRUE */
+static unchar gdth_from_wait = FALSE; /* gdth_wait() */
+static int wait_index,wait_hanum; /* gdth_wait() */
+static int gdth_ctr_count = 0; /* controller count */
+static int gdth_ctr_vcount = 0; /* virt. ctr. count */
+static struct Scsi_Host *gdth_ctr_tab[MAXHA]; /* controller table */
+static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS]; /* virt. ctr. table */
+static unchar gdth_write_through = FALSE; /* write through */
+static char *gdth_ioctl_tab[4][MAXHA]; /* ioctl buffer */
+static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */
+static int elastidx;
+static int eoldidx;
+
+static struct {
+ Scsi_Cmnd *cmnd; /* pending request */
+ ushort service; /* service */
+} gdth_cmd_tab[GDTH_MAXCMDS][MAXHA]; /* table of pend. requests */
+
+#define DIN 1 /* IN data direction */
+#define DOU 2 /* OUT data direction */
+#define DNO DIN /* no data transfer */
+#define DUN DIN /* unknown data direction */
+static unchar gdth_direction_tab[0x100] = {
+ DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN,
+ DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN,
+ DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DIN,DUN,DUN,DIN,DIN,DIN,
+ DIN,DIN,DIN,DNO,DIN,DNO,DNO,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,
+ DIN,DIN,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DIN,DIN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DIN,DUN,DNO,DUN,DIN,DIN,
+ DIN,DIN,DIN,DNO,DUN,DIN,DIN,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
+};
+
+/* LILO params: gdth=<IRQ>
+ *
+ * Where: <IRQ> is any of the valid IRQs for EISA controllers (10,11,12,14)
+ * Sets the IRQ of the GDT3000/3020 EISA controller to this value,
+ * if the IRQ can not automat. detect (controller BIOS disabled)
+ * See gdth_init_eisa()
+ *
+ * You can use the command line gdth=0 to disable the driver
+ */
+static unchar irqs[MAXHA] = {0xff};
+static unchar disable_gdth_scan = FALSE;
+
+/* /proc support */
+#if LINUX_VERSION_CODE >= 0x010300
+#include <linux/stat.h>
+struct proc_dir_entry proc_scsi_gdth = {
+ PROC_SCSI_GDTH, 4, "gdth",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#include "gdth_proc.h"
+#include "gdth_proc.c"
+#endif
+
+
+/* controller search and initialization functions */
+
+static int gdth_search_eisa(ushort eisa_adr)
+{
+ ulong id;
+
+ TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr));
+ id = inl(eisa_adr+ID0REG);
+ if (id == GDT3A_ID || id == GDT3B_ID) { /* GDT3000A or GDT3000B */
+ if ((inb(eisa_adr+EISAREG) & 8) == 0)
+ return 0; /* not EISA configured */
+ return 1;
+ }
+ if (id == GDT3_ID) /* GDT3000 */
+ return 1;
+
+ return 0;
+}
+
+
+static int gdth_search_isa(ulong bios_adr)
+{
+ ulong id;
+
+ TRACE(("gdth_search_isa() bios adr. %lx\n",bios_adr));
+ id = *(ulong *)(bios_adr+BIOS_ID_OFFS);
+ if (id == GDT2_ID) /* GDT2000 */
+ return 1;
+ return 0;
+}
+
+
+static int gdth_search_pci(ushort device_id,ushort index,gdth_pci_str *pcistr)
+{
+ int error;
+ ulong base0,base1,base2;
+
+ TRACE(("gdth_search_pci() device_id %d, index %d\n",
+ device_id,index));
+
+ if (!pcibios_present())
+ return 0;
+
+ if (pcibios_find_device(PCI_VENDOR_ID_VORTEX,device_id,index,
+ &pcistr->bus,&pcistr->device_fn))
+ return 0;
+
+ /* GDT PCI controller found, now read resources from config space */
+#if LINUX_VERSION_CODE >= 0x010300
+#define GDTH_BASEP (int *)
+#else
+#define GDTH_BASEP
+#endif
+ if ((error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+ PCI_BASE_ADDRESS_0,
+ GDTH_BASEP&base0)) ||
+ (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+ PCI_BASE_ADDRESS_1,
+ GDTH_BASEP&base1)) ||
+ (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+ PCI_BASE_ADDRESS_2,
+ GDTH_BASEP&base2)) ||
+ (error = pcibios_read_config_dword(pcistr->bus,pcistr->device_fn,
+ PCI_ROM_ADDRESS,
+ GDTH_BASEP&pcistr->bios)) ||
+ (error = pcibios_read_config_byte(pcistr->bus,pcistr->device_fn,
+ PCI_INTERRUPT_LINE,&pcistr->irq))) {
+ printk("GDT-PCI: error %s reading configuration space",
+ pcibios_strerror(error));
+ return -1;
+ }
+
+ pcistr->device_id = device_id;
+ if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000 or GDT6000B */
+ device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */
+ if ((base0 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY)
+ return -1;
+ pcistr->dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+ } else { /* GDT6110, GDT6120, .. */
+ if ((base0 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY ||
+ (base2 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_MEMORY ||
+ (base1 & PCI_BASE_ADDRESS_SPACE)!=PCI_BASE_ADDRESS_SPACE_IO)
+ return -1;
+ pcistr->dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
+ pcistr->io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
+ pcistr->io = base1 & PCI_BASE_ADDRESS_IO_MASK;
+ }
+ return 1;
+}
+
+
+static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha,int firsttime)
+{
+ ulong retries,id;
+ unchar prot_ver,eisacf,i,irq_found;
+
+ TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr));
+
+ /* disable board interrupts, deinitialize services */
+ outb(0xff,eisa_adr+EDOORREG);
+ outb(0x00,eisa_adr+EDENABREG);
+ outb(0x00,eisa_adr+EINTENABREG);
+
+ outb(0xff,eisa_adr+LDOORREG);
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (inb(eisa_adr+EDOORREG) != 0xff) {
+ if (--retries == 0) {
+ printk("GDT-EISA: Initialization error (DEINIT failed)\n");
+ return 0;
+ }
+ udelay(1000);
+ TRACE2(("wait for DEINIT: retries=%ld\n",retries));
+ }
+ prot_ver = inb(eisa_adr+MAILBOXREG);
+ outb(0xff,eisa_adr+EDOORREG);
+ if (prot_ver != PROTOCOL_VERSION) {
+ printk("GDT-EISA: Illegal protocol version\n");
+ return 0;
+ }
+ ha->brd = (ulong)eisa_adr;
+ ha->brd_phys = (ulong)eisa_adr >> 12;
+
+ outl(0,eisa_adr+MAILBOXREG);
+ outl(0,eisa_adr+MAILBOXREG+4);
+ outl(0,eisa_adr+MAILBOXREG+8);
+ outl(0,eisa_adr+MAILBOXREG+12);
+
+ /* detect IRQ */
+ if ((id = inl(eisa_adr+ID0REG)) == GDT3_ID) {
+ ha->type = GDT_EISA;
+ ha->stype = id;
+ outl(1,eisa_adr+MAILBOXREG+8);
+ outb(0xfe,eisa_adr+LDOORREG);
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (inb(eisa_adr+EDOORREG) != 0xfe) {
+ if (--retries == 0) {
+ printk("GDT-EISA: Initialization error (get IRQ failed)\n");
+ return 0;
+ }
+ udelay(1000);
+ }
+ if (firsttime)
+ ha->irq = inb(eisa_adr+MAILBOXREG);
+ outb(0xff,eisa_adr+EDOORREG);
+ TRACE2(("GDT3000/3020: IRQ=%d\n",ha->irq));
+ if (firsttime) {
+ /* check the result */
+ if (ha->irq == 0) {
+ TRACE2(("Unknown IRQ, check IRQ table from cmd line !\n"));
+ for (i=0,irq_found=FALSE; i<MAXHA && irqs[i]!=0xff; ++i) {
+ if (irqs[i]!=0) {
+ irq_found=TRUE;
+ break;
+ }
+ }
+ if (irq_found) {
+ ha->irq = irqs[i];
+ irqs[i] = 0;
+ printk("GDT-EISA: Can not detect controller IRQ,\n");
+ printk("Use IRQ setting from command line (IRQ = %d)\n",
+ ha->irq);
+ } else {
+ printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n");
+ printk("the controller BIOS or use command line parameters\n");
+ return 0;
+ }
+ }
+ }
+ } else {
+ eisacf = inb(eisa_adr+EISAREG) & 7;
+ if (eisacf > 4) /* level triggered */
+ eisacf -= 4;
+ ha->irq = gdth_irq_tab[eisacf];
+ ha->type = GDT_EISA;
+ ha->stype= id;
+ }
+ return 1;
+}
+
+
+static int gdth_init_isa(ulong bios_adr,gdth_ha_str *ha,int firsttime)
+{
+ register gdt2_dpram_str *dp2_ptr;
+ int i;
+ unchar irq_drq,prot_ver;
+ ulong retries;
+
+ TRACE(("gdth_init_isa() bios adr. %lx\n",bios_adr));
+
+ ha->brd = bios_adr;
+ dp2_ptr = (gdt2_dpram_str *)ha->brd;
+ dp2_ptr->io.memlock = 1; /* switch off write protection */
+ /* reset interface area */
+ memset((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u));
+
+ /* disable board interrupts, read DRQ and IRQ */
+ dp2_ptr->io.irqdel = 0xff;
+ dp2_ptr->io.irqen = 0x00;
+ dp2_ptr->u.ic.S_Status = 0x00;
+ dp2_ptr->u.ic.Cmd_Index= 0x00;
+
+ irq_drq = dp2_ptr->io.rq;
+ for (i=0; i<3; ++i) {
+ if ((irq_drq & 1)==0)
+ break;
+ irq_drq >>= 1;
+ }
+ ha->drq = gdth_drq_tab[i];
+
+ irq_drq = dp2_ptr->io.rq >> 3;
+ for (i=1; i<5; ++i) {
+ if ((irq_drq & 1)==0)
+ break;
+ irq_drq >>= 1;
+ }
+ ha->irq = gdth_irq_tab[i];
+
+ /* deinitialize services */
+ dp2_ptr->u.ic.S_Info[0] = bios_adr;
+ dp2_ptr->u.ic.S_Cmd_Indx= 0xff;
+ dp2_ptr->io.event = 0;
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (dp2_ptr->u.ic.S_Status != 0xff) {
+ if (--retries == 0) {
+ printk("GDT-ISA: Initialization error (DEINIT failed)\n");
+ return 0;
+ }
+ udelay(1000);
+ }
+ prot_ver = (unchar)dp2_ptr->u.ic.S_Info[0];
+ dp2_ptr->u.ic.Status = 0;
+ dp2_ptr->io.irqdel = 0xff;
+ if (prot_ver != PROTOCOL_VERSION) {
+ printk("GDT-ISA: Illegal protocol version\n");
+ return 0;
+ }
+
+ ha->type = GDT_ISA;
+ ha->ic_all_size = sizeof(dp2_ptr->u);
+ ha->stype= GDT2_ID;
+ ha->brd_phys = bios_adr >> 4;
+
+ /* special request to controller BIOS */
+ dp2_ptr->u.ic.S_Info[0] = 0x00;
+ dp2_ptr->u.ic.S_Info[1] = 0x00;
+ dp2_ptr->u.ic.S_Info[2] = 0x01;
+ dp2_ptr->u.ic.S_Info[3] = 0x00;
+ dp2_ptr->u.ic.S_Cmd_Indx= 0xfe;
+ dp2_ptr->io.event = 0;
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (dp2_ptr->u.ic.S_Status != 0xfe) {
+ if (--retries == 0) {
+ printk("GDT-ISA: Initialization error\n");
+ return 0;
+ }
+ udelay(1000);
+ }
+ dp2_ptr->u.ic.Status = 0;
+ dp2_ptr->io.irqdel = 0xff;
+ return 1;
+}
+
+
+static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha,int firsttime)
+{
+ register gdt6_dpram_str *dp6_ptr;
+ register gdt6c_dpram_str *dp6c_ptr;
+ register gdt6m_dpram_str *dp6m_ptr;
+ ulong retries;
+ unchar prot_ver;
+ unchar remapped = FALSE;
+
+ TRACE(("gdth_init_pci()\n"));
+
+ if (firsttime) {
+ ha->brd = pcistr->dpmem;
+ ha->brd_phys = (pcistr->bus << 8) | (pcistr->device_fn & 0xf8);
+ ha->stype = (ulong)pcistr->device_id;
+ ha->irq = pcistr->irq;
+ }
+
+ if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) { /* GDT6000 or GDT6000B */
+ TRACE2(("init_pci() dpmem %lx irq %d\n",ha->brd,ha->irq));
+ dp6_ptr = (gdt6_dpram_str *)ha->brd;
+ /* reset interface area */
+ memset((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
+ if (*(ulong *)&dp6_ptr->u != 0) {
+ printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+ return 0;
+ }
+
+ /* disable board interrupts, deinit services */
+ dp6_ptr->io.irqdel = 0xff;
+ dp6_ptr->io.irqen = 0x00;
+ dp6_ptr->u.ic.S_Status = 0x00;
+ dp6_ptr->u.ic.Cmd_Index= 0x00;
+
+ dp6_ptr->u.ic.S_Info[0] = ha->brd;
+ dp6_ptr->u.ic.S_Cmd_Indx= 0xff;
+ dp6_ptr->io.event = 0;
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (dp6_ptr->u.ic.S_Status != 0xff) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+ return 0;
+ }
+ udelay(1000);
+ }
+ prot_ver = (unchar)dp6_ptr->u.ic.S_Info[0];
+ dp6_ptr->u.ic.S_Status = 0;
+ dp6_ptr->io.irqdel = 0xff;
+ if (prot_ver != PROTOCOL_VERSION) {
+ printk("GDT-PCI: Illegal protocol version\n");
+ return 0;
+ }
+
+ ha->type = GDT_PCI;
+ ha->ic_all_size = sizeof(dp6_ptr->u);
+
+ /* special command to controller BIOS */
+ dp6_ptr->u.ic.S_Info[0] = 0x00;
+ dp6_ptr->u.ic.S_Info[1] = 0x00;
+ dp6_ptr->u.ic.S_Info[2] = 0x01;
+ dp6_ptr->u.ic.S_Info[3] = 0x00;
+ dp6_ptr->u.ic.S_Cmd_Indx= 0xfe;
+ dp6_ptr->io.event = 0;
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (dp6_ptr->u.ic.S_Status != 0xfe) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error\n");
+ return 0;
+ }
+ udelay(1000);
+ }
+ dp6_ptr->u.ic.S_Status = 0;
+ dp6_ptr->io.irqdel = 0xff;
+
+ } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, GDT6120, .. */
+ if (firsttime) {
+ ha->plx = (gdt6c_plx_regs *)pcistr->io;
+ }
+ TRACE2(("init_pci_new() dpmem %lx io %lx irq %d\n",
+ ha->brd,(ulong)ha->plx,ha->irq));
+ dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
+ /* reset interface area */
+ memset((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
+ if (*(ulong *)&dp6c_ptr->u != 0) {
+ printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+ return 0;
+ }
+
+ /* disable board interrupts, deinit services */
+ outb(0x00,PTR2USHORT(&ha->plx->control1));
+ outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
+
+ dp6c_ptr->u.ic.S_Status = 0x00;
+ dp6c_ptr->u.ic.Cmd_Index= 0x00;
+
+ dp6c_ptr->u.ic.S_Info[0] = ha->brd;
+ dp6c_ptr->u.ic.S_Cmd_Indx= 0xff;
+
+ outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (dp6c_ptr->u.ic.S_Status != 0xff) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+ return 0;
+ }
+ udelay(1000);
+ }
+ prot_ver = (unchar)dp6c_ptr->u.ic.S_Info[0];
+ dp6c_ptr->u.ic.Status = 0;
+ if (prot_ver != PROTOCOL_VERSION) {
+ printk("GDT-PCI: Illegal protocol version\n");
+ return 0;
+ }
+
+ ha->type = GDT_PCINEW;
+ ha->ic_all_size = sizeof(dp6c_ptr->u);
+
+ /* special command to controller BIOS */
+ dp6c_ptr->u.ic.S_Info[0] = 0x00;
+ dp6c_ptr->u.ic.S_Info[1] = 0x00;
+ dp6c_ptr->u.ic.S_Info[2] = 0x01;
+ dp6c_ptr->u.ic.S_Info[3] = 0x00;
+ dp6c_ptr->u.ic.S_Cmd_Indx= 0xfe;
+
+ outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (dp6c_ptr->u.ic.S_Status != 0xfe) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error\n");
+ return 0;
+ }
+ udelay(1000);
+ }
+ dp6c_ptr->u.ic.S_Status = 0;
+
+ } else { /* MPR */
+ if (ha->brd > 0xfffff) { /* NOT below 1MB */
+#if LINUX_VERSION_CODE >= 0x010300
+ /* Linux 1.3.X allow to remap physical pages adresses greater
+ than the highest physical memory address to kernel virtual
+ pages using vremap()/vfree(), Linux 1.2.X doesn't */
+ TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",ha->brd,ha->irq));
+ ha->brd = (ulong)vremap(ha->brd, sizeof(gdt6m_dpram_str));
+ if (ha->brd == 0L) {
+ printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+ return 0;
+ }
+ TRACE2(("init_pci_mpr() remapped dpmem %lx\n",ha->brd));
+ remapped = TRUE;
+#else
+ printk("GDT-PCI: Initialization error (DPMEM not below 1MB)\n");
+ return 0;
+#endif
+ }
+
+ dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+ /* reset interface area */
+ memset((char *)&dp6m_ptr->u,0,sizeof(dp6m_ptr->u));
+ if (*(ulong *)&dp6m_ptr->u != 0) {
+ printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+#if LINUX_VERSION_CODE >= 0x010300
+ if (remapped)
+ vfree((void *)ha->brd);
+#endif
+ return 0;
+ }
+
+ /* disable board interrupts, deinit services */
+ dp6m_ptr->i960r.edoor_en_reg |= 4;
+ dp6m_ptr->i960r.edoor_reg = 0xff;
+ dp6m_ptr->u.ic.S_Status = 0x00;
+ dp6m_ptr->u.ic.Cmd_Index = 0x00;
+
+ dp6m_ptr->u.ic.S_Info[0] = ha->brd;
+ dp6m_ptr->u.ic.S_Cmd_Indx = 0xff;
+ dp6m_ptr->i960r.ldoor_reg = 1;
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (dp6m_ptr->u.ic.S_Status != 0xff) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+#if LINUX_VERSION_CODE >= 0x010300
+ if (remapped)
+ vfree((void *)ha->brd);
+#endif
+ return 0;
+ }
+ udelay(1000);
+ }
+ prot_ver = (unchar)dp6m_ptr->u.ic.S_Info[0];
+ dp6m_ptr->u.ic.S_Status = 0;
+ if (prot_ver != PROTOCOL_VERSION) {
+ printk("GDT-PCI: Illegal protocol version\n");
+#if LINUX_VERSION_CODE >= 0x010300
+ if (remapped)
+ vfree((void *)ha->brd);
+#endif
+ return 0;
+ }
+
+ ha->type = GDT_PCIMPR;
+ ha->ic_all_size = sizeof(dp6m_ptr->u);
+
+ /* special command to controller BIOS */
+ dp6m_ptr->u.ic.S_Info[0] = 0x00;
+ dp6m_ptr->u.ic.S_Info[1] = 0x00;
+ dp6m_ptr->u.ic.S_Info[2] = 0x01;
+ dp6m_ptr->u.ic.S_Info[3] = 0x00;
+ dp6m_ptr->u.ic.S_Cmd_Indx = 0xfe;
+ dp6m_ptr->i960r.ldoor_reg = 1;
+ retries = INIT_RETRIES;
+ JIFFYWAIT(2);
+ while (dp6m_ptr->u.ic.S_Status != 0xfe) {
+ if (--retries == 0) {
+ printk("GDT-PCI: Initialization error\n");
+#if LINUX_VERSION_CODE >= 0x010300
+ if (remapped)
+ vfree((void *)ha->brd);
+#endif
+ return 0;
+ }
+ udelay(1000);
+ }
+ dp6m_ptr->u.ic.S_Status = 0;
+ }
+
+ return 1;
+}
+
+
+/* controller protocol functions */
+
+static void gdth_enable_int(int hanum)
+{
+ gdth_ha_str *ha;
+ ulong flags;
+ ushort addr;
+ gdt2_dpram_str *dp2_ptr;
+ gdt6_dpram_str *dp6_ptr;
+ gdt6m_dpram_str *dp6m_ptr;
+
+ TRACE(("gdth_enable_int() hanum %d\n",hanum));
+ ha = HADATA(gdth_ctr_tab[hanum]);
+
+ save_flags(flags);
+ cli();
+
+ if (ha->type == GDT_EISA) {
+ addr = (ushort)ha->brd;
+ outb(0xff,addr+EDOORREG);
+ outb(0xff,addr+EDENABREG);
+ outb(0x01,addr+EINTENABREG);
+ } else if (ha->type == GDT_ISA) {
+ dp2_ptr = (gdt2_dpram_str *)ha->brd;
+ dp2_ptr->io.irqdel = 1;
+ dp2_ptr->u.ic.Cmd_Index = 0;
+ dp2_ptr->io.irqen = 1;
+ } else if (ha->type == GDT_PCI) {
+ dp6_ptr = (gdt6_dpram_str *)ha->brd;
+ dp6_ptr->io.irqdel = 1;
+ dp6_ptr->u.ic.Cmd_Index = 0;
+ dp6_ptr->io.irqen = 1;
+ } else if (ha->type == GDT_PCINEW) {
+ outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
+ outb(0x03,PTR2USHORT(&ha->plx->control1));
+ } else if (ha->type == GDT_PCIMPR) {
+ dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+ dp6m_ptr->i960r.edoor_reg = 0xff;
+ dp6m_ptr->i960r.edoor_en_reg &= ~4;
+ }
+ restore_flags(flags);
+}
+
+
+static int gdth_get_status(unchar *pIStatus,int irq)
+{
+ register gdth_ha_str *ha;
+ int i;
+
+ TRACE(("gdth_get_status() irq %d ctr_count %d\n",
+ irq,gdth_ctr_count));
+
+ *pIStatus = 0;
+ for (i=0; i<gdth_ctr_count; ++i) {
+ ha = HADATA(gdth_ctr_tab[i]);
+ if (ha->irq != (unchar)irq) /* check IRQ */
+ continue;
+ if (ha->type == GDT_EISA)
+ *pIStatus = inb((ushort)ha->brd+EDOORREG);
+ else if (ha->type == GDT_ISA)
+ *pIStatus = ((gdt2_dpram_str *)ha->brd)->u.ic.Cmd_Index;
+ else if (ha->type == GDT_PCI)
+ *pIStatus = ((gdt6_dpram_str *)ha->brd)->u.ic.Cmd_Index;
+ else if (ha->type == GDT_PCINEW)
+ *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
+ else if (ha->type == GDT_PCIMPR)
+ *pIStatus = ((gdt6m_dpram_str *)ha->brd)->i960r.edoor_reg;
+
+ if (*pIStatus)
+ return i; /* board found */
+ }
+ return -1;
+}
+
+
+static int gdth_test_busy(int hanum)
+{
+ register gdth_ha_str *ha;
+ register int gdtsema0 = 0;
+
+ TRACE(("gdth_test_busy() hanum %d\n",hanum));
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ if (ha->type == GDT_EISA)
+ gdtsema0 = (int)inb((ushort)ha->brd+SEMA0REG);
+ else if (ha->type == GDT_ISA)
+ gdtsema0 = (int)((gdt2_dpram_str *)ha->brd)->u.ic.Sema0;
+ else if (ha->type == GDT_PCI)
+ gdtsema0 = (int)((gdt6_dpram_str *)ha->brd)->u.ic.Sema0;
+ else if (ha->type == GDT_PCINEW)
+ gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
+ else if (ha->type == GDT_PCIMPR)
+ gdtsema0 = (int)((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg;
+
+ return (gdtsema0 & 1);
+}
+
+
+static int gdth_get_cmd_index(int hanum)
+{
+ register gdth_ha_str *ha;
+ int i;
+
+ TRACE(("gdth_get_cmd_index() hanum %d\n",hanum));
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ for (i=0; i<GDTH_MAXCMDS; ++i) {
+ if (gdth_cmd_tab[i][hanum].cmnd == UNUSED_CMND) {
+ gdth_cmd_tab[i][hanum].cmnd = ha->pccb->RequestBuffer;
+ gdth_cmd_tab[i][hanum].service = ha->pccb->Service;
+ ha->pccb->CommandIndex = (ulong)i+2;
+ return (i+2);
+ }
+ }
+ return 0;
+}
+
+
+static void gdth_set_sema0(int hanum)
+{
+ register gdth_ha_str *ha;
+
+ TRACE(("gdth_set_sema0() hanum %d\n",hanum));
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ if (ha->type == GDT_EISA)
+ outb(1,(ushort)ha->brd+SEMA0REG);
+ else if (ha->type == GDT_ISA)
+ ((gdt2_dpram_str *)ha->brd)->u.ic.Sema0 = 1;
+ else if (ha->type == GDT_PCI)
+ ((gdt6_dpram_str *)ha->brd)->u.ic.Sema0 = 1;
+ else if (ha->type == GDT_PCINEW)
+ outb(1,PTR2USHORT(&ha->plx->sema0_reg));
+ else if (ha->type == GDT_PCIMPR)
+ ((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg = 1;
+
+}
+
+
+static void gdth_copy_command(int hanum)
+{
+ register gdth_ha_str *ha;
+ register gdth_cmd_str *cmd_ptr;
+ register gdt6m_dpram_str *dp6m_ptr;
+ register gdt6c_dpram_str *dp6c_ptr;
+ gdt6_dpram_str *dp6_ptr;
+ gdt2_dpram_str *dp2_ptr;
+ ushort cp_count,dp_offset,cmd_no;
+
+ TRACE(("gdth_copy_command() hanum %d\n",hanum));
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ cp_count = ha->cmd_len;
+ dp_offset= ha->cmd_offs_dpmem;
+ cmd_no = ha->cmd_cnt;
+ cmd_ptr = ha->pccb;
+
+ ++ha->cmd_cnt;
+ if (ha->type == GDT_EISA)
+ return; /* no DPMEM, no copy */
+
+ /* set cpcount dword aligned */
+ if (cp_count & 3)
+ cp_count += (4 - (cp_count & 3));
+
+ ha->cmd_offs_dpmem += cp_count;
+
+ /* set offset and service, copy command to DPMEM */
+ if (ha->type == GDT_ISA) {
+ dp2_ptr = (gdt2_dpram_str *)ha->brd;
+ dp2_ptr->u.ic.comm_queue[cmd_no].offset =
+ dp_offset + DPMEM_COMMAND_OFFSET;
+ dp2_ptr->u.ic.comm_queue[cmd_no].serv_id =
+ (ushort)cmd_ptr->Service;
+ memcpy(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+ } else if (ha->type == GDT_PCI) {
+ dp6_ptr = (gdt6_dpram_str *)ha->brd;
+ dp6_ptr->u.ic.comm_queue[cmd_no].offset =
+ dp_offset + DPMEM_COMMAND_OFFSET;
+ dp6_ptr->u.ic.comm_queue[cmd_no].serv_id =
+ (ushort)cmd_ptr->Service;
+ memcpy(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+ } else if (ha->type == GDT_PCINEW) {
+ dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
+ dp6c_ptr->u.ic.comm_queue[cmd_no].offset =
+ dp_offset + DPMEM_COMMAND_OFFSET;
+ dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id =
+ (ushort)cmd_ptr->Service;
+ memcpy(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+ } else if (ha->type == GDT_PCIMPR) {
+ dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+ dp6m_ptr->u.ic.comm_queue[cmd_no].offset =
+ dp_offset + DPMEM_COMMAND_OFFSET;
+ dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id =
+ (ushort)cmd_ptr->Service;
+ memcpy(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+ }
+}
+
+
+static void gdth_release_event(int hanum)
+{
+ register gdth_ha_str *ha;
+
+#ifdef GDTH_STATISTICS
+ ulong i,j;
+ for (i=0,j=0; j<GDTH_MAXCMDS; ++j) {
+ if (gdth_cmd_tab[j][hanum].cmnd != UNUSED_CMND)
+ ++i;
+ }
+ if (max_index < i) {
+ max_index = i;
+ TRACE3(("GDT: max_index = %d\n",(ushort)i));
+ }
+#endif
+
+ TRACE(("gdth_release_event() hanum %d\n",hanum));
+ ha = HADATA(gdth_ctr_tab[hanum]);
+
+ if (ha->pccb->OpCode == GDT_INIT)
+ ha->pccb->Service |= 0x80;
+
+ if (ha->type == GDT_EISA) {
+ outb(ha->pccb->Service,(ushort)ha->brd+LDOORREG);
+ if (ha->pccb->OpCode == GDT_INIT) /* store DMA buffer */
+ outl((ulong)ha->pccb,(ushort)ha->brd+MAILBOXREG);
+ } else if (ha->type == GDT_ISA)
+ ((gdt2_dpram_str *)ha->brd)->io.event = 0;
+ else if (ha->type == GDT_PCI)
+ ((gdt6_dpram_str *)ha->brd)->io.event = 0;
+ else if (ha->type == GDT_PCINEW)
+ outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+ else if (ha->type == GDT_PCIMPR)
+ ((gdt6m_dpram_str *)ha->brd)->i960r.ldoor_reg = 1;
+}
+
+
+static int gdth_wait(int hanum,int index,ulong time)
+{
+ gdth_ha_str *ha;
+ int answer_found = FALSE;
+
+ TRACE(("gdth_wait() hanum %d index %d time %ld\n",hanum,index,time));
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ if (index == 0)
+ return 1; /* no wait required */
+
+ gdth_from_wait = TRUE;
+ do {
+#if LINUX_VERSION_CODE >= 0x010346
+ gdth_interrupt((int)ha->irq,NULL,NULL);
+#else
+ gdth_interrupt((int)ha->irq,NULL);
+#endif
+ if (wait_hanum==hanum && wait_index==index) {
+ answer_found = TRUE;
+ break;
+ }
+ udelay(1000);
+ } while (--time);
+ gdth_from_wait = FALSE;
+
+ while (gdth_test_busy(hanum))
+ udelay(1);
+
+ return (answer_found);
+}
+
+
+static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong p1,
+ ulong p2,ulong p3)
+{
+ register gdth_ha_str *ha;
+ register gdth_cmd_str *cmd_ptr;
+ int retries,index;
+
+ TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode));
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ cmd_ptr = ha->pccb;
+ memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str));
+
+ /* make command */
+ for (retries = INIT_RETRIES;;) {
+ cmd_ptr->Service = service;
+ cmd_ptr->RequestBuffer = INTERNAL_CMND;
+ if (!(index=gdth_get_cmd_index(hanum))) {
+ TRACE(("GDT: No free command index found\n"));
+ return 0;
+ }
+ gdth_set_sema0(hanum);
+ cmd_ptr->OpCode = opcode;
+ cmd_ptr->BoardNode = LOCALBOARD;
+ if (service == CACHESERVICE) {
+ if (opcode == GDT_IOCTL) {
+ cmd_ptr->u.ioctl.subfunc = p1;
+ cmd_ptr->u.ioctl.channel = p2;
+ cmd_ptr->u.ioctl.param_size = (ushort)p3;
+ cmd_ptr->u.ioctl.p_param = (ulong)ha->pscratch;
+ } else {
+ cmd_ptr->u.cache.DeviceNo = (ushort)p1;
+ cmd_ptr->u.cache.BlockNo = p2;
+ }
+ } else if (service == SCSIRAWSERVICE) {
+ cmd_ptr->u.raw.direction = p1;
+ cmd_ptr->u.raw.bus = (unchar)p2;
+ cmd_ptr->u.raw.target = (unchar)p3;
+ cmd_ptr->u.raw.lun = 0;
+ }
+ ha->cmd_len = sizeof(gdth_cmd_str);
+ ha->cmd_offs_dpmem = 0;
+ ha->cmd_cnt = 0;
+ gdth_copy_command(hanum);
+ gdth_release_event(hanum);
+ JIFFYWAIT(2);
+ if (!gdth_wait(hanum,index,INIT_TIMEOUT)) {
+ printk("GDT: Initialization error (timeout service %d)\n",service);
+ return 0;
+ }
+ if (ha->status != S_BSY || --retries == 0)
+ break;
+ udelay(1000);
+ }
+
+ return (ha->status != S_OK ? 0:1);
+}
+
+
+/* search for devices */
+
+static int gdth_search_drives(int hanum,int firsttime)
+{
+ register gdth_ha_str *ha;
+ ushort cdev_cnt,i;
+ unchar b,t,pos_found;
+ ulong drv_cyls, drv_hds, drv_secs;
+ ulong bus_no;
+ gdth_getch_str *chn;
+
+ TRACE(("gdth_search_drives() hanum %d flag %d\n",hanum,firsttime));
+ ha = HADATA(gdth_ctr_tab[hanum]);
+
+ /* initialize controller services, at first: screen service */
+ if (!gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0)) {
+ printk("GDT: Initialization error screen service (code %d)\n",
+ ha->status);
+ return 0;
+ }
+ TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
+
+ /* initialize cache service */
+ if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
+ printk("GDT: Initialization error cache service (code %d)\n",
+ ha->status);
+ return 0;
+ }
+ TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
+ cdev_cnt = (ushort)ha->info;
+
+ if (firsttime) {
+ /* mount all cache devices */
+ if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0)) {
+ printk("GDT: Initialization error cache service (code %d)\n",
+ ha->status);
+ return 0;
+ }
+ TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n"));
+
+ /* initialize cache service after mountall */
+ if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
+ printk("GDT: Initialization error cache service (code %d)\n",
+ ha->status);
+ return 0;
+ }
+ TRACE2(("gdth_search_drives() CACHES. init. after mountall\n"));
+ cdev_cnt = (ushort)ha->info;
+
+ /* detect number of SCSI buses */
+ chn = (gdth_getch_str *)DMADATA(gdth_ctr_tab[hanum]);
+ for (bus_no=0; bus_no<MAXBUS; ++bus_no) {
+ chn->channel_no = bus_no;
+ if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ SCSI_CHAN_CNT | L_CTRL_PATTERN,
+ IO_CHANNEL | INVALID_CHANNEL,
+ sizeof(gdth_getch_str))) {
+ if (bus_no == 0) {
+ printk("GDT: Error detecting SCSI channel count (0x%x)\n",
+ ha->status);
+ return 0;
+ }
+ break;
+ }
+ if (chn->siop_id < MAXID)
+ ha->id[bus_no][chn->siop_id].type = SIOP_DTYP;
+ }
+ ha->bus_cnt = (unchar)bus_no;
+ TRACE2(("gdth_search_drives() %d SCSI channels\n",ha->bus_cnt));
+
+ /* read cache configuration */
+ if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
+ INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
+ printk("GDT: Initialization error cache service (code %d)\n",
+ ha->status);
+ return 0;
+ }
+ ha->cpar = ((gdth_cinfo_str *)DMADATA(gdth_ctr_tab[hanum]))->cpar;
+ TRACE2(("gdth_search_drives() cinfo: vs %lx sta %d str %d dw %d b %d\n",
+ ha->cpar.version,ha->cpar.state,ha->cpar.strategy,
+ ha->cpar.write_back,ha->cpar.block_size));
+ }
+
+ /* initialize raw service */
+ if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) {
+ printk("GDT: Initialization error raw service (code %d)\n",
+ ha->status);
+ return 0;
+ }
+ TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
+
+ /* set/get features raw service (scatter/gather) */
+ ha->raw_feat = 0;
+ if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
+ 0,0)) {
+ TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
+ if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0))
+ {
+ TRACE2(("gdth_search_dr(): get feat RAWSERVICE %ld\n",
+ ha->info));
+ ha->raw_feat = (ushort)ha->info;
+ }
+ }
+
+ /* set/get features cache service (equal to raw service) */
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_SET_FEAT,0,
+ SCATTER_GATHER,0)) {
+ TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n"));
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
+ TRACE2(("gdth_search_dr(): get feat CACHESERV. %ld\n",
+ ha->info));
+ ha->cache_feat = (ushort)ha->info;
+ }
+ }
+
+ /* if it is not the first scan, we are ready */
+ if (!firsttime)
+ return 1;
+
+ /* scanning for raw devices */
+ for (b=0; b<ha->bus_cnt; ++b) {
+ for (t=0; t<MAXID; ++t) {
+ TRACE(("gdth_search_drives() rawd. bus %d id %d\n",b,t));
+ if (ha->id[b][t].type != SIOP_DTYP &&
+ gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INFO,0,b,t)) {
+ ha->id[b][t].type = RAW_DTYP;
+ }
+ }
+ }
+
+ /* scanning for cache devices */
+ for (i=0; i<cdev_cnt && i<MAX_HDRIVES; ++i) {
+ TRACE(("gdth_search_drives() cachedev. %d\n",i));
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,i,0,0)) {
+ /* dynamic relation between host drive number and Bus/ID */
+ /* search free position */
+ pos_found = FALSE;
+ for (b=0,t=0; b<ha->bus_cnt; ++b) {
+ for (t=0; t<MAXID; ++t) {
+ if (ha->id[b][t].type == EMPTY_DTYP) {
+ pos_found = TRUE;
+ break;
+ }
+ }
+ if (pos_found)
+ break;
+ }
+ TRACE(("gdth_search_dr() drive %d free pos at bus/id %d/%d\n",
+ i,b,t));
+
+ ha->id[b][t].type = CACHE_DTYP;
+ ha->id[b][t].devtype = 0;
+ ha->id[b][t].size = ha->info;
+ ha->id[b][t].hostdrive = i;
+
+ /* evaluate mapping (sectors per head, heads per cylinder) */
+ ha->id[b][t].size &= ~SECS32;
+ drv_cyls = ha->id[b][t].size /HEADS/SECS;
+ if (drv_cyls <= MAXCYLS) {
+ drv_hds = HEADS;
+ drv_secs= SECS;
+ } else { /* too high for 64*32 */
+ drv_cyls = ha->id[b][t].size /MEDHEADS/MEDSECS;
+ if (drv_cyls <= MAXCYLS) {
+ drv_hds = MEDHEADS;
+ drv_secs= MEDSECS;
+ } else { /* too high for 127*63 */
+ drv_cyls = ha->id[b][t].size /BIGHEADS/BIGSECS;
+ drv_hds = BIGHEADS;
+ drv_secs= BIGSECS;
+ }
+ }
+ ha->id[b][t].heads = (unchar)drv_hds;
+ ha->id[b][t].secs = (unchar)drv_secs;
+ /* round size */
+ ha->id[b][t].size = drv_cyls * drv_hds * drv_secs;
+ TRACE(("gdth_search_dr() cdr. %d size %ld hds %ld scs %ld\n",
+ i,ha->id[b][t].size,drv_hds,drv_secs));
+
+ /* get informations about device */
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i,
+ 0,0)) {
+ TRACE(("gdth_search_dr() cache drive %d devtype %ld\n",
+ i,ha->info));
+ ha->id[b][t].devtype = (ushort)ha->info;
+ }
+ }
+ }
+
+ TRACE(("gdth_search_drives() OK\n"));
+ return 1;
+}
+
+
+/* command queueing/sending functions */
+
+static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
+{
+ register gdth_ha_str *ha;
+ register Scsi_Cmnd *pscp;
+ register Scsi_Cmnd *nscp;
+ ulong flags;
+ unchar b, t;
+
+ TRACE(("gdth_putq() priority %d\n",priority));
+ save_flags(flags);
+ cli();
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ scp->SCp.this_residual = (int)priority;
+ gdth_update_timeout(scp, scp->timeout * 6);
+#if LINUX_VERSION_CODE >= 0x010400
+ b = scp->channel;
+#else
+ b = NUMDATA(nscp->host)->busnum;
+#endif
+ t = scp->target;
+#if LINUX_VERSION_CODE >= 0x010300
+ if (priority >= DEFAULT_PRI && ha->id[b][t].lock) {
+ TRACE2(("gdth_putq(): locked IO -> update_timeout()\n"));
+ scp->SCp.buffers_residual = gdth_update_timeout(scp, 0);
+ }
+#endif
+
+ if (ha->req_first==NULL) {
+ ha->req_first = scp; /* queue was empty */
+ scp->SCp.ptr = NULL;
+ } else { /* queue not empty */
+ pscp = ha->req_first;
+ nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+ /* priority: 0-highest,..,0xff-lowest */
+ while (nscp && (unchar)nscp->SCp.this_residual <= priority) {
+ pscp = nscp;
+ nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+ }
+ pscp->SCp.ptr = (char *)scp;
+ scp->SCp.ptr = (char *)nscp;
+ }
+ restore_flags(flags);
+
+#ifdef GDTH_STATISTICS
+ flags = 0;
+ for (nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr)
+ ++flags;
+ if (max_rq < flags) {
+ max_rq = flags;
+ TRACE3(("GDT: max_rq = %d\n",(ushort)max_rq));
+ }
+#endif
+}
+
+static void gdth_next(int hanum)
+{
+ register gdth_ha_str *ha;
+ register Scsi_Cmnd *pscp;
+ register Scsi_Cmnd *nscp;
+ unchar b, t, next_cmd, firsttime;
+ ushort hdrive;
+ ulong flags;
+ int cmd_index;
+
+ TRACE(("gdth_next() hanum %d\n",hanum));
+ save_flags(flags);
+ cli();
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ ha->cmd_cnt = ha->cmd_offs_dpmem = 0;
+ next_cmd = firsttime = TRUE;
+ cmd_index = 0;
+
+ for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
+ if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
+ pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+#if LINUX_VERSION_CODE >= 0x010400
+ b = nscp->channel;
+#else
+ b = NUMDATA(nscp->host)->busnum;
+#endif
+ t = nscp->target;
+ if (nscp->SCp.this_residual < DEFAULT_PRI || !ha->id[b][t].lock) {
+
+ if (firsttime) {
+ if (gdth_test_busy(hanum)) { /* controller busy ? */
+ TRACE(("gdth_next() controller %d busy !\n",hanum));
+ if (!gdth_polling) {
+ restore_flags(flags);
+ return;
+ }
+ while (gdth_test_busy(hanum))
+ udelay(1000);
+ }
+ firsttime = FALSE;
+ }
+
+#if LINUX_VERSION_CODE >= 0x010300
+ if (nscp->done == gdth_scsi_done) {
+ if (!(cmd_index=gdth_special_cmd(hanum,nscp,b)))
+ next_cmd = FALSE;
+ } else
+#endif
+ if (ha->id[b][t].type != CACHE_DTYP) {
+ if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,b)))
+ next_cmd = FALSE;
+ } else {
+ hdrive = ha->id[b][t].hostdrive;
+ switch (nscp->cmnd[0]) {
+ case TEST_UNIT_READY:
+ case INQUIRY:
+ case REQUEST_SENSE:
+ case READ_CAPACITY:
+ case VERIFY:
+ case START_STOP:
+ case MODE_SENSE:
+ TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
+ nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+ nscp->cmnd[4],nscp->cmnd[5]));
+ gdth_internal_cache_cmd(hanum,nscp,b,&flags);
+ break;
+
+ case ALLOW_MEDIUM_REMOVAL:
+ TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
+ nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+ nscp->cmnd[4],nscp->cmnd[5]));
+ if ( (nscp->cmnd[4]&1) && !(ha->id[b][t].devtype&1) ) {
+ TRACE2(("Prevent r. nonremov. drive->do nothing\n"));
+ nscp->result = DID_OK << 16;
+ restore_flags( flags );
+ nscp->scsi_done(nscp);
+ save_flags( flags );
+ cli();
+ } else {
+ nscp->cmnd[3] = (ha->id[b][t].devtype&1) ? 1:0;
+ TRACE2(("Prevent/allow r. %d rem. drive %d\n",
+ nscp->cmnd[4],nscp->cmnd[3]));
+ if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,hdrive)))
+ next_cmd = FALSE;
+ }
+ break;
+
+ case READ_6:
+ case WRITE_6:
+ case READ_10:
+ case WRITE_10:
+ if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,hdrive)))
+ next_cmd = FALSE;
+ break;
+
+ default:
+ TRACE2(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
+ nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+ nscp->cmnd[4],nscp->cmnd[5]));
+ printk("GDT: Unknown SCSI command 0x%x to cache service !\n",
+ nscp->cmnd[0]);
+ nscp->result = DID_ABORT << 16;
+ restore_flags( flags );
+ nscp->scsi_done( nscp );
+ save_flags( flags );
+ cli();
+ break;
+ }
+ }
+
+ if (!next_cmd)
+ break;
+ if (nscp == ha->req_first)
+ ha->req_first = pscp = (Scsi_Cmnd *)nscp->SCp.ptr;
+ else
+ pscp->SCp.ptr = nscp->SCp.ptr;
+ if (gdth_polling)
+ break;
+ }
+ }
+
+ if (ha->cmd_cnt > 0) {
+ gdth_release_event(hanum);
+ }
+
+ restore_flags(flags);
+
+ if (gdth_polling && ha->cmd_cnt > 0) {
+ if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
+ printk("GDT: Controller %d: Command %d timed out !\n",
+ hanum,cmd_index);
+ }
+}
+
+static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count)
+{
+ ushort cpcount,i;
+ ushort cpsum,cpnow;
+ struct scatterlist *sl;
+
+ cpcount = count<=(ushort)scp->bufflen ? count:(ushort)scp->bufflen;
+ if (scp->use_sg) {
+ sl = (struct scatterlist *)scp->request_buffer;
+ for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) {
+ cpnow = (ushort)sl->length;
+ TRACE(("copy_internal() now %d sum %d count %d %d\n",
+ cpnow,cpsum,cpcount,(ushort)scp->bufflen));
+ if (cpsum+cpnow > cpcount)
+ cpnow = cpcount - cpsum;
+ cpsum += cpnow;
+ memcpy((char*)sl->address,buffer,cpnow);
+ if (cpsum == cpcount)
+ break;
+ buffer += cpnow;
+ }
+ } else {
+ TRACE(("copy_internal() count %d\n",cpcount));
+ memcpy((char*)scp->request_buffer,buffer,cpcount);
+ }
+}
+
+static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp,
+ unchar b,ulong *flags)
+{
+ register gdth_ha_str *ha;
+ ushort hdrive;
+ unchar t;
+ gdth_inq_data inq;
+ gdth_rdcap_data rdc;
+ gdth_sense_data sd;
+ gdth_modep_data mpd;
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ t = scp->target;
+ hdrive = ha->id[b][t].hostdrive;
+ TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
+ scp->cmnd[0],hdrive));
+
+ if (scp->lun !=0)
+ scp->result = DID_BAD_TARGET << 16;
+ else {
+ switch (scp->cmnd[0]) {
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case START_STOP:
+ TRACE2(("Test/Verify/Start hdrive %d\n",hdrive));
+ break;
+
+ case INQUIRY:
+ TRACE2(("Inquiry hdrive %d devtype %d\n",
+ hdrive,ha->id[b][t].devtype));
+ inq.type_qual = (ha->id[b][t].devtype&4) ? TYPE_ROM:TYPE_DISK;
+ /* you can here set all disks to removable, if you want to do
+ a flush using the ALLOW_MEDIUM_REMOVAL command */
+ inq.modif_rmb = ha->id[b][t].devtype&1 ? 0x80:0x00;
+ inq.version = 2;
+ inq.resp_aenc = 2;
+ inq.add_length= 32;
+ strcpy(inq.vendor,"ICP ");
+ sprintf(inq.product,"Host Drive #%02d",hdrive);
+ strcpy(inq.revision," ");
+ gdth_copy_internal_data(scp,(char*)&inq,sizeof(gdth_inq_data));
+ break;
+
+ case REQUEST_SENSE:
+ TRACE2(("Request sense hdrive %d\n",hdrive));
+ sd.errorcode = 0x70;
+ sd.segno = 0x00;
+ sd.key = NO_SENSE;
+ sd.info = 0;
+ sd.add_length= 0;
+ gdth_copy_internal_data(scp,(char*)&sd,sizeof(gdth_sense_data));
+ break;
+
+ case MODE_SENSE:
+ TRACE2(("Mode sense hdrive %d\n",hdrive));
+ memset((char*)&mpd,0,sizeof(gdth_modep_data));
+ mpd.hd.data_length = sizeof(gdth_modep_data);
+ mpd.hd.dev_par = (ha->id[b][t].devtype&2) ? 0x80:0;
+ mpd.hd.bd_length = sizeof(mpd.bd);
+ mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
+ mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
+ mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
+ gdth_copy_internal_data(scp,(char*)&mpd,sizeof(gdth_modep_data));
+ break;
+
+ case READ_CAPACITY:
+ TRACE2(("Read capacity hdrive %d\n",hdrive));
+ rdc.last_block_no = ntohl(ha->id[b][t].size-1);
+ rdc.block_length = ntohl(SECTOR_SIZE);
+ gdth_copy_internal_data(scp,(char*)&rdc,sizeof(gdth_rdcap_data));
+ break;
+
+ default:
+ TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
+ break;
+ }
+ scp->result = DID_OK << 16;
+ }
+
+ restore_flags(*flags);
+ scp->scsi_done(scp);
+ save_flags(*flags);
+ cli();
+ return 1;
+}
+
+static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
+{
+ register gdth_ha_str *ha;
+ register gdth_cmd_str *cmdp;
+ struct scatterlist *sl;
+ ushort i;
+ int cmd_index;
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ cmdp = ha->pccb;
+ TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n",
+ scp->cmnd[0],scp->cmd_len,hdrive));
+
+ if (ha->type==GDT_EISA && ha->cmd_cnt>0)
+ return 0;
+
+ cmdp->Service = CACHESERVICE;
+ cmdp->RequestBuffer = scp;
+ /* search free command index */
+ if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ TRACE(("GDT: No free command index found\n"));
+ return 0;
+ }
+ /* if it's the first command, set command semaphore */
+ if (ha->cmd_cnt == 0)
+ gdth_set_sema0(hanum);
+
+ /* fill command */
+ if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
+ if (scp->cmnd[4] & 1) /* prevent ? */
+ cmdp->OpCode = GDT_MOUNT;
+ else if (scp->cmnd[3] & 1) /* removable drive ? */
+ cmdp->OpCode = GDT_UNMOUNT;
+ else
+ cmdp->OpCode = GDT_FLUSH;
+ } else {
+ if (scp->cmnd[0]==WRITE_6 || scp->cmnd[0]==WRITE_10) {
+ if (gdth_write_through)
+ cmdp->OpCode = GDT_WRITE_THR;
+ else
+ cmdp->OpCode = GDT_WRITE;
+ } else {
+ cmdp->OpCode = GDT_READ;
+ }
+ }
+
+ cmdp->BoardNode = LOCALBOARD;
+ cmdp->u.cache.DeviceNo = hdrive;
+
+ if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
+ cmdp->u.cache.BlockNo = 1;
+ cmdp->u.cache.sg_canz = 0;
+ } else {
+ if (scp->cmd_len != 6) {
+ cmdp->u.cache.BlockNo = ntohl(*(ulong*)&scp->cmnd[2]);
+ cmdp->u.cache.BlockCnt= (ulong)ntohs(*(ushort*)&scp->cmnd[7]);
+ } else {
+ cmdp->u.cache.BlockNo = ntohl(*(ulong*)&scp->cmnd[0]) & 0x001fffffUL;
+ cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
+ }
+
+ if (scp->use_sg) {
+ cmdp->u.cache.DestAddr= -1UL;
+ sl = (struct scatterlist *)scp->request_buffer;
+ for (i=0; i<scp->use_sg; ++i,++sl) {
+ cmdp->u.cache.sg_lst[i].sg_ptr = (ulong)sl->address;
+ cmdp->u.cache.sg_lst[i].sg_len = (ulong)sl->length;
+ }
+ cmdp->u.cache.sg_canz = (ulong)i;
+
+#ifdef GDTH_STATISTICS
+ if (max_sg < (ulong)i) {
+ max_sg = (ulong)i;
+ TRACE3(("GDT: max_sg = %d\n",i));
+ }
+#endif
+ if (i<GDTH_MAXSG)
+ cmdp->u.cache.sg_lst[i].sg_len = 0;
+ } else {
+ if (ha->cache_feat & SCATTER_GATHER) {
+ cmdp->u.cache.DestAddr = -1UL;
+ cmdp->u.cache.sg_canz = 1;
+ cmdp->u.cache.sg_lst[0].sg_ptr = (ulong)scp->request_buffer;
+ cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
+ cmdp->u.cache.sg_lst[1].sg_len = 0;
+ } else {
+ cmdp->u.cache.DestAddr = (ulong)scp->request_buffer;
+ cmdp->u.cache.sg_canz= 0;
+ }
+ }
+ }
+ TRACE(("cache cmd: addr. %lx sganz %lx sgptr0 %lx sglen0 %lx\n",
+ cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
+ cmdp->u.cache.sg_lst[0].sg_ptr,
+ cmdp->u.cache.sg_lst[0].sg_len));
+ TRACE(("cache cmd: cmd %d blockno. %ld, blockcnt %ld\n",
+ cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
+
+ /* evaluate command size, check space */
+ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
+ (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
+ if (ha->cmd_len & 3)
+ ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+ if (ha->cmd_cnt > 0) {
+ if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+ ha->ic_all_size) {
+ TRACE2(("gdth_fill_cache() DPMEM overflow\n"));
+ gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
+ return 0;
+ }
+ }
+
+ /* copy command */
+ gdth_copy_command(hanum);
+ return cmd_index;
+}
+
+static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
+{
+ register gdth_ha_str *ha;
+ register gdth_cmd_str *cmdp;
+ struct scatterlist *sl;
+ ushort i;
+ int cmd_index;
+ unchar t,l;
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ t = scp->target;
+ l = scp->lun;
+ cmdp = ha->pccb;
+ TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n",
+ scp->cmnd[0],b,t,l));
+
+ if (ha->type==GDT_EISA && ha->cmd_cnt>0)
+ return 0;
+
+ cmdp->Service = SCSIRAWSERVICE;
+ cmdp->RequestBuffer = scp;
+ /* search free command index */
+ if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ TRACE(("GDT: No free command index found\n"));
+ return 0;
+ }
+ /* if it's the first command, set command semaphore */
+ if (ha->cmd_cnt == 0)
+ gdth_set_sema0(hanum);
+
+ /* fill command */
+ cmdp->OpCode = GDT_WRITE; /* always */
+ cmdp->BoardNode = LOCALBOARD;
+ cmdp->u.raw.reserved = 0;
+ cmdp->u.raw.mdisc_time = 0;
+ cmdp->u.raw.mcon_time = 0;
+ cmdp->u.raw.clen = scp->cmd_len;
+ cmdp->u.raw.target = t;
+ cmdp->u.raw.lun = l;
+ cmdp->u.raw.bus = b;
+ cmdp->u.raw.priority = 0;
+ cmdp->u.raw.link_p = NULL;
+ cmdp->u.raw.sdlen = scp->request_bufflen;
+ cmdp->u.raw.sense_len = 16;
+ cmdp->u.raw.sense_data = (ulong)scp->sense_buffer;
+ cmdp->u.raw.direction =
+ gdth_direction_tab[scp->cmnd[0]]==DOU ? DATA_OUT : DATA_IN;
+ memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
+
+ if (scp->use_sg) {
+ cmdp->u.raw.sdata = -1UL;
+ sl = (struct scatterlist *)scp->request_buffer;
+ for (i=0; i<scp->use_sg; ++i,++sl) {
+ cmdp->u.raw.sg_lst[i].sg_ptr = (ulong)sl->address;
+ cmdp->u.raw.sg_lst[i].sg_len = (ulong)sl->length;
+ }
+ cmdp->u.raw.sg_ranz = (ulong)i;
+
+#ifdef GDTH_STATISTICS
+ if (max_sg < (ulong)i) {
+ max_sg = (ulong)i;
+ TRACE3(("GDT: max_sg = %d\n",i));
+ }
+#endif
+ if (i<GDTH_MAXSG)
+ cmdp->u.raw.sg_lst[i].sg_len = 0;
+ } else {
+ if (ha->raw_feat & SCATTER_GATHER) {
+ cmdp->u.raw.sdata = -1UL;
+ cmdp->u.raw.sg_ranz= 1;
+ cmdp->u.raw.sg_lst[0].sg_ptr = (ulong)scp->request_buffer;
+ cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
+ cmdp->u.raw.sg_lst[1].sg_len = 0;
+ } else {
+ cmdp->u.raw.sdata = (ulong)scp->request_buffer;
+ cmdp->u.raw.sg_ranz= 0;
+ }
+ }
+ TRACE(("raw cmd: addr. %lx sganz %lx sgptr0 %lx sglen0 %lx\n",
+ cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
+ cmdp->u.raw.sg_lst[0].sg_ptr,
+ cmdp->u.raw.sg_lst[0].sg_len));
+
+ /* evaluate command size, check space */
+ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
+ (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
+ if (ha->cmd_len & 3)
+ ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+ if (ha->cmd_cnt > 0) {
+ if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+ ha->ic_all_size) {
+ TRACE2(("gdth_fill_raw() DPMEM overflow\n"));
+ gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
+ return 0;
+ }
+ }
+
+ /* copy command */
+ gdth_copy_command(hanum);
+ return cmd_index;
+}
+
+static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
+{
+ register gdth_ha_str *ha;
+ register gdth_cmd_str *cmdp;
+ int cmd_index;
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ cmdp= ha->pccb;
+ TRACE2(("gdth_special_cmd(): "));
+
+ if (ha->type==GDT_EISA && ha->cmd_cnt>0)
+ return 0;
+
+ memcpy( cmdp, scp->request_buffer, sizeof(gdth_cmd_str));
+ cmdp->RequestBuffer = scp;
+
+ /* search free command index */
+ if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ TRACE(("GDT: No free command index found\n"));
+ return 0;
+ }
+
+ /* if it's the first command, set command semaphore */
+ if (ha->cmd_cnt == 0)
+ gdth_set_sema0(hanum);
+
+ /* evaluate command size, check space */
+ if (cmdp->OpCode == GDT_IOCTL) {
+ TRACE2(("IOCTL\n"));
+ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong);
+ } else if (cmdp->Service == CACHESERVICE) {
+ TRACE2(("cache command %d\n",cmdp->OpCode));
+ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str);
+ } else if (cmdp->Service == SCSIRAWSERVICE) {
+ TRACE2(("raw command %d/%d\n",cmdp->OpCode,cmdp->u.raw.cmd[0]));
+ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str);
+ }
+
+ if (ha->cmd_len & 3)
+ ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+ if (ha->cmd_cnt > 0) {
+ if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+ ha->ic_all_size) {
+ TRACE2(("gdth_special_cmd() DPMEM overflow\n"));
+ gdth_cmd_tab[cmd_index-2][hanum].cmnd = UNUSED_CMND;
+ return 0;
+ }
+ }
+
+ /* copy command */
+ gdth_copy_command(hanum);
+ return cmd_index;
+}
+
+
+/* Controller event handling functions */
+static gdth_evt_str *gdth_store_event(ushort source, ushort idx,
+ gdth_evt_data *evt)
+{
+ gdth_evt_str *e;
+ ulong flags;
+ struct timeval tv;
+
+ TRACE2(("gdth_store_event() source %d idx %d\n", source, idx));
+ if (source == 0) /* no source -> no event */
+ return 0;
+
+ save_flags(flags);
+ cli();
+ if (ebuffer[elastidx].event_source == source &&
+ ebuffer[elastidx].event_idx == idx &&
+ !memcmp((char *)&ebuffer[elastidx].event_data.eu,
+ (char *)&evt->eu, evt->size)) {
+ e = &ebuffer[elastidx];
+ do_gettimeofday(&tv);
+ e->last_stamp = tv.tv_sec;
+ ++e->same_count;
+ } else {
+ if (ebuffer[elastidx].event_source != 0) { /* entry not free ? */
+ ++elastidx;
+ if (elastidx == MAX_EVENTS)
+ elastidx = 0;
+ if (elastidx == eoldidx) { /* reached mark ? */
+ ++eoldidx;
+ if (eoldidx == MAX_EVENTS)
+ eoldidx = 0;
+ }
+ }
+ e = &ebuffer[elastidx];
+ e->event_source = source;
+ e->event_idx = idx;
+ do_gettimeofday(&tv);
+ e->first_stamp = e->last_stamp = tv.tv_sec;
+ e->same_count = 1;
+ e->event_data = *evt;
+ }
+ restore_flags(flags);
+ return e;
+}
+
+static int gdth_read_event(int handle, gdth_evt_str *estr)
+{
+ gdth_evt_str *e;
+ int eindex;
+ ulong flags;
+
+ TRACE2(("gdth_read_event() handle %d\n", handle));
+ save_flags(flags);
+ cli();
+ if (handle == -1)
+ eindex = eoldidx;
+ else
+ eindex = handle;
+ estr->event_source = 0;
+
+ if (eindex >= MAX_EVENTS) {
+ restore_flags(flags);
+ return eindex;
+ }
+ e = &ebuffer[eindex];
+ if (e->event_source != 0) {
+ if (eindex != elastidx) {
+ if (++eindex == MAX_EVENTS)
+ eindex = 0;
+ } else {
+ eindex = -1;
+ }
+ memcpy(estr, e, sizeof(gdth_evt_str));
+ }
+ restore_flags(flags);
+ return eindex;
+}
+
+static void gdth_readapp_event(unchar application, gdth_evt_str *estr)
+{
+ gdth_evt_str *e;
+ int eindex;
+ ulong flags;
+ unchar found = FALSE;
+
+ TRACE2(("gdth_readapp_event() app. %d\n", application));
+ save_flags(flags);
+ cli();
+ eindex = eoldidx;
+ for (;;) {
+ e = &ebuffer[eindex];
+ if (e->event_source == 0)
+ break;
+ if ((e->application & application) == 0) {
+ e->application |= application;
+ found = TRUE;
+ break;
+ }
+ if (eindex == elastidx)
+ break;
+ if (++eindex == MAX_EVENTS)
+ eindex = 0;
+ }
+ if (found)
+ memcpy(estr, e, sizeof(gdth_evt_str));
+ else
+ estr->event_source = 0;
+ restore_flags(flags);
+}
+
+static void gdth_clear_events()
+{
+ ulong flags;
+
+ TRACE(("gdth_clear_events()"));
+ save_flags(flags);
+ cli();
+
+ eoldidx = elastidx = 0;
+ ebuffer[0].event_source = 0;
+ restore_flags(flags);
+}
+
+
+/* SCSI interface functions */
+
+#if LINUX_VERSION_CODE >= 0x010346
+static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+#else
+static void gdth_interrupt(int irq,struct pt_regs *regs)
+#endif
+{
+ register gdth_ha_str *ha;
+ gdt6m_dpram_str *dp6m_ptr;
+ gdt6_dpram_str *dp6_ptr;
+ gdt2_dpram_str *dp2_ptr;
+ Scsi_Cmnd *scp;
+ int hanum;
+ unchar IStatus;
+ ushort CmdStatus, Service = 0;
+ ulong InfoBytes, InfoBytes2 = 0;
+ gdth_evt_data dvr;
+
+ TRACE(("gdth_interrupt() IRQ %d\n",irq));
+
+ /* if polling and not from gdth_wait() -> return */
+ if (gdth_polling) {
+ if (!gdth_from_wait) {
+ return;
+ }
+ }
+
+ wait_index = 0;
+
+ /* search controller */
+ if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
+ /*
+ TRACE2(("gdth_interrupt(): Spurious interrupt received\n"));
+ */
+ return;
+ }
+
+#ifdef GDTH_STATISTICS
+ ++act_ints;
+#endif
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ if (ha->type == GDT_EISA) {
+ if (IStatus & 0x80) { /* error flag */
+ IStatus &= ~0x80;
+ CmdStatus = inw((ushort)ha->brd+MAILBOXREG+8);
+ TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+ if (IStatus == ASYNCINDEX) { /* async. event ? */
+ Service = inw((ushort)ha->brd+MAILBOXREG+10);
+ InfoBytes2 = inl((ushort)ha->brd+MAILBOXREG+4);
+ }
+ } else /* no error */
+ CmdStatus = S_OK;
+ InfoBytes = inl((ushort)ha->brd+MAILBOXREG+12);
+ outb(0xff,(ushort)ha->brd+EDOORREG); /* acknowledge interrupt */
+ outb(0x00,(ushort)ha->brd+SEMA1REG); /* reset status semaphore */
+ } else if (ha->type == GDT_ISA) {
+ dp2_ptr = (gdt2_dpram_str *)ha->brd;
+ if (IStatus & 0x80) { /* error flag */
+ IStatus &= ~0x80;
+ CmdStatus = dp2_ptr->u.ic.Status;
+ TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+ if (IStatus == ASYNCINDEX) { /* async. event ? */
+ Service = dp2_ptr->u.ic.Service;
+ InfoBytes2 = dp2_ptr->u.ic.Info[1];
+ }
+ } else /* no error */
+ CmdStatus = S_OK;
+ InfoBytes = dp2_ptr->u.ic.Info[0];
+ dp2_ptr->io.irqdel = 0xff; /* acknowledge interrupt */
+ dp2_ptr->u.ic.Cmd_Index = 0; /* reset command index */
+ dp2_ptr->io.Sema1 = 0; /* reset status semaphore */
+ } else if (ha->type == GDT_PCI) {
+ dp6_ptr = (gdt6_dpram_str *)ha->brd;
+ if (IStatus & 0x80) { /* error flag */
+ IStatus &= ~0x80;
+ CmdStatus = dp6_ptr->u.ic.Status;
+ TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+ if (IStatus == ASYNCINDEX) { /* async. event ? */
+ Service = dp6_ptr->u.ic.Service;
+ InfoBytes2 = dp6_ptr->u.ic.Info[1];
+ }
+ } else /* no error */
+ CmdStatus = S_OK;
+ InfoBytes = dp6_ptr->u.ic.Info[0];
+ dp6_ptr->io.irqdel = 0xff; /* acknowledge interrupt */
+ dp6_ptr->u.ic.Cmd_Index = 0; /* reset command index */
+ dp6_ptr->io.Sema1 = 0; /* reset status semaphore */
+ } else if (ha->type == GDT_PCINEW) {
+ if (IStatus & 0x80) { /* error flag */
+ IStatus &= ~0x80;
+ CmdStatus = inw(PTR2USHORT(&ha->plx->status));
+ TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+ if (IStatus == ASYNCINDEX) { /* async. event ? */
+ Service = inw(PTR2USHORT(&ha->plx->service));
+ InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
+ }
+ } else
+ CmdStatus = S_OK;
+
+ InfoBytes = inl(PTR2USHORT(&ha->plx->info[0]));
+ outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
+ outb(0x00,PTR2USHORT(&ha->plx->sema1_reg));
+ } else if (ha->type == GDT_PCIMPR) {
+ dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+ if (IStatus & 0x80) { /* error flag */
+ IStatus &= ~0x80;
+ CmdStatus = dp6m_ptr->i960r.status;
+ TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
+ if (IStatus == ASYNCINDEX) { /* async. event ? */
+ Service = dp6m_ptr->i960r.service;
+ InfoBytes2 = dp6m_ptr->i960r.info[1];
+ }
+ } else /* no error */
+ CmdStatus = S_OK;
+ InfoBytes = dp6m_ptr->i960r.info[0];
+ dp6m_ptr->i960r.edoor_reg = 0xff;
+ dp6m_ptr->i960r.sema1_reg = 0;
+ } else {
+ TRACE2(("gdth_interrupt() unknown controller type\n"));
+ return;
+ }
+
+ TRACE(("gdth_interrupt() index %d stat %d info %ld\n",
+ IStatus,CmdStatus,InfoBytes));
+ ha->status = CmdStatus;
+ ha->info = InfoBytes;
+ ha->info2 = InfoBytes2;
+
+ if (gdth_from_wait) {
+ wait_hanum = hanum;
+ wait_index = (int)IStatus;
+ }
+
+ if (IStatus == ASYNCINDEX) {
+ TRACE2(("gdth_interrupt() async. event\n"));
+ gdth_async_event(hanum,Service);
+ } else {
+ if (IStatus == SPEZINDEX) {
+ TRACE2(("Service unknown or not initialized !\n"));
+ dvr.size = sizeof(dvr.eu.driver);
+ dvr.eu.driver.ionode = hanum;
+ gdth_store_event(ES_DRIVER, 4, &dvr);
+ return;
+ }
+ scp = gdth_cmd_tab[IStatus-2][hanum].cmnd;
+ Service = gdth_cmd_tab[IStatus-2][hanum].service;
+ gdth_cmd_tab[IStatus-2][hanum].cmnd = UNUSED_CMND;
+ if (scp == UNUSED_CMND) {
+ TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
+ dvr.size = sizeof(dvr.eu.driver);
+ dvr.eu.driver.ionode = hanum;
+ dvr.eu.driver.index = IStatus;
+ gdth_store_event(ES_DRIVER, 1, &dvr);
+ return;
+ }
+ if (scp == INTERNAL_CMND) {
+ TRACE(("gdth_interrupt() answer to internal command\n"));
+ return;
+ }
+ TRACE(("gdth_interrupt() sync. status\n"));
+ gdth_sync_event(hanum,Service,IStatus,scp);
+ }
+ gdth_next(hanum);
+}
+
+static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
+{
+ register gdth_ha_str *ha;
+ gdth_msg_str *msg;
+ gdth_cmd_str *cmdp;
+ char c='\r';
+ ushort i;
+ gdth_evt_data dvr;
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ cmdp = ha->pccb;
+ TRACE(("gdth_sync_event() scp %lx serv %d status %d\n",
+ (ulong)scp,service,ha->status));
+
+ if (service == SCREENSERVICE) {
+ msg = (gdth_msg_str *)ha->pscratch;
+ TRACE(("len: %ld, answer: %d, ext: %d, alen: %ld\n",
+ msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen));
+ if (msg->msg_len)
+ if (!(msg->msg_answer && msg->msg_ext)) {
+ msg->msg_text[msg->msg_len] = '\0';
+ printk("%s",msg->msg_text);
+ }
+
+ if (msg->msg_ext && !msg->msg_answer) {
+ while (gdth_test_busy(hanum))
+ udelay(1);
+ cmdp->Service = SCREENSERVICE;
+ cmdp->RequestBuffer = SCREEN_CMND;
+ gdth_get_cmd_index(hanum);
+ gdth_set_sema0(hanum);
+ cmdp->OpCode = GDT_READ;
+ cmdp->BoardNode = LOCALBOARD;
+ cmdp->u.screen.reserved = 0;
+ cmdp->u.screen.msg_handle= msg->msg_handle;
+ cmdp->u.screen.msg_addr = (ulong)msg;
+ ha->cmd_offs_dpmem = 0;
+ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr)
+ + sizeof(ulong);
+ ha->cmd_cnt = 0;
+ gdth_copy_command(hanum);
+ gdth_release_event(hanum);
+ return 1;
+ }
+
+ if (msg->msg_answer && msg->msg_alen) {
+ for (i=0; i<msg->msg_alen && i<MSGLEN; ++i) {
+ /* getchar() ?? */
+ /* .. */
+ if (c == '\r')
+ break;
+ msg->msg_text[i] = c;
+ }
+ msg->msg_alen -= i;
+ if (c!='\r' && msg->msg_alen!=0) {
+ msg->msg_answer = 1;
+ msg->msg_ext = 1;
+ } else {
+ msg->msg_ext = 0;
+ msg->msg_answer = 0;
+ }
+ msg->msg_len = i;
+ while (gdth_test_busy(hanum))
+ udelay(1);
+ cmdp->Service = SCREENSERVICE;
+ cmdp->RequestBuffer = SCREEN_CMND;
+ gdth_get_cmd_index(hanum);
+ gdth_set_sema0(hanum);
+ cmdp->OpCode = GDT_WRITE;
+ cmdp->BoardNode = LOCALBOARD;
+ cmdp->u.screen.reserved = 0;
+ cmdp->u.screen.msg_handle= msg->msg_handle;
+ cmdp->u.screen.msg_addr = (ulong)msg;
+ ha->cmd_offs_dpmem = 0;
+ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr)
+ + sizeof(ulong);
+ ha->cmd_cnt = 0;
+ gdth_copy_command(hanum);
+ gdth_release_event(hanum);
+ return 1;
+ }
+ printk("\n");
+
+ } else {
+ scp->SCp.Message = (int)ha->status;
+ /* cache or raw service */
+ if (ha->status == S_OK) {
+ scp->result = DID_OK << 16;
+ } else if (ha->status == S_BSY) {
+ TRACE2(("Controller busy -> retry !\n"));
+ gdth_putq(hanum,scp,DEFAULT_PRI);
+ return 1;
+ } else {
+ if (service == CACHESERVICE) {
+ memset((char*)scp->sense_buffer,0,16);
+ scp->sense_buffer[0] = 0x70;
+ scp->sense_buffer[2] = NOT_READY;
+ scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+
+ if (scp->done != gdth_scsi_done) {
+ dvr.size = sizeof(dvr.eu.sync);
+ dvr.eu.sync.ionode = hanum;
+ dvr.eu.sync.service = service;
+ dvr.eu.sync.status = ha->status;
+ dvr.eu.sync.info = ha->info;
+ dvr.eu.sync.hostdrive =
+#if LINUX_VERSION_CODE >= 0x010400
+ ha->id[scp->channel][scp->target].hostdrive;
+#else
+ ha->id[NUMDATA(scp->host)->busnum][scp->target].hostdrive;
+#endif
+ if (ha->status >= 0x8000)
+ gdth_store_event(ES_SYNC, 0, &dvr);
+ else
+ gdth_store_event(ES_SYNC, service, &dvr);
+ }
+ } else {
+ if (ha->status!=S_RAW_SCSI || ha->status==S_RAW_ILL) {
+ scp->result = DID_BAD_TARGET << 16;
+ } else {
+ scp->result = (DID_OK << 16) | ha->info;
+ }
+ }
+ }
+ scp->SCp.have_data_in++;
+ scp->scsi_done(scp);
+ }
+
+ return 1;
+}
+
+static char *async_cache_tab[] = {
+/* 0*/ "\011\000\002\002\002\004\002\006\004"
+ "GDT HA %u, service %u, async. status %u/%lu unknown",
+/* 1*/ "\011\000\002\002\002\004\002\006\004"
+ "GDT HA %u, service %u, async. status %u/%lu unknown",
+/* 2*/ "\005\000\002\006\004"
+ "GDT HA %u, Host Drive %lu not ready",
+/* 3*/ "\005\000\002\006\004"
+ "GDT HA %u, Host Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced",
+/* 4*/ "\005\000\002\006\004"
+ "GDT HA %u, mirror update on Host Drive %lu failed",
+/* 5*/ "\005\000\002\006\004"
+ "GDT HA %u, Mirror Drive %lu failed",
+/* 6*/ "\005\000\002\006\004"
+ "GDT HA %u, Mirror Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced",
+/* 7*/ "\005\000\002\006\004"
+ "GDT HA %u, Host Drive %lu write protected",
+/* 8*/ "\005\000\002\006\004"
+ "GDT HA %u, media changed in Host Drive %lu",
+/* 9*/ "\005\000\002\006\004"
+ "GDT HA %u, Host Drive %lu is offline",
+/*10*/ "\005\000\002\006\004"
+ "GDT HA %u, media change of Mirror Drive %lu",
+/*11*/ "\005\000\002\006\004"
+ "GDT HA %u, Mirror Drive %lu is write protected",
+/*12*/ "\005\000\002\006\004"
+ "GDT HA %u, general error on Host Drive %lu. Please check the devices of this drive!",
+/*13*/ "\007\000\002\006\002\010\002"
+ "GDT HA %u, Array Drive %u: Cache Drive %u failed",
+/*14*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: FAIL state entered",
+/*15*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: error",
+/*16*/ "\007\000\002\006\002\010\002"
+ "GDT HA %u, Array Drive %u: failed drive replaced by Cache Drive %u",
+/*17*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: parity build failed",
+/*18*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: drive rebuild failed",
+/*19*/ "\007\000\002\010\002"
+ "GDT HA %u, Test of Hot Fix %u failed",
+/*20*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: drive build finished successfully",
+/*21*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: drive rebuild finished successfully",
+/*22*/ "\007\000\002\006\002\010\002"
+ "GDT HA %u, Array Drive %u: Hot Fix %u activated",
+/*23*/ "\005\000\002\006\002"
+ "GDT HA %u, Host Drive %u: processing of i/o aborted due to serious drive error",
+/*24*/ "\005\000\002\010\002"
+ "GDT HA %u, mirror update on Cache Drive %u completed",
+/*25*/ "\005\000\002\010\002"
+ "GDT HA %u, mirror update on Cache Drive %lu failed",
+/*26*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: drive rebuild started",
+/*27*/ "\005\000\002\012\001"
+ "GDT HA %u, Fault bus %u: SHELF OK detected",
+/*28*/ "\005\000\002\012\001"
+ "GDT HA %u, Fault bus %u: SHELF not OK detected",
+/*29*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug started",
+/*30*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: new disk detected",
+/*31*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: old disk detected",
+/*32*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is illegal",
+/*33*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: illegal device detected",
+/*34*/ "\011\000\002\012\001\013\001\006\004"
+ "GDT HA %u, Fault bus %u, ID %u: insufficient disk capacity (%lu MB required)",
+/*35*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: disk write protected",
+/*36*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: disk not available",
+/*37*/ "\007\000\002\012\001\006\004"
+ "GDT HA %u, Fault bus %u: swap detected (%lu)",
+/*38*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug finished successfully",
+/*39*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted due to user Hot Plug",
+/*40*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted",
+/*41*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug for Hot Fix started",
+/*42*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: drive build started",
+/*43*/ "\003\000\002"
+ "GDT HA %u, DRAM parity error detected",
+/*44*/ "\005\000\002\006\002"
+ "GDT HA %u, Mirror Drive %u: update started",
+/*45*/ "\007\000\002\006\002\010\002"
+ "GDT HA %u, Mirror Drive %u: Hot Fix %u activated",
+/*46*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: no matching Pool Hot Fix Drive available",
+/*47*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: Pool Hot Fix Drive available",
+/*48*/ "\005\000\002\006\002"
+ "GDT HA %u, Mirror Drive %u: no matching Pool Hot Fix Drive available",
+/*49*/ "\005\000\002\006\002"
+ "GDT HA %u, Mirror Drive %u: Pool Hot Fix Drive available",
+/*50*/ "\007\000\002\012\001\013\001"
+ "GDT HA %u, SCSI bus %u, ID %u: IGNORE_WIDE_RESIDUE message received",
+/*51*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: expand started",
+/*52*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: expand finished successfully",
+/*53*/ "\005\000\002\006\002"
+ "GDT HA %u, Array Drive %u: expand failed",
+/*54*/ "\003\000\002"
+ "GDT HA %u, CPU temperature critical",
+/*55*/ "\003\000\002"
+ "GDT HA %u, CPU temperature OK",
+};
+
+
+static int gdth_async_event(int hanum,int service)
+{
+ gdth_stackframe stack;
+ gdth_evt_data dvr;
+ char *f = NULL;
+ int i,j;
+ gdth_ha_str *ha;
+ gdth_msg_str *msg;
+ gdth_cmd_str *cmdp;
+ int cmd_index;
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ cmdp= ha->pccb;
+ msg = (gdth_msg_str *)ha->pscratch;
+ TRACE2(("gdth_async_event() ha %d serv %d\n",
+ hanum,service));
+
+ if (service == SCREENSERVICE) {
+ if (ha->status == MSG_REQUEST) {
+ while (gdth_test_busy(hanum))
+ udelay(1);
+ cmdp->Service = SCREENSERVICE;
+ cmdp->RequestBuffer = SCREEN_CMND;
+ cmd_index = gdth_get_cmd_index(hanum);
+ gdth_set_sema0(hanum);
+ cmdp->OpCode = GDT_READ;
+ cmdp->BoardNode = LOCALBOARD;
+ cmdp->u.screen.reserved = 0;
+ cmdp->u.screen.msg_handle= MSG_INV_HANDLE;
+ cmdp->u.screen.msg_addr = (ulong)msg;
+ ha->cmd_offs_dpmem = 0;
+ ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr)
+ + sizeof(ulong);
+ ha->cmd_cnt = 0;
+ gdth_copy_command(hanum);
+ if (ha->type == GDT_EISA)
+ printk("[EISA slot %d] ",(ushort)ha->brd_phys);
+ else if (ha->type == GDT_ISA)
+ printk("[DPMEM 0x%4X] ",(ushort)ha->brd_phys);
+ else
+ printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8),
+ (ushort)((ha->brd_phys>>3)&0x1f));
+ gdth_release_event(hanum);
+ }
+
+ } else {
+ dvr.size = sizeof(dvr.eu.async);
+ dvr.eu.async.ionode = hanum;
+ dvr.eu.async.service = service;
+ dvr.eu.async.status = ha->status;
+ dvr.eu.async.info = ha->info;
+ *(ulong *)dvr.eu.async.scsi_coord = ha->info2;
+ gdth_store_event(ES_ASYNC, service, &dvr);
+
+ if (service==CACHESERVICE && INDEX_OK(ha->status,async_cache_tab)) {
+ TRACE2(("GDT: Async. event cache service, event no.: %d\n",
+ ha->status));
+
+ f = async_cache_tab[ha->status];
+
+ /* i: parameter to push, j: stack element to fill */
+ for (j=0,i=1; i < f[0]; i+=2) {
+ switch (f[i+1]) {
+ case 4:
+ stack.b[j++] = *(ulong*)&dvr.eu.stream[(int)f[i]];
+ break;
+ case 2:
+ stack.b[j++] = *(ushort*)&dvr.eu.stream[(int)f[i]];
+ break;
+ case 1:
+ stack.b[j++] = *(unchar*)&dvr.eu.stream[(int)f[i]];
+ break;
+ default:
+ break;
+ }
+ }
+
+ printk(&f[f[0]],stack); printk("\n");
+
+ } else {
+ printk("GDT: Unknown async. event service %d event no. %d\n",
+ service,ha->status);
+ }
+ }
+ return 1;
+}
+
+#ifdef GDTH_STATISTICS
+void gdth_timeout(void)
+{
+ ulong flags,i;
+ Scsi_Cmnd *nscp;
+ gdth_ha_str *ha;
+ int hanum = 0;
+
+ save_flags(flags);
+ cli();
+
+ for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i)
+ if (gdth_cmd_tab[i][hanum].cmnd != UNUSED_CMND)
+ ++act_stats;
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ for (act_rq=0,nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr)
+ ++act_rq;
+
+ TRACE2(("gdth_to(): ints %ld, ios %ld, act_stats %ld, act_rq %ld\n",
+ act_ints, act_ios, act_stats, act_rq));
+ act_ints = act_ios = 0;
+
+ timer_table[GDTH_TIMER].expires = jiffies + 30*HZ;
+ timer_active |= 1<<GDTH_TIMER;
+ sti();
+}
+#endif
+
+int gdth_detect(Scsi_Host_Template *shtp)
+{
+ struct Scsi_Host *shp;
+ gdth_ha_str *ha;
+ unsigned long flags;
+ ulong isa_bios;
+ ushort eisa_slot,device_id,index;
+ gdth_pci_str pcistr;
+ int i,j,hanum;
+ unchar b;
+
+
+#ifdef DEBUG_GDTH
+ printk("GDT: This driver contains debugging information !! Trace level = %d\n",
+ DebugState);
+ printk(" Destination of debugging information: ");
+#ifdef __SERIAL__
+#ifdef __COM2__
+ printk("Serial port COM2\n");
+#else
+ printk("Serial port COM1\n");
+#endif
+#else
+ printk("Console\n");
+#endif
+ WAITSEC(3);
+#endif
+
+ TRACE(("gdth_detect()\n"));
+
+ if (disable_gdth_scan) {
+ printk("GDT: Controller driver disabled from command line !\n");
+ return 0;
+ }
+
+ /* initializations */
+ gdth_polling = TRUE; b = 0;
+ for (i=0; i<GDTH_MAXCMDS; ++i)
+ for (j=0; j<MAXHA; ++j)
+ gdth_cmd_tab[i][j].cmnd = UNUSED_CMND;
+ for (i=0; i<4; ++i)
+ for (j=0; j<MAXHA; ++j)
+ gdth_ioctl_tab[i][j] = NULL;
+ gdth_clear_events();
+
+ /* scanning for controllers, at first: ISA controller */
+ for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
+ if (gdth_search_isa(isa_bios)) { /* controller found */
+ shp = scsi_register(shtp,sizeof(gdth_ext_str));
+ ha = HADATA(shp);
+ if (!gdth_init_isa(isa_bios,ha,TRUE)) {
+ scsi_unregister(shp);
+ continue;
+ }
+ /* controller found and initialized */
+ printk("Configuring GDT-ISA HA at BIOS 0x%05lX IRQ %u DRQ %u\n",
+ isa_bios,ha->irq,ha->drq);
+
+ save_flags(flags);
+ cli();
+#if LINUX_VERSION_CODE >= 0x010346
+ if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#else
+ if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth"))
+#endif
+ {
+ printk("GDT-ISA: Unable to allocate IRQ\n");
+ restore_flags(flags);
+ scsi_unregister(shp);
+ continue;
+ }
+ if (request_dma(ha->drq,"gdth")) {
+ printk("GDT-ISA: Unable to allocate DMA channel\n");
+#if LINUX_VERSION_CODE >= 0x010346
+ free_irq(ha->irq,NULL);
+#else
+ free_irq(ha->irq);
+#endif
+ restore_flags(flags);
+ scsi_unregister(shp);
+ continue;
+ }
+ set_dma_mode(ha->drq,DMA_MODE_CASCADE);
+ enable_dma(ha->drq);
+ shp->unchecked_isa_dma = 1;
+ shp->irq = ha->irq;
+ shp->dma_channel = ha->drq;
+ for (i=0; i<MAXID; ++i) {
+ if (ha->id[0][i].type==SIOP_DTYP) {
+ shp->this_id = i;
+ break;
+ }
+ }
+ hanum = gdth_ctr_count;
+ gdth_ctr_tab[gdth_ctr_count++] = shp;
+ gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+ NUMDATA(shp)->hanum = (ushort)hanum;
+ NUMDATA(shp)->busnum= 0;
+
+ ha->pccb = CMDDATA(shp);
+ ha->pscratch = DMADATA(shp);
+ ha->req_first = NULL;
+ for (i=0; i<MAXBUS; ++i) {
+ for (j=0; j<MAXID; ++j) {
+ ha->id[i][j].type = EMPTY_DTYP;
+ ha->id[i][j].lock = 0;
+ }
+ }
+ restore_flags(flags);
+
+ if (!gdth_search_drives(hanum,TRUE)) {
+ printk("GDT-ISA: Error during device scan\n");
+ --gdth_ctr_count;
+ save_flags(flags);
+ cli();
+#if LINUX_VERSION_CODE >= 0x010346
+ free_irq(ha->irq,NULL);
+#else
+ free_irq(ha->irq);
+#endif
+ restore_flags(flags);
+ scsi_unregister(shp);
+ continue;
+ }
+
+#if LINUX_VERSION_CODE >= 0x010400
+ shp->max_id = 8;
+ shp->max_lun = 8;
+ shp->max_channel = ha->bus_cnt - 1;
+#else
+ /* register addit. SCSI channels as virtual controllers */
+ for (b=1; b<ha->bus_cnt; ++b) {
+ shp = scsi_register(shtp,sizeof(gdth_num_str));
+ shp->unchecked_isa_dma = 1;
+ shp->irq = ha->irq;
+ shp->dma_channel = ha->drq;
+ for (i=0; i<MAXID; ++i) {
+ if (ha->id[b][i].type==SIOP_DTYP) {
+ shp->this_id = i;
+ break;
+ }
+ }
+ gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+ NUMDATA(shp)->hanum = (ushort)hanum;
+ NUMDATA(shp)->busnum = b;
+ }
+#endif
+
+ gdth_enable_int(hanum);
+ }
+ }
+
+ /* scanning for EISA controllers */
+ for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
+ if (gdth_search_eisa(eisa_slot)) { /* controller found */
+ shp = scsi_register(shtp,sizeof(gdth_ext_str));
+ ha = HADATA(shp);
+ if (!gdth_init_eisa(eisa_slot,ha,TRUE)) {
+ scsi_unregister(shp);
+ continue;
+ }
+ /* controller found and initialized */
+ printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
+ eisa_slot>>12,ha->irq);
+
+ save_flags(flags);
+ cli();
+#if LINUX_VERSION_CODE >= 0x010346
+ if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#else
+ if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth"))
+#endif
+ {
+ printk("GDT-EISA: Unable to allocate IRQ\n");
+ restore_flags(flags);
+ scsi_unregister(shp);
+ continue;
+ }
+ shp->unchecked_isa_dma = 0;
+ shp->irq = ha->irq;
+ shp->dma_channel = 0xff;
+ for (i=0; i<MAXID; ++i) {
+ if (ha->id[0][i].type==SIOP_DTYP) {
+ shp->this_id = i;
+ break;
+ }
+ }
+ hanum = gdth_ctr_count;
+ gdth_ctr_tab[gdth_ctr_count++] = shp;
+ gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+ NUMDATA(shp)->hanum = (ushort)hanum;
+ NUMDATA(shp)->busnum= 0;
+ TRACE2(("EISA detect Bus 0: shp %lx hanum %d\n",
+ (ulong)shp,NUMDATA(shp)->hanum));
+
+ ha->pccb = CMDDATA(shp);
+ ha->pscratch = DMADATA(shp);
+ ha->req_first = NULL;
+ for (i=0; i<MAXBUS; ++i) {
+ for (j=0; j<MAXID; ++j) {
+ ha->id[i][j].type = EMPTY_DTYP;
+ ha->id[i][j].lock = 0;
+ }
+ }
+ restore_flags(flags);
+
+ if (!gdth_search_drives(hanum,TRUE)) {
+ printk("GDT-EISA: Error during device scan\n");
+ --gdth_ctr_count;
+ save_flags(flags);
+ cli();
+#if LINUX_VERSION_CODE >= 0x010346
+ free_irq(ha->irq,NULL);
+#else
+ free_irq(ha->irq);
+#endif
+ restore_flags(flags);
+ scsi_unregister(shp);
+ continue;
+ }
+
+#if LINUX_VERSION_CODE >= 0x010400
+ shp->max_id = 8;
+ shp->max_lun = 8;
+ shp->max_channel = ha->bus_cnt - 1;
+#else
+ /* register addit. SCSI channels as virtual controllers */
+ for (b=1; b<ha->bus_cnt; ++b) {
+ shp = scsi_register(shtp,sizeof(gdth_num_str));
+ shp->unchecked_isa_dma = 0;
+ shp->irq = ha->irq;
+ shp->dma_channel = 0xff;
+ for (i=0; i<MAXID; ++i) {
+ if (ha->id[b][i].type==SIOP_DTYP) {
+ shp->this_id = i;
+ break;
+ }
+ }
+ gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+ NUMDATA(shp)->hanum = (ushort)hanum;
+ NUMDATA(shp)->busnum = b;
+ TRACE2(("EISA detect Bus %d: shp %lx hanum %d\n",
+ NUMDATA(shp)->busnum,(ulong)shp,
+ NUMDATA(shp)->hanum));
+ }
+#endif
+
+ gdth_enable_int(hanum);
+ }
+ }
+
+ /* scanning for PCI controllers */
+ for (device_id = 0; device_id <= PCI_DEVICE_ID_VORTEX_GDT6x21RP2; ++device_id) {
+ if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 &&
+ device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP)
+ continue;
+ for (index = 0; ; ++index) {
+ if (!gdth_search_pci(device_id,index,&pcistr))
+ break; /* next device_id */
+ shp = scsi_register(shtp,sizeof(gdth_ext_str));
+ ha = HADATA(shp);
+ if (!gdth_init_pci(&pcistr,ha,TRUE)) {
+ scsi_unregister(shp);
+ continue;
+ }
+ /* controller found and initialized */
+ printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+ pcistr.bus,pcistr.device_fn>>3,ha->irq);
+
+ save_flags(flags);
+ cli();
+#if LINUX_VERSION_CODE >= 0x010346
+ if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",NULL))
+#else
+ if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth"))
+#endif
+ {
+ printk("GDT-PCI: Unable to allocate IRQ\n");
+ restore_flags(flags);
+ scsi_unregister(shp);
+ continue;
+ }
+ shp->unchecked_isa_dma = 0;
+ shp->irq = ha->irq;
+ shp->dma_channel = 0xff;
+ for (i=0; i<MAXID; ++i) {
+ if (ha->id[0][i].type==SIOP_DTYP) {
+ shp->this_id = i;
+ break;
+ }
+ }
+ hanum = gdth_ctr_count;
+ gdth_ctr_tab[gdth_ctr_count++] = shp;
+ gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+ NUMDATA(shp)->hanum = (ushort)hanum;
+ NUMDATA(shp)->busnum= 0;
+
+ ha->pccb = CMDDATA(shp);
+ ha->pscratch = DMADATA(shp);
+ ha->req_first = NULL;
+ for (i=0; i<MAXBUS; ++i) {
+ for (j=0; j<MAXID; ++j) {
+ ha->id[i][j].type = EMPTY_DTYP;
+ ha->id[i][j].lock = 0;
+ }
+ }
+ restore_flags(flags);
+
+ if (!gdth_search_drives(hanum,TRUE)) {
+ printk("GDT-PCI: Error during device scan\n");
+ --gdth_ctr_count;
+ save_flags(flags);
+ cli();
+#if LINUX_VERSION_CODE >= 0x010346
+ free_irq(ha->irq,NULL);
+#else
+ free_irq(ha->irq);
+#endif
+ restore_flags(flags);
+ scsi_unregister(shp);
+ continue;
+ }
+
+#if LINUX_VERSION_CODE >= 0x010400
+ shp->max_id = 8;
+ shp->max_lun = 8;
+ shp->max_channel = ha->bus_cnt - 1;
+#else
+ /* register addit. SCSI channels as virtual controllers */
+ for (b=1; b<ha->bus_cnt; ++b) {
+ shp = scsi_register(shtp,sizeof(gdth_num_str));
+ shp->unchecked_isa_dma = 0;
+ shp->irq = ha->irq;
+ shp->dma_channel = 0xff;
+ for (i=0; i<MAXID; ++i) {
+ if (ha->id[b][i].type==SIOP_DTYP) {
+ shp->this_id = i;
+ break;
+ }
+ }
+ gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+ NUMDATA(shp)->hanum = (ushort)hanum;
+ NUMDATA(shp)->busnum = b;
+ }
+#endif
+
+ gdth_enable_int(hanum);
+ }
+ }
+
+ TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
+
+#ifdef GDTH_STATISTICS
+ TRACE2(("gdth_detect(): Initializing timer !\n"));
+ timer_table[GDTH_TIMER].fn = gdth_timeout;
+ timer_table[GDTH_TIMER].expires = jiffies + HZ;
+ timer_active |= 1<<GDTH_TIMER;
+#endif
+
+ gdth_polling = FALSE;
+ return gdth_ctr_vcount;
+}
+
+
+int gdth_release(struct Scsi_Host *shp)
+{
+ unsigned long flags;
+
+ TRACE2(("gdth_release()\n"));
+
+ save_flags(flags);
+ cli();
+ if (NUMDATA(shp)->busnum == 0) {
+ if (shp->irq) {
+#if LINUX_VERSION_CODE >= 0x010346
+ free_irq(shp->irq,NULL);
+#else
+ free_irq(shp->irq);
+#endif
+ }
+ if (shp->dma_channel != 0xff) {
+ free_dma(shp->dma_channel);
+ }
+ }
+
+ restore_flags(flags);
+ scsi_unregister(shp);
+ return 0;
+}
+
+
+static const char *gdth_ctr_name(int hanum)
+{
+ gdth_ha_str *ha;
+
+ TRACE2(("gdth_ctr_name()\n"));
+
+ ha = HADATA(gdth_ctr_tab[hanum]);
+
+ if (ha->type == GDT_EISA) {
+ switch (ha->stype) {
+ case GDT3_ID:
+ return("GDT3000/3020 (EISA)");
+ case GDT3A_ID:
+ return("GDT3000A/3020A/3050A (EISA)");
+ case GDT3B_ID:
+ return("GDT3000B/3010A (EISA)");
+ }
+ } else if (ha->type == GDT_ISA) {
+ return("GDT2000/2020 (ISA)");
+ } else if (ha->type == GDT_PCI) {
+ switch (ha->stype) {
+ case PCI_DEVICE_ID_VORTEX_GDT60x0:
+ return("GDT6000/6020/6050 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6000B:
+ return("GDT6000B/6010 (PCI)");
+ }
+ } else if (ha->type == GDT_PCINEW) {
+ switch (ha->stype) {
+ case PCI_DEVICE_ID_VORTEX_GDT6x10:
+ return("GDT6110/6510 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x20:
+ return("GDT6120/6520 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6530:
+ return("GDT6530 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6550:
+ return("GDT6550 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x17:
+ return("GDT6117/6517 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x27:
+ return("GDT6127/6527 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6537:
+ return("GDT6537 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6557:
+ return("GDT6557/6557-ECC (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x15:
+ return("GDT6115/6515 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x25:
+ return("GDT6125/6525 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6535:
+ return("GDT6535 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6555:
+ return("GDT6555/6555-ECC (PCI)");
+ }
+ } else if (ha->type == GDT_PCIMPR) {
+ switch (ha->stype) {
+ case PCI_DEVICE_ID_VORTEX_GDT6x17RP:
+ return("GDT6117RP/GDT6517RP (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x27RP:
+ return("GDT6127RP/GDT6527RP (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6537RP:
+ return("GDT6537RP (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6557RP:
+ return("GDT6557RP (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x11RP:
+ return("GDT6111RP/GDT6511RP (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x21RP:
+ return("GDT6121RP/GDT6521RP (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x17RP1:
+ return("GDT6117RP1/GDT6517RP1 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x27RP1:
+ return("GDT6127RP1/GDT6527RP1 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6537RP1:
+ return("GDT6537RP1 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6557RP1:
+ return("GDT6557RP1 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x11RP1:
+ return("GDT6111RP1/GDT6511RP1 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x21RP1:
+ return("GDT6121RP1/GDT6521RP1 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x17RP2:
+ return("GDT6117RP2/GDT6517RP2 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x27RP2:
+ return("GDT6127RP2/GDT6527RP2 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6537RP2:
+ return("GDT6537RP2 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6557RP2:
+ return("GDT6557RP2 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x11RP2:
+ return("GDT6111RP2/GDT6511RP2 (PCI)");
+ case PCI_DEVICE_ID_VORTEX_GDT6x21RP2:
+ return("GDT6121RP2/GDT6521RP2 (PCI)");
+ }
+ }
+ return("");
+}
+
+const char *gdth_info(struct Scsi_Host *shp)
+{
+ int hanum;
+
+ TRACE2(("gdth_info()\n"));
+ hanum = NUMDATA(shp)->hanum;
+
+ return (gdth_ctr_name(hanum));
+}
+
+
+int gdth_abort(Scsi_Cmnd *scp)
+{
+ TRACE2(("gdth_abort() reason %d\n",scp->abort_reason));
+ return SCSI_ABORT_SNOOZE;
+}
+
+#if LINUX_VERSION_CODE >= 0x010346
+int gdth_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
+#else
+int gdth_reset(Scsi_Cmnd *scp)
+#endif
+{
+ TRACE2(("gdth_reset()\n"));
+ return SCSI_RESET_PUNT;
+}
+
+
+#if LINUX_VERSION_CODE >= 0x010300
+int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
+#else
+int gdth_bios_param(Disk *disk,int dev,int *ip)
+#endif
+{
+ TRACE2(("gdth_bios_param()\n"));
+
+ ip[2] = disk->capacity / HEADS / SECS;
+ if (ip[2] <= MAXCYLS) {
+ ip[0] = HEADS;
+ ip[1] = SECS;
+ } else {
+ ip[2] = disk->capacity / MEDHEADS / MEDSECS;
+ if (ip[2] <= MAXCYLS) {
+ ip[0] = MEDHEADS;
+ ip[1] = MEDSECS;
+ } else {
+ ip[2] = disk->capacity / BIGHEADS / BIGSECS;
+ ip[0] = BIGHEADS;
+ ip[1] = BIGSECS;
+ }
+ }
+ TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
+ ip[0],ip[1],ip[2]));
+ return 0;
+}
+
+
+static void internal_done(Scsi_Cmnd *scp)
+{
+ scp->SCp.sent_command++;
+}
+
+int gdth_command(Scsi_Cmnd *scp)
+{
+ TRACE2(("gdth_command()\n"));
+
+ scp->SCp.sent_command = 0;
+ gdth_queuecommand(scp,internal_done);
+
+ while (!scp->SCp.sent_command)
+ barrier();
+ return scp->result;
+}
+
+
+int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
+{
+ int hanum;
+ int priority;
+
+ TRACE(("gdth_queuecommand() cmd 0x%x id %d lun %d\n",
+ scp->cmnd[0],scp->target,scp->lun));
+
+ scp->scsi_done = (void *)done;
+ scp->SCp.have_data_in = 0;
+ hanum = NUMDATA(scp->host)->hanum;
+#ifdef GDTH_STATISTICS
+ ++act_ios;
+#endif
+
+ priority = DEFAULT_PRI;
+#if LINUX_VERSION_CODE >= 0x010300
+ if (scp->done == gdth_scsi_done)
+ priority = scp->SCp.this_residual;
+#endif
+ gdth_putq( hanum, scp, priority );
+ gdth_next( hanum );
+ return 0;
+}
+
+
+/* shutdown routine */
+void gdth_halt()
+{
+ int hanum, i, j;
+ gdth_ha_str *ha;
+ Scsi_Cmnd scp;
+ Scsi_Device sdev;
+ gdth_cmd_str gdtcmd;
+ char cmnd[12];
+
+ TRACE2(("gdth_halt()\n"));
+ printk("GDT: Flushing all host drives .. ");
+
+ for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ memset(&sdev,0,sizeof(Scsi_Device));
+ memset(&scp, 0,sizeof(Scsi_Cmnd));
+ sdev.host = gdth_ctr_tab[hanum];
+ sdev.id = sdev.host->this_id;
+ scp.cmd_len = 12;
+ scp.host = gdth_ctr_tab[hanum];
+ scp.target = sdev.host->this_id;
+ scp.device = &sdev;
+ scp.use_sg = 0;
+
+ /* flush */
+ for (i = 0; i < MAXBUS; ++i) {
+ for (j = 0; j < MAXID; ++j) {
+ if (ha->id[i][j].type == CACHE_DTYP) {
+ gdtcmd.BoardNode = LOCALBOARD;
+ gdtcmd.Service = CACHESERVICE;
+ gdtcmd.OpCode = GDT_FLUSH;
+ gdtcmd.u.cache.DeviceNo = ha->id[i][j].hostdrive;
+ gdtcmd.u.cache.BlockNo = 1;
+ gdtcmd.u.cache.sg_canz = 0;
+ TRACE2(("gdth_halt(): flush ha %d drive %d\n",
+ hanum, ha->id[i][j].hostdrive));
+ {
+ struct semaphore sem = MUTEX_LOCKED;
+ scp.request.rq_status = RQ_SCSI_BUSY;
+ scp.request.sem = &sem;
+ scsi_do_cmd(&scp, cmnd, &gdtcmd,
+ sizeof(gdth_cmd_str), gdth_scsi_done,
+ 30*HZ, 1);
+ down(&sem);
+ }
+ }
+ }
+ }
+
+ /* controller reset */
+ gdtcmd.BoardNode = LOCALBOARD;
+ gdtcmd.Service = CACHESERVICE;
+ gdtcmd.OpCode = GDT_RESET;
+ TRACE2(("gdth_halt(): reset controller %d\n", hanum));
+ {
+ struct semaphore sem = MUTEX_LOCKED;
+ scp.request.rq_status = RQ_SCSI_BUSY;
+ scp.request.sem = &sem;
+ scsi_do_cmd(&scp, cmnd, &gdtcmd,
+ sizeof(gdth_cmd_str), gdth_scsi_done,
+ 10*HZ, 1);
+ down(&sem);
+ }
+ }
+ printk("Done.\n");
+}
+
+
+/* called from init/main.c */
+void gdth_setup(char *str,int *ints)
+{
+ static size_t setup_idx = 0;
+
+ TRACE2(("gdth_setup() str %s ints[0] %d ints[1] %d\n",
+ str ? str:"NULL", ints[0],
+ ints[0] ? ints[1]:0));
+
+ if (setup_idx >= MAXHA) {
+ printk("GDT: gdth_setup() called too many times. Bad LILO params ?\n");
+ return;
+ }
+ if (ints[0] != 1) {
+ printk("GDT: Illegal command line !\n");
+ printk("Usage: gdth=<IRQ>\n");
+ printk("Where: <IRQ>: valid EISA controller IRQ (10,11,12,14)\n");
+ printk(" or 0 to disable controller driver\n");
+ return;
+ }
+ if (ints[1] == 10 || ints[1] == 11 || ints[1] == 12 || ints[1] == 14) {
+ irqs[setup_idx++] = ints[1];
+ irqs[setup_idx] = 0xff;
+ return;
+ }
+ if (ints[1] == 0) {
+ disable_gdth_scan = TRUE;
+ return;
+ }
+ printk("GDT: Invalid IRQ (%d) specified\n",ints[1]);
+}
+
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = GDTH;
+#include "scsi_module.c"
+#endif
+
--- /dev/null
+#ifndef _GDTH_H
+#define _GDTH_H
+
+/*
+ * Header file for the GDT ISA/EISA/PCI Disk Array Controller driver for Linux
+ *
+ * gdth.h Copyright (C) 1995-97 ICP vortex Computersysteme GmbH, Achim Leubner
+ * See gdth.c for further informations and
+ * below for supported controller types
+ *
+ * <achim@vortex.de>
+ *
+ * $Id: gdth.h,v 1.7 1997/03/20 16:01:59 achim Exp $
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* defines, macros */
+
+/* driver version */
+#define GDTH_VERSION_STR "1.00"
+#define GDTH_VERSION 1
+#define GDTH_SUBVERSION 0
+
+/* protocol version */
+#define PROTOCOL_VERSION 1
+
+/* controller classes */
+#define GDT_ISA 0x01 /* ISA controller */
+#define GDT_EISA 0x02 /* EISA controller */
+#define GDT_PCI 0x03 /* PCI controller */
+#define GDT_PCINEW 0x04 /* new PCI controller */
+#define GDT_PCIMPR 0x05 /* PCI MPR controller */
+/* GDT_EISA, controller subtypes EISA */
+#define GDT3_ID 0x0130941c /* GDT3000/3020 */
+#define GDT3A_ID 0x0230941c /* GDT3000A/3020A/3050A */
+#define GDT3B_ID 0x0330941c /* GDT3000B/3010A */
+/* GDT_ISA */
+#define GDT2_ID 0x0120941c /* GDT2000/2020 */
+/* vendor ID, device IDs (PCI) */
+/* these defines should already exist in <linux/pci.h> */
+#ifndef PCI_VENDOR_ID_VORTEX
+#define PCI_VENDOR_ID_VORTEX 0x1119 /* PCI controller vendor ID */
+#endif
+#ifndef PCI_DEVICE_ID_VORTEX_GDT60x0
+/* GDT_PCI */
+#define PCI_DEVICE_ID_VORTEX_GDT60x0 0 /* GDT6000/6020/6050 */
+#define PCI_DEVICE_ID_VORTEX_GDT6000B 1 /* GDT6000B/6010 */
+/* GDT_PCINEW */
+#define PCI_DEVICE_ID_VORTEX_GDT6x10 2 /* GDT6110/6510 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x20 3 /* GDT6120/6520 */
+#define PCI_DEVICE_ID_VORTEX_GDT6530 4 /* GDT6530 */
+#define PCI_DEVICE_ID_VORTEX_GDT6550 5 /* GDT6550 */
+/* GDT_PCINEW, wide/ultra SCSI controllers */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17 6 /* GDT6117/6517 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27 7 /* GDT6127/6527 */
+#define PCI_DEVICE_ID_VORTEX_GDT6537 8 /* GDT6537 */
+#define PCI_DEVICE_ID_VORTEX_GDT6557 9 /* GDT6557/6557-ECC */
+/* GDT_PCINEW, wide SCSI controllers */
+#define PCI_DEVICE_ID_VORTEX_GDT6x15 10 /* GDT6115/6515 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x25 11 /* GDT6125/6525 */
+#define PCI_DEVICE_ID_VORTEX_GDT6535 12 /* GDT6535 */
+#define PCI_DEVICE_ID_VORTEX_GDT6555 13 /* GDT6555/6555-ECC */
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDT6x17RP
+/* GDT_MPR, RP series, wide/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP 0x100 /* GDT6117RP/GDT6517RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP 0x101 /* GDT6127RP/GDT6527RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP 0x102 /* GDT6537RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x103 /* GDT6557RP */
+/* GDT_MPR, RP series, narrow/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x104 /* GDT6111RP/GDT6511RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x105 /* GDT6121RP/GDT6521RP */
+/* GDT_MPR, RP1 series, wide/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP1 0x110 /* GDT6117RP1/GDT6517RP1 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP1 0x111 /* GDT6127RP1/GDT6527RP1 */
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP1 0x112 /* GDT6537RP1 */
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP1 0x113 /* GDT6557RP1 */
+/* GDT_MPR, RP1 series, narrow/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP1 0x114 /* GDT6111RP1/GDT6511RP1 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP1 0x115 /* GDT6121RP1/GDT6521RP1 */
+/* GDT_MPR, RP2 series, wide/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP2 0x120 /* GDT6117RP2/GDT6517RP2 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP2 0x121 /* GDT6127RP2/GDT6527RP2 */
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP2 0x122 /* GDT6537RP2 */
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP2 0x123 /* GDT6557RP2 */
+/* GDT_MPR, RP2 series, narrow/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP2 0x124 /* GDT6111RP2/GDT6511RP2 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP2 0x125 /* GDT6121RP2/GDT6521RP2 */
+#endif
+
+/* limits */
+#define GDTH_SCRATCH 4096 /* 4KB scratch buffer */
+#define GDTH_MAXCMDS 124
+#define GDTH_MAXC_P_L 16 /* max. cmds per lun */
+#define MAXOFFSETS 128
+#define MAXHA 8
+#define MAXID 8
+#define MAXLUN 8
+#define MAXBUS 5
+#define MAX_HDRIVES 35 /* max. host drive count */
+#define MAX_EVENTS 100 /* event buffer count */
+#define MAXCYLS 1024
+#define HEADS 64
+#define SECS 32 /* mapping 64*32 */
+#define MEDHEADS 127
+#define MEDSECS 63 /* mapping 127*63 */
+#define BIGHEADS 255
+#define BIGSECS 63 /* mapping 255*63 */
+
+/* special command ptr. */
+#define UNUSED_CMND ((Scsi_Cmnd *)-1)
+#define INTERNAL_CMND ((Scsi_Cmnd *)-2)
+#define SCREEN_CMND ((Scsi_Cmnd *)-3)
+#define SPECIAL_SCP(p) (p==UNUSED_CMND || p==INTERNAL_CMND || p==SCREEN_CMND)
+
+/* device types */
+#define EMPTY_DTYP 0
+#define CACHE_DTYP 1
+#define RAW_DTYP 2
+#define SIOP_DTYP 3 /* the SCSI processor */
+
+/* controller services */
+#define SCSIRAWSERVICE 3
+#define CACHESERVICE 9
+#define SCREENSERVICE 11
+
+/* screenservice defines */
+#define MSG_INV_HANDLE -1 /* special message handle */
+#define MSGLEN 16 /* size of message text */
+#define MSG_SIZE 34 /* size of message structure */
+#define MSG_REQUEST 0 /* async. event: message */
+
+/* cacheservice defines */
+#define SECTOR_SIZE 0x200 /* always 512 bytes per sector */
+
+/* DPMEM constants */
+#define IC_HEADER_BYTES 48
+#define IC_QUEUE_BYTES 4
+#define DPMEM_COMMAND_OFFSET IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS
+
+/* service commands */
+#define GDT_INIT 0 /* service initialization */
+#define GDT_READ 1 /* read command */
+#define GDT_WRITE 2 /* write command */
+#define GDT_INFO 3 /* information about devices */
+#define GDT_FLUSH 4 /* flush dirty cache buffers */
+#define GDT_IOCTL 5 /* ioctl command */
+#define GDT_DEVTYPE 9 /* additional information */
+#define GDT_MOUNT 10 /* mount cache device */
+#define GDT_UNMOUNT 11 /* unmount cache device */
+#define GDT_SET_FEAT 12 /* set feat. (scatter/gather) */
+#define GDT_GET_FEAT 13 /* get features */
+#define GDT_RESERVE 14 /* reserve dev. to raw service */
+#define GDT_WRITE_THR 16 /* write through */
+#define GDT_EXT_INFO 18 /* extended info */
+#define GDT_RESET 19 /* controller reset */
+
+/* IOCTL command defines */
+#define SCSI_CHAN_CNT 5 /* subfunctions */
+#define L_CTRL_PATTERN 0x20000000L
+#define CACHE_INFO 4
+#define CACHE_CONFIG 5
+#define IO_CHANNEL 0x00020000L /* channels */
+#define INVALID_CHANNEL 0x0000ffffL
+
+/* IOCTLs */
+#define GDTIOCTL_MASK ('J'<<8)
+#define GDTIOCTL_GENERAL (GDTIOCTL_MASK | 0) /* general IOCTL */
+#define GDTIOCTL_DRVERS (GDTIOCTL_MASK | 1) /* get driver version */
+#define GDTIOCTL_CTRTYPE (GDTIOCTL_MASK | 2) /* get controller type */
+#define GDTIOCTL_CTRCNT (GDTIOCTL_MASK | 5) /* get controller count */
+#define GDTIOCTL_LOCKDRV (GDTIOCTL_MASK | 6) /* lock host drive */
+#define GDTIOCTL_LOCKCHN (GDTIOCTL_MASK | 7) /* lock channel */
+#define GDTIOCTL_EVENT (GDTIOCTL_MASK | 8) /* read controller events */
+
+/* service errors */
+#define S_OK 1 /* no error */
+#define S_BSY 7 /* controller busy */
+#define S_RAW_SCSI 12 /* raw serv.: target error */
+#define S_RAW_ILL 0xff /* raw serv.: illegal */
+
+/* timeout values */
+#define INIT_RETRIES 10000 /* 10000 * 1ms = 10s */
+#define INIT_TIMEOUT 100000 /* 1000 * 1ms = 1s */
+#define POLL_TIMEOUT 10000 /* 10000 * 1ms = 10s */
+
+/* priorities */
+#define DEFAULT_PRI 0x20
+#define IOCTL_PRI 0x10
+
+/* data directions */
+#define DATA_IN 0x01000000L /* data from target */
+#define DATA_OUT 0x00000000L /* data to target */
+
+/* BMIC registers (EISA controllers) */
+#define ID0REG 0x0c80 /* board ID */
+#define EINTENABREG 0x0c89 /* interrupt enable */
+#define SEMA0REG 0x0c8a /* command semaphore */
+#define SEMA1REG 0x0c8b /* status semaphore */
+#define LDOORREG 0x0c8d /* local doorbell */
+#define EDENABREG 0x0c8e /* EISA system doorbell enable */
+#define EDOORREG 0x0c8f /* EISA system doorbell */
+#define MAILBOXREG 0x0c90 /* mailbox reg. (16 bytes) */
+#define EISAREG 0x0cc0 /* EISA configuration */
+
+/* other defines */
+#define LINUX_OS 8 /* used for cache optim. */
+#define SCATTER_GATHER 1 /* s/g feature */
+#define GDTH_MAXSG 32 /* max. s/g elements */
+#define SECS32 0x1f /* round capacity */
+#define BIOS_ID_OFFS 0x10 /* offset contr. ID in ISABIOS */
+#define LOCALBOARD 0 /* board node always 0 */
+#define ASYNCINDEX 0 /* cmd index async. event */
+#define SPEZINDEX 1 /* cmd index unknown service */
+#define GDT_WR_THROUGH 0x100 /* WRITE_THROUGH supported */
+
+/* typedefs */
+
+#pragma pack(1)
+
+typedef struct {
+ char buffer[GDTH_SCRATCH]; /* scratch buffer */
+} gdth_scratch_str;
+
+/* screenservice message */
+typedef struct {
+ ulong msg_handle; /* message handle */
+ ulong msg_len; /* size of message */
+ ulong msg_alen; /* answer length */
+ unchar msg_answer; /* answer flag */
+ unchar msg_ext; /* more messages */
+ unchar msg_reserved[2];
+ char msg_text[MSGLEN+2]; /* the message text */
+} gdth_msg_str;
+
+/* get channel count IOCTL */
+typedef struct {
+ ulong channel_no; /* number of channel */
+ ulong drive_cnt; /* number of drives */
+ unchar siop_id; /* SCSI processor ID */
+ unchar siop_state; /* SCSI processor state */
+} gdth_getch_str;
+
+/* cache info/config IOCTL */
+typedef struct {
+ ulong version; /* firmware version */
+ ushort state; /* cache state (on/off) */
+ ushort strategy; /* cache strategy */
+ ushort write_back; /* write back state (on/off) */
+ ushort block_size; /* cache block size */
+} gdth_cpar_str;
+
+typedef struct {
+ ulong csize; /* cache size */
+ ulong read_cnt; /* read/write counter */
+ ulong write_cnt;
+ ulong tr_hits; /* hits */
+ ulong sec_hits;
+ ulong sec_miss; /* misses */
+} gdth_cstat_str;
+
+typedef struct {
+ gdth_cpar_str cpar;
+ gdth_cstat_str cstat;
+} gdth_cinfo_str;
+
+/* scatter/gather element */
+typedef struct {
+ ulong sg_ptr; /* address */
+ ulong sg_len; /* length */
+} gdth_sg_str;
+
+/* command structure */
+typedef struct {
+ ulong BoardNode; /* board node (always 0) */
+ ulong CommandIndex; /* command number */
+ ushort OpCode; /* the command (READ,..) */
+ union {
+ struct {
+ ushort DeviceNo; /* number of cache drive */
+ ulong BlockNo; /* block number */
+ ulong BlockCnt; /* block count */
+ ulong DestAddr; /* dest. addr. (if s/g: -1) */
+ ulong sg_canz; /* s/g element count */
+ gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */
+ } cache; /* cache service cmd. str. */
+ struct {
+ ushort param_size; /* size of p_param buffer */
+ ulong subfunc; /* IOCTL function */
+ ulong channel; /* device */
+ ulong p_param; /* buffer */
+ } ioctl; /* IOCTL command structure */
+ struct {
+ ushort reserved;
+ ulong msg_handle; /* message handle */
+ ulong msg_addr; /* message buffer address */
+ } screen; /* screen service cmd. str. */
+ struct {
+ ushort reserved;
+ ulong direction; /* data direction */
+ ulong mdisc_time; /* disc. time (0: no timeout)*/
+ ulong mcon_time; /* connect time(0: no to.) */
+ ulong sdata; /* dest. addr. (if s/g: -1) */
+ ulong sdlen; /* data length (bytes) */
+ ulong clen; /* SCSI cmd. length(6,10,12) */
+ unchar cmd[12]; /* SCSI command */
+ unchar target; /* target ID */
+ unchar lun; /* LUN */
+ unchar bus; /* SCSI bus number */
+ unchar priority; /* only 0 used */
+ ulong sense_len; /* sense data length */
+ ulong sense_data; /* sense data addr. */
+ struct raw *link_p; /* linked cmds (not supp.) */
+ ulong sg_ranz; /* s/g element count */
+ gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */
+ } raw; /* raw service cmd. struct. */
+ } u;
+ /* additional variables */
+ unchar Service; /* controller service */
+ ushort Status; /* command result */
+ ulong Info; /* additional information */
+ Scsi_Cmnd *RequestBuffer; /* request buffer */
+} gdth_cmd_str;
+
+/* controller event structure */
+#define ES_ASYNC 1
+#define ES_DRIVER 2
+#define ES_TEST 3
+#define ES_SYNC 4
+typedef struct {
+ ushort size; /* size of structure */
+ union {
+ char stream[16];
+ struct {
+ ushort ionode;
+ ushort service;
+ ulong index;
+ } driver;
+ struct {
+ ushort ionode;
+ ushort service;
+ ushort status;
+ ulong info;
+ unchar scsi_coord[3];
+ } async;
+ struct {
+ ushort ionode;
+ ushort service;
+ ushort status;
+ ulong info;
+ ushort hostdrive;
+ unchar scsi_coord[3];
+ unchar sense_key;
+ } sync;
+ struct {
+ ulong l1, l2, l3, l4;
+ } test;
+ } eu;
+} gdth_evt_data;
+
+typedef struct {
+ ulong first_stamp;
+ ulong last_stamp;
+ ushort same_count;
+ ushort event_source;
+ ushort event_idx;
+ unchar application;
+ unchar reserved;
+ gdth_evt_data event_data;
+} gdth_evt_str;
+
+
+/* DPRAM structures */
+
+/* interface area ISA/PCI */
+typedef struct {
+ unchar S_Cmd_Indx; /* special command */
+ unchar volatile S_Status; /* status special command */
+ ushort reserved1;
+ ulong S_Info[4]; /* add. info special command */
+ unchar volatile Sema0; /* command semaphore */
+ unchar reserved2[3];
+ unchar Cmd_Index; /* command number */
+ unchar reserved3[3];
+ ushort volatile Status; /* command status */
+ ushort Service; /* service(for async.events) */
+ ulong Info[2]; /* additional info */
+ struct {
+ ushort offset; /* command offs. in the DPRAM*/
+ ushort serv_id; /* service */
+ } comm_queue[MAXOFFSETS]; /* command queue */
+ ulong bios_reserved[2];
+ unchar gdt_dpr_cmd[1]; /* commands */
+} gdt_dpr_if;
+
+/* SRAM structure PCI controllers */
+typedef struct {
+ ulong magic; /* controller ID from BIOS */
+ ushort need_deinit; /* switch betw. BIOS/driver */
+ unchar switch_support; /* see need_deinit */
+ unchar padding[9];
+ unchar os_used[16]; /* OS code per service */
+ unchar unused[28];
+ unchar fw_magic; /* contr. ID from firmware */
+} gdt_pci_sram;
+
+/* SRAM structure EISA controllers (but NOT GDT3000/3020) */
+typedef struct {
+ unchar os_used[16]; /* OS code per service */
+ ushort need_deinit; /* switch betw. BIOS/driver */
+ unchar switch_support; /* see need_deinit */
+ unchar padding;
+} gdt_eisa_sram;
+
+
+/* DPRAM ISA controllers */
+typedef struct {
+ union {
+ struct {
+ unchar bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */
+ ulong magic; /* controller (EISA) ID */
+ ushort need_deinit; /* switch betw. BIOS/driver */
+ unchar switch_support; /* see need_deinit */
+ unchar padding[9];
+ unchar os_used[16]; /* OS code per service */
+ } dp_sram;
+ unchar bios_area[0x4000]; /* 16KB reserved for BIOS */
+ } bu;
+ union {
+ gdt_dpr_if ic; /* interface area */
+ unchar if_area[0x3000]; /* 12KB for interface */
+ } u;
+ struct {
+ unchar memlock; /* write protection DPRAM */
+ unchar event; /* release event */
+ unchar irqen; /* board interrupts enable */
+ unchar irqdel; /* acknowledge board int. */
+ unchar volatile Sema1; /* status semaphore */
+ unchar rq; /* IRQ/DRQ configuration */
+ } io;
+} gdt2_dpram_str;
+
+/* DPRAM PCI controllers */
+typedef struct {
+ union {
+ gdt_dpr_if ic; /* interface area */
+ unchar if_area[0xff0-sizeof(gdt_pci_sram)];
+ } u;
+ gdt_pci_sram gdt6sr; /* SRAM structure */
+ struct {
+ unchar unused0[1];
+ unchar volatile Sema1; /* command semaphore */
+ unchar unused1[3];
+ unchar irqen; /* board interrupts enable */
+ unchar unused2[2];
+ unchar event; /* release event */
+ unchar unused3[3];
+ unchar irqdel; /* acknowledge board int. */
+ unchar unused4[3];
+ } io;
+} gdt6_dpram_str;
+
+/* PLX register structure (new PCI controllers) */
+typedef struct {
+ unchar cfg_reg; /* DPRAM cfg.(2:below 1MB,0:anywhere)*/
+ unchar unused1[0x3f];
+ unchar volatile sema0_reg; /* command semaphore */
+ unchar volatile sema1_reg; /* status semaphore */
+ unchar unused2[2];
+ ushort volatile status; /* command status */
+ ushort service; /* service */
+ ulong info[2]; /* additional info */
+ unchar unused3[0x10];
+ unchar ldoor_reg; /* PCI to local doorbell */
+ unchar unused4[3];
+ unchar volatile edoor_reg; /* local to PCI doorbell */
+ unchar unused5[3];
+ unchar control0; /* control0 register(unused) */
+ unchar control1; /* board interrupts enable */
+ unchar unused6[0x16];
+} gdt6c_plx_regs;
+
+/* DPRAM new PCI controllers */
+typedef struct {
+ union {
+ gdt_dpr_if ic; /* interface area */
+ unchar if_area[0x4000-sizeof(gdt_pci_sram)];
+ } u;
+ gdt_pci_sram gdt6sr; /* SRAM structure */
+} gdt6c_dpram_str;
+
+/* i960 register structure (PCI MPR controllers) */
+typedef struct {
+ unchar unused1[16];
+ unchar volatile sema0_reg; /* command semaphore */
+ unchar unused2;
+ unchar volatile sema1_reg; /* status semaphore */
+ unchar unused3;
+ ushort volatile status; /* command status */
+ ushort service; /* service */
+ ulong info[2]; /* additional info */
+ unchar ldoor_reg; /* PCI to local doorbell */
+ unchar unused4[11];
+ unchar volatile edoor_reg; /* local to PCI doorbell */
+ unchar unused5[7];
+ unchar edoor_en_reg; /* board interrupts enable */
+ unchar unused6[27];
+ ulong unused7[1004]; /* size: 4 KB */
+} gdt6m_i960_regs;
+
+/* DPRAM PCI MPR controllers */
+typedef struct {
+ gdt6m_i960_regs i960r; /* 4KB i960 registers */
+ union {
+ gdt_dpr_if ic; /* interface area */
+ unchar if_area[0x3000-sizeof(gdt_pci_sram)];
+ } u;
+ gdt_pci_sram gdt6sr; /* SRAM structure */
+} gdt6m_dpram_str;
+
+
+/* PCI resources */
+typedef struct {
+ ushort device_id; /* device ID (0,..,9) */
+ unchar bus; /* PCI bus */
+ unchar device_fn; /* PCI device/function no. */
+ ulong dpmem; /* DPRAM address */
+ ulong io; /* IO address */
+ ulong io_mm; /* IO address mem. mapped */
+ ulong bios; /* BIOS address */
+ unchar irq; /* IRQ */
+} gdth_pci_str;
+
+
+/* controller information structure */
+typedef struct {
+ unchar bus_cnt; /* SCSI bus count */
+ unchar type; /* controller class */
+ ushort raw_feat; /* feat. raw service (s/g,..) */
+ ushort cache_feat; /* feat. cache serv. (s/g,..) */
+ ulong stype; /* controller subtype */
+ ulong brd; /* BMIC/DPRAM address */
+ ulong brd_phys; /* slot number/BIOS address */
+ gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */
+ gdth_cmd_str *pccb; /* address command structure */
+ gdth_scratch_str *pscratch;
+ unchar irq; /* IRQ */
+ unchar drq; /* DRQ (ISA controllers) */
+ ushort status; /* command status */
+ ulong info;
+ ulong info2; /* additional info */
+ Scsi_Cmnd *req_first; /* top of request queue */
+ struct {
+ unchar type; /* device type */
+ unchar heads; /* mapping */
+ unchar secs;
+ unchar lock; /* drive locked ? (hot plug) */
+ ushort hostdrive; /* host drive number */
+ ushort devtype; /* further information */
+ ulong size; /* capacity */
+ } id[MAXBUS][MAXID];
+ ushort cmd_cnt; /* command count in DPRAM */
+ ushort cmd_len; /* length of actual command */
+ ushort cmd_offs_dpmem; /* actual offset in DPRAM */
+ ushort ic_all_size; /* sizeof DPRAM interf. area */
+ unchar reserved;
+ unchar mode; /* information from /proc */
+ ushort param_size;
+ gdth_cpar_str cpar; /* controller cache par. */
+} gdth_ha_str;
+
+/* structure for scsi_register(), SCSI bus != 0 */
+typedef struct {
+ ushort hanum;
+ ushort busnum;
+} gdth_num_str;
+
+/* structure for scsi_register() */
+typedef struct {
+ gdth_num_str numext; /* must be the first element */
+ gdth_ha_str haext;
+ gdth_cmd_str cmdext;
+ gdth_scratch_str dmaext;
+} gdth_ext_str;
+
+
+/* INQUIRY data format */
+typedef struct {
+ unchar type_qual;
+ unchar modif_rmb;
+ unchar version;
+ unchar resp_aenc;
+ unchar add_length;
+ unchar reserved1;
+ unchar reserved2;
+ unchar misc;
+ unchar vendor[8];
+ unchar product[16];
+ unchar revision[4];
+} gdth_inq_data;
+
+/* READ_CAPACITY data format */
+typedef struct {
+ ulong last_block_no;
+ ulong block_length;
+} gdth_rdcap_data;
+
+/* REQUEST_SENSE data format */
+typedef struct {
+ unchar errorcode;
+ unchar segno;
+ unchar key;
+ ulong info;
+ unchar add_length;
+ ulong cmd_info;
+ unchar adsc;
+ unchar adsq;
+ unchar fruc;
+ unchar key_spec[3];
+} gdth_sense_data;
+
+/* MODE_SENSE data format */
+typedef struct {
+ struct {
+ unchar data_length;
+ unchar med_type;
+ unchar dev_par;
+ unchar bd_length;
+ } hd;
+ struct {
+ unchar dens_code;
+ unchar block_count[3];
+ unchar reserved;
+ unchar block_length[3];
+ } bd;
+} gdth_modep_data;
+
+typedef struct {
+ ulong b[10]; /* 32 bit compiler ! */
+} gdth_stackframe;
+
+#pragma pack()
+
+/* function prototyping */
+
+int gdth_detect(Scsi_Host_Template *);
+int gdth_release(struct Scsi_Host *);
+int gdth_command(Scsi_Cmnd *);
+int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *));
+int gdth_abort(Scsi_Cmnd *);
+#if LINUX_VERSION_CODE >= 0x010346
+int gdth_reset(Scsi_Cmnd *, unsigned int reset_flags);
+#else
+int gdth_reset(Scsi_Cmnd *);
+#endif
+const char *gdth_info(struct Scsi_Host *);
+
+
+#if LINUX_VERSION_CODE >= 0x010300
+int gdth_bios_param(Disk *,kdev_t,int *);
+extern struct proc_dir_entry proc_scsi_gdth;
+int gdth_proc_info(char *,char **,off_t,int,int,int);
+#define GDTH { NULL, NULL, \
+ &proc_scsi_gdth, \
+ gdth_proc_info, \
+ "GDT SCSI Disk Array Controller", \
+ gdth_detect, \
+ gdth_release, \
+ gdth_info, \
+ gdth_command, \
+ gdth_queuecommand, \
+ gdth_abort, \
+ gdth_reset, \
+ NULL, \
+ gdth_bios_param, \
+ GDTH_MAXCMDS, \
+ -1, \
+ GDTH_MAXSG, \
+ GDTH_MAXC_P_L, \
+ 0, \
+ 1, \
+ ENABLE_CLUSTERING}
+#else
+int gdth_bios_param(Disk *,int,int *);
+#define GDTH { NULL, NULL, \
+ "GDT SCSI Disk Array Controller", \
+ gdth_detect, \
+ gdth_release, \
+ gdth_info, \
+ gdth_command, \
+ gdth_queuecommand, \
+ gdth_abort, \
+ gdth_reset, \
+ NULL, \
+ gdth_bios_param, \
+ GDTH_MAXCMDS, \
+ -1, \
+ GDTH_MAXSG, \
+ GDTH_MAXC_P_L, \
+ 0, \
+ 1, \
+ ENABLE_CLUSTERING}
+#endif
+
+#endif
+
--- /dev/null
+#ifndef _GDTH_IOCTL_H
+#define _GDTH_IOCTL_H
+
+/* gdth_ioctl.h
+ * $Id: gdth_ioctl.h,v 1.1 1997/02/21 08:07:27 achim Exp $
+ */
+
+/* IOCTLs */
+#define GDTIOCTL_MASK ('J'<<8)
+#define GDTIOCTL_GENERAL (GDTIOCTL_MASK | 0) /* general IOCTL */
+#define GDTIOCTL_DRVERS (GDTIOCTL_MASK | 1) /* get driver version */
+#define GDTIOCTL_CTRTYPE (GDTIOCTL_MASK | 2) /* get controller type */
+#define GDTIOCTL_OSVERS (GDTIOCTL_MASK | 3) /* get OS version */
+#define GDTIOCTL_CTRCNT (GDTIOCTL_MASK | 5) /* get controller count */
+#define GDTIOCTL_LOCKDRV (GDTIOCTL_MASK | 6) /* lock host drive */
+#define GDTIOCTL_LOCKCHN (GDTIOCTL_MASK | 7) /* lock channel */
+#define GDTIOCTL_EVENT (GDTIOCTL_MASK | 8) /* read controller events */
+
+#define GDTIOCTL_MAGIC 0x06030f07UL
+
+
+/* IOCTL structure (write) */
+typedef struct {
+ ulong magic; /* IOCTL magic */
+ ushort ioctl; /* IOCTL */
+ ushort ionode; /* controller number */
+ ushort service; /* controller service */
+ ushort timeout; /* timeout */
+ union {
+ struct {
+ unchar command[512]; /* controller command */
+ unchar data[1]; /* add. data */
+ } general;
+ struct {
+ unchar lock; /* lock/unlock */
+ unchar drive_cnt; /* drive count */
+ ushort drives[35]; /* drives */
+ } lockdrv;
+ struct {
+ unchar lock; /* lock/unlock */
+ unchar channel; /* channel */
+ } lockchn;
+ struct {
+ int erase; /* erase event ? */
+ int handle;
+ } event;
+ } iu;
+} gdth_iowr_str;
+
+/* IOCTL structure (read) */
+typedef struct {
+ ulong size; /* buffer size */
+ ulong status; /* IOCTL error code */
+ union {
+ struct {
+ unchar data[1]; /* data */
+ } general;
+ struct {
+ ushort version; /* driver version */
+ } drvers;
+ struct {
+ unchar type; /* controller type */
+ ushort info; /* slot etc. */
+ ushort oem_id; /* OEM ID */
+ ushort bios_ver; /* not used */
+ ushort access; /* not used */
+ ushort ext_type; /* extended type */
+ } ctrtype;
+ struct {
+ unchar version; /* OS version */
+ unchar subversion; /* OS subversion */
+ ushort revision; /* revision */
+ } osvers;
+ struct {
+ ushort count; /* controller count */
+ } ctrcnt;
+ struct {
+ int handle;
+ unchar evt[32]; /* event structure */
+ } event;
+ } iu;
+} gdth_iord_str;
+
+
+#endif
+
--- /dev/null
+/* gdth_proc.c
+ * $Id: gdth_proc.c,v 1.4 1997/02/25 13:33:47 achim Exp $
+ */
+
+#include "gdth_ioctl.h"
+
+int gdth_proc_info(char *buffer,char **start,off_t offset,int length,
+ int hostno,int inout)
+{
+ int hanum,busnum,i;
+
+ TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n",
+ length,hostno,offset,inout));
+
+ for (i=0; i<gdth_ctr_vcount; ++i) {
+ if (gdth_ctr_vtab[i]->host_no == hostno)
+ break;
+ }
+ if (i==gdth_ctr_vcount)
+ return(-EINVAL);
+
+ hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
+ busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
+
+ if (inout)
+ return(gdth_set_info(buffer,length,i,hanum,busnum));
+ else
+ return(gdth_get_info(buffer,start,offset,length,i,hanum,busnum));
+}
+
+static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
+{
+ int ret_val;
+ Scsi_Cmnd scp;
+ Scsi_Device sdev;
+ gdth_iowr_str *piowr;
+
+ TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
+ piowr = (gdth_iowr_str *)buffer;
+
+ memset(&sdev,0,sizeof(Scsi_Device));
+ memset(&scp, 0,sizeof(Scsi_Cmnd));
+ sdev.host = gdth_ctr_vtab[vh];
+ sdev.id = sdev.host->this_id;
+ scp.cmd_len = 12;
+ scp.host = gdth_ctr_vtab[vh];
+ scp.target = sdev.host->this_id;
+ scp.device = &sdev;
+ scp.use_sg = 0;
+
+ if (length >= 4) {
+ if (strncmp(buffer,"gdth",4) == 0) {
+ buffer += 5;
+ length -= 5;
+ ret_val = gdth_set_asc_info( buffer, length, hanum, scp );
+ } else if (piowr->magic == GDTIOCTL_MAGIC) {
+ ret_val = gdth_set_bin_info( buffer, length, hanum, scp );
+ } else {
+ printk("GDT: Wrong signature: %6s\n",buffer);
+ ret_val = -EINVAL;
+ }
+ } else {
+ ret_val = -EINVAL;
+ }
+ return ret_val;
+}
+
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+{
+ int orig_length, drive, wb_mode;
+ char cmnd[12];
+ int i, j, found;
+ gdth_ha_str *ha;
+ gdth_cmd_str gdtcmd;
+ gdth_cpar_str *pcpar;
+
+ TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ memset(cmnd, 0,10);
+ orig_length = length + 5;
+ drive = -1;
+ wb_mode = 0;
+ found = FALSE;
+
+ if (length >= 5 && strncmp(buffer,"flush",5)==0) {
+ buffer += 6;
+ length -= 6;
+ if (length && *buffer>='0' && *buffer<='9') {
+ drive = (int)(*buffer-'0');
+ ++buffer; --length;
+ if (length && *buffer>='0' && *buffer<='9') {
+ drive = drive*10 + (int)(*buffer-'0');
+ ++buffer; --length;
+ }
+ printk("GDT: Flushing host drive %d .. ",drive);
+ } else {
+ printk("GDT: Flushing all host drives .. ");
+ }
+ for (i = 0; i < MAXBUS; ++i) {
+ for (j = 0; j < MAXID; ++j) {
+ if (ha->id[i][j].type == CACHE_DTYP) {
+ if (drive != -1 &&
+ ha->id[i][j].hostdrive != (ushort)drive)
+ continue;
+ found = TRUE;
+ gdtcmd.BoardNode = LOCALBOARD;
+ gdtcmd.Service = CACHESERVICE;
+ gdtcmd.OpCode = GDT_FLUSH;
+ gdtcmd.u.cache.DeviceNo = ha->id[i][j].hostdrive;
+ gdtcmd.u.cache.BlockNo = 1;
+ gdtcmd.u.cache.sg_canz = 0;
+ {
+ struct semaphore sem = MUTEX_LOCKED;
+ scp.request.rq_status = RQ_SCSI_BUSY;
+ scp.request.sem = &sem;
+ scsi_do_cmd(&scp, cmnd, &gdtcmd,
+ sizeof(gdth_cmd_str), gdth_scsi_done,
+ 30*HZ, 1);
+ down(&sem);
+ }
+ }
+ }
+ }
+ if (!found)
+ printk("\nNo host drive found !\n");
+ else
+ printk("Done.\n");
+ return(orig_length);
+ }
+
+ if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
+ buffer += 8;
+ length -= 8;
+ printk("GDT: Disabling write back permanently .. ");
+ wb_mode = 1;
+ } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
+ buffer += 7;
+ length -= 7;
+ printk("GDT: Enabling write back permanently .. ");
+ wb_mode = 2;
+ } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
+ buffer += 7;
+ length -= 7;
+ printk("GDT: Disabling write back commands .. ");
+ if (ha->cache_feat & GDT_WR_THROUGH) {
+ gdth_write_through = TRUE;
+ printk("Done.\n");
+ } else {
+ printk("Not supported !\n");
+ }
+ return(orig_length);
+ } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
+ buffer += 6;
+ length -= 6;
+ printk("GDT: Enabling write back commands .. ");
+ gdth_write_through = FALSE;
+ printk("Done.\n");
+ return(orig_length);
+ }
+
+ if (wb_mode) {
+ pcpar = (gdth_cpar_str *)kmalloc( sizeof(gdth_cpar_str),
+ GFP_ATOMIC | GFP_DMA );
+ if (pcpar == NULL) {
+ TRACE2(("gdth_set_info(): Unable to allocate memory.\n"));
+ printk("Unable to allocate memory.\n");
+ return(-EINVAL);
+ }
+ memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
+ gdtcmd.BoardNode = LOCALBOARD;
+ gdtcmd.Service = CACHESERVICE;
+ gdtcmd.OpCode = GDT_IOCTL;
+ gdtcmd.u.ioctl.p_param = (ulong)pcpar;
+ gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
+ gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
+ gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
+ pcpar->write_back = wb_mode==1 ? 0:1;
+ {
+ struct semaphore sem = MUTEX_LOCKED;
+ scp.request.rq_status = RQ_SCSI_BUSY;
+ scp.request.sem = &sem;
+ scsi_do_cmd(&scp, cmnd, &gdtcmd, sizeof(gdth_cmd_str),
+ gdth_scsi_done, 30*HZ, 1);
+ down(&sem);
+ }
+ kfree( pcpar );
+ printk("Done.\n");
+ return(orig_length);
+ }
+
+ printk("GDT: Unknown command: %s Length: %d\n",buffer,length);
+ return(-EINVAL);
+}
+
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+{
+ char cmnd[12];
+ int id;
+ unchar i, j, k, found;
+ gdth_ha_str *ha;
+ gdth_iowr_str *piowr;
+ gdth_iord_str *piord;
+ gdth_cmd_str *pcmd;
+ ulong *ppadd;
+ ulong add_size, flags;
+
+
+ TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ memset(cmnd, 0,10);
+ piowr = (gdth_iowr_str *)buffer;
+ piord = NULL;
+ pcmd = NULL;
+
+ if (length < GDTOFFSOF(gdth_iowr_str,iu))
+ return(-EINVAL);
+
+ switch (piowr->ioctl) {
+ case GDTIOCTL_GENERAL:
+ if (length < GDTOFFSOF(gdth_iowr_str,iu.general.data[0]))
+ return(-EINVAL);
+ pcmd = (gdth_cmd_str *)piowr->iu.general.command;
+ pcmd->Service = piowr->service;
+ if (pcmd->OpCode == GDT_IOCTL) {
+ ppadd = &pcmd->u.ioctl.p_param;
+ add_size = pcmd->u.ioctl.param_size;
+ } else if (piowr->service == CACHESERVICE) {
+ add_size = pcmd->u.cache.BlockCnt * SECTOR_SIZE;
+ if (ha->cache_feat & SCATTER_GATHER) {
+ ppadd = &pcmd->u.cache.sg_lst[0].sg_ptr;
+ pcmd->u.cache.DestAddr = -1UL;
+ pcmd->u.cache.sg_lst[0].sg_len = add_size;
+ pcmd->u.cache.sg_canz = 1;
+ } else {
+ ppadd = &pcmd->u.cache.DestAddr;
+ pcmd->u.cache.sg_canz = 0;
+ }
+ } else if (piowr->service == SCSIRAWSERVICE) {
+ add_size = pcmd->u.raw.sdlen;
+ if (ha->raw_feat & SCATTER_GATHER) {
+ ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr;
+ pcmd->u.raw.sdata = -1UL;
+ pcmd->u.raw.sg_lst[0].sg_len = add_size;
+ pcmd->u.raw.sg_ranz = 1;
+ } else {
+ ppadd = &pcmd->u.raw.sdata;
+ pcmd->u.raw.sg_ranz = 0;
+ }
+ } else {
+ return(-EINVAL);
+ }
+ id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) + add_size );
+ if (id == -1)
+ return(-EBUSY);
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+
+ piord->size = sizeof(gdth_iord_str) + add_size;
+ if (add_size > 0) {
+ memcpy(piord->iu.general.data, piowr->iu.general.data, add_size);
+ *ppadd = (ulong)piord->iu.general.data;
+ }
+ /* do IOCTL */
+ {
+ struct semaphore sem = MUTEX_LOCKED;
+ scp.request.rq_status = RQ_SCSI_BUSY;
+ scp.request.sem = &sem;
+ scp.SCp.this_residual = IOCTL_PRI;
+ scsi_do_cmd(&scp, cmnd, pcmd,
+ sizeof(gdth_cmd_str), gdth_scsi_done,
+ piowr->timeout*HZ, 1);
+ down(&sem);
+ piord->status = (ulong)scp.SCp.Message;
+ }
+ break;
+
+ case GDTIOCTL_DRVERS:
+ id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+ if (id == -1)
+ return(-EBUSY);
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+ piord->size = sizeof(gdth_iord_str);
+ piord->status = S_OK;
+ piord->iu.drvers.version = (GDTH_VERSION<<8) | GDTH_SUBVERSION;
+ break;
+
+ case GDTIOCTL_CTRTYPE:
+ id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+ if (id == -1)
+ return(-EBUSY);
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+ piord->size = sizeof(gdth_iord_str);
+ piord->status = S_OK;
+ if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
+ piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 10);
+ } else if (ha->type != GDT_PCIMPR) {
+ piord->iu.ctrtype.type = (unchar)((ha->stype<<8) + 6);
+ } else {
+ piord->iu.ctrtype.type = 0xfe;
+ piord->iu.ctrtype.ext_type = 0x6000 | ha->stype;
+ }
+ piord->iu.ctrtype.info = ha->brd_phys;
+ piord->iu.ctrtype.oem_id = (ushort)GDT3_ID;
+ break;
+
+ case GDTIOCTL_CTRCNT:
+ id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+ if (id == -1)
+ return(-EBUSY);
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+ piord->size = sizeof(gdth_iord_str);
+ piord->status = S_OK;
+ piord->iu.ctrcnt.count = (ushort)gdth_ctr_count;
+ break;
+
+ case GDTIOCTL_OSVERS:
+ id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+ if (id == -1)
+ return(-EBUSY);
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+ piord->size = sizeof(gdth_iord_str);
+ piord->status = S_OK;
+ piord->iu.osvers.version = (unchar)(LINUX_VERSION_CODE >> 16);
+ piord->iu.osvers.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
+ piord->iu.osvers.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
+ break;
+
+ case GDTIOCTL_LOCKDRV:
+ id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+ if (id == -1)
+ return(-EBUSY);
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+ for (i = k = 0; i < piowr->iu.lockdrv.drive_cnt; ++i) {
+ found = FALSE;
+ for (j = 0; j < ha->bus_cnt; ++j) {
+ for (k = 0; k < MAXID; ++k) {
+ if (ha->id[j][k].type == CACHE_DTYP &&
+ ha->id[j][k].hostdrive == piowr->iu.lockdrv.drives[i]) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ if (!found)
+ continue;
+
+ if (piowr->iu.lockdrv.lock) {
+ save_flags( flags );
+ cli();
+ ha->id[j][k].lock = 1;
+ restore_flags( flags );
+ gdth_wait_completion( hanum, j, k );
+ gdth_stop_timeout( hanum, j, k );
+ } else {
+ save_flags( flags );
+ cli();
+ ha->id[j][k].lock = 0;
+ restore_flags( flags );
+ gdth_start_timeout( hanum, j, k );
+ gdth_next( hanum );
+ }
+ }
+ piord->size = sizeof(gdth_iord_str);
+ piord->status = S_OK;
+ break;
+
+ case GDTIOCTL_LOCKCHN:
+ id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+ if (id == -1)
+ return(-EBUSY);
+ for (k = 0, j = piowr->iu.lockchn.channel; k < MAXID; ++k) {
+ if (ha->id[j][k].type != RAW_DTYP)
+ continue;
+
+ if (piowr->iu.lockchn.lock) {
+ save_flags( flags );
+ cli();
+ ha->id[j][k].lock = 1;
+ restore_flags( flags );
+ gdth_wait_completion( hanum, j, k );
+ gdth_stop_timeout( hanum, j, k );
+ } else {
+ save_flags( flags );
+ cli();
+ ha->id[j][k].lock = 0;
+ restore_flags( flags );
+ gdth_start_timeout( hanum, j, k );
+ gdth_next( hanum );
+ }
+ }
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+ piord->size = sizeof(gdth_iord_str);
+ piord->status = S_OK;
+ break;
+
+ case GDTIOCTL_EVENT:
+ id = gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) );
+ if (id == -1)
+ return(-EBUSY);
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+ if (piowr->iu.event.erase == 0) {
+ piord->iu.event.handle = gdth_read_event( piowr->iu.event.handle,
+ (gdth_evt_str *)piord->iu.event.evt );
+ } else {
+ piord->iu.event.handle = piowr->iu.event.handle;
+ gdth_readapp_event( (unchar)piowr->iu.event.erase,
+ (gdth_evt_str *)piord->iu.event.evt );
+ }
+ piord->size = sizeof(gdth_iord_str);
+ piord->status = S_OK;
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+ /* we return a buffer ID to detect the right buffer during READ-IOCTL */
+ return id;
+}
+
+static int gdth_get_info(char *buffer,char **start,off_t offset,
+ int length,int vh,int hanum,int busnum)
+{
+ int size = 0,len = 0;
+ off_t begin = 0,pos = 0;
+ gdth_ha_str *ha;
+ gdth_iord_str *piord;
+ int id;
+
+ TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ id = length;
+
+ /* look for buffer ID in length */
+ if (id > 4) {
+#if LINUX_VERSION_CODE >= 0x010400
+ size = sprintf(buffer+len,
+ "%s SCSI Disk Array Controller\n",
+ gdth_ctr_name(hanum));
+#else
+ size = sprintf(buffer+len,
+ "%s SCSI Disk Array Controller (SCSI Bus %d)\n",
+ gdth_ctr_name(hanum),busnum);
+#endif
+ len += size; pos = begin + len;
+ size = sprintf(buffer+len,
+ "Firmware Version: %d.%2d\tDriver Version: %s\n",
+ (unchar)(ha->cpar.version>>8),
+ (unchar)(ha->cpar.version),GDTH_VERSION_STR);
+ len += size; pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+
+ } else {
+ piord = (gdth_iord_str *)gdth_ioctl_tab[id-1][hanum];
+ if (piord == NULL)
+ goto stop_output;
+ length = piord->size;
+ memcpy(buffer+len, (char *)piord, length);
+ gdth_ioctl_free(hanum, id);
+ len += length; pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+ }
+
+stop_output:
+ *start = buffer +(offset-begin);
+ len -= (offset-begin);
+ if (len > length)
+ len = length;
+ TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n",
+ len,pos,begin,offset,length,size));
+ return(len);
+}
+
+
+void gdth_scsi_done(Scsi_Cmnd *scp)
+{
+ TRACE2(("gdth_scsi_done()\n"));
+
+ scp->request.rq_status = RQ_SCSI_DONE;
+
+ if (scp->request.sem != NULL)
+ up(scp->request.sem);
+}
+
+static int gdth_ioctl_alloc(int hanum, ushort size)
+{
+ ulong flags;
+ int i;
+
+ if (size == 0)
+ return -1;
+
+ save_flags(flags);
+ cli();
+
+ for (i = 0; i < 4; ++i) {
+ if (gdth_ioctl_tab[i][hanum] == NULL) {
+ gdth_ioctl_tab[i][hanum] = kmalloc( size, GFP_ATOMIC | GFP_DMA );
+ break;
+ }
+ }
+
+ restore_flags(flags);
+ if (i == 4 || gdth_ioctl_tab[i][hanum] == NULL)
+ return -1;
+ return (i+1);
+}
+
+static void gdth_ioctl_free(int hanum, int idx)
+{
+ ulong flags;
+
+ save_flags(flags);
+ cli();
+
+ kfree( gdth_ioctl_tab[idx-1][hanum] );
+ gdth_ioctl_tab[idx-1][hanum] = NULL;
+
+ restore_flags(flags);
+}
+
+static void gdth_wait_completion(int hanum, int busnum, int id)
+{
+ ulong flags;
+ int i;
+ Scsi_Cmnd *scp;
+
+ save_flags(flags);
+ cli();
+
+ for (i = 0; i < GDTH_MAXCMDS; ++i) {
+ scp = gdth_cmd_tab[i][hanum].cmnd;
+ if (!SPECIAL_SCP(scp) && scp->target == (unchar)id &&
+#if LINUX_VERSION_CODE >= 0x010400
+ scp->channel == (unchar)busnum)
+#else
+ NUMDATA(scp->host)->busnum == (unchar)busnum)
+#endif
+ {
+ restore_flags(flags);
+ while (!scp->SCp.have_data_in)
+ barrier();
+ save_flags(flags);
+ cli();
+ }
+ }
+ restore_flags(flags);
+}
+
+static void gdth_stop_timeout(int hanum, int busnum, int id)
+{
+ ulong flags;
+ Scsi_Cmnd *scp;
+ gdth_ha_str *ha;
+
+ save_flags(flags);
+ cli();
+ ha = HADATA(gdth_ctr_tab[hanum]);
+
+ for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+ if (scp->target == (unchar)id &&
+#if LINUX_VERSION_CODE >= 0x010400
+ scp->channel == (unchar)busnum)
+#else
+ NUMDATA(scp->host)->busnum == (unchar)busnum)
+#endif
+ {
+ TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
+ scp->SCp.buffers_residual = gdth_update_timeout(scp, 0);
+ }
+ }
+ restore_flags(flags);
+}
+
+static void gdth_start_timeout(int hanum, int busnum, int id)
+{
+ ulong flags;
+ Scsi_Cmnd *scp;
+ gdth_ha_str *ha;
+
+ save_flags(flags);
+ cli();
+ ha = HADATA(gdth_ctr_tab[hanum]);
+
+ for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+ if (scp->target == (unchar)id &&
+#if LINUX_VERSION_CODE >= 0x010400
+ scp->channel == (unchar)busnum)
+#else
+ NUMDATA(scp->host)->busnum == (unchar)busnum)
+#endif
+ {
+ TRACE2(("gdth_start_timeout(): update_timeout()\n"));
+ gdth_update_timeout(scp, scp->SCp.buffers_residual);
+ }
+ }
+ restore_flags(flags);
+}
+
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
+{
+ ulong flags;
+ int oldto;
+
+ save_flags(flags);
+ cli();
+
+ oldto = scp->timeout;
+ scp->timeout = timeout;
+ if (timeout > 0) {
+ if (timer_table[SCSI_TIMER].expires == 0) {
+ timer_table[SCSI_TIMER].expires = jiffies + timeout;
+ timer_active |= 1 << SCSI_TIMER;
+ } else {
+ if (jiffies + timeout < timer_table[SCSI_TIMER].expires)
+ timer_table[SCSI_TIMER].expires = jiffies + timeout;
+ }
+ }
+
+ restore_flags(flags);
+ return oldto;
+}
+
--- /dev/null
+#ifndef _GDTH_PROC_H
+#define _GDTH_PROC_H
+
+/* gdth_proc.h
+ * $Id: gdth_proc.h,v 1.2 1997/02/21 08:08:51 achim Exp $
+ */
+
+static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+static int gdth_get_info(char *buffer,char **start,off_t offset,
+ int length,int vh,int hanum,int busnum);
+
+static int gdth_ioctl_alloc(int hanum, ushort size);
+static void gdth_ioctl_free(int hanum, int id);
+static void gdth_wait_completion(int hanum, int busnum, int id);
+static void gdth_stop_timeout(int hanum, int busnum, int id);
+static void gdth_start_timeout(int hanum, int busnum, int id);
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout);
+
+void gdth_scsi_done(Scsi_Cmnd *scp);
+
+#endif
+
#include "ide-scsi.h"
#endif
+#ifdef CONFIG_SCSI_GDTH
+#include "gdth.h"
+#endif
+
#ifdef CONFIG_SCSI_DEBUG
#include "scsi_debug.h"
#endif
#ifdef CONFIG_SCSI_SUNESP
SCSI_SPARC_ESP,
#endif
+#ifdef CONFIG_SCSI_GDTH
+ GDTH,
+#endif
#ifdef CONFIG_BLK_DEV_IDESCSI
IDESCSI,
#endif
--- /dev/null
+/*
+ * $Id: b1lli.h,v 1.1 1997/03/04 21:27:32 calle Exp $
+ *
+ * ISDN lowlevel-module for AVM B1-card.
+ *
+ * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1lli.h,v $
+ * Revision 1.1 1997/03/04 21:27:32 calle
+ * First 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 _B1LLI_H_
+#define _B1LLI_H_
+/*
+ * struct for loading t4 file
+ */
+typedef struct avmb1_t4file {
+ int len;
+ unsigned char *data;
+} avmb1_t4file;
+
+typedef struct avmb1_loaddef {
+ int contr;
+ avmb1_t4file t4file;
+} avmb1_loaddef;
+
+typedef struct avmb1_resetdef {
+ int contr;
+} avmb1_resetdef;
+
+/*
+ * struct for adding new cards
+ */
+typedef struct avmb1_carddef {
+ int port;
+ int irq;
+} avmb1_carddef;
+
+#define AVMB1_LOAD 0 /* load image to card */
+#define AVMB1_ADDCARD 1 /* add a new card */
+#define AVMB1_RESETCARD 2 /* reset a card */
+
+
+
+#ifdef __KERNEL__
+
+/*
+ * card states for startup
+ */
+
+#define CARD_NONE 0
+#define CARD_DETECTED 1
+#define CARD_LOADING 2
+#define CARD_INITSTATE 4
+#define CARD_RUNNING 5
+#define CARD_ACTIVE 6
+
+#define AVMB1_PORTLEN 0x1f
+
+#define AVM_MAXVERSION 8
+#define AVM_NBCHAN 2
+
+#define AVM_NAPPS 30
+#define AVM_NPLCI 5
+#define AVM_NNCCI 6
+
+/*
+ * Main driver data
+ */
+
+typedef struct avmb1_card {
+ struct avmb1_card *next;
+ int cnr;
+ unsigned short port;
+ unsigned irq;
+ volatile unsigned short cardstate;
+ int interrupt;
+ int blocked;
+ int versionlen;
+ char versionbuf[1024];
+ char *version[AVM_MAXVERSION];
+ char msgbuf[128]; /* capimsg msg part */
+ char databuf[2048]; /* capimsg data part */
+ capi_version cversion;
+ char name[10];
+} avmb1_card;
+
+/*
+ * 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
+
+
+/* b1lli.c */
+int B1_detect(unsigned short base);
+void B1_reset(unsigned short base);
+int B1_load_t4file(unsigned short base, avmb1_t4file * t4file);
+int B1_loaded(unsigned short base);
+unsigned char B1_assign_irq(unsigned short base, unsigned irq);
+unsigned char B1_enable_irq(unsigned short base);
+unsigned char B1_disable_irq(unsigned short base);
+int B1_valid_irq(unsigned irq);
+void B1_handle_interrupt(avmb1_card * card);
+void B1_send_init(unsigned short port,
+ unsigned int napps, unsigned int nncci, unsigned int cardnr);
+void B1_send_register(unsigned short port,
+ __u16 appid, __u32 nmsg,
+ __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize);
+void B1_send_release(unsigned short port, __u16 appid);
+void B1_send_message(unsigned short port, struct sk_buff *skb);
+
+/* b1capi.c */
+void avmb1_handle_new_ncci(avmb1_card * card,
+ __u16 appl, __u32 ncci, __u32 winsize);
+void avmb1_handle_free_ncci(avmb1_card * card,
+ __u16 appl, __u32 ncci);
+void avmb1_handle_capimsg(avmb1_card * card, __u16 appl, struct sk_buff *skb);
+void avmb1_card_ready(avmb1_card * card);
+
+int avmb1_addcard(int port, int irq);
+int avmb1_probecard(int port, int irq);
+
+#endif /* __KERNEL__ */
+
+#endif /* _B1LLI_H_ */
--- /dev/null
+/*
+ * $Id: capi.h,v 1.1 1997/03/04 21:27:33 calle Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+ * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: capi.h,v $
+ * Revision 1.1 1997/03/04 21:27:33 calle
+ * First 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 __LINUX_CAPI_H__
+#define __LINUX_CAPI_H__
+
+#include <asm/types.h>
+#include <linux/ioctl.h>
+#ifndef __KERNEL__
+#include <linux/kernelcapi.h>
+#endif
+
+/*
+ * CAPI_REGISTER
+ */
+
+typedef struct capi_register_params { /* CAPI_REGISTER */
+ __u32 level3cnt; /* No. of simulatneous user data connections */
+ __u32 datablkcnt; /* No. of buffered data messages */
+ __u32 datablklen; /* Size of buffered data messages */
+} capi_register_params;
+
+#define CAPI_REGISTER _IOW('C',0x01,struct capi_register_params)
+
+/*
+ * CAPI_GET_MANUFACTURER
+ */
+
+#define CAPI_MANUFACTURER_LEN 64
+
+#define CAPI_GET_MANUFACTURER _IOWR('C',0x06,CAPI_MANUFACTURER_LEN)
+
+/*
+ * CAPI_GET_VERSION
+ */
+
+typedef struct capi_version {
+ __u32 majorversion;
+ __u32 minorversion;
+ __u32 majormanuversion;
+ __u32 minormanuversion;
+} capi_version;
+
+#define CAPI_GET_VERSION _IOWR('C',0x07,struct capi_version)
+
+/*
+ * CAPI_GET_SERIAL
+ */
+
+#define CAPI_SERIAL_LEN 8
+#define CAPI_GET_SERIAL _IOWR('C',0x08, CAPI_SERIAL_LEN)
+
+/*
+ * CAPI_GET_PROFILE
+ */
+
+typedef struct capi_profile {
+ __u16 ncontroller; /* number of installed controller */
+ __u16 nbchannel; /* number of B-Channels */
+ __u32 goptions; /* global options */
+ __u32 support1; /* B1 protocols support */
+ __u32 support2; /* B2 protocols support */
+ __u32 support3; /* B3 protocols support */
+ __u32 reserved[6]; /* reserved */
+ __u32 manu[5]; /* manufacturer specific information */
+} capi_profile;
+
+#define CAPI_GET_PROFILE _IOWR('C',0x09,struct capi_profile)
+
+typedef struct capi_manufacturer_cmd {
+ unsigned long cmd;
+ void *data;
+} capi_manufacturer_cmd;
+
+/*
+ * CAPI_MANUFACTURER_CMD
+ */
+
+#define CAPI_MANUFACTURER_CMD _IOWR('C',0x20, struct capi_manufacturer_cmd)
+
+/*
+ * CAPI_GET_ERRCODE
+ * capi errcode is set, * if read, write, or ioctl returns EIO,
+ * ioctl returns errcode directly, and in arg, if != 0
+ */
+
+#define CAPI_GET_ERRCODE _IOR('C',0x21, __u16)
+
+/*
+ * CAPI_INSTALLED
+ */
+#define CAPI_INSTALLED _IOR('C',0x22, __u16)
+
+/*
+ * member contr is input for
+ * CAPI_GET_MANUFACTURER, CAPI_VERSION, CAPI_GET_SERIAL
+ * and CAPI_GET_PROFILE
+ */
+typedef union capi_ioctl_struct {
+ __u32 contr;
+ capi_register_params rparams;
+ __u8 manufacturer[CAPI_MANUFACTURER_LEN];
+ capi_version version;
+ __u8 serial[CAPI_SERIAL_LEN];
+ capi_profile profile;
+ capi_manufacturer_cmd cmd;
+ __u16 errcode;
+} capi_ioctl_struct;
+
+#endif /* __LINUX_CAPI_H__ */
-/* $Id: isdn.h,v 1.18 1996/11/06 17:37:50 keil Exp $
+/* $Id: isdn.h,v 1.30 1997/06/17 13:07:23 hipp Exp $
*
* Main header for the Linux ISDN subsystem (linklevel).
*
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn.h,v $
+ * Revision 1.30 1997/06/17 13:07:23 hipp
+ * compression changes , MP changes
+ *
+ * Revision 1.29 1997/05/27 15:18:02 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.28 1997/03/07 01:33:01 fritz
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.27 1997/03/05 21:11:49 fritz
+ * Minor fixes.
+ *
+ * Revision 1.26 1997/02/28 02:37:53 fritz
+ * Added some comments.
+ *
+ * Revision 1.25 1997/02/23 16:54:23 hipp
+ * some initial changes for future PPP compresion
+ *
+ * Revision 1.24 1997/02/18 09:42:45 fritz
+ * Bugfix: Increased ISDN_MODEM_ANZREG.
+ * Increased TTY_DV.
+ *
+ * Revision 1.23 1997/02/10 22:07:13 fritz
+ * Added 2 modem registers for numbering plan and screening info.
+ *
+ * Revision 1.22 1997/02/03 23:42:08 fritz
+ * Added ISDN_TIMER_RINGING
+ * Misc. changes for Kernel 2.1.X compatibility
+ *
+ * Revision 1.21 1997/01/17 01:19:10 fritz
+ * Applied chargeint patch.
+ *
+ * Revision 1.20 1997/01/17 00:41:19 fritz
+ * Increased TTY_DV.
+ *
+ * Revision 1.19 1997/01/14 01:41:07 fritz
+ * Added ATI2 related variables.
+ * Added variables for audio support in skbuffs.
+ *
* Revision 1.18 1996/11/06 17:37:50 keil
* more changes for 2.1.X
*
#define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */
#define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing */
-#define ISDN_MODEM_ANZREG 21 /* Number of Modem-Registers */
+#define ISDN_MODEM_ANZREG 23 /* Number of Modem-Registers */
#define ISDN_MSNLEN 20
typedef struct {
typedef struct {
char name[10];
- char phone[20];
+ char phone[ISDN_MSNLEN];
int outgoing;
} isdn_net_ioctl_phone;
-#define NET_DV 0x01 /* Data version for net_cfg */
-#define TTY_DV 0x01 /* Data version for iprofd etc. */
+#define NET_DV 0x03 /* Data version for net_cfg */
+#define TTY_DV 0x04 /* Data version for iprofd etc. */
typedef struct {
char name[10]; /* Name of interface */
int exclusive; /* Channel, if bound exclusive */
int dialmax; /* Dial Retry-Counter */
int slavedelay; /* Delay until slave starts up */
+ int triggercps; /* BogoCPS needed for triggering slave */
int cbdelay; /* Delay before Callback */
int chargehup; /* Flag: Charge-Hangup */
int ihup; /* Flag: Hangup-Timeout on incoming line */
int callback; /* Flag: Callback */
int cbhup; /* Flag: Reject Call before Callback */
int pppbind; /* ippp device for bindings */
+ int chargeint; /* Use fixed charge interval length */
} isdn_net_ioctl_cfg;
#ifdef __KERNEL__
#define ISDN_TIMER_RES 3 /* Main Timer-Resolution */
#define ISDN_TIMER_02SEC (HZ/(ISDN_TIMER_RES+1)/5) /* Slow-Timer1 .2 sec */
#define ISDN_TIMER_1SEC (HZ/(ISDN_TIMER_RES+1)) /* Slow-Timer2 1 sec */
+#define ISDN_TIMER_RINGING 5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */
#define ISDN_TIMER_MODEMREAD 1
#define ISDN_TIMER_MODEMPLUS 2
#define ISDN_TIMER_MODEMRING 4
/* Phone-list-element */
typedef struct {
void *next;
- char num[20];
+ char num[ISDN_MSNLEN];
} isdn_net_phone;
/* Local interface-data */
/* bit0: chargeint is invalid */
/* bit1: Getting charge-interval */
/* bit2: Do charge-unit-hangup */
+ /* bit3: Do hangup even on incoming */
int outgoing; /* Flag: outgoing call */
int onhtime; /* Time to keep link up */
int chargeint; /* Interval between charge-infos */
int sqfull; /* Flag: netdev-queue overloaded */
ulong sqfull_stamp; /* Start-Time of overload */
ulong slavedelay; /* Dynamic bundling delaytime */
+ int triggercps; /* BogoCPS needed for trigger slave */
struct device *srobin; /* Ptr to Master device for slaves */
isdn_net_phone *phone[2]; /* List of remote-phonenumbers */
/* phone[0] = Incoming Numbers */
struct isdn_net_dev_s *netdev; /* Ptr to netdev */
struct sk_buff *first_skb; /* Ptr to skb that triggers dialing */
struct sk_buff *sav_skb; /* Ptr to skb, rejected by LL-driver*/
+#if (LINUX_VERSION_CODE < 0x02010F)
/* Ptr to orig. header_cache_bind */
- void (*org_hcb)(struct hh_cache **, struct device *,
- unsigned short, __u32);
+ void (*org_hcb)(struct hh_cache **,
+ struct device *,
+ unsigned short,
+ __u32);
+#else
+#if (LINUX_VERSION_CODE < 0x2011E)
+ /* Ptr to orig. hard_header_cache */
+ int (*org_hhc)(struct dst_entry *dst,
+ struct dst_entry *neigh,
+ struct hh_cache *hh);
+#else
+ /* Ptr to orig. hard_header_cache */
+ int (*org_hhc)(struct dst_entry *dst,
+ struct neighbour *neigh,
+ struct hh_cache *hh);
+#endif
+#endif
/* Ptr to orig. header_cache_update */
- void (*org_hcu)(struct hh_cache *, struct device *,
+ void (*org_hcu)(struct hh_cache *,
+ struct device *,
unsigned char *);
int pppbind; /* ippp device for bindings */
} isdn_net_local;
#define ISDN_SERIAL_TYPE_NORMAL 1
#define ISDN_SERIAL_TYPE_CALLOUT 2
+#ifdef CONFIG_ISDN_AUDIO
+/* For using sk_buffs with audio we need some private variables
+ * within each sk_buff. For this purpose, we declare a struct here,
+ * and put it always at skb->head. A few macros help accessing the
+ * variables. Of course, we need to check skb_headroom prior to
+ * any access.
+ */
+typedef struct isdn_audio_skb {
+ unsigned short dle_count;
+ unsigned char lock;
+} isdn_audio_skb;
+
+#define ISDN_AUDIO_SKB_DLECOUNT(skb) (((isdn_audio_skb*)skb->head)->dle_count)
+#define ISDN_AUDIO_SKB_LOCK(skb) (((isdn_audio_skb*)skb->head)->lock)
+#endif
+
/* Private data of AT-command-interpreter */
typedef struct atemu {
u_char profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0 */
u_char mdmreg[ISDN_MODEM_ANZREG]; /* Modem-Registers */
char pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0 */
char msn[ISDN_MSNLEN];/* EAZ/MSN */
+#ifdef CONFIG_ISDN_AUDIO
u_char vpar[10]; /* Voice-parameters */
+ int lastDLE; /* Flag for voice-coding: DLE seen */
+#endif
int mdmcmdl; /* Length of Modem-Commandbuffer */
int pluscount; /* Counter for +++ sequence */
int lastplus; /* Timestamp of last + */
- int lastDLE; /* Flag for voice-coding: DLE seen */
char mdmcmd[255]; /* Modem-Commandbuffer */
} atemu;
int blocked_open; /* # of blocked opens */
long session; /* Session of opening process */
long pgrp; /* pgrp of opening process */
- int online; /* B-Channel is up */
- int vonline; /* Voice-channel status */
+ int online; /* 1 = B-Channel is up, drop data */
+ /* 2 = B-Channel is up, deliver d.*/
int dialing; /* Dial in progress */
int rcvsched; /* Receive needs schedule */
int isdn_driver; /* Index to isdn-driver */
int isdn_channel; /* Index to isdn-channel */
int drv_index; /* Index to dev->usage */
int ncarrier; /* Flag: schedule NO CARRIER */
+ unsigned char last_cause[8]; /* Last cause message */
+ unsigned char last_num[ISDN_MSNLEN];
+ /* Last phone-number */
+ unsigned char last_l2; /* Last layer-2 protocol */
+ unsigned char last_si; /* Last service */
+ unsigned char last_lhup; /* Last hangup local? */
+ unsigned char last_dir; /* Last direction (in or out) */
struct timer_list nc_timer; /* Timer for delayed NO CARRIER */
int send_outstanding;/* # of outstanding send-requests */
int xmit_size; /* max. # of chars in xmit_buf */
int xmit_count; /* # of chars in xmit_buf */
unsigned char *xmit_buf; /* transmit buffer */
struct sk_buff_head xmit_queue; /* transmit queue */
+#ifdef CONFIG_ISDN_AUDIO
+ int vonline; /* Voice-channel status */
+ /* Bit 0 = recording */
+ /* Bit 1 = playback */
+ /* Bit 2 = playback, DLE-ETX seen */
struct sk_buff_head dtmf_queue; /* queue for dtmf results */
- struct tty_struct *tty; /* Pointer to corresponding tty */
- atemu emu; /* AT-emulator data */
void *adpcms; /* state for adpcm decompression */
void *adpcmr; /* state for adpcm compression */
void *dtmf_state; /* state for dtmf decoder */
+#endif
+ struct tty_struct *tty; /* Pointer to corresponding tty */
+ atemu emu; /* AT-emulator data */
struct termios normal_termios; /* For saving termios structs */
struct termios callout_termios;
struct wait_queue *open_wait;
struct sqqueue {
struct sqqueue *next;
- int sqno_start;
- int sqno_end;
+ long sqno_start;
+ long sqno_end;
struct sk_buff *skb;
long timer;
};
struct mpqueue {
struct mpqueue *next;
struct mpqueue *last;
- int sqno;
+ long sqno;
struct sk_buff *skb;
int BEbyte;
unsigned long time;
struct slcompress *slcomp;
#endif
unsigned long debug;
+ struct isdn_ppp_compressor *compressor,*link_compressor;
+ void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat;
};
#endif
isdn_if *interface; /* Interface to driver */
int *rcverr; /* Error-counters for B-Ch.-receive */
int *rcvcount; /* Byte-counters for B-Ch.-receive */
+#ifdef CONFIG_ISDN_AUDIO
unsigned long DLEflag; /* Flags: Insert DLE at next read */
+#endif
struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */
struct wait_queue **rcv_waitq; /* Wait-Queues for B-Channel-Reads */
struct wait_queue **snd_waitq; /* Wait-Queue for B-Channel-Send's */
int chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel */
int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */
int usage[ISDN_MAX_CHANNELS]; /* Used by tty/ip/voice */
- char num[ISDN_MAX_CHANNELS][20];/* Remote number of active ch.*/
+ char num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
+ /* Remote number of active ch.*/
int m_idx[ISDN_MAX_CHANNELS]; /* Index for mdm.... */
driver *drv[ISDN_MAX_DRIVERS]; /* Array of drivers */
isdn_net_dev *netdev; /* Linked list of net-if's */
extern int isdn_ppp_dial_slave(char *);
extern int isdn_ppp_hangup_slave(char *);
-struct pppinfo
+#define CALLTYPE_INCOMING 0x1
+#define CALLTYPE_OUTGOING 0x2
+#define CALLTYPE_CALLBACK 0x4
+
+struct pppcallinfo
{
- int type; /* set by user */
- union {
- char clid[32]; /* calling ID */
- int bundles;
- int linknumber;
- } info;
+ int calltype;
+ unsigned char local_num[64];
+ unsigned char remote_num[64];
+ int charge_units;
};
-
-#define PPPIOCLINKINFO _IOWR('t',128,struct pppinfo)
+#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo)
#define PPPIOCBUNDLE _IOW('t',129,int)
#define PPPIOCGMPFLAGS _IOR('t',130,int)
#define PPPIOCSMPFLAGS _IOW('t',131,int)
#define PPPIOCSMPMTU _IOW('t',132,int)
#define PPPIOCSMPMRU _IOW('t',133,int)
+#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long)
+#define PPPIOCSCOMPRESSOR _IOW('t',135,int)
-#define PPP_MP 0x003d
+#define PPP_MP 0x003d
+#define PPP_LINK_COMP 0x00fb
#define SC_MP_PROT 0x00000200
#define SC_REJ_MP_PROT 0x00000400
#define MP_END_FRAG 0x40
#define MP_BEGIN_FRAG 0x80
-#endif
+#ifdef __KERNEL__
+/*
+ * this is an 'old friend' from ppp-comp.h under a new name
+ * check the original include for more information
+ */
+struct isdn_ppp_compressor {
+ struct isdn_ppp_compressor *next,*prev;
+ int num; /* CCP compression protocol number */
+ void *(*comp_alloc) (unsigned char *options, int opt_len);
+ void (*comp_free) (void *state);
+ int (*comp_init) (void *state, unsigned char *options, int opt_len,
+ int unit, int opthdr, int debug);
+ void (*comp_reset) (void *state);
+ int (*compress) (void *state,struct sk_buff *in, struct sk_buff *skb_out,
+ int proto);
+ void (*comp_stat) (void *state, struct compstat *stats);
+ void *(*decomp_alloc) (unsigned char *options, int opt_len);
+ void (*decomp_free) (void *state);
+ int (*decomp_init) (void *state, unsigned char *options,
+ int opt_len, int unit, int opthdr, int mru, int debug);
+ void (*decomp_reset) (void *state);
+ int (*decompress) (void *state, unsigned char *ibuf, int isize, unsigned char *obuf, int osize);
+ void (*incomp) (void *state, unsigned char *ibuf, int icnt);
+ void (*decomp_stat) (void *state, struct compstat *stats);
+};
+
+extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
+extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_ISDN_PPP_H */
+
-/* $Id: isdnif.h,v 1.13 1996/11/13 02:39:59 fritz Exp $
+/* $Id: isdnif.h,v 1.20 1997/05/27 15:18:06 fritz Exp $
*
* Linux ISDN subsystem
*
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdnif.h,v $
+ * Revision 1.20 1997/05/27 15:18:06 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.19 1997/03/25 23:13:56 keil
+ * NI-1 US protocol
+ *
+ * Revision 1.18 1997/03/04 22:09:18 calle
+ * Change macros copy_from_user and copy_to_user in inline function.
+ * These are now correct replacements of the functions for 2.1.xx
+ *
+ * Revision 1.17 1997/02/10 21:12:53 fritz
+ * More setup-interface changes.
+ *
+ * Revision 1.16 1997/02/10 19:42:57 fritz
+ * New interface for reporting incoming calls.
+ *
+ * Revision 1.15 1997/02/09 00:18:42 keil
+ * leased line support
+ *
+ * Revision 1.14 1997/02/03 23:43:00 fritz
+ * Misc changes for Kernel 2.1.X compatibility.
+ *
* Revision 1.13 1996/11/13 02:39:59 fritz
* More compatibility changes.
*
#define ISDN_PTYPE_UNKNOWN 0 /* Protocol undefined */
#define ISDN_PTYPE_1TR6 1 /* german 1TR6-protocol */
#define ISDN_PTYPE_EURO 2 /* EDSS1-protocol */
+#define ISDN_PTYPE_LEASED 3 /* for leased lines */
+#define ISDN_PTYPE_NI1 4 /* US NI-1 protocol */
/*
* Values for Layer-2-protocol-selection
#define ISDN_FEATURE_P_UNKNOWN (0x1000 << ISDN_PTYPE_UNKNOWN)
#define ISDN_FEATURE_P_1TR6 (0x1000 << ISDN_PTYPE_1TR6)
#define ISDN_FEATURE_P_EURO (0x1000 << ISDN_PTYPE_EURO)
+#define ISDN_FEATURE_P_NI1 (0x1000 << ISDN_PTYPE_NI1)
+
+typedef struct setup_parm {
+ char phone[32]; /* Remote Phone-Number */
+ char eazmsn[32]; /* Local EAZ or MSN */
+ unsigned char si1; /* Service Indicator 1 */
+ unsigned char si2; /* Service Indicator 2 */
+ unsigned char plan; /* Numbering plan */
+ unsigned char screen; /* Screening info */
+} setup_parm;
/*
* Structure for exchanging above infos
int driver; /* Lowlevel-Driver-ID */
int command; /* Command or Status (see above) */
ulong arg; /* Additional Data */
- char num[50]; /* Additional Data */
+ union {
+ char num[50]; /* Additional Data */
+ setup_parm setup;
+ } parm;
} isdn_ctrl;
/*
#endif
#if (LINUX_VERSION_CODE < 0x020100)
#include <linux/mm.h>
-#define copy_from_user memcpy_fromfs
-#define copy_to_user memcpy_tofs
+
+static inline unsigned long copy_from_user(void *to, const void *from, unsigned long n)
+{
+ int i;
+ if ((i = verify_area(VERIFY_READ, from, n)) != 0)
+ return i;
+ memcpy_fromfs(to, from, n);
+ return 0;
+}
+
+static inline unsigned long copy_to_user(void *to, const void *from, unsigned long n)
+{
+ int i;
+ if ((i = verify_area(VERIFY_WRITE, to, n)) != 0)
+ return i;
+ memcpy_tofs(to, from, n);
+ return 0;
+}
+
#define GET_USER(x, addr) ( x = get_user(addr) )
#define RWTYPE int
#define LSTYPE int
#define LSARG long long
#endif
+#if (LINUX_VERSION_CODE < 0x02010F)
+#define SET_SKB_FREE(x) ( x->free = 1 )
+#else
+#define SET_SKB_FREE(x)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02011F)
+#define CLOSETYPE void
+#define CLOSEVAL
+#else
+#define CLOSETYPE int
+#define CLOSEVAL (0)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x020125)
+#define test_and_clear_bit clear_bit
+#define test_and_set_bit set_bit
+#endif
+
#endif /* __KERNEL__ */
#endif /* isdnif_h */
-
--- /dev/null
+/*
+ * $Id: kernelcapi.h,v 1.1 1997/03/04 21:27:33 calle Exp $
+ *
+ * Kernel CAPI 2.0 Interface for Linux
+ *
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: kernelcapi.h,v $
+ * Revision 1.1 1997/03/04 21:27:33 calle
+ * First 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 __KERNEL_CAPI_H__
+#define __KERNEL_CAPI_H__
+
+#define CAPI_MAXAPPL 20 /*
+ * maximum number of applications
+ */
+#define CAPI_MAXCONTR 4 /*
+ * maximum number of controller
+ */
+#define CAPI_MAXDATAWINDOW 8
+
+#ifdef __KERNEL__
+
+struct capi_interface {
+ int (*capi_installed) (void);
+
+ __u16(*capi_register) (capi_register_params * rparam, __u16 * applidp);
+ __u16(*capi_release) (__u16 applid);
+ __u16(*capi_put_message) (__u16 applid, struct sk_buff * msg);
+ __u16(*capi_get_message) (__u16 applid, struct sk_buff ** msgp);
+ __u16(*capi_set_signal) (__u16 applid,
+ void (*signal) (__u16 applid, __u32 param),
+ __u32 param);
+ __u16(*capi_get_manufacturer) (__u16 contr, __u8 buf[CAPI_MANUFACTURER_LEN]);
+ __u16(*capi_get_version) (__u16 contr, struct capi_version * verp);
+ __u16(*capi_get_serial) (__u16 contr, __u8 serial[CAPI_SERIAL_LEN]);
+ __u16(*capi_get_profile) (__u16 contr, struct capi_profile * profp);
+
+ /*
+ * to init controllers, data is always in user memory
+ */
+ int (*capi_manufacturer) (unsigned int cmd, void *data);
+
+};
+
+#define KCI_CONTRUP 0
+#define KCI_CONTRDOWN 1
+
+struct capi_interface_user {
+ char name[20];
+ void (*callback) (unsigned int cmd, __u16 contr, void *data);
+ struct capi_interface_user *next;
+};
+
+struct capi_interface *attach_capi_interface(struct capi_interface_user *);
+int detach_capi_interface(struct capi_interface_user *);
+
+
+#define CAPI_NOERROR 0x0000
+
+#define CAPI_TOOMANYAPPLS 0x1001
+#define CAPI_LOGBLKSIZETOSMALL 0x1002
+#define CAPI_BUFFEXECEEDS64K 0x1003
+#define CAPI_MSGBUFSIZETOOSMALL 0x1004
+#define CAPI_ANZLOGCONNNOTSUPPORTED 0x1005
+#define CAPI_REGRESERVED 0x1006
+#define CAPI_REGBUSY 0x1007
+#define CAPI_REGOSRESOURCEERR 0x1008
+#define CAPI_REGNOTINSTALLED 0x1009
+#define CAPI_REGCTRLERNOTSUPPORTEXTEQUIP 0x100a
+#define CAPI_REGCTRLERONLYSUPPORTEXTEQUIP 0x100b
+
+#define CAPI_ILLAPPNR 0x1101
+#define CAPI_ILLCMDORSUBCMDORMSGTOSMALL 0x1102
+#define CAPI_SENDQUEUEFULL 0x1103
+#define CAPI_RECEIVEQUEUEEMPTY 0x1104
+#define CAPI_RECEIVEOVERFLOW 0x1105
+#define CAPI_UNKNOWNNOTPAR 0x1106
+#define CAPI_MSGBUSY 0x1107
+#define CAPI_MSGOSRESOURCEERR 0x1108
+#define CAPI_MSGNOTINSTALLED 0x1109
+#define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP 0x110a
+#define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b
+
+#endif /* __KERNEL__ */
+
+#endif /* __KERNEL_CAPI_H__ */
#define PCI_VENDOR_ID_OAK 0x104e
#define PCI_DEVICE_ID_OAK_OTI107 0x0107
+/* Winbond have two vendor ID! See 0x10ad as well */
+#define PCI_VENDOR_ID_WINBOND2 0x1050
+#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940
+
#define PCI_VENDOR_ID_PROMISE 0x105a
#define PCI_DEVICE_ID_PROMISE_5300 0x5300
#define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000
#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000
+#define PCI_VENDOR_ID_COMPEX 0x11f6
+#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401
+
#define PCI_VENDOR_ID_RP 0x11fe
#define PCI_DEVICE_ID_RP8OCTA 0x0001
#define PCI_DEVICE_ID_RP8INTF 0x0002
PROC_SCSI_A2091,
PROC_SCSI_GVP11,
PROC_SCSI_ATARI,
+ PROC_SCSI_GDTH,
PROC_SCSI_IDESCSI,
PROC_SCSI_SCSI_DEBUG,
PROC_SCSI_NOT_PRESENT,
extern void generic_NCR53C400_setup(char *str, int *intr);
extern void aha152x_setup(char *str, int *ints);
extern void aha1542_setup(char *str, int *ints);
+extern void gdth_setup(char *str, int *ints);
extern void aic7xxx_setup(char *str, int *ints);
extern void AM53C974_setup(char *str, int *ints);
extern void BusLogic_Setup(char *str, int *ints);
#ifdef CONFIG_ISDN_DRV_ICN
extern void icn_setup(char *str, int *ints);
#endif
-#ifdef CONFIG_ISDN_DRV_TELES
-extern void teles_setup(char *str, int *ints);
+#ifdef CONFIG_ISDN_DRV_HISAX
+extern void HiSax_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_ISDN_DRV_PCBIT
+extern void pcbit_setup(char *str, int *ints);
#endif
#ifdef CONFIG_ATARIMOUSE
#ifdef CONFIG_DIGI
extern void pcxx_setup(char *str, int *ints);
#endif
-#ifdef CONFIG_ISDN_DRV_PCBIT
-extern void pcbit_setup(char *str, int *ints);
-#endif
#ifdef CONFIG_RISCOM8
extern void riscom8_setup(char *str, int *ints);
#endif
#ifdef CONFIG_SCSI_AHA1542
{ "aha1542=", aha1542_setup},
#endif
+#ifdef CONFIG_SCSI_GDTH
+ { "gdth=", gdth_setup},
+#endif
#ifdef CONFIG_SCSI_AIC7XXX
{ "aic7xxx=", aic7xxx_setup},
#endif
#ifdef CONFIG_ISDN_DRV_ICN
{ "icn=", icn_setup },
#endif
-#ifdef CONFIG_ISDN_DRV_TELES
- { "teles=", teles_setup },
+#ifdef CONFIG_ISDN_DRV_HISAX
+ { "hisax=", HiSax_setup },
+ { "HiSax=", HiSax_setup },
#endif
#ifdef CONFIG_ISDN_DRV_PCBIT
{ "pcbit=", pcbit_setup },
asmlinkage void sys_sync(void); /* it's really int */
extern void hard_reset_now(void);
extern void do_unblank_screen(void);
+extern void gdth_halt(void);
extern int C_A_D;
int panic_timeout = 0;
printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout);
for(i = 0; i < (panic_timeout*1000); i++)
udelay(1000);
+#ifdef CONFIG_SCSI_GDTH
+ gdth_halt();
+#endif
hard_reset_now();
}
for(;;);
int C_A_D = 1;
extern void adjust_clock(void);
+extern void gdth_halt(void);
asmlinkage int sys_ni_syscall(void)
{
return -EPERM;
if (magic != 0xfee1dead || magic_too != 672274793)
return -EINVAL;
- if (flag == 0x01234567)
+ if (flag == 0x01234567) {
+#ifdef CONFIG_SCSI_GDTH
+ gdth_halt();
+#endif
hard_reset_now();
- else if (flag == 0x89ABCDEF)
+ } else if (flag == 0x89ABCDEF)
C_A_D = 1;
else if (!flag)
C_A_D = 0;
*/
void ctrl_alt_del(void)
{
- if (C_A_D)
+ if (C_A_D) {
+#ifdef CONFIG_SCSI_GDTH
+ gdth_halt();
+#endif
hard_reset_now();
- else
+ } else
kill_proc(1, SIGINT, 1);
}