1
0
Fork 0

isdn: remove hisax driver

With the decline of ISDN, this seems to have become almost completely
obsolete, and even in the past years before that, almost all remaining
users appear to have used mISDN instead.

Birger Harzenetter noted that he is still using i4l/hisax to take
advantage of the 'divert' driver for call diversion, but otherwise uses
mISDN on the same hardware. This is a rare edge case as far as I
can tell, but we are still breaking an actively used work flow
(see https://xkcd.com/1172/).

We debated moving i4l/hisax to staging as an intermediate step, but as
he is not likely to change the setup, and that would just delay breaking
this use case.  The alternatives here are to stay on stable kernels
< 5.2, to create an external driver repository for isdn4linux, or to
add divert functionality to mISDN.

Cc: Birger Harzenetter <WIMPy@yeti.dk>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
alistair/sunxi64-5.4-dsi
Arnd Bergmann 2019-04-18 22:47:35 +02:00
parent 8e6c8aa3b5
commit 85993b8c97
104 changed files with 0 additions and 56236 deletions

View File

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

View File

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

View File

@ -8,7 +8,6 @@ obj-$(CONFIG_ISDN_CAPI) += capi/
obj-$(CONFIG_MISDN) += mISDN/
obj-$(CONFIG_ISDN) += hardware/
obj-$(CONFIG_ISDN_DIVERSION) += divert/
obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/
obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/
obj-$(CONFIG_HYSDN) += hysdn/
obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/

View File

@ -1,423 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "Passive cards"
config ISDN_DRV_HISAX
tristate "HiSax SiemensChipSet driver support"
select CRC_CCITT
---help---
This is a driver supporting the Siemens chipset on various
ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles
S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
compatibles).
HiSax is just the name of this driver, not the name of any hardware.
If you have a card with such a chipset, you should say Y here and
also to the configuration option of the driver for your particular
card, below.
if ISDN_DRV_HISAX
comment "D-channel protocol features"
config HISAX_EURO
bool "HiSax Support for EURO/DSS1"
help
Say Y or N according to the D-channel protocol which your local
telephone service company provides.
The call control protocol E-DSS1 is used in most European countries.
If unsure, say Y.
config DE_AOC
bool "Support for german chargeinfo"
depends on HISAX_EURO
help
If you want that the HiSax hardware driver sends messages to the
upper level of the isdn code on each AOCD (Advice Of Charge, During
the call -- transmission of the fee information during a call) and
on each AOCE (Advice Of Charge, at the End of the call --
transmission of fee information at the end of the call), say Y here.
This works only in Germany.
config HISAX_NO_SENDCOMPLETE
bool "Disable sending complete"
depends on HISAX_EURO
help
If you have trouble with some ugly exchanges or you live in
Australia select this option.
config HISAX_NO_LLC
bool "Disable sending low layer compatibility"
depends on HISAX_EURO
help
If you have trouble with some ugly exchanges try to select this
option.
config HISAX_NO_KEYPAD
bool "Disable keypad protocol option"
depends on HISAX_EURO
help
If you like to send special dial strings including * or # without
using the keypad protocol, select this option.
config HISAX_1TR6
bool "HiSax Support for german 1TR6"
help
Say Y or N according to the D-channel protocol which your local
telephone service company provides.
1TR6 is an old call control protocol which was used in Germany
before E-DSS1 was established. Nowadays, all new lines in Germany
use E-DSS1.
config HISAX_NI1
bool "HiSax Support for US NI1"
help
Enable this if you like to use ISDN in US on a NI1 basic rate
interface.
config HISAX_MAX_CARDS
int "Maximum number of cards supported by HiSax"
default "8"
help
This option allows you to specify the maximum number of cards which
the HiSax driver will be able to handle.
comment "HiSax supported cards"
config HISAX_16_0
bool "Teles 16.0/8.0"
depends on ISA
help
This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8
and many compatibles.
See <file: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.
config HISAX_16_3
bool "Teles 16.3 or PNP or PCMCIA"
help
This enables HiSax support for the Teles ISDN-cards S0-16.3 the
Teles/Creatix PnP and the Teles PCMCIA.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_TELESPCI
bool "Teles PCI"
depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
help
This enables HiSax support for the Teles PCI.
See <file:Documentation/isdn/README.HiSax> on how to configure it.
config HISAX_S0BOX
bool "Teles S0Box"
help
This enables HiSax support for the Teles/Creatix parallel port
S0BOX. See <file:Documentation/isdn/README.HiSax> on how to
configure it.
config HISAX_AVM_A1
bool "AVM A1 (Fritz)"
depends on ISA
help
This enables HiSax support for the AVM A1 (aka "Fritz").
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_FRITZPCI
bool "AVM PnP/PCI (Fritz!PnP/PCI)"
depends on BROKEN || !PPC64
help
This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI".
See <file:Documentation/isdn/README.HiSax> on how to configure it.
config HISAX_AVM_A1_PCMCIA
bool "AVM A1 PCMCIA (Fritz)"
help
This enables HiSax support for the AVM A1 "Fritz!PCMCIA").
See <file:Documentation/isdn/README.HiSax> on how to configure it.
config HISAX_ELSA
bool "Elsa cards"
help
This enables HiSax support for the Elsa Mircolink ISA cards, for the
Elsa Quickstep series cards and Elsa PCMCIA.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_IX1MICROR2
bool "ITK ix1-micro Revision 2"
depends on ISA
help
This enables HiSax support for the ITK ix1-micro Revision 2 card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_DIEHLDIVA
bool "Eicon.Diehl Diva cards"
help
This enables HiSax support for the Eicon.Diehl Diva none PRO
versions passive ISDN cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_ASUSCOM
bool "ASUSCOM ISA cards"
depends on ISA
help
This enables HiSax support for the AsusCom and their OEM versions
passive ISDN ISA cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_TELEINT
bool "TELEINT cards"
depends on ISA
help
This enables HiSax support for the TELEINT SA1 semiactiv ISDN card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_HFCS
bool "HFC-S based cards"
depends on ISA
help
This enables HiSax support for the HFC-S 2BDS0 based cards, like
teles 16.3c.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_SEDLBAUER
bool "Sedlbauer cards"
help
This enables HiSax support for the Sedlbauer passive ISDN cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using the different cards, a different D-channel protocol, or
non-standard IRQ/port settings.
config HISAX_SPORTSTER
bool "USR Sportster internal TA"
depends on ISA
help
This enables HiSax support for the USR Sportster internal TA card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_MIC
bool "MIC card"
depends on ISA
help
This enables HiSax support for the ITH MIC card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_NETJET
bool "NETjet card"
depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
depends on VIRT_TO_BUS
help
This enables HiSax support for the NetJet from Traverse
Technologies.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_NETJET_U
bool "NETspider U card"
depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE))
depends on VIRT_TO_BUS
help
This enables HiSax support for the Netspider U interface ISDN card
from Traverse Technologies.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_NICCY
bool "Niccy PnP/PCI card"
help
This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_ISURF
bool "Siemens I-Surf card"
depends on ISA
help
This enables HiSax support for the Siemens I-Talk/I-Surf card with
ISAR chip.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_HSTSAPHIR
bool "HST Saphir card"
depends on ISA
help
This enables HiSax support for the HST Saphir card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_BKM_A4T
bool "Telekom A4T card"
depends on PCI
help
This enables HiSax support for the Telekom A4T card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_SCT_QUADRO
bool "Scitel Quadro card"
depends on PCI
help
This enables HiSax support for the Scitel Quadro card.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_GAZEL
bool "Gazel cards"
help
This enables HiSax support for the Gazel cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_HFC_PCI
bool "HFC PCI-Bus cards"
depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
help
This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
For more information see under
<file:Documentation/isdn/README.hfc-pci>.
config HISAX_W6692
bool "Winbond W6692 based cards"
depends on PCI
help
This enables HiSax support for Winbond W6692 based PCI ISDN cards.
See <file:Documentation/isdn/README.HiSax> on how to configure it
using a different D-channel protocol, or non-standard IRQ/port
settings.
config HISAX_HFC_SX
bool "HFC-S+, HFC-SP, HFC-PCMCIA cards"
help
This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
cards. This code is not finished yet.
config HISAX_ENTERNOW_PCI
bool "Formula-n enter:now PCI card"
depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN)))
help
This enables HiSax support for the Formula-n enter:now PCI
ISDN card.
config HISAX_DEBUG
bool "HiSax debugging"
help
This enables debugging code in the new-style HiSax drivers, i.e.
the ST5481 USB driver currently.
If in doubt, say yes.
comment "HiSax PCMCIA card service modules"
config HISAX_SEDLBAUER_CS
tristate "Sedlbauer PCMCIA cards"
depends on PCMCIA && HISAX_SEDLBAUER
help
This enables the PCMCIA client driver for the Sedlbauer Speed Star
and Speed Star II cards.
config HISAX_ELSA_CS
tristate "ELSA PCMCIA MicroLink cards"
depends on PCMCIA && HISAX_ELSA
help
This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink
card.
config HISAX_AVM_A1_CS
tristate "AVM A1 PCMCIA cards"
depends on PCMCIA && ISDN_DRV_HISAX
help
This enables the PCMCIA client driver for the AVM A1 / Fritz!Card
PCMCIA cards.
config HISAX_TELES_CS
tristate "TELES PCMCIA cards"
depends on PCMCIA && HISAX_16_3
help
This enables the PCMCIA client driver for the Teles PCMCIA cards.
comment "HiSax sub driver modules"
config HISAX_ST5481
tristate "ST5481 USB ISDN modem"
depends on USB
select ISDN_HDLC
select CRC_CCITT
select BITREVERSE
help
This enables the driver for ST5481 based USB ISDN adapters,
e.g. the BeWan Gazel 128 USB
config HISAX_HFCUSB
tristate "HFC USB based ISDN modems"
depends on USB
help
This enables the driver for HFC USB based ISDN modems.
config HISAX_HFC4S8S
tristate "HFC-4S/8S based ISDN cards"
help
This enables the driver for HFC-4S/8S based ISDN cards.
config HISAX_FRITZ_PCIPNP
tristate "AVM Fritz!Card PCI/PCIv2/PnP support"
depends on PCI
help
This enables the driver for the AVM Fritz!Card PCI,
Fritz!Card PCI v2 and Fritz!Card PnP.
(the latter also needs you to select "ISA Plug and Play support"
from the menu "Plug and Play configuration")
endif
endmenu

View File

@ -1,60 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for the hisax ISDN device driver
# The target object and module list name.
# Define maximum number of cards
ccflags-y := -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o
obj-$(CONFIG_HISAX_TELES_CS) += teles_cs.o
obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o
obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o
obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
# Multipart objects.
hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \
st5481_b.o
hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
lmgr.o q931.o callc.o fsm.o
hisax-$(CONFIG_HISAX_EURO) += l3dss1.o
hisax-$(CONFIG_HISAX_NI1) += l3ni1.o
hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o
hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o
hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o \
isar.o
hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o
hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o
hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o
hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o
hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o
hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o
hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_W6692) += w6692.o
hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o

View File

@ -1,794 +0,0 @@
/* gerdes_amd7930.c,v 0.99 2001/10/02
*
* gerdes_amd7930.c Amd 79C30A and 79C32A specific routines
* (based on HiSax driver by Karsten Keil)
*
* Author Christoph Ersfeld <info@formula-n.de>
* Formula-n Europe AG (www.formula-n.com)
* previously Gerdes AG
*
*
* This file is (c) under GNU PUBLIC LICENSE
*
*
* Notes:
* Version 0.99 is the first release of this driver and there are
* certainly a few bugs.
*
* Please don't report any malfunction to me without sending
* (compressed) debug-logs.
* It would be nearly impossible to retrace it.
*
* Log D-channel-processing as follows:
*
* 1. Load hisax with card-specific parameters, this example ist for
* Formula-n enter:now ISDN PCI and compatible
* (f.e. Gerdes Power ISDN PCI)
*
* modprobe hisax type=41 protocol=2 id=gerdes
*
* if you chose an other value for id, you need to modify the
* code below, too.
*
* 2. set debug-level
*
* hisaxctrl gerdes 1 0x3ff
* hisaxctrl gerdes 11 0x4f
* cat /dev/isdnctrl >> ~/log &
*
* Please take also a look into /var/log/messages if there is
* anything importand concerning HISAX.
*
*
* Credits:
* Programming the driver for Formula-n enter:now ISDN PCI and
* necessary this driver for the used Amd 7930 D-channel-controller
* was spnsored by Formula-n Europe AG.
* Thanks to Karsten Keil and Petr Novak, who gave me support in
* Hisax-specific questions.
* I want so say special thanks to Carl-Friedrich Braun, who had to
* answer a lot of questions about generally ISDN and about handling
* of the Amd-Chip.
*
*/
#include "hisax.h"
#include "isdnl1.h"
#include "isac.h"
#include "amd7930_fn.h"
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/gfp.h>
static void Amd7930_new_ph(struct IsdnCardState *cs);
static WORD initAMD[] = {
0x0100,
0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2
0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on)
0x0087, 1, 0xFF, // DMR2
0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on)
0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition )
0x0084, 2, 0x80, 0x00, // DRLR
0x00C0, 1, 0x47, // PPCR1
0x00C8, 1, 0x01, // PPCR2
0x0102,
0x0107,
0x01A1, 1,
0x0121, 1,
0x0189, 2,
0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4
0x0063, 2, 0x08, 0x08, // GX
0x0064, 2, 0x08, 0x08, // GR
0x0065, 2, 0x99, 0x00, // GER
0x0066, 2, 0x7C, 0x8B, // STG
0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2
0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2
0x0069, 1, 0x4F, // MMR1
0x006A, 1, 0x00, // MMR2
0x006C, 1, 0x40, // MMR3
0x0021, 1, 0x02, // INIT
0x00A3, 1, 0x40, // LMR1
0xFFFF
};
static void /* macro wWordAMD */
WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
{
wByteAMD(cs, 0x00, reg);
wByteAMD(cs, 0x01, LOBYTE(val));
wByteAMD(cs, 0x01, HIBYTE(val));
}
static WORD /* macro rWordAMD */
ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
{
WORD res;
/* direct access register */
if (reg < 8) {
res = rByteAMD(cs, reg);
res += 256 * rByteAMD(cs, reg);
}
/* indirect access register */
else {
wByteAMD(cs, 0x00, reg);
res = rByteAMD(cs, 0x01);
res += 256 * rByteAMD(cs, 0x01);
}
return (res);
}
static void
Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
cs->dc.amd7930.lmr1 = command;
wByteAMD(cs, 0xA3, command);
}
static BYTE i430States[] = {
// to reset F3 F4 F5 F6 F7 F8 AR from
0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init
0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset
0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04, // F3
0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F4
0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F5
0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, // F6
0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00, // F7
0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // F8
0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A}; // AR
/* Row init - reset F3 F4 F5 F6 F7 F8 AR */
static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
static void
Amd7930_get_state(struct IsdnCardState *cs) {
BYTE lsr = rByteAMD(cs, 0xA1);
cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
Amd7930_new_ph(cs);
}
static void
Amd7930_new_ph(struct IsdnCardState *cs)
{
u_char index = stateHelper[cs->dc.amd7930.old_state] * 8 + stateHelper[cs->dc.amd7930.ph_state] - 1;
u_char message = i430States[index];
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
/* abort transmit if nessesary */
if ((message & 0xf0) && (cs->tx_skb)) {
wByteAMD(cs, 0x21, 0xC2);
wByteAMD(cs, 0x21, 0x02);
}
switch (message & 0x0f) {
case (1):
l1_msg(cs, HW_RESET | INDICATION, NULL);
Amd7930_get_state(cs);
break;
case (2): /* init, Card starts in F3 */
l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
break;
case (3):
l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
break;
case (4):
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
break;
case (5):
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
break;
case (6):
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
break;
case (7): /* init, Card starts in F7 */
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
break;
case (8):
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
/* fall through */
case (9):
Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
break;
case (10):
Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
cs->dc.amd7930.old_state = 3;
break;
case (11):
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
break;
default:
break;
}
}
static void
Amd7930_bh(struct work_struct *work)
{
struct IsdnCardState *cs =
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
Amd7930_new_ph(cs);
}
if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
DChannel_proc_rcv(cs);
}
if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
DChannel_proc_xmt(cs);
}
}
static void
Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
{
BYTE stat, der;
BYTE *ptr;
struct sk_buff *skb;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "Amd7930: empty_Dfifo");
ptr = cs->rcvbuf + cs->rcvidx;
/* AMD interrupts off */
AmdIrqOff(cs);
/* read D-Channel-Fifo*/
stat = rByteAMD(cs, 0x07); // DSR2
/* while Data in Fifo ... */
while ((stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1)) {
*ptr = rByteAMD(cs, 0x04); // DCRB
ptr++;
stat = rByteAMD(cs, 0x07); // DSR2
cs->rcvidx = ptr - cs->rcvbuf;
/* Paket ready? */
if (stat & 1) {
der = rWordAMD(cs, 0x03);
/* no errors, packet ok */
if (!der && !flag) {
rWordAMD(cs, 0x89); // clear DRCR
if ((cs->rcvidx) > 0) {
if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
else {
/* Debugging */
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
QuickHex(t, cs->rcvbuf, cs->rcvidx);
debugl1(cs, "%s", cs->dlog);
}
/* moves received data in sk-buffer */
skb_put_data(skb, cs->rcvbuf,
cs->rcvidx);
skb_queue_tail(&cs->rq, skb);
}
}
}
/* throw damaged packets away, reset receive-buffer, indicate RX */
ptr = cs->rcvbuf;
cs->rcvidx = 0;
schedule_event(cs, D_RCVBUFREADY);
}
}
/* Packet to long, overflow */
if (cs->rcvidx >= MAX_DFRAME_LEN_L1) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
cs->rcvidx = 0;
return;
}
/* AMD interrupts on */
AmdIrqOn(cs);
}
static void
Amd7930_fill_Dfifo(struct IsdnCardState *cs)
{
WORD dtcrr, dtcrw, len, count;
BYTE txstat, dmr3;
BYTE *ptr, *deb_ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "Amd7930: fill_Dfifo");
if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
return;
dtcrw = 0;
if (!cs->dc.amd7930.tx_xmtlen)
/* new Frame */
len = dtcrw = cs->tx_skb->len;
/* continue frame */
else len = cs->dc.amd7930.tx_xmtlen;
/* AMD interrupts off */
AmdIrqOff(cs);
deb_ptr = ptr = cs->tx_skb->data;
/* while free place in tx-fifo available and data in sk-buffer */
txstat = 0x10;
while ((txstat & 0x10) && (cs->tx_cnt < len)) {
wByteAMD(cs, 0x04, *ptr);
ptr++;
cs->tx_cnt++;
txstat = rByteAMD(cs, 0x07);
}
count = ptr - cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
dtcrr = rWordAMD(cs, 0x85); // DTCR
dmr3 = rByteAMD(cs, 0x8E);
if (cs->debug & L1_DEB_ISAC) {
debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
}
/* writeing of dtcrw starts transmit */
if (!cs->dc.amd7930.tx_xmtlen) {
wWordAMD(cs, 0x85, dtcrw);
cs->dc.amd7930.tx_xmtlen = dtcrw;
}
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
del_timer(&cs->dbusytimer);
}
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
add_timer(&cs->dbusytimer);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
QuickHex(t, deb_ptr, count);
debugl1(cs, "%s", cs->dlog);
}
/* AMD interrupts on */
AmdIrqOn(cs);
}
void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
{
BYTE dsr1, dsr2, lsr;
WORD der;
while (irflags)
{
dsr1 = rByteAMD(cs, 0x02);
der = rWordAMD(cs, 0x03);
dsr2 = rByteAMD(cs, 0x07);
lsr = rByteAMD(cs, 0xA1);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
/* D error -> read DER and DSR2 bit 2 */
if (der || (dsr2 & 4)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
/* RX, TX abort if collision detected */
if (der & 2) {
wByteAMD(cs, 0x21, 0xC2);
wByteAMD(cs, 0x21, 0x02);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
/* restart frame */
if (cs->tx_skb) {
skb_push(cs->tx_skb, cs->tx_cnt);
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
Amd7930_fill_Dfifo(cs);
} else {
printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
}
}
/* remove damaged data from fifo */
Amd7930_empty_Dfifo(cs, 1);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
/* restart TX-Frame */
if (cs->tx_skb) {
skb_push(cs->tx_skb, cs->tx_cnt);
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
Amd7930_fill_Dfifo(cs);
}
}
/* D TX FIFO empty -> fill */
if (irflags & 1) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
/* AMD interrupts off */
AmdIrqOff(cs);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->tx_skb->len)
Amd7930_fill_Dfifo(cs);
}
/* AMD interrupts on */
AmdIrqOn(cs);
}
/* D RX FIFO full or tiny packet in Fifo -> empty */
if ((irflags & 2) || (dsr1 & 2)) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
Amd7930_empty_Dfifo(cs, 0);
}
/* D-Frame transmit complete */
if (dsr1 & 64) {
if (cs->debug & L1_DEB_ISAC) {
debugl1(cs, "Amd7930: interrupt: transmit packet ready");
}
/* AMD interrupts off */
AmdIrqOff(cs);
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
cs->tx_skb = NULL;
}
if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
Amd7930_fill_Dfifo(cs);
}
else
schedule_event(cs, D_XMTBUFREADY);
/* AMD interrupts on */
AmdIrqOn(cs);
}
/* LIU status interrupt -> read LSR, check statechanges */
if (lsr & 0x38) {
/* AMD interrupts off */
AmdIrqOff(cs);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) + 2));
cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
schedule_event(cs, D_L1STATECHANGE);
/* AMD interrupts on */
AmdIrqOn(cs);
}
/* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
irflags = rByteAMD(cs, 0x00);
}
}
static void
Amd7930_l1hw(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
u_long flags;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
switch (pr) {
case (PH_DATA | REQUEST):
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
skb_queue_tail(&cs->sq, skb);
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
#endif
} else {
cs->tx_skb = skb;
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
#endif
Amd7930_fill_Dfifo(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
skb_queue_tail(&cs->sq, skb);
spin_unlock_irqrestore(&cs->lock, flags);
break;
}
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
cs->tx_skb = skb;
cs->tx_cnt = 0;
cs->dc.amd7930.tx_xmtlen = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
#endif
Amd7930_fill_Dfifo(cs);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | REQUEST):
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb) ? "yes" : "no");
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
if (cs->dc.amd7930.ph_state == 8) {
/* b-channels off, PH-AR cleared
* change to F3 */
Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5
spin_unlock_irqrestore(&cs->lock, flags);
} else {
Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
cs->dc.amd7930.ph_state = 2;
spin_unlock_irqrestore(&cs->lock, flags);
Amd7930_new_ph(cs);
}
break;
case (HW_ENABLE | REQUEST):
cs->dc.amd7930.ph_state = 9;
Amd7930_new_ph(cs);
break;
case (HW_INFO3 | REQUEST):
// automatic
break;
case (HW_TESTLOOP | REQUEST):
/* not implemented yet */
break;
case (HW_DEACTIVATE | RESPONSE):
skb_queue_purge(&cs->rq);
skb_queue_purge(&cs->sq);
if (cs->tx_skb) {
dev_kfree_skb(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
break;
default:
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
break;
}
}
static void
setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: setstack called");
st->l1.l1hw = Amd7930_l1hw;
}
static void
DC_Close_Amd7930(struct IsdnCardState *cs) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: DC_Close called");
}
static void
dbusy_timer_handler(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
u_long flags;
struct PStack *stptr;
WORD dtcr, der;
BYTE dsr1, dsr2;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: dbusy_timer expired!");
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
spin_lock_irqsave(&cs->lock, flags);
/* D Transmit Byte Count Register:
* Counts down packet's number of Bytes, 0 if packet ready */
dtcr = rWordAMD(cs, 0x85);
dsr1 = rByteAMD(cs, 0x02);
dsr2 = rByteAMD(cs, 0x07);
der = rWordAMD(cs, 0x03);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
spin_unlock_irqrestore(&cs->lock, flags);
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
/* discard frame; reset transceiver */
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
cs->dc.amd7930.tx_xmtlen = 0;
} else {
printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
debugl1(cs, "Amd7930: D-Channel Busy no skb");
}
/* Transmitter reset, abort transmit */
wByteAMD(cs, 0x21, 0x82);
wByteAMD(cs, 0x21, 0x02);
spin_unlock_irqrestore(&cs->lock, flags);
cs->irq_func(cs->irq, cs);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
}
}
}
void Amd7930_init(struct IsdnCardState *cs)
{
WORD *ptr;
BYTE cmd, cnt;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: initamd called");
cs->dc.amd7930.tx_xmtlen = 0;
cs->dc.amd7930.old_state = 0;
cs->dc.amd7930.lmr1 = 0x40;
cs->dc.amd7930.ph_command = Amd7930_ph_command;
cs->setstack_d = setstack_Amd7930;
cs->DC_Close = DC_Close_Amd7930;
/* AMD Initialisation */
for (ptr = initAMD; *ptr != 0xFFFF; ) {
cmd = LOBYTE(*ptr);
/* read */
if (*ptr++ >= 0x100) {
if (cmd < 8)
/* reset register */
rByteAMD(cs, cmd);
else {
wByteAMD(cs, 0x00, cmd);
for (cnt = *ptr++; cnt > 0; cnt--)
rByteAMD(cs, 0x01);
}
}
/* write */
else if (cmd < 8)
wByteAMD(cs, cmd, LOBYTE(*ptr++));
else {
wByteAMD(cs, 0x00, cmd);
for (cnt = *ptr++; cnt > 0; cnt--)
wByteAMD(cs, 0x01, LOBYTE(*ptr++));
}
}
}
void setup_Amd7930(struct IsdnCardState *cs)
{
INIT_WORK(&cs->tqueue, Amd7930_bh);
timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
}

View File

@ -1,37 +0,0 @@
/* drivers/isdn/hisax/amd7930_fn.h
*
* gerdes_amd7930.h Header-file included by
* gerdes_amd7930.c
*
* Author Christoph Ersfeld <info@formula-n.de>
* Formula-n Europe AG (www.formula-n.com)
* previously Gerdes AG
*
*
* This file is (c) under GNU PUBLIC LICENSE
*/
#define BYTE unsigned char
#define WORD unsigned int
#define rByteAMD(cs, reg) cs->readisac(cs, reg)
#define wByteAMD(cs, reg, val) cs->writeisac(cs, reg, val)
#define rWordAMD(cs, reg) ReadWordAmd7930(cs, reg)
#define wWordAMD(cs, reg, val) WriteWordAmd7930(cs, reg, val)
#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256))
#define LOBYTE(w) ((unsigned char)(w & 0x00ff))
#define AmdIrqOff(cs) cs->dc.amd7930.setIrqMask(cs, 0)
#define AmdIrqOn(cs) cs->dc.amd7930.setIrqMask(cs, 1)
#define AMD_CR 0x00
#define AMD_DR 0x01
#define DBUSY_TIMER_VALUE 80
extern void Amd7930_interrupt(struct IsdnCardState *, unsigned char);
extern void Amd7930_init(struct IsdnCardState *);
extern void setup_Amd7930(struct IsdnCardState *);

View File

@ -1,131 +0,0 @@
/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $
*
* Ansteuerung ARCOFI 2165
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/sched.h>
#include "hisax.h"
#include "isdnl1.h"
#include "isac.h"
#include "arcofi.h"
#define ARCOFI_TIMER_VALUE 20
static void
add_arcofi_timer(struct IsdnCardState *cs) {
if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ) / 1000);
add_timer(&cs->dc.isac.arcofitimer);
}
static void
send_arcofi(struct IsdnCardState *cs) {
add_arcofi_timer(cs);
cs->dc.isac.mon_txp = 0;
cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len;
memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc);
switch (cs->dc.isac.arcofi_bc) {
case 0: break;
case 1: cs->dc.isac.mon_tx[1] |= 0x40;
break;
default: break;
}
cs->dc.isac.mocr &= 0x0f;
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
(void) cs->readisac(cs, ISAC_MOSR);
cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
cs->dc.isac.mocr |= 0x10;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
}
int
arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
if (cs->debug & L1_DEB_MONITOR) {
debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event);
}
if (event == ARCOFI_TIMEOUT) {
cs->dc.isac.arcofi_state = ARCOFI_NOP;
test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags);
wake_up(&cs->dc.isac.arcofi_wait);
return (1);
}
switch (cs->dc.isac.arcofi_state) {
case ARCOFI_NOP:
if (event == ARCOFI_START) {
cs->dc.isac.arcofi_list = data;
cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(cs);
}
break;
case ARCOFI_TRANSMIT:
if (event == ARCOFI_TX_END) {
if (cs->dc.isac.arcofi_list->receive) {
add_arcofi_timer(cs);
cs->dc.isac.arcofi_state = ARCOFI_RECEIVE;
} else {
if (cs->dc.isac.arcofi_list->next) {
cs->dc.isac.arcofi_list =
cs->dc.isac.arcofi_list->next;
send_arcofi(cs);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofi_state = ARCOFI_NOP;
wake_up(&cs->dc.isac.arcofi_wait);
}
}
}
break;
case ARCOFI_RECEIVE:
if (event == ARCOFI_RX_END) {
if (cs->dc.isac.arcofi_list->next) {
cs->dc.isac.arcofi_list =
cs->dc.isac.arcofi_list->next;
cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(cs);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
del_timer(&cs->dc.isac.arcofitimer);
}
cs->dc.isac.arcofi_state = ARCOFI_NOP;
wake_up(&cs->dc.isac.arcofi_wait);
}
}
break;
default:
debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state);
return (2);
}
return (0);
}
static void
arcofi_timer(struct timer_list *t) {
struct IsdnCardState *cs = from_timer(cs, t, dc.isac.arcofitimer);
arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL);
}
void
clear_arcofi(struct IsdnCardState *cs) {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
del_timer(&cs->dc.isac.arcofitimer);
}
}
void
init_arcofi(struct IsdnCardState *cs) {
timer_setup(&cs->dc.isac.arcofitimer, arcofi_timer, 0);
init_waitqueue_head(&cs->dc.isac.arcofi_wait);
test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
}

View File

@ -1,27 +0,0 @@
/* $Id: arcofi.h,v 1.6.6.2 2001/09/23 22:24:46 kai Exp $
*
* Ansteuerung ARCOFI 2165
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define ARCOFI_USE 1
/* states */
#define ARCOFI_NOP 0
#define ARCOFI_TRANSMIT 1
#define ARCOFI_RECEIVE 2
/* events */
#define ARCOFI_START 1
#define ARCOFI_TX_END 2
#define ARCOFI_RX_END 3
#define ARCOFI_TIMEOUT 4
extern int arcofi_fsm(struct IsdnCardState *cs, int event, void *data);
extern void init_arcofi(struct IsdnCardState *cs);
extern void clear_arcofi(struct IsdnCardState *cs);

View File

@ -1,423 +0,0 @@
/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for information
*
*/
#include <linux/init.h>
#include <linux/isapnp.h>
#include "hisax.h"
#include "isac.h"
#include "ipac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define ASUS_ISAC 0
#define ASUS_HSCX 1
#define ASUS_ADR 2
#define ASUS_CTRL_U7 3
#define ASUS_CTRL_POTS 5
#define ASUS_IPAC_ALE 0
#define ASUS_IPAC_DATA 1
#define ASUS_ISACHSCX 1
#define ASUS_IPAC 2
/* CARD_ADR (Write) */
#define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
}
static u_char
ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80));
}
static void
WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80, value);
}
static void
ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
}
static void
WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.asus.adr,
cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.asus.adr,
cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
asuscom_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t
asuscom_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
Start_IPAC:
if (cs->debug & L1_DEB_IPAC)
debugl1(cs, "IPAC ISTA %02X", ista);
if (ista & 0x0f) {
val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
if (ista & 0x01)
val |= 0x01;
if (ista & 0x04)
val |= 0x02;
if (ista & 0x08)
val |= 0x04;
if (val)
hscx_int_main(cs, val);
}
if (ista & 0x20) {
val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80);
if (val) {
isac_interrupt(cs, val);
}
}
if (ista & 0x10) {
val = 0x01;
isac_interrupt(cs, val);
}
ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
if ((ista & 0x3f) && icnt) {
icnt--;
goto Start_IPAC;
}
if (!icnt)
printk(KERN_WARNING "ASUS IRQ LOOP\n");
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_asuscom(struct IsdnCardState *cs)
{
int bytecnt = 8;
if (cs->hw.asus.cfg_reg)
release_region(cs->hw.asus.cfg_reg, bytecnt);
}
static void
reset_asuscom(struct IsdnCardState *cs)
{
if (cs->subtyp == ASUS_IPAC)
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
else
byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
mdelay(10);
if (cs->subtyp == ASUS_IPAC)
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
else
byteout(cs->hw.asus.adr, 0); /* Reset Off */
mdelay(10);
if (cs->subtyp == ASUS_IPAC) {
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
}
}
static int
Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_asuscom(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_asuscom(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
cs->debug |= L1_DEB_IPAC;
inithscxisac(cs, 3);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
#ifdef __ISAPNP__
static struct isapnp_device_id asus_ids[] = {
{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
(unsigned long) "Asus1688 PnP" },
{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
(unsigned long) "Asus1690 PnP" },
{ ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
(unsigned long) "Isurf2 PnP" },
{ ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
(unsigned long) "Iscas TE320" },
{ 0, }
};
static struct isapnp_device_id *ipid = &asus_ids[0];
static struct pnp_card *pnp_c = NULL;
#endif
int setup_asuscom(struct IsdnCard *card)
{
int bytecnt;
struct IsdnCardState *cs = card->cs;
u_char val;
char tmp[64];
strcpy(tmp, Asuscom_revision);
printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_ASUSCOM)
return (0);
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d;
while (ipid->card_vendor) {
if ((pnp_c = pnp_find_card(ipid->card_vendor,
ipid->card_device, pnp_c))) {
pnp_d = NULL;
if ((pnp_d = pnp_find_dev(pnp_c,
ipid->vendor, ipid->function, pnp_d))) {
int err;
printk(KERN_INFO "HiSax: %s detected\n",
(char *)ipid->driver_data);
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[0] = pnp_irq(pnp_d, 0);
if (card->para[0] == -1 || !card->para[1]) {
printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
return (0);
}
break;
} else {
printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
}
}
ipid++;
pnp_c = NULL;
}
if (!ipid->card_vendor) {
printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
return (0);
}
}
#endif
bytecnt = 8;
cs->hw.asus.cfg_reg = card->para[1];
cs->irq = card->para[0];
if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) {
printk(KERN_WARNING
"HiSax: ISDNLink config port %x-%x already in use\n",
cs->hw.asus.cfg_reg,
cs->hw.asus.cfg_reg + bytecnt);
return (0);
}
printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n",
cs->hw.asus.cfg_reg, cs->irq);
setup_isac(cs);
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Asus_card_msg;
val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE,
cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
if ((val == 1) || (val == 2)) {
cs->subtyp = ASUS_IPAC;
cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
cs->readisac = &ReadISAC_IPAC;
cs->writeisac = &WriteISAC_IPAC;
cs->readisacfifo = &ReadISACfifo_IPAC;
cs->writeisacfifo = &WriteISACfifo_IPAC;
cs->irq_func = &asuscom_interrupt_ipac;
printk(KERN_INFO "Asus: IPAC version %x\n", val);
} else {
cs->subtyp = ASUS_ISACHSCX;
cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->irq_func = &asuscom_interrupt;
ISACVersion(cs, "ISDNLink:");
if (HscxVersion(cs, "ISDNLink:")) {
printk(KERN_WARNING
"ISDNLink: wrong HSCX versions check IO address\n");
release_io_asuscom(cs);
return (0);
}
}
return (1);
}

View File

@ -1,307 +0,0 @@
/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $
*
* low level stuff for AVM A1 (Fritz) isdn cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *avm_revision = "$Revision: 2.15.2.4 $";
#define AVM_A1_STAT_ISAC 0x01
#define AVM_A1_STAT_HSCX 0x02
#define AVM_A1_STAT_TIMER 0x04
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(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, data, size);
}
static void
write_fifo(unsigned int adr, u_char *data, int size)
{
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.avm.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.avm.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
read_fifo(cs->hw.avm.isacfifo, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
write_fifo(cs->hw.avm.isacfifo, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.avm.hscx[hscx], offset));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.avm.hscx[hscx], offset, value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg)
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
avm_a1_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) {
if (!(sval & AVM_A1_STAT_TIMER)) {
byteout(cs->hw.avm.cfg_reg, 0x1E);
sval = bytein(cs->hw.avm.cfg_reg);
} else if (cs->debug & L1_DEB_INTSTAT)
debugl1(cs, "avm IntStatus %x", sval);
if (!(sval & AVM_A1_STAT_HSCX)) {
val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA);
if (val)
hscx_int_main(cs, val);
}
if (!(sval & AVM_A1_STAT_ISAC)) {
val = readreg(cs->hw.avm.isac, ISAC_ISTA);
if (val)
isac_interrupt(cs, val);
}
}
writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF);
writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF);
writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.avm.isac, ISAC_MASK, 0x0);
writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0);
writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static inline void
release_ioregs(struct IsdnCardState *cs, int mask)
{
release_region(cs->hw.avm.cfg_reg, 8);
if (mask & 1)
release_region(cs->hw.avm.isac + 32, 32);
if (mask & 2)
release_region(cs->hw.avm.isacfifo, 1);
if (mask & 4)
release_region(cs->hw.avm.hscx[0] + 32, 32);
if (mask & 8)
release_region(cs->hw.avm.hscxfifo[0], 1);
if (mask & 0x10)
release_region(cs->hw.avm.hscx[1] + 32, 32);
if (mask & 0x20)
release_region(cs->hw.avm.hscxfifo[1], 1);
}
static int
AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
return (0);
case CARD_RELEASE:
release_ioregs(cs, 0x3f);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscxisac(cs, 1);
byteout(cs->hw.avm.cfg_reg, 0x16);
byteout(cs->hw.avm.cfg_reg, 0x1E);
inithscxisac(cs, 2);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
int setup_avm_a1(struct IsdnCard *card)
{
u_char val;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, avm_revision);
printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_A1)
return (0);
cs->hw.avm.cfg_reg = card->para[1] + 0x1800;
cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20;
cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20;
cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20;
cs->hw.avm.isacfifo = card->para[1] + 0x1000;
cs->hw.avm.hscxfifo[0] = card->para[1];
cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800;
cs->irq = card->para[0];
if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) {
printk(KERN_WARNING
"HiSax: AVM A1 config port %x-%x already in use\n",
cs->hw.avm.cfg_reg,
cs->hw.avm.cfg_reg + 8);
return (0);
}
if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) {
printk(KERN_WARNING
"HiSax: AVM A1 isac ports %x-%x already in use\n",
cs->hw.avm.isac + 32,
cs->hw.avm.isac + 64);
release_ioregs(cs, 0);
return (0);
}
if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) {
printk(KERN_WARNING
"HiSax: AVM A1 isac fifo port %x already in use\n",
cs->hw.avm.isacfifo);
release_ioregs(cs, 1);
return (0);
}
if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) {
printk(KERN_WARNING
"HiSax: AVM A1 hscx A ports %x-%x already in use\n",
cs->hw.avm.hscx[0] + 32,
cs->hw.avm.hscx[0] + 64);
release_ioregs(cs, 3);
return (0);
}
if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) {
printk(KERN_WARNING
"HiSax: AVM A1 hscx A fifo port %x already in use\n",
cs->hw.avm.hscxfifo[0]);
release_ioregs(cs, 7);
return (0);
}
if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) {
printk(KERN_WARNING
"HiSax: AVM A1 hscx B ports %x-%x already in use\n",
cs->hw.avm.hscx[1] + 32,
cs->hw.avm.hscx[1] + 64);
release_ioregs(cs, 0xf);
return (0);
}
if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) {
printk(KERN_WARNING
"HiSax: AVM A1 hscx B fifo port %x already in use\n",
cs->hw.avm.hscxfifo[1]);
release_ioregs(cs, 0x1f);
return (0);
}
byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg, 0x1);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
val = cs->irq;
if (val == 9)
val = 2;
byteout(cs->hw.avm.cfg_reg + 1, val);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
val = bytein(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
cs->hw.avm.cfg_reg, val);
val = bytein(cs->hw.avm.cfg_reg + 3);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
cs->hw.avm.cfg_reg + 3, val);
val = bytein(cs->hw.avm.cfg_reg + 2);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
cs->hw.avm.cfg_reg + 2, val);
val = bytein(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
cs->hw.avm.cfg_reg, val);
printk(KERN_INFO "HiSax: AVM A1 config irq:%d cfg:0x%X\n",
cs->irq,
cs->hw.avm.cfg_reg);
printk(KERN_INFO
"HiSax: isac:0x%X/0x%X\n",
cs->hw.avm.isac + 32, cs->hw.avm.isacfifo);
printk(KERN_INFO
"HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n",
cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0],
cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
setup_isac(cs);
cs->cardmsg = &AVM_card_msg;
cs->irq_func = &avm_a1_interrupt;
ISACVersion(cs, "AVM A1:");
if (HscxVersion(cs, "AVM A1:")) {
printk(KERN_WARNING
"AVM A1: wrong HSCX versions check IO address\n");
release_ioregs(cs, 0x3f);
return (0);
}
return (1);
}

View File

@ -1,267 +0,0 @@
/* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil Exp $
*
* low level stuff for the following AVM cards:
* A1 PCMCIA
* FRITZ!Card PCMCIA
* FRITZ!Card PCMCIA 2.0
*
* Author Carsten Paeth
* Copyright by Carsten Paeth <calle@calle.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
/* register offsets */
#define ADDRREG_OFFSET 0x02
#define DATAREG_OFFSET 0x03
#define ASL0_OFFSET 0x04
#define ASL1_OFFSET 0x05
#define MODREG_OFFSET 0x06
#define VERREG_OFFSET 0x07
/* address offsets */
#define ISAC_FIFO_OFFSET 0x00
#define ISAC_REG_OFFSET 0x20
#define HSCX_CH_DIFF 0x40
#define HSCX_FIFO_OFFSET 0x80
#define HSCX_REG_OFFSET 0xa0
/* read bits ASL0 */
#define ASL0_R_TIMER 0x10 /* active low */
#define ASL0_R_ISAC 0x20 /* active low */
#define ASL0_R_HSCX 0x40 /* active low */
#define ASL0_R_TESTBIT 0x80
#define ASL0_R_IRQPENDING (ASL0_R_ISAC | ASL0_R_HSCX | ASL0_R_TIMER)
/* write bits ASL0 */
#define ASL0_W_RESET 0x01
#define ASL0_W_TDISABLE 0x02
#define ASL0_W_TRESET 0x04
#define ASL0_W_IRQENABLE 0x08
#define ASL0_W_TESTBIT 0x80
/* write bits ASL1 */
#define ASL1_W_LED0 0x10
#define ASL1_W_LED1 0x20
#define ASL1_W_ENABLE_S0 0xC0
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
static const char *avm_revision = "$Revision: 2.9.2.5 $";
static inline u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
u_char ret;
offset -= 0x20;
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset);
ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET);
return ret;
}
static inline void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
offset -= 0x20;
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset);
byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value);
}
static inline void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET);
insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
}
static inline void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET);
outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
}
static inline u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
u_char ret;
offset -= 0x20;
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset);
ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET);
return ret;
}
static inline void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
offset -= 0x20;
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset);
byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value);
}
static inline void
ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
{
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF);
insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
}
static inline void
WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
{
byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET,
HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF);
outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
avm_a1p_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
while ((sval = (~bytein(cs->hw.avm.cfg_reg + ASL0_OFFSET) & ASL0_R_IRQPENDING))) {
if (cs->debug & L1_DEB_INTSTAT)
debugl1(cs, "avm IntStatus %x", sval);
if (sval & ASL0_R_HSCX) {
val = ReadHSCX(cs, 1, HSCX_ISTA);
if (val)
hscx_int_main(cs, val);
}
if (sval & ASL0_R_ISAC) {
val = ReadISAC(cs, ISAC_ISTA);
if (val)
isac_interrupt(cs, val);
}
}
WriteHSCX(cs, 0, HSCX_MASK, 0xff);
WriteHSCX(cs, 1, HSCX_MASK, 0xff);
WriteISAC(cs, ISAC_MASK, 0xff);
WriteISAC(cs, ISAC_MASK, 0x00);
WriteHSCX(cs, 0, HSCX_MASK, 0x00);
WriteHSCX(cs, 1, HSCX_MASK, 0x00);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static int
AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
spin_unlock_irqrestore(&cs->lock, flags);
return 0;
case CARD_RELEASE:
/* free_irq is done in HiSax_closecard(). */
/* free_irq(cs->irq, cs); */
return 0;
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET | ASL0_W_IRQENABLE);
clear_pending_isac_ints(cs);
clear_pending_hscx_ints(cs);
inithscxisac(cs, 1);
inithscxisac(cs, 2);
spin_unlock_irqrestore(&cs->lock, flags);
return 0;
case CARD_TEST:
/* we really don't need it for the PCMCIA Version */
return 0;
default:
/* all card drivers ignore others, so we do the same */
return 0;
}
return 0;
}
int setup_avm_a1_pcmcia(struct IsdnCard *card)
{
u_char model, vers;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, avm_revision);
printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_A1_PCMCIA)
return (0);
cs->hw.avm.cfg_reg = card->para[1];
cs->irq = card->para[0];
byteout(cs->hw.avm.cfg_reg + ASL1_OFFSET, ASL1_W_ENABLE_S0);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET);
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00);
byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET);
model = bytein(cs->hw.avm.cfg_reg + MODREG_OFFSET);
vers = bytein(cs->hw.avm.cfg_reg + VERREG_OFFSET);
printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
cs->hw.avm.cfg_reg, cs->irq, model, vers);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &AVM_card_msg;
cs->irq_flags = IRQF_SHARED;
cs->irq_func = &avm_a1p_interrupt;
ISACVersion(cs, "AVM A1 PCMCIA:");
if (HscxVersion(cs, "AVM A1 PCMCIA:")) {
printk(KERN_WARNING
"AVM A1 PCMCIA: wrong HSCX versions check IO address\n");
return (0);
}
return (1);
}

View File

@ -1,904 +0,0 @@
/* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $
*
* low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to AVM, Berlin for information
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/isapnp.h>
#include <linux/interrupt.h>
static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
#define AVM_FRITZ_PCI 1
#define AVM_FRITZ_PNP 2
#define HDLC_FIFO 0x0
#define HDLC_STATUS 0x4
#define AVM_HDLC_1 0x00
#define AVM_HDLC_2 0x01
#define AVM_ISAC_FIFO 0x02
#define AVM_ISAC_REG_LOW 0x04
#define AVM_ISAC_REG_HIGH 0x06
#define AVM_STATUS0_IRQ_ISAC 0x01
#define AVM_STATUS0_IRQ_HDLC 0x02
#define AVM_STATUS0_IRQ_TIMER 0x04
#define AVM_STATUS0_IRQ_MASK 0x07
#define AVM_STATUS0_RESET 0x01
#define AVM_STATUS0_DIS_TIMER 0x02
#define AVM_STATUS0_RES_TIMER 0x04
#define AVM_STATUS0_ENA_IRQ 0x08
#define AVM_STATUS0_TESTBIT 0x10
#define AVM_STATUS1_INT_SEL 0x0f
#define AVM_STATUS1_ENA_IOM 0x80
#define HDLC_MODE_ITF_FLG 0x01
#define HDLC_MODE_TRANS 0x02
#define HDLC_MODE_CCR_7 0x04
#define HDLC_MODE_CCR_16 0x08
#define HDLC_MODE_TESTLOOP 0x80
#define HDLC_INT_XPR 0x80
#define HDLC_INT_XDU 0x40
#define HDLC_INT_RPR 0x20
#define HDLC_INT_MASK 0xE0
#define HDLC_STAT_RME 0x01
#define HDLC_STAT_RDO 0x10
#define HDLC_STAT_CRCVFRRAB 0x0E
#define HDLC_STAT_CRCVFR 0x06
#define HDLC_STAT_RML_MASK 0x3f00
#define HDLC_CMD_XRS 0x80
#define HDLC_CMD_XME 0x01
#define HDLC_CMD_RRS 0x20
#define HDLC_CMD_XML_MASK 0x3f00
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
register u_char val;
outb(idx, cs->hw.avm.cfg_reg + 4);
val = inb(cs->hw.avm.isac + (offset & 0xf));
return (val);
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
outb(idx, cs->hw.avm.cfg_reg + 4);
outb(value, cs->hw.avm.isac + (offset & 0xf));
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
insb(cs->hw.avm.isac, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4);
outsb(cs->hw.avm.isac, data, size);
}
static inline u_int
ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset)
{
register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
register u_int val;
outl(idx, cs->hw.avm.cfg_reg + 4);
val = inl(cs->hw.avm.isac + offset);
return (val);
}
static inline void
WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value)
{
register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
outl(idx, cs->hw.avm.cfg_reg + 4);
outl(value, cs->hw.avm.isac + offset);
}
static inline u_char
ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset)
{
register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
register u_char val;
outb(idx, cs->hw.avm.cfg_reg + 4);
val = inb(cs->hw.avm.isac + offset);
return (val);
}
static inline void
WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
{
register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
outb(idx, cs->hw.avm.cfg_reg + 4);
outb(value, cs->hw.avm.isac + offset);
}
static u_char
ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset)
{
return (0xff & ReadHDLCPCI(cs, chan, offset));
}
static void
WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
{
WriteHDLCPCI(cs, chan, offset, value);
}
static inline
struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
{
if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
return (&cs->bcs[0]);
else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
return (&cs->bcs[1]);
else
return (NULL);
}
static void
write_ctrl(struct BCState *bcs, int which) {
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "hdlc %c wr%x ctrl %x",
'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl);
if (bcs->cs->subtyp == AVM_FRITZ_PCI) {
WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl);
} else {
if (which & 4)
WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2,
bcs->hw.hdlc.ctrl.sr.mode);
if (which & 2)
WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1,
bcs->hw.hdlc.ctrl.sr.xml);
if (which & 1)
WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS,
bcs->hw.hdlc.ctrl.sr.cmd);
}
}
static void
modehdlc(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
int hdlc = bcs->channel;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d",
'A' + hdlc, bcs->mode, mode, hdlc, bc);
bcs->hw.hdlc.ctrl.ctrl = 0;
switch (mode) {
case (-1): /* used for init */
bcs->mode = 1;
bcs->channel = bc;
bc = 0;
/* fall through */
case (L1_MODE_NULL):
if (bcs->mode == L1_MODE_NULL)
return;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bcs, 5);
bcs->mode = L1_MODE_NULL;
bcs->channel = bc;
break;
case (L1_MODE_TRANS):
bcs->mode = mode;
bcs->channel = bc;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
write_ctrl(bcs, 5);
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.ctrl.sr.cmd = 0;
schedule_event(bcs, B_XMTBUFREADY);
break;
case (L1_MODE_HDLC):
bcs->mode = mode;
bcs->channel = bc;
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
write_ctrl(bcs, 5);
bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.ctrl.sr.cmd = 0;
schedule_event(bcs, B_XMTBUFREADY);
break;
}
}
static inline void
hdlc_empty_fifo(struct BCState *bcs, int count)
{
register u_int *ptr;
u_char *p;
u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1;
int cnt = 0;
struct IsdnCardState *cs = bcs->cs;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hdlc_empty_fifo %d", count);
if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hdlc_empty_fifo: incoming packet too large");
return;
}
p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
ptr = (u_int *)p;
bcs->hw.hdlc.rcvidx += count;
if (cs->subtyp == AVM_FRITZ_PCI) {
outl(idx, cs->hw.avm.cfg_reg + 4);
while (cnt < count) {
#ifdef __powerpc__
*ptr++ = in_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE));
#else
*ptr++ = inl(cs->hw.avm.isac);
#endif /* __powerpc__ */
cnt += 4;
}
} else {
outb(idx, cs->hw.avm.cfg_reg + 4);
while (cnt < count) {
*p++ = inb(cs->hw.avm.isac);
cnt++;
}
}
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
if (cs->subtyp == AVM_FRITZ_PNP)
p = (u_char *) ptr;
t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
bcs->channel ? 'B' : 'A', count);
QuickHex(t, p, count);
debugl1(cs, "%s", bcs->blog);
}
}
static inline void
hdlc_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int count, cnt = 0;
int fifo_size = 32;
u_char *p;
u_int *ptr;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hdlc_fill_fifo");
if (!bcs->tx_skb)
return;
if (bcs->tx_skb->len <= 0)
return;
bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME;
if (bcs->tx_skb->len > fifo_size) {
count = fifo_size;
} else {
count = bcs->tx_skb->len;
if (bcs->mode != L1_MODE_TRANS)
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
}
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hdlc_fill_fifo %d/%u", count, bcs->tx_skb->len);
p = bcs->tx_skb->data;
ptr = (u_int *)p;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hdlc.count += count;
bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count);
write_ctrl(bcs, 3); /* sets the correct index too */
if (cs->subtyp == AVM_FRITZ_PCI) {
while (cnt < count) {
#ifdef __powerpc__
out_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE), *ptr++);
#else
outl(*ptr++, cs->hw.avm.isac);
#endif /* __powerpc__ */
cnt += 4;
}
} else {
while (cnt < count) {
outb(*p++, cs->hw.avm.isac);
cnt++;
}
}
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
if (cs->subtyp == AVM_FRITZ_PNP)
p = (u_char *) ptr;
t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
bcs->channel ? 'B' : 'A', count);
QuickHex(t, p, count);
debugl1(cs, "%s", bcs->blog);
}
}
static void
HDLC_irq(struct BCState *bcs, u_int stat) {
int len;
struct sk_buff *skb;
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
if (stat & HDLC_INT_RPR) {
if (stat & HDLC_STAT_RDO) {
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "RDO");
else
debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat);
bcs->hw.hdlc.ctrl.sr.xml = 0;
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.rcvidx = 0;
} else {
if (!(len = (stat & HDLC_STAT_RML_MASK) >> 8))
len = 32;
hdlc_empty_fifo(bcs, len);
if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) {
if (((stat & HDLC_STAT_CRCVFRRAB) == HDLC_STAT_CRCVFR) ||
(bcs->mode == L1_MODE_TRANS)) {
if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx)))
printk(KERN_WARNING "HDLC: receive out of memory\n");
else {
skb_put_data(skb,
bcs->hw.hdlc.rcvbuf,
bcs->hw.hdlc.rcvidx);
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->hw.hdlc.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
} else {
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "invalid frame");
else
debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat);
bcs->hw.hdlc.rcvidx = 0;
}
}
}
}
if (stat & HDLC_INT_XDU) {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->hw.hdlc.count);
bcs->tx_cnt += bcs->hw.hdlc.count;
bcs->hw.hdlc.count = 0;
if (bcs->cs->debug & L1_DEB_WARN)
debugl1(bcs->cs, "ch%d XDU", bcs->channel);
} else if (bcs->cs->debug & L1_DEB_WARN)
debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel);
bcs->hw.hdlc.ctrl.sr.xml = 0;
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
write_ctrl(bcs, 1);
bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS;
write_ctrl(bcs, 1);
hdlc_fill_fifo(bcs);
} else if (stat & HDLC_INT_XPR) {
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
hdlc_fill_fifo(bcs);
return;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hdlc.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hdlc.count = 0;
bcs->tx_skb = NULL;
}
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hdlc.count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
hdlc_fill_fifo(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
}
static inline void
HDLC_irq_main(struct IsdnCardState *cs)
{
u_int stat;
struct BCState *bcs;
if (cs->subtyp == AVM_FRITZ_PCI) {
stat = ReadHDLCPCI(cs, 0, HDLC_STATUS);
} else {
stat = ReadHDLCPnP(cs, 0, HDLC_STATUS);
if (stat & HDLC_INT_RPR)
stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS + 1)) << 8;
}
if (stat & HDLC_INT_MASK) {
if (!(bcs = Sel_BCS(cs, 0))) {
if (cs->debug)
debugl1(cs, "hdlc spurious channel 0 IRQ");
} else
HDLC_irq(bcs, stat);
}
if (cs->subtyp == AVM_FRITZ_PCI) {
stat = ReadHDLCPCI(cs, 1, HDLC_STATUS);
} else {
stat = ReadHDLCPnP(cs, 1, HDLC_STATUS);
if (stat & HDLC_INT_RPR)
stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS + 1)) << 8;
}
if (stat & HDLC_INT_MASK) {
if (!(bcs = Sel_BCS(cs, 1))) {
if (cs->debug)
debugl1(cs, "hdlc spurious channel 1 IRQ");
} else
HDLC_irq(bcs, stat);
}
}
static void
hdlc_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hdlc.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n");
} else {
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->hw.hdlc.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
modehdlc(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
modehdlc(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
static void
close_hdlcstate(struct BCState *bcs)
{
modehdlc(bcs, 0, 0);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
kfree(bcs->hw.hdlc.rcvbuf);
bcs->hw.hdlc.rcvbuf = NULL;
kfree(bcs->blog);
bcs->blog = NULL;
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
static int
open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for hdlc.rcvbuf\n");
return (1);
}
if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for bcs->blog\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
kfree(bcs->hw.hdlc.rcvbuf);
bcs->hw.hdlc.rcvbuf = NULL;
return (2);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hdlc.rcvidx = 0;
bcs->tx_cnt = 0;
return (0);
}
static int
setstack_hdlc(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_hdlcstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = hdlc_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
#if 0
void __init
clear_pending_hdlc_ints(struct IsdnCardState *cs)
{
u_int val;
if (cs->subtyp == AVM_FRITZ_PCI) {
val = ReadHDLCPCI(cs, 0, HDLC_STATUS);
debugl1(cs, "HDLC 1 STA %x", val);
val = ReadHDLCPCI(cs, 1, HDLC_STATUS);
debugl1(cs, "HDLC 2 STA %x", val);
} else {
val = ReadHDLCPnP(cs, 0, HDLC_STATUS);
debugl1(cs, "HDLC 1 STA %x", val);
val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1);
debugl1(cs, "HDLC 1 RML %x", val);
val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2);
debugl1(cs, "HDLC 1 MODE %x", val);
val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3);
debugl1(cs, "HDLC 1 VIN %x", val);
val = ReadHDLCPnP(cs, 1, HDLC_STATUS);
debugl1(cs, "HDLC 2 STA %x", val);
val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1);
debugl1(cs, "HDLC 2 RML %x", val);
val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2);
debugl1(cs, "HDLC 2 MODE %x", val);
val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3);
debugl1(cs, "HDLC 2 VIN %x", val);
}
}
#endif /* 0 */
static void
inithdlc(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_hdlc;
cs->bcs[1].BC_SetStack = setstack_hdlc;
cs->bcs[0].BC_Close = close_hdlcstate;
cs->bcs[1].BC_Close = close_hdlcstate;
modehdlc(cs->bcs, -1, 0);
modehdlc(cs->bcs + 1, -1, 1);
}
static irqreturn_t
avm_pcipnp_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_long flags;
u_char val;
u_char sval;
spin_lock_irqsave(&cs->lock, flags);
sval = inb(cs->hw.avm.cfg_reg + 2);
if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
/* possible a shared IRQ reqest */
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
val = ReadISAC(cs, ISAC_ISTA);
isac_interrupt(cs, val);
}
if (!(sval & AVM_STATUS0_IRQ_HDLC)) {
HDLC_irq_main(cs);
}
WriteISAC(cs, ISAC_MASK, 0xFF);
WriteISAC(cs, ISAC_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
reset_avmpcipnp(struct IsdnCardState *cs)
{
printk(KERN_INFO "AVM PCI/PnP: reset\n");
outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
mdelay(10);
outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
mdelay(10);
printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
}
static int
AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_avmpcipnp(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
outb(0, cs->hw.avm.cfg_reg + 2);
release_region(cs->hw.avm.cfg_reg, 32);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
reset_avmpcipnp(cs);
clear_pending_isac_ints(cs);
initisac(cs);
inithdlc(cs);
outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER,
cs->hw.avm.cfg_reg + 2);
WriteISAC(cs, ISAC_MASK, 0);
outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
/* RESET Receiver and Transmitter */
WriteISAC(cs, ISAC_CMDR, 0x41);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int avm_setup_rest(struct IsdnCardState *cs)
{
u_int val, ver;
cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
if (!request_region(cs->hw.avm.cfg_reg, 32,
(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
printk(KERN_WARNING
"HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
cs->hw.avm.cfg_reg,
cs->hw.avm.cfg_reg + 31);
return (0);
}
switch (cs->subtyp) {
case AVM_FRITZ_PCI:
val = inl(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM PCI: stat %#x\n", val);
printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
val & 0xff, (val >> 8) & 0xff);
cs->BC_Read_Reg = &ReadHDLC_s;
cs->BC_Write_Reg = &WriteHDLC_s;
break;
case AVM_FRITZ_PNP:
val = inb(cs->hw.avm.cfg_reg);
ver = inb(cs->hw.avm.cfg_reg + 1);
printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
cs->BC_Read_Reg = &ReadHDLCPnP;
cs->BC_Write_Reg = &WriteHDLCPnP;
break;
default:
printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp);
return (0);
}
printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n",
(cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP",
cs->irq, cs->hw.avm.cfg_reg);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Send_Data = &hdlc_fill_fifo;
cs->cardmsg = &AVM_card_msg;
cs->irq_func = &avm_pcipnp_interrupt;
cs->writeisac(cs, ISAC_MASK, 0xFF);
ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
return (1);
}
#ifndef __ISAPNP__
static int avm_pnp_setup(struct IsdnCardState *cs)
{
return (1); /* no-op: success */
}
#else
static struct pnp_card *pnp_avm_c = NULL;
static int avm_pnp_setup(struct IsdnCardState *cs)
{
struct pnp_dev *pnp_avm_d = NULL;
if (!isapnp_present())
return (1); /* no-op: success */
if ((pnp_avm_c = pnp_find_card(
ISAPNP_VENDOR('A', 'V', 'M'),
ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
ISAPNP_VENDOR('A', 'V', 'M'),
ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
int err;
pnp_disable_dev(pnp_avm_d);
err = pnp_activate_dev(pnp_avm_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
cs->hw.avm.cfg_reg =
pnp_port_start(pnp_avm_d, 0);
cs->irq = pnp_irq(pnp_avm_d, 0);
if (cs->irq == -1) {
printk(KERN_ERR "FritzPnP:No IRQ\n");
return (0);
}
if (!cs->hw.avm.cfg_reg) {
printk(KERN_ERR "FritzPnP:No IO address\n");
return (0);
}
cs->subtyp = AVM_FRITZ_PNP;
return (2); /* goto 'ready' label */
}
}
return (1);
}
#endif /* __ISAPNP__ */
#ifndef CONFIG_PCI
static int avm_pci_setup(struct IsdnCardState *cs)
{
return (1); /* no-op: success */
}
#else
static struct pci_dev *dev_avm = NULL;
static int avm_pci_setup(struct IsdnCardState *cs)
{
if ((dev_avm = hisax_find_pci_device(PCI_VENDOR_ID_AVM,
PCI_DEVICE_ID_AVM_A1, dev_avm))) {
if (pci_enable_device(dev_avm))
return (0);
cs->irq = dev_avm->irq;
if (!cs->irq) {
printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
return (0);
}
cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
if (!cs->hw.avm.cfg_reg) {
printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
return (0);
}
cs->subtyp = AVM_FRITZ_PCI;
} else {
printk(KERN_WARNING "FritzPCI: No PCI card found\n");
return (0);
}
cs->irq_flags |= IRQF_SHARED;
return (1);
}
#endif /* CONFIG_PCI */
int setup_avm_pcipnp(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
int rc;
strcpy(tmp, avm_pci_rev);
printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_FRITZPCI)
return (0);
if (card->para[1]) {
/* old manual method */
cs->hw.avm.cfg_reg = card->para[1];
cs->irq = card->para[0];
cs->subtyp = AVM_FRITZ_PNP;
goto ready;
}
rc = avm_pnp_setup(cs);
if (rc < 1)
return (0);
if (rc == 2)
goto ready;
rc = avm_pci_setup(cs);
if (rc < 1)
return (0);
ready:
return avm_setup_rest(cs);
}

View File

@ -1,162 +0,0 @@
/*
* PCMCIA client driver for AVM A1 / Fritz!PCMCIA
*
* Author Carsten Paeth
* Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include "hisax_cfg.h"
MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int isdnprot = 2;
module_param(isdnprot, int, 0);
/*====================================================================*/
static int avma1cs_config(struct pcmcia_device *link);
static void avma1cs_release(struct pcmcia_device *link);
static void avma1cs_detach(struct pcmcia_device *p_dev);
static int avma1cs_probe(struct pcmcia_device *p_dev)
{
dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
/* General socket configuration */
p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
p_dev->config_index = 1;
p_dev->config_regs = PRESENT_OPTION;
return avma1cs_config(p_dev);
} /* avma1cs_attach */
static void avma1cs_detach(struct pcmcia_device *link)
{
dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
avma1cs_release(link);
kfree(link->priv);
} /* avma1cs_detach */
static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
{
p_dev->resource[0]->end = 16;
p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
p_dev->io_lines = 5;
return pcmcia_request_io(p_dev);
}
static int avma1cs_config(struct pcmcia_device *link)
{
int i = -1;
char devname[128];
IsdnCard_t icard;
int busy = 0;
dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link);
devname[0] = 0;
if (link->prod_id[1])
strlcpy(devname, link->prod_id[1], sizeof(devname));
if (pcmcia_loop_config(link, avma1cs_configcheck, NULL))
return -ENODEV;
do {
/*
* allocate an interrupt line
*/
if (!link->irq) {
/* undo */
pcmcia_disable_device(link);
break;
}
/*
* configure the PCMCIA socket
*/
i = pcmcia_enable_device(link);
if (i != 0) {
pcmcia_disable_device(link);
break;
}
} while (0);
/* If any step failed, release any partially configured state */
if (i != 0) {
avma1cs_release(link);
return -ENODEV;
}
icard.para[0] = link->irq;
icard.para[1] = link->resource[0]->start;
icard.protocol = isdnprot;
icard.typ = ISDN_CTYPE_A1_PCMCIA;
i = hisax_init_pcmcia(link, &busy, &icard);
if (i < 0) {
printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 "
"PCMCIA %d at i/o %#x\n", i,
(unsigned int) link->resource[0]->start);
avma1cs_release(link);
return -ENODEV;
}
link->priv = (void *) (unsigned long) i;
return 0;
} /* avma1cs_config */
static void avma1cs_release(struct pcmcia_device *link)
{
unsigned long minor = (unsigned long) link->priv;
dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link);
/* now unregister function with hisax */
HiSax_closecard(minor);
pcmcia_disable_device(link);
} /* avma1cs_release */
static const struct pcmcia_device_id avma1cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
static struct pcmcia_driver avma1cs_driver = {
.owner = THIS_MODULE,
.name = "avma1_cs",
.probe = avma1cs_probe,
.remove = avma1cs_detach,
.id_table = avma1cs_ids,
};
module_pcmcia_driver(avma1cs_driver);

View File

@ -1,358 +0,0 @@
/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $
*
* low level stuff for T-Berkom A4T
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "jade.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include "bkm_ax.h"
static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
static inline u_char
readreg(unsigned int ale, unsigned long adr, u_char off)
{
register u_int ret;
unsigned int *po = (unsigned int *) adr; /* Postoffice */
*po = (GCS_2 | PO_WRITE | off);
__WAITI20__(po);
*po = (ale | PO_READ);
__WAITI20__(po);
ret = *po;
return ((unsigned char) ret);
}
static inline void
readfifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size)
{
int i;
for (i = 0; i < size; i++)
*data++ = readreg(ale, adr, off);
}
static inline void
writereg(unsigned int ale, unsigned long adr, u_char off, u_char data)
{
unsigned int *po = (unsigned int *) adr; /* Postoffice */
*po = (GCS_2 | PO_WRITE | off);
__WAITI20__(po);
*po = (ale | PO_WRITE | data);
__WAITI20__(po);
}
static inline void
writefifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size)
{
int i;
for (i = 0; i < size; i++)
writereg(ale, adr, off, *data++);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
}
static u_char
ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
{
return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
}
static void
WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
{
writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
}
/*
* fast interrupt JADE stuff goes here
*/
#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale, \
cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale, \
cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale, \
cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.jade_ale, \
cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
#include "jade_irq.c"
static irqreturn_t
bkm_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val = 0;
u_long flags;
I20_REGISTER_FILE *pI20_Regs;
spin_lock_irqsave(&cs->lock, flags);
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
/* ISDN interrupt pending? */
if (pI20_Regs->i20IntStatus & intISDN) {
/* Reset the ISDN interrupt */
pI20_Regs->i20IntStatus = intISDN;
/* Disable ISDN interrupt */
pI20_Regs->i20IntCtrl &= ~intISDN;
/* Channel A first */
val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80);
if (val) {
jade_int_main(cs, val, 0);
}
/* Channel B */
val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0);
if (val) {
jade_int_main(cs, val, 1);
}
/* D-Channel */
val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA);
if (val) {
isac_interrupt(cs, val);
}
/* Reenable ISDN interrupt */
pI20_Regs->i20IntCtrl |= intISDN;
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
} else {
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
}
static void
release_io_bkm(struct IsdnCardState *cs)
{
if (cs->hw.ax.base) {
iounmap((void *) cs->hw.ax.base);
cs->hw.ax.base = 0;
}
}
static void
enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
{
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
if (bEnable)
pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
else
/* CAUTION: This disables the video capture driver too */
pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
}
}
static void
reset_bkm(struct IsdnCardState *cs)
{
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
/* Issue the I20 soft reset */
pI20_Regs->i20SysControl = 0xFF; /* all in */
mdelay(10);
/* Remove the soft reset */
pI20_Regs->i20SysControl = sysRESET | 0xFF;
mdelay(10);
/* Set our configuration */
pI20_Regs->i20SysControl = sysRESET | sysCFG;
/* Issue ISDN reset */
pI20_Regs->i20GuestControl = guestWAIT_CFG |
g_A4T_JADE_RES |
g_A4T_ISAR_RES |
g_A4T_ISAC_RES |
g_A4T_JADE_BOOTR |
g_A4T_ISAR_BOOTR;
mdelay(10);
/* Remove RESET state from ISDN */
pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
g_A4T_JADE_RES |
g_A4T_ISAR_RES);
mdelay(10);
}
}
static int
BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
/* Disable ints */
spin_lock_irqsave(&cs->lock, flags);
enable_bkm_int(cs, 0);
reset_bkm(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
/* Sanity */
spin_lock_irqsave(&cs->lock, flags);
enable_bkm_int(cs, 0);
reset_bkm(cs);
spin_unlock_irqrestore(&cs->lock, flags);
release_io_bkm(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
clear_pending_isac_ints(cs);
clear_pending_jade_ints(cs);
initisac(cs);
initjade(cs);
/* Enable ints */
enable_bkm_int(cs, 1);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int a4t_pci_probe(struct pci_dev *dev_a4t, struct IsdnCardState *cs,
u_int *found, u_int *pci_memaddr)
{
u16 sub_sys;
u16 sub_vendor;
sub_vendor = dev_a4t->subsystem_vendor;
sub_sys = dev_a4t->subsystem_device;
if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
if (pci_enable_device(dev_a4t))
return (0); /* end loop & function */
*found = 1;
*pci_memaddr = pci_resource_start(dev_a4t, 0);
cs->irq = dev_a4t->irq;
return (1); /* end loop */
}
return (-1); /* continue looping */
}
static int a4t_cs_init(struct IsdnCard *card, struct IsdnCardState *cs,
u_int pci_memaddr)
{
I20_REGISTER_FILE *pI20_Regs;
if (!cs->irq) { /* IRQ range check ?? */
printk(KERN_WARNING "HiSax: Telekom A4T: No IRQ\n");
return (0);
}
cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
/* Check suspecious address */
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
printk(KERN_WARNING "HiSax: Telekom A4T address "
"%lx-%lx suspicious\n",
cs->hw.ax.base, cs->hw.ax.base + 4096);
iounmap((void *) cs->hw.ax.base);
cs->hw.ax.base = 0;
return (0);
}
cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
cs->hw.ax.isac_ale = GCS_1;
cs->hw.ax.jade_ale = GCS_3;
printk(KERN_INFO "HiSax: Telekom A4T: Card configured at "
"0x%lX IRQ %d\n",
cs->hw.ax.base, cs->irq);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadJADE;
cs->BC_Write_Reg = &WriteJADE;
cs->BC_Send_Data = &jade_fill_fifo;
cs->cardmsg = &BKM_card_msg;
cs->irq_func = &bkm_interrupt;
cs->irq_flags |= IRQF_SHARED;
ISACVersion(cs, "Telekom A4T:");
/* Jade version */
JadeVersion(cs, "Telekom A4T:");
return (1);
}
static struct pci_dev *dev_a4t = NULL;
int setup_bkm_a4t(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int pci_memaddr = 0, found = 0;
int ret;
strcpy(tmp, bkm_a4t_revision);
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
cs->subtyp = BKM_A4T;
} else
return (0);
while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN,
PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr);
if (!ret)
return (0);
if (ret > 0)
break;
}
if (!found) {
printk(KERN_WARNING "HiSax: Telekom A4T: Card not found\n");
return (0);
}
if (!pci_memaddr) {
printk(KERN_WARNING "HiSax: Telekom A4T: "
"No Memory base address\n");
return (0);
}
return a4t_cs_init(card, cs, pci_memaddr);
}

View File

@ -1,433 +0,0 @@
/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $
*
* low level stuff for Scitel Quadro (4*S0, passive)
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "ipac.h"
#include "hscx.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include "bkm_ax.h"
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
static const char *sct_quadro_subtypes[] =
{
"",
"#1",
"#2",
"#3",
"#4"
};
#define wordout(addr, val) outw(val, addr)
#define wordin(addr) inw(addr)
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
wordout(ale, off);
ret = wordin(adr) & 0xFF;
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
int i;
wordout(ale, off);
for (i = 0; i < size; i++)
data[i] = wordin(adr) & 0xFF;
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
wordout(ale, off);
wordout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
int i;
wordout(ale, off);
for (i = 0; i < size; i++)
wordout(adr, data[i]);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
}
/* Set the specific ipac to active */
static void
set_ipac_active(struct IsdnCardState *cs, u_int active)
{
/* set irq mask */
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
active ? 0xc0 : 0xff);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
bkm_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
if (!(ista & 0x3f)) { /* not this IPAC */
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
Start_IPAC:
if (cs->debug & L1_DEB_IPAC)
debugl1(cs, "IPAC ISTA %02X", ista);
if (ista & 0x0f) {
val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
if (ista & 0x01)
val |= 0x01;
if (ista & 0x04)
val |= 0x02;
if (ista & 0x08)
val |= 0x04;
if (val) {
hscx_int_main(cs, val);
}
}
if (ista & 0x20) {
val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
if (val) {
isac_interrupt(cs, val);
}
}
if (ista & 0x10) {
val = 0x01;
isac_interrupt(cs, val);
}
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
if ((ista & 0x3f) && icnt) {
icnt--;
goto Start_IPAC;
}
if (!icnt)
printk(KERN_WARNING "HiSax: Scitel Quadro (%s) IRQ LOOP\n",
sct_quadro_subtypes[cs->subtyp]);
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_sct_quadro(struct IsdnCardState *cs)
{
release_region(cs->hw.ax.base & 0xffffffc0, 128);
if (cs->subtyp == SCT_1)
release_region(cs->hw.ax.plx_adr, 64);
}
static void
enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
{
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
if (bEnable)
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
else
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
}
}
static void
reset_bkm(struct IsdnCardState *cs)
{
if (cs->subtyp == SCT_1) {
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
mdelay(10);
/* Remove the soft reset */
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
mdelay(10);
}
}
static int
BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
/* Disable ints */
set_ipac_active(cs, 0);
enable_bkm_int(cs, 0);
reset_bkm(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
/* Sanity */
spin_lock_irqsave(&cs->lock, flags);
set_ipac_active(cs, 0);
enable_bkm_int(cs, 0);
spin_unlock_irqrestore(&cs->lock, flags);
release_io_sct_quadro(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
cs->debug |= L1_DEB_IPAC;
set_ipac_active(cs, 1);
inithscxisac(cs, 3);
/* Enable ints */
enable_bkm_int(cs, 1);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int sct_alloc_io(u_int adr, u_int len)
{
if (!request_region(adr, len, "scitel")) {
printk(KERN_WARNING
"HiSax: Scitel port %#x-%#x already in use\n",
adr, adr + len);
return (1);
}
return (0);
}
static struct pci_dev *dev_a8 = NULL;
static u16 sub_vendor_id = 0;
static u16 sub_sys_id = 0;
static u_char pci_bus = 0;
static u_char pci_device_fn = 0;
static u_char pci_irq = 0;
int setup_sct_quadro(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int found = 0;
u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
strcpy(tmp, sct_quadro_revision);
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
cs->subtyp = SCT_1; /* Preset */
} else
return (0);
/* Identify subtype by para[0] */
if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
cs->subtyp = card->para[0];
else {
printk(KERN_WARNING "HiSax: Scitel Quadro: Invalid "
"subcontroller in configuration, default to 1\n");
return (0);
}
if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) ||
(sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
return (0);
if (cs->subtyp == SCT_1) {
while ((dev_a8 = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
PCI_DEVICE_ID_PLX_9050, dev_a8))) {
sub_vendor_id = dev_a8->subsystem_vendor;
sub_sys_id = dev_a8->subsystem_device;
if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
(sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
if (pci_enable_device(dev_a8))
return (0);
pci_ioaddr1 = pci_resource_start(dev_a8, 1);
pci_irq = dev_a8->irq;
pci_bus = dev_a8->bus->number;
pci_device_fn = dev_a8->devfn;
found = 1;
break;
}
}
if (!found) {
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
"Card not found\n",
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
#ifdef ATTEMPT_PCI_REMAPPING
/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
if ((pci_ioaddr1 & 0x80) && (dev_a8->revision == 1)) {
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
"PLX rev 1, remapping required!\n",
sct_quadro_subtypes[cs->subtyp]);
/* Restart PCI negotiation */
pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int)-1);
/* Move up by 0x80 byte */
pci_ioaddr1 += 0x80;
pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1);
dev_a8->resource[1].start = pci_ioaddr1;
}
#endif /* End HACK */
}
if (!pci_irq) { /* IRQ range check ?? */
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): No IRQ\n",
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
printk(KERN_WARNING "HiSax: Scitel Quadro (%s): "
"No IO base address(es)\n",
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
/* Take over */
cs->irq = pci_irq;
cs->irq_flags |= IRQF_SHARED;
/* pci_ioaddr1 is unique to all subdevices */
/* pci_ioaddr2 is for the fourth subdevice only */
/* pci_ioaddr3 is for the third subdevice only */
/* pci_ioaddr4 is for the second subdevice only */
/* pci_ioaddr5 is for the first subdevice only */
cs->hw.ax.plx_adr = pci_ioaddr1;
/* Enter all ipac_base addresses */
switch (cs->subtyp) {
case 1:
cs->hw.ax.base = pci_ioaddr5 + 0x00;
if (sct_alloc_io(pci_ioaddr1, 128))
return (0);
if (sct_alloc_io(pci_ioaddr5, 64))
return (0);
/* disable all IPAC */
writereg(pci_ioaddr5, pci_ioaddr5 + 4,
IPAC_MASK, 0xFF);
writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
IPAC_MASK, 0xFF);
writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
IPAC_MASK, 0xFF);
writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
IPAC_MASK, 0xFF);
break;
case 2:
cs->hw.ax.base = pci_ioaddr4 + 0x08;
if (sct_alloc_io(pci_ioaddr4, 64))
return (0);
break;
case 3:
cs->hw.ax.base = pci_ioaddr3 + 0x10;
if (sct_alloc_io(pci_ioaddr3, 64))
return (0);
break;
case 4:
cs->hw.ax.base = pci_ioaddr2 + 0x20;
if (sct_alloc_io(pci_ioaddr2, 64))
return (0);
break;
}
/* For isac and hscx data path */
cs->hw.ax.data_adr = cs->hw.ax.base + 4;
printk(KERN_INFO "HiSax: Scitel Quadro (%s) configured at "
"0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n",
sct_quadro_subtypes[cs->subtyp],
cs->hw.ax.plx_adr,
cs->hw.ax.base,
cs->hw.ax.data_adr,
cs->irq);
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &BKM_card_msg;
cs->irq_func = &bkm_interrupt_ipac;
printk(KERN_INFO "HiSax: Scitel Quadro (%s): IPAC Version %d\n",
sct_quadro_subtypes[cs->subtyp],
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
return (1);
}

View File

@ -1,119 +0,0 @@
/* $Id: bkm_ax.h,v 1.5.6.3 2001/09/23 22:24:46 kai Exp $
*
* low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __BKM_AX_H__
#define __BKM_AX_H__
/* Supported boards (subtypes) */
#define SCT_1 1
#define SCT_2 2
#define SCT_3 3
#define SCT_4 4
#define BKM_A4T 5
#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */
#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */
#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */
#define PLX_ADDR_ALE 0x20 /* Addr ALE */
#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */
#define PLX_SUBVEN 0x2C /* Offset SubVendor */
#define PLX_SUBSYS 0x2E /* Offset SubSystem */
/* Application specific registers I20 (Siemens SZB6120H) */
typedef struct {
/* Video front end horizontal configuration register */
volatile u_int i20VFEHorzCfg; /* Offset 00 */
/* Video front end vertical configuration register */
volatile u_int i20VFEVertCfg; /* Offset 04 */
/* Video front end scaler and pixel format register */
volatile u_int i20VFEScaler; /* Offset 08 */
/* Video display top register */
volatile u_int i20VDispTop; /* Offset 0C */
/* Video display bottom register */
volatile u_int i20VDispBottom; /* Offset 10 */
/* Video stride, status and frame grab register */
volatile u_int i20VidFrameGrab;/* Offset 14 */
/* Video display configuration register */
volatile u_int i20VDispCfg; /* Offset 18 */
/* Video masking map top */
volatile u_int i20VMaskTop; /* Offset 1C */
/* Video masking map bottom */
volatile u_int i20VMaskBottom; /* Offset 20 */
/* Overlay control register */
volatile u_int i20OvlyControl; /* Offset 24 */
/* System, PCI and general purpose pins control register */
volatile u_int i20SysControl; /* Offset 28 */
#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */
/* GPIO 4...0: Output fixed for our cfg! */
#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */
/* General purpose pins and guest bus control register */
volatile u_int i20GuestControl;/* Offset 2C */
#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */
#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */
#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */
#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */
#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */
#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */
#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */
#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */
#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */
#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */
#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */
#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */
#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */
#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */
#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */
#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */
#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */
volatile u_int i20CodeSource; /* Offset 30 */
volatile u_int i20CodeXferCtrl;/* Offset 34 */
volatile u_int i20CodeMemPtr; /* Offset 38 */
volatile u_int i20IntStatus; /* Offset 3C */
volatile u_int i20IntCtrl; /* Offset 40 */
#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */
#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */
#define intCOD 0x10000000 /* CodRepIrqEn (High) */
#define intPCI 0x01000000 /* PCI IntA enable (High) */
volatile u_int i20I2CCtrl; /* Offset 44 */
} I20_REGISTER_FILE, *PI20_REGISTER_FILE;
/*
* Postoffice structure for A4T
*
*/
#define PO_OFFSET 0x00000200 /* Postoffice offset from base */
#define GCS_0 0x00000000 /* Guest bus chip selects */
#define GCS_1 0x00100000
#define GCS_2 0x00200000
#define GCS_3 0x00300000
#define PO_READ 0x00000000 /* R/W from/to guest bus */
#define PO_WRITE 0x00800000
#define PO_PEND 0x02000000
#define POSTOFFICE(postoffice) *(volatile unsigned int *)(postoffice)
/* Wait unlimited (don't worry) */
#define __WAITI20__(postoffice) \
do { \
while ((POSTOFFICE(postoffice) & PO_PEND)) ; \
} while (0)
#endif /* __BKM_AX_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,218 +0,0 @@
/*======================================================================
An elsa_cs PCMCIA client driver
This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The initial developer of the original code is David A. Hinds
<dahinds@users.sourceforge.net>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus
Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved.
Alternatively, the contents of this file may be used under the
terms of the GNU General Public License version 2 (the "GPL"), in
which case the provisions of the GPL are applicable instead of the
above. If you wish to allow the use of your version of this file
only under the terms of the GPL and not to allow others to use
your version of this file under the MPL, indicate your decision
by deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
======================================================================*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#include "hisax_cfg.h"
MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards");
MODULE_AUTHOR("Klaus Lichtenwalder");
MODULE_LICENSE("Dual MPL/GPL");
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int protocol = 2; /* EURO-ISDN Default */
module_param(protocol, int, 0);
static int elsa_cs_config(struct pcmcia_device *link);
static void elsa_cs_release(struct pcmcia_device *link);
static void elsa_cs_detach(struct pcmcia_device *p_dev);
typedef struct local_info_t {
struct pcmcia_device *p_dev;
int busy;
int cardnr;
} local_info_t;
static int elsa_cs_probe(struct pcmcia_device *link)
{
local_info_t *local;
dev_dbg(&link->dev, "elsa_cs_attach()\n");
/* Allocate space for private device-specific data */
local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
local->p_dev = link;
link->priv = local;
local->cardnr = -1;
return elsa_cs_config(link);
} /* elsa_cs_attach */
static void elsa_cs_detach(struct pcmcia_device *link)
{
local_info_t *info = link->priv;
dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link);
info->busy = 1;
elsa_cs_release(link);
kfree(info);
} /* elsa_cs_detach */
static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
{
int j;
p_dev->io_lines = 3;
p_dev->resource[0]->end = 8;
p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
if (!pcmcia_request_io(p_dev))
return 0;
} else {
printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n");
for (j = 0x2f0; j > 0x100; j -= 0x10) {
p_dev->resource[0]->start = j;
if (!pcmcia_request_io(p_dev))
return 0;
}
}
return -ENODEV;
}
static int elsa_cs_config(struct pcmcia_device *link)
{
int i;
IsdnCard_t icard;
dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
if (i != 0)
goto failed;
if (!link->irq)
goto failed;
i = pcmcia_enable_device(link);
if (i != 0)
goto failed;
icard.para[0] = link->irq;
icard.para[1] = link->resource[0]->start;
icard.protocol = protocol;
icard.typ = ISDN_CTYPE_ELSA_PCMCIA;
i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard);
if (i < 0) {
printk(KERN_ERR "elsa_cs: failed to initialize Elsa "
"PCMCIA %d with %pR\n", i, link->resource[0]);
elsa_cs_release(link);
} else
((local_info_t *)link->priv)->cardnr = i;
return 0;
failed:
elsa_cs_release(link);
return -ENODEV;
} /* elsa_cs_config */
static void elsa_cs_release(struct pcmcia_device *link)
{
local_info_t *local = link->priv;
dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link);
if (local) {
if (local->cardnr >= 0) {
/* no unregister function with hisax */
HiSax_closecard(local->cardnr);
}
}
pcmcia_disable_device(link);
} /* elsa_cs_release */
static int elsa_suspend(struct pcmcia_device *link)
{
local_info_t *dev = link->priv;
dev->busy = 1;
return 0;
}
static int elsa_resume(struct pcmcia_device *link)
{
local_info_t *dev = link->priv;
dev->busy = 0;
return 0;
}
static const struct pcmcia_device_id elsa_ids[] = {
PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
static struct pcmcia_driver elsa_cs_driver = {
.owner = THIS_MODULE,
.name = "elsa_cs",
.probe = elsa_cs_probe,
.remove = elsa_cs_detach,
.id_table = elsa_ids,
.suspend = elsa_suspend,
.resume = elsa_resume,
};
module_pcmcia_driver(elsa_cs_driver);

View File

@ -1,659 +0,0 @@
/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $
*
* stuff for the serial modem on ELSA cards
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/serial.h>
#include <linux/serial_reg.h>
#include <linux/slab.h>
#define MAX_MODEM_BUF 256
#define WAKEUP_CHARS (MAX_MODEM_BUF / 2)
#define RS_ISR_PASS_LIMIT 256
#define BASE_BAUD (1843200 / 16)
//#define SERIAL_DEBUG_OPEN 1
//#define SERIAL_DEBUG_INTR 1
//#define SERIAL_DEBUG_FLOW 1
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_REG
//#define SERIAL_DEBUG_REG 1
#ifdef SERIAL_DEBUG_REG
static u_char deb[32];
const char *ModemIn[] = {"RBR", "IER", "IIR", "LCR", "MCR", "LSR", "MSR", "SCR"};
const char *ModemOut[] = {"THR", "IER", "FCR", "LCR", "MCR", "LSR", "MSR", "SCR"};
#endif
static char *MInit_1 = "AT&F&C1E0&D2\r\0";
static char *MInit_2 = "ATL2M1S64=13\r\0";
static char *MInit_3 = "AT+FCLASS=0\r\0";
static char *MInit_4 = "ATV1S2=128X1\r\0";
static char *MInit_5 = "AT\\V8\\N3\r\0";
static char *MInit_6 = "ATL0M0&G0%E1\r\0";
static char *MInit_7 = "AT%L1%M0%C3\r\0";
static char *MInit_speed28800 = "AT%G0%B28800\r\0";
static char *MInit_dialout = "ATs7=60 x1 d\r\0";
static char *MInit_dialin = "ATs7=60 x1 a\r\0";
static inline unsigned int serial_in(struct IsdnCardState *cs, int offset)
{
#ifdef SERIAL_DEBUG_REG
u_int val = inb(cs->hw.elsa.base + 8 + offset);
debugl1(cs, "in %s %02x", ModemIn[offset], val);
return (val);
#else
return inb(cs->hw.elsa.base + 8 + offset);
#endif
}
static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset)
{
#ifdef SERIAL_DEBUG_REG
#ifdef ELSA_SERIAL_NOPAUSE_IO
u_int val = inb(cs->hw.elsa.base + 8 + offset);
debugl1(cs, "inp %s %02x", ModemIn[offset], val);
#else
u_int val = inb_p(cs->hw.elsa.base + 8 + offset);
debugl1(cs, "inP %s %02x", ModemIn[offset], val);
#endif
return (val);
#else
#ifdef ELSA_SERIAL_NOPAUSE_IO
return inb(cs->hw.elsa.base + 8 + offset);
#else
return inb_p(cs->hw.elsa.base + 8 + offset);
#endif
#endif
}
static inline void serial_out(struct IsdnCardState *cs, int offset, int value)
{
#ifdef SERIAL_DEBUG_REG
debugl1(cs, "out %s %02x", ModemOut[offset], value);
#endif
outb(value, cs->hw.elsa.base + 8 + offset);
}
static inline void serial_outp(struct IsdnCardState *cs, int offset,
int value)
{
#ifdef SERIAL_DEBUG_REG
#ifdef ELSA_SERIAL_NOPAUSE_IO
debugl1(cs, "outp %s %02x", ModemOut[offset], value);
#else
debugl1(cs, "outP %s %02x", ModemOut[offset], value);
#endif
#endif
#ifdef ELSA_SERIAL_NOPAUSE_IO
outb(value, cs->hw.elsa.base + 8 + offset);
#else
outb_p(value, cs->hw.elsa.base + 8 + offset);
#endif
}
/*
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
static void change_speed(struct IsdnCardState *cs, int baud)
{
int quot = 0, baud_base;
unsigned cval, fcr = 0;
/* byte size and parity */
cval = 0x03;
/* Determine divisor based on baud rate */
baud_base = BASE_BAUD;
quot = baud_base / baud;
/* If the quotient is ever zero, default to 9600 bps */
if (!quot)
quot = baud_base / 9600;
/* Set up FIFO's */
if ((baud_base / quot) < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
serial_outp(cs, UART_FCR, fcr);
/* CTS flow control flag and modem status interrupts */
cs->hw.elsa.IER &= ~UART_IER_MSI;
cs->hw.elsa.IER |= UART_IER_MSI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
debugl1(cs, "modem quot=0x%x", quot);
serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */
serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */
serial_outp(cs, UART_LCR, cval); /* reset DLAB */
serial_inp(cs, UART_RX);
}
static int mstartup(struct IsdnCardState *cs)
{
int retval = 0;
/*
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
*/
serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
/*
* At this point there's no way the LSR could still be 0xFF;
* if it is, then bail out, because there's likely no UART
* here.
*/
if (serial_inp(cs, UART_LSR) == 0xff) {
retval = -ENODEV;
goto errout;
}
/*
* Clear the interrupt registers.
*/
(void) serial_inp(cs, UART_RX);
(void) serial_inp(cs, UART_IIR);
(void) serial_inp(cs, UART_MSR);
/*
* Now, initialize the UART
*/
serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */
cs->hw.elsa.MCR = 0;
cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
/*
* Finally, enable interrupts
*/
cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */
/*
* And clear the interrupt registers again for luck.
*/
(void)serial_inp(cs, UART_LSR);
(void)serial_inp(cs, UART_RX);
(void)serial_inp(cs, UART_IIR);
(void)serial_inp(cs, UART_MSR);
cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0;
cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp = 0;
/*
* and set the speed of the serial port
*/
change_speed(cs, BASE_BAUD);
cs->hw.elsa.MFlag = 1;
errout:
return retval;
}
/*
* 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 mshutdown(struct IsdnCardState *cs)
{
#ifdef SERIAL_DEBUG_OPEN
printk(KERN_DEBUG"Shutting down serial ....");
#endif
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
* here so the queue might never be waken up
*/
cs->hw.elsa.IER = 0;
serial_outp(cs, UART_IER, 0x00); /* disable all intrs */
cs->hw.elsa.MCR &= ~UART_MCR_OUT2;
/* disable break condition */
serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC);
cs->hw.elsa.MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
serial_outp(cs, UART_MCR, cs->hw.elsa.MCR);
/* disable FIFO's */
serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
serial_inp(cs, UART_RX); /* read data port to reset things */
#ifdef SERIAL_DEBUG_OPEN
printk(" done\n");
#endif
}
static inline int
write_modem(struct BCState *bcs) {
int ret = 0;
struct IsdnCardState *cs = bcs->cs;
int count, len, fp;
if (!bcs->tx_skb)
return 0;
if (bcs->tx_skb->len <= 0)
return 0;
len = bcs->tx_skb->len;
if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt)
len = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
fp &= (MAX_MODEM_BUF - 1);
count = len;
if (count > MAX_MODEM_BUF - fp) {
count = MAX_MODEM_BUF - fp;
skb_copy_from_linear_data(bcs->tx_skb,
cs->hw.elsa.transbuf + fp, count);
skb_pull(bcs->tx_skb, count);
cs->hw.elsa.transcnt += count;
ret = count;
count = len - count;
fp = 0;
}
skb_copy_from_linear_data(bcs->tx_skb,
cs->hw.elsa.transbuf + fp, count);
skb_pull(bcs->tx_skb, count);
cs->hw.elsa.transcnt += count;
ret += count;
if (cs->hw.elsa.transcnt &&
!(cs->hw.elsa.IER & UART_IER_THRI)) {
cs->hw.elsa.IER |= UART_IER_THRI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
}
return (ret);
}
static inline void
modem_fill(struct BCState *bcs) {
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
write_modem(bcs);
return;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hscx.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
}
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hscx.count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
write_modem(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
static inline void receive_chars(struct IsdnCardState *cs,
int *status)
{
unsigned char ch;
struct sk_buff *skb;
do {
ch = serial_in(cs, UART_RX);
if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF)
break;
cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch;
#ifdef SERIAL_DEBUG_INTR
printk("DR%02x:%02x...", ch, *status);
#endif
if (*status & (UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE)) {
#ifdef SERIAL_DEBUG_INTR
printk("handling exept....");
#endif
}
*status = serial_inp(cs, UART_LSR);
} while (*status & UART_LSR_DR);
if (cs->hw.elsa.MFlag == 2) {
if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt)))
printk(KERN_WARNING "ElsaSER: receive out of memory\n");
else {
skb_put_data(skb, cs->hw.elsa.rcvbuf,
cs->hw.elsa.rcvcnt);
skb_queue_tail(&cs->hw.elsa.bcs->rqueue, skb);
}
schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY);
} else {
char tmp[128];
char *t = tmp;
t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt);
QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt);
debugl1(cs, "%s", tmp);
}
cs->hw.elsa.rcvcnt = 0;
}
static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done)
{
int count;
debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp,
cs->hw.elsa.transcnt);
if (cs->hw.elsa.transcnt <= 0) {
cs->hw.elsa.IER &= ~UART_IER_THRI;
serial_out(cs, UART_IER, cs->hw.elsa.IER);
return;
}
count = 16;
do {
serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]);
if (cs->hw.elsa.transp >= MAX_MODEM_BUF)
cs->hw.elsa.transp = 0;
if (--cs->hw.elsa.transcnt <= 0)
break;
} while (--count > 0);
if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag == 2))
modem_fill(cs->hw.elsa.bcs);
#ifdef SERIAL_DEBUG_INTR
printk("THRE...");
#endif
if (intr_done)
*intr_done = 0;
if (cs->hw.elsa.transcnt <= 0) {
cs->hw.elsa.IER &= ~UART_IER_THRI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
}
}
static void rs_interrupt_elsa(struct IsdnCardState *cs)
{
int status, iir, msr;
int pass_counter = 0;
#ifdef SERIAL_DEBUG_INTR
printk(KERN_DEBUG "rs_interrupt_single(%d)...", cs->irq);
#endif
do {
status = serial_inp(cs, UART_LSR);
debugl1(cs, "rs LSR %02x", status);
#ifdef SERIAL_DEBUG_INTR
printk("status = %x...", status);
#endif
if (status & UART_LSR_DR)
receive_chars(cs, &status);
if (status & UART_LSR_THRE)
transmit_chars(cs, NULL);
if (pass_counter++ > RS_ISR_PASS_LIMIT) {
printk("rs_single loop break.\n");
break;
}
iir = serial_inp(cs, UART_IIR);
debugl1(cs, "rs IIR %02x", iir);
if ((iir & 0xf) == 0) {
msr = serial_inp(cs, UART_MSR);
debugl1(cs, "rs MSR %02x", msr);
}
} while (!(iir & UART_IIR_NO_INT));
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
#endif
}
extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs);
extern void modehscx(struct BCState *bcs, int mode, int bc);
extern void hscx_l2l1(struct PStack *st, int pr, void *arg);
static void
close_elsastate(struct BCState *bcs)
{
modehscx(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
if (bcs->hw.hscx.rcvbuf) {
if (bcs->mode != L1_MODE_MODEM)
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
}
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
static void
modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
int count, fp;
u_char *msg = buf;
if (!len)
return;
if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) {
return;
}
fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
fp &= (MAX_MODEM_BUF - 1);
count = len;
if (count > MAX_MODEM_BUF - fp) {
count = MAX_MODEM_BUF - fp;
memcpy(cs->hw.elsa.transbuf + fp, msg, count);
cs->hw.elsa.transcnt += count;
msg += count;
count = len - count;
fp = 0;
}
memcpy(cs->hw.elsa.transbuf + fp, msg, count);
cs->hw.elsa.transcnt += count;
if (cs->hw.elsa.transcnt &&
!(cs->hw.elsa.IER & UART_IER_THRI)) {
cs->hw.elsa.IER |= UART_IER_THRI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
}
}
static void
modem_set_init(struct IsdnCardState *cs) {
int timeout;
#define RCV_DELAY 20
modem_write_cmd(cs, MInit_1, strlen(MInit_1));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_2, strlen(MInit_2));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_3, strlen(MInit_3));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_4, strlen(MInit_4));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_5, strlen(MInit_5));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_6, strlen(MInit_6));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
modem_write_cmd(cs, MInit_7, strlen(MInit_7));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
}
static void
modem_set_dial(struct IsdnCardState *cs, int outgoing) {
int timeout;
#define RCV_DELAY 20
modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
if (outgoing)
modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout));
else
modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin));
timeout = 1000;
while (timeout-- && cs->hw.elsa.transcnt)
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
mdelay(RCV_DELAY);
}
static void
modem_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
if (pr == (PH_DATA | REQUEST)) {
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hscx.count = 0;
write_modem(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
} else if (pr == (PH_ACTIVATE | REQUEST)) {
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
set_arcofi(bcs->cs, st->l1.bc);
mstartup(bcs->cs);
modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag));
bcs->cs->hw.elsa.MFlag = 2;
} else if (pr == (PH_DEACTIVATE | REQUEST)) {
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait,
bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP);
bcs->cs->hw.elsa.MFlag = 1;
} else {
printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr);
}
}
static int
setstack_elsa(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
switch (st->l1.mode) {
case L1_MODE_HDLC:
case L1_MODE_TRANS:
if (open_hscxstate(st->l1.hardware, bcs))
return (-1);
st->l2.l2l1 = hscx_l2l1;
break;
case L1_MODE_MODEM:
bcs->mode = L1_MODE_MODEM;
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf;
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
bcs->cs->hw.elsa.bcs = bcs;
st->l2.l2l1 = modem_l2l1;
break;
}
st->l1.bcs = bcs;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
static void
init_modem(struct IsdnCardState *cs) {
cs->bcs[0].BC_SetStack = setstack_elsa;
cs->bcs[1].BC_SetStack = setstack_elsa;
cs->bcs[0].BC_Close = close_elsastate;
cs->bcs[1].BC_Close = close_elsastate;
if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF,
GFP_ATOMIC))) {
printk(KERN_WARNING
"Elsa: No modem mem hw.elsa.rcvbuf\n");
return;
}
if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF,
GFP_ATOMIC))) {
printk(KERN_WARNING
"Elsa: No modem mem hw.elsa.transbuf\n");
kfree(cs->hw.elsa.rcvbuf);
cs->hw.elsa.rcvbuf = NULL;
return;
}
if (mstartup(cs)) {
printk(KERN_WARNING "Elsa: problem startup modem\n");
}
modem_set_init(cs);
}
static void
release_modem(struct IsdnCardState *cs) {
cs->hw.elsa.MFlag = 0;
if (cs->hw.elsa.transbuf) {
if (cs->hw.elsa.rcvbuf) {
mshutdown(cs);
kfree(cs->hw.elsa.rcvbuf);
cs->hw.elsa.rcvbuf = NULL;
}
kfree(cs->hw.elsa.transbuf);
cs->hw.elsa.transbuf = NULL;
}
}

View File

@ -1,420 +0,0 @@
/* enternow_pci.c,v 0.99 2001/10/02
*
* enternow_pci.c Card-specific routines for
* Formula-n enter:now ISDN PCI ab
* Gerdes AG Power ISDN PCI
* Woerltronic SA 16 PCI
* (based on HiSax driver by Karsten Keil)
*
* Author Christoph Ersfeld <info@formula-n.de>
* Formula-n Europe AG (www.formula-n.com)
* previously Gerdes AG
*
*
* This file is (c) under GNU PUBLIC LICENSE
*
* Notes:
* This driver interfaces to netjet.c which performs B-channel
* processing.
*
* Version 0.99 is the first release of this driver and there are
* certainly a few bugs.
* It isn't testet on linux 2.4 yet, so consider this code to be
* beta.
*
* Please don't report me any malfunction without sending
* (compressed) debug-logs.
* It would be nearly impossible to retrace it.
*
* Log D-channel-processing as follows:
*
* 1. Load hisax with card-specific parameters, this example ist for
* Formula-n enter:now ISDN PCI and compatible
* (f.e. Gerdes Power ISDN PCI)
*
* modprobe hisax type=41 protocol=2 id=gerdes
*
* if you chose an other value for id, you need to modify the
* code below, too.
*
* 2. set debug-level
*
* hisaxctrl gerdes 1 0x3ff
* hisaxctrl gerdes 11 0x4f
* cat /dev/isdnctrl >> ~/log &
*
* Please take also a look into /var/log/messages if there is
* anything importand concerning HISAX.
*
*
* Credits:
* Programming the driver for Formula-n enter:now ISDN PCI and
* necessary the driver for the used Amd 7930 D-channel-controller
* was spnsored by Formula-n Europe AG.
* Thanks to Karsten Keil and Petr Novak, who gave me support in
* Hisax-specific questions.
* I want so say special thanks to Carl-Friedrich Braun, who had to
* answer a lot of questions about generally ISDN and about handling
* of the Amd-Chip.
*
*/
#include "hisax.h"
#include "isac.h"
#include "isdnl1.h"
#include "amd7930_fn.h"
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
#include <linux/pci.h>
#include <linux/init.h>
#include "netjet.h"
static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
/* for PowerISDN PCI */
#define TJ_AMD_IRQ 0x20
#define TJ_LED1 0x40
#define TJ_LED2 0x80
/* The window to [the] AMD [chip]...
* From address hw.njet.base + TJ_AMD_PORT onwards, the AMD
* maps [consecutive/multiple] 8 bits into the TigerJet I/O space
* -> 0x01 of the AMD at hw.njet.base + 0C4 */
#define TJ_AMD_PORT 0xC0
/* *************************** I/O-Interface functions ************************************* */
/* cs->readisac, macro rByteAMD */
static unsigned char
ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset)
{
/* direct register */
if (offset < 8)
return (inb(cs->hw.njet.isac + 4 * offset));
/* indirect register */
else {
outb(offset, cs->hw.njet.isac + 4 * AMD_CR);
return (inb(cs->hw.njet.isac + 4 * AMD_DR));
}
}
/* cs->writeisac, macro wByteAMD */
static void
WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value)
{
/* direct register */
if (offset < 8)
outb(value, cs->hw.njet.isac + 4 * offset);
/* indirect register */
else {
outb(offset, cs->hw.njet.isac + 4 * AMD_CR);
outb(value, cs->hw.njet.isac + 4 * AMD_DR);
}
}
static void
enpci_setIrqMask(struct IsdnCardState *cs, unsigned char val) {
if (!val)
outb(0x00, cs->hw.njet.base + NETJET_IRQMASK1);
else
outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
}
static unsigned char dummyrr(struct IsdnCardState *cs, int chan, unsigned char off)
{
return (5);
}
static void dummywr(struct IsdnCardState *cs, int chan, unsigned char off, unsigned char value)
{
}
/* ******************************************************************************** */
static void
reset_enpci(struct IsdnCardState *cs)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: reset");
/* Reset on, (also for AMD) */
cs->hw.njet.ctrl_reg = 0x07;
outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
mdelay(20);
/* Reset off */
cs->hw.njet.ctrl_reg = 0x30;
outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
/* 20ms delay */
mdelay(20);
cs->hw.njet.auxd = 0; // LED-status
cs->hw.njet.dmactrl = 0;
outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
outb(cs->hw.njet.auxd, cs->hw.njet.auxa); // LED off
}
static int
enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
unsigned char *chan;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_enpci(cs);
Amd7930_init(cs);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case CARD_RELEASE:
release_io_netjet(cs);
break;
case CARD_INIT:
reset_enpci(cs);
inittiger(cs);
/* irq must be on here */
Amd7930_init(cs);
break;
case CARD_TEST:
break;
case MDL_ASSIGN:
/* TEI assigned, LED1 on */
cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_REMOVE:
/* TEI removed, LEDs off */
cs->hw.njet.auxd = 0;
outb(0x00, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_BC_ASSIGN:
/* activate B-channel */
chan = (unsigned char *)arg;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
/* at least one b-channel in use, LED 2 on */
cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_BC_RELEASE:
/* deactivate B-channel */
chan = (unsigned char *)arg;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
/* no b-channel active -> LED2 off */
if (!(cs->dc.amd7930.lmr1 & 3)) {
cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
}
break;
default:
break;
}
return (0);
}
static irqreturn_t
enpci_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
unsigned char s0val, s1val, ir;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
s1val = inb(cs->hw.njet.base + NETJET_IRQSTAT1);
/* AMD threw an interrupt */
if (!(s1val & TJ_AMD_IRQ)) {
/* read and clear interrupt-register */
ir = ReadByteAmd7930(cs, 0x00);
Amd7930_interrupt(cs, ir);
s1val = 1;
} else
s1val = 0;
s0val = inb(cs->hw.njet.base + NETJET_IRQSTAT0);
if ((s0val | s1val) == 0) { // shared IRQ
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
if (s0val)
outb(s0val, cs->hw.njet.base + NETJET_IRQSTAT0);
/* DMA-Interrupt: B-channel-stuff */
/* set bits in sval to indicate which page is free */
if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
/* the 2nd write page is free */
s0val = 0x08;
else /* the 1st write page is free */
s0val = 0x04;
if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
/* the 2nd read page is free */
s0val = s0val | 0x02;
else /* the 1st read page is free */
s0val = s0val | 0x01;
if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
{
if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
cs->hw.njet.irqstat0 = s0val;
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
/* we have a read dma int */
read_tiger(cs);
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
/* we have a write dma int */
write_tiger(cs);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
}
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static int en_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
{
if (pci_enable_device(dev_netjet))
return (0);
cs->irq = dev_netjet->irq;
if (!cs->irq) {
printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
return (0);
}
cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
if (!cs->hw.njet.base) {
printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
return (0);
}
/* checks Sub-Vendor ID because system crashes with Traverse-Card */
if ((dev_netjet->subsystem_vendor != 0x55) ||
(dev_netjet->subsystem_device != 0x02)) {
printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
return (0);
}
return (1);
}
static void en_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
{
cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
/* Reset an */
cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff
outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
/* 20 ms Pause */
mdelay(20);
cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */
outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
mdelay(10);
cs->hw.njet.auxd = 0x00; // war 0xc0
cs->hw.njet.dmactrl = 0;
outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
}
static int en_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
{
const int bytecnt = 256;
printk(KERN_INFO
"enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
cs->hw.njet.base, cs->irq);
if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) {
printk(KERN_WARNING
"HiSax: enter:now config port %lx-%lx already in use\n",
cs->hw.njet.base,
cs->hw.njet.base + bytecnt);
return (0);
}
setup_Amd7930(cs);
cs->hw.njet.last_is0 = 0;
/* macro rByteAMD */
cs->readisac = &ReadByteAmd7930;
/* macro wByteAMD */
cs->writeisac = &WriteByteAmd7930;
cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
cs->BC_Read_Reg = &dummyrr;
cs->BC_Write_Reg = &dummywr;
cs->BC_Send_Data = &netjet_fill_dma;
cs->cardmsg = &enpci_card_msg;
cs->irq_func = &enpci_interrupt;
cs->irq_flags |= IRQF_SHARED;
return (1);
}
static struct pci_dev *dev_netjet = NULL;
/* called by config.c */
int setup_enternow_pci(struct IsdnCard *card)
{
int ret;
struct IsdnCardState *cs = card->cs;
char tmp[64];
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
strcpy(tmp, enternow_pci_rev);
printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_ENTERNOW)
return (0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
for (;;)
{
if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
ret = en_pci_probe(dev_netjet, cs);
if (!ret)
return (0);
} else {
printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
return (0);
}
en_cs_init(card, cs);
break;
}
return en_cs_init_rest(card, cs);
}

View File

@ -1,161 +0,0 @@
/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $
*
* Finite state machine
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
* by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include "hisax.h"
#define FSM_TIMER_DEBUG 0
int
FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
{
int i;
fsm->jumpmatrix =
kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count,
fsm->event_count),
GFP_KERNEL);
if (!fsm->jumpmatrix)
return -ENOMEM;
for (i = 0; i < fncount; i++)
if ((fnlist[i].state >= fsm->state_count) || (fnlist[i].event >= fsm->event_count)) {
printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n",
i, (long)fnlist[i].state, (long)fsm->state_count,
(long)fnlist[i].event, (long)fsm->event_count);
} else
fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
fnlist[i].state] = (FSMFNPTR)fnlist[i].routine;
return 0;
}
void
FsmFree(struct Fsm *fsm)
{
kfree((void *) fsm->jumpmatrix);
}
int
FsmEvent(struct FsmInst *fi, int event, void *arg)
{
FSMFNPTR r;
if ((fi->state >= fi->fsm->state_count) || (event >= fi->fsm->event_count)) {
printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
(long)fi->state, (long)fi->fsm->state_count, event, (long)fi->fsm->event_count);
return (1);
}
r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
if (r) {
if (fi->debug)
fi->printdebug(fi, "State %s Event %s",
fi->fsm->strState[fi->state],
fi->fsm->strEvent[event]);
r(fi, event, arg);
return (0);
} else {
if (fi->debug)
fi->printdebug(fi, "State %s Event %s no routine",
fi->fsm->strState[fi->state],
fi->fsm->strEvent[event]);
return (!0);
}
}
void
FsmChangeState(struct FsmInst *fi, int newstate)
{
fi->state = newstate;
if (fi->debug)
fi->printdebug(fi, "ChangeState %s",
fi->fsm->strState[newstate]);
}
static void
FsmExpireTimer(struct timer_list *t)
{
struct FsmTimer *ft = from_timer(ft, t, tl);
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
#endif
FsmEvent(ft->fi, ft->event, ft->arg);
}
void
FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
{
ft->fi = fi;
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft);
#endif
timer_setup(&ft->tl, FsmExpireTimer, 0);
}
void
FsmDelTimer(struct FsmTimer *ft, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where);
#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)
ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl)) {
printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
return -1;
}
ft->event = event;
ft->arg = arg;
ft->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&ft->tl);
return 0;
}
void
FsmRestartTimer(struct FsmTimer *ft,
int millisec, int event, void *arg, int where)
{
#if FSM_TIMER_DEBUG
if (ft->fi->debug)
ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d",
(long) ft, millisec, where);
#endif
if (timer_pending(&ft->tl))
del_timer(&ft->tl);
ft->event = event;
ft->arg = arg;
ft->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&ft->tl);
}

View File

@ -1,61 +0,0 @@
/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $
*
* Finite state machine
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
* by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __FSM_H__
#define __FSM_H__
#include <linux/timer.h>
struct FsmInst;
typedef void (*FSMFNPTR)(struct FsmInst *, int, void *);
struct Fsm {
FSMFNPTR *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;
};
int 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 FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
void *arg, int where);
void FsmDelTimer(struct FsmTimer *ft, int where);
#endif

View File

@ -1,691 +0,0 @@
/* $Id: gazel.c,v 2.19.2.4 2004/01/14 16:04:48 keil Exp $
*
* low level stuff for Gazel isdn cards
*
* Author BeWan Systems
* based on source code from Karsten Keil
* Copyright by BeWan Systems
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
#include "ipac.h"
#include <linux/pci.h>
static const char *gazel_revision = "$Revision: 2.19.2.4 $";
#define R647 1
#define R685 2
#define R753 3
#define R742 4
#define PLX_CNTRL 0x50 /* registre de controle PLX */
#define RESET_GAZEL 0x4
#define RESET_9050 0x40000000
#define PLX_INCSR 0x4C /* registre d'IT du 9050 */
#define INT_ISAC_EN 0x8 /* 1 = enable IT isac */
#define INT_ISAC 0x20 /* 1 = IT isac en cours */
#define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */
#define INT_HSCX 0x4 /* 1 = IT hscx en cours */
#define INT_PCI_EN 0x40 /* 1 = enable IT PCI */
#define INT_IPAC_EN 0x3 /* enable IT ipac */
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
static inline u_char
readreg(unsigned int adr, u_short off)
{
return bytein(adr + off);
}
static inline void
writereg(unsigned int adr, u_short off, u_char data)
{
byteout(adr + off, data);
}
static inline void
read_fifo(unsigned int adr, u_char *data, int size)
{
insb(adr, data, size);
}
static void
write_fifo(unsigned int adr, u_char *data, int size)
{
outsb(adr, data, size);
}
static inline u_char
readreg_ipac(unsigned int adr, u_short off)
{
register u_char ret;
byteout(adr, off);
ret = bytein(adr + 4);
return ret;
}
static inline void
writereg_ipac(unsigned int adr, u_short off, u_char data)
{
byteout(adr, off);
byteout(adr + 4, data);
}
static inline void
read_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size)
{
byteout(adr, off);
insb(adr + 4, data, size);
}
static void
write_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size)
{
byteout(adr, off);
outsb(adr + 4, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
u_short off2 = offset;
switch (cs->subtyp) {
case R647:
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
/* fall through */
case R685:
return (readreg(cs->hw.gazel.isac, off2));
case R753:
case R742:
return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2));
}
return 0;
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
u_short off2 = offset;
switch (cs->subtyp) {
case R647:
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
/* fall through */
case R685:
writereg(cs->hw.gazel.isac, off2, value);
break;
case R753:
case R742:
writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value);
break;
}
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
switch (cs->subtyp) {
case R647:
case R685:
read_fifo(cs->hw.gazel.isacfifo, data, size);
break;
case R753:
case R742:
read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
break;
}
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
switch (cs->subtyp) {
case R647:
case R685:
write_fifo(cs->hw.gazel.isacfifo, data, size);
break;
case R753:
case R742:
write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size);
break;
}
}
static void
ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
{
switch (cs->subtyp) {
case R647:
case R685:
read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
break;
case R753:
case R742:
read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
break;
}
}
static void
WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size)
{
switch (cs->subtyp) {
case R647:
case R685:
write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
break;
case R753:
case R742:
write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size);
break;
}
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
u_short off2 = offset;
switch (cs->subtyp) {
case R647:
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
/* fall through */
case R685:
return (readreg(cs->hw.gazel.hscx[hscx], off2));
case R753:
case R742:
return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2));
}
return 0;
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
u_short off2 = offset;
switch (cs->subtyp) {
case R647:
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf));
/* fall through */
case R685:
writereg(cs->hw.gazel.hscx[hscx], off2, value);
break;
case R753:
case R742:
writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value);
break;
}
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
gazel_interrupt(int intno, void *dev_id)
{
#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
u_char valisac, valhscx;
int count = 0;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
do {
valhscx = ReadHSCX(cs, 1, HSCX_ISTA);
if (valhscx)
hscx_int_main(cs, valhscx);
valisac = ReadISAC(cs, ISAC_ISTA);
if (valisac)
isac_interrupt(cs, valisac);
count++;
} while ((valhscx || valisac) && (count < MAXCOUNT));
WriteHSCX(cs, 0, HSCX_MASK, 0xFF);
WriteHSCX(cs, 1, HSCX_MASK, 0xFF);
WriteISAC(cs, ISAC_MASK, 0xFF);
WriteISAC(cs, ISAC_MASK, 0x0);
WriteHSCX(cs, 0, HSCX_MASK, 0x0);
WriteHSCX(cs, 1, HSCX_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t
gazel_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val;
int count = 0;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
ista = ReadISAC(cs, IPAC_ISTA - 0x80);
do {
if (ista & 0x0f) {
val = ReadHSCX(cs, 1, HSCX_ISTA);
if (ista & 0x01)
val |= 0x01;
if (ista & 0x04)
val |= 0x02;
if (ista & 0x08)
val |= 0x04;
if (val) {
hscx_int_main(cs, val);
}
}
if (ista & 0x20) {
val = 0xfe & ReadISAC(cs, ISAC_ISTA);
if (val) {
isac_interrupt(cs, val);
}
}
if (ista & 0x10) {
val = 0x01;
isac_interrupt(cs, val);
}
ista = ReadISAC(cs, IPAC_ISTA - 0x80);
count++;
}
while ((ista & 0x3f) && (count < MAXCOUNT));
WriteISAC(cs, IPAC_MASK - 0x80, 0xFF);
WriteISAC(cs, IPAC_MASK - 0x80, 0xC0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_gazel(struct IsdnCardState *cs)
{
unsigned int i;
switch (cs->subtyp) {
case R647:
for (i = 0x0000; i < 0xC000; i += 0x1000)
release_region(i + cs->hw.gazel.hscx[0], 16);
release_region(0xC000 + cs->hw.gazel.hscx[0], 1);
break;
case R685:
release_region(cs->hw.gazel.hscx[0], 0x100);
release_region(cs->hw.gazel.cfg_reg, 0x80);
break;
case R753:
release_region(cs->hw.gazel.ipac, 0x8);
release_region(cs->hw.gazel.cfg_reg, 0x80);
break;
case R742:
release_region(cs->hw.gazel.ipac, 8);
break;
}
}
static int
reset_gazel(struct IsdnCardState *cs)
{
unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
switch (cs->subtyp) {
case R647:
writereg(addr, 0, 0);
HZDELAY(10);
writereg(addr, 0, 1);
HZDELAY(2);
break;
case R685:
plxcntrl = inl(addr + PLX_CNTRL);
plxcntrl |= (RESET_9050 + RESET_GAZEL);
outl(plxcntrl, addr + PLX_CNTRL);
plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
HZDELAY(4);
outl(plxcntrl, addr + PLX_CNTRL);
HZDELAY(10);
outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
break;
case R753:
plxcntrl = inl(addr + PLX_CNTRL);
plxcntrl |= (RESET_9050 + RESET_GAZEL);
outl(plxcntrl, addr + PLX_CNTRL);
plxcntrl &= ~(RESET_9050 + RESET_GAZEL);
WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
HZDELAY(4);
outl(plxcntrl, addr + PLX_CNTRL);
HZDELAY(10);
WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR);
WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
break;
case R742:
WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20);
HZDELAY(4);
WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00);
WriteISAC(cs, IPAC_ACFG - 0x80, 0xff);
WriteISAC(cs, IPAC_AOE - 0x80, 0x0);
WriteISAC(cs, IPAC_MASK - 0x80, 0xff);
WriteISAC(cs, IPAC_CONF - 0x80, 0x1);
WriteISAC(cs, IPAC_MASK - 0x80, 0xc0);
break;
}
return (0);
}
static int
Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_gazel(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_gazel(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscxisac(cs, 1);
if ((cs->subtyp == R647) || (cs->subtyp == R685)) {
int i;
for (i = 0; i < (2 + MAX_WAITING_CALLS); i++) {
cs->bcs[i].hw.hscx.tsaxr0 = 0x1f;
cs->bcs[i].hw.hscx.tsaxr1 = 0x23;
}
}
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int
reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
{
unsigned int i, j, base = 0, adr = 0, len = 0;
switch (cs->subtyp) {
case R647:
base = cs->hw.gazel.hscx[0];
if (!request_region(adr = (0xC000 + base), len = 1, "gazel"))
goto error;
for (i = 0x0000; i < 0xC000; i += 0x1000) {
if (!request_region(adr = (i + base), len = 16, "gazel"))
goto error;
}
if (i != 0xC000) {
for (j = 0; j < i; j += 0x1000)
release_region(j + base, 16);
release_region(0xC000 + base, 1);
goto error;
}
break;
case R685:
if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel"))
goto error;
if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
release_region(cs->hw.gazel.hscx[0], 0x100);
goto error;
}
break;
case R753:
if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
goto error;
if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) {
release_region(cs->hw.gazel.ipac, 8);
goto error;
}
break;
case R742:
if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel"))
goto error;
break;
}
return 0;
error:
printk(KERN_WARNING "Gazel: io ports 0x%x-0x%x already in use\n",
adr, adr + len);
return 1;
}
static int setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
{
printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
// we got an irq parameter, assume it is an ISA card
// R742 decodes address even in not started...
// R647 returns FF if not present or not started
// eventually needs improvment
if (readreg_ipac(card->para[1], IPAC_ID) == 1)
cs->subtyp = R742;
else
cs->subtyp = R647;
setup_isac(cs);
cs->hw.gazel.cfg_reg = card->para[1] + 0xC000;
cs->hw.gazel.ipac = card->para[1];
cs->hw.gazel.isac = card->para[1] + 0x8000;
cs->hw.gazel.hscx[0] = card->para[1];
cs->hw.gazel.hscx[1] = card->para[1] + 0x4000;
cs->irq = card->para[0];
cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
switch (cs->subtyp) {
case R647:
printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n");
cs->dc.isac.adf2 = 0x87;
printk(KERN_INFO
"Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
printk(KERN_INFO
"Gazel: hscx A:0x%X hscx B:0x%X\n",
cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
break;
case R742:
printk(KERN_INFO "Gazel: Card ISA R742 found\n");
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
printk(KERN_INFO
"Gazel: config irq:%d ipac:0x%X\n",
cs->irq, cs->hw.gazel.ipac);
break;
}
return (0);
}
#ifdef CONFIG_PCI
static struct pci_dev *dev_tel = NULL;
static int setup_gazelpci(struct IsdnCardState *cs)
{
u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
u_char pci_irq = 0, found;
u_int nbseek, seekcard;
printk(KERN_WARNING "Gazel: PCI card automatic recognition\n");
found = 0;
seekcard = PCI_DEVICE_ID_PLX_R685;
for (nbseek = 0; nbseek < 4; nbseek++) {
if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_PLX,
seekcard, dev_tel))) {
if (pci_enable_device(dev_tel))
return 1;
pci_irq = dev_tel->irq;
pci_ioaddr0 = pci_resource_start(dev_tel, 1);
pci_ioaddr1 = pci_resource_start(dev_tel, 2);
found = 1;
}
if (found)
break;
else {
switch (seekcard) {
case PCI_DEVICE_ID_PLX_R685:
seekcard = PCI_DEVICE_ID_PLX_R753;
break;
case PCI_DEVICE_ID_PLX_R753:
seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO;
break;
case PCI_DEVICE_ID_PLX_DJINN_ITOO:
seekcard = PCI_DEVICE_ID_PLX_OLITEC;
break;
}
}
}
if (!found) {
printk(KERN_WARNING "Gazel: No PCI card found\n");
return (1);
}
if (!pci_irq) {
printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n");
return 1;
}
cs->hw.gazel.pciaddr[0] = pci_ioaddr0;
cs->hw.gazel.pciaddr[1] = pci_ioaddr1;
setup_isac(cs);
pci_ioaddr1 &= 0xfffe;
cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe;
cs->hw.gazel.ipac = pci_ioaddr1;
cs->hw.gazel.isac = pci_ioaddr1 + 0x80;
cs->hw.gazel.hscx[0] = pci_ioaddr1;
cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40;
cs->hw.gazel.isacfifo = cs->hw.gazel.isac;
cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
cs->irq = pci_irq;
cs->irq_flags |= IRQF_SHARED;
switch (seekcard) {
case PCI_DEVICE_ID_PLX_R685:
printk(KERN_INFO "Gazel: Card PCI R685 found\n");
cs->subtyp = R685;
cs->dc.isac.adf2 = 0x87;
printk(KERN_INFO
"Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg);
printk(KERN_INFO
"Gazel: hscx A:0x%X hscx B:0x%X\n",
cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
break;
case PCI_DEVICE_ID_PLX_R753:
case PCI_DEVICE_ID_PLX_DJINN_ITOO:
case PCI_DEVICE_ID_PLX_OLITEC:
printk(KERN_INFO "Gazel: Card PCI R753 found\n");
cs->subtyp = R753;
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
printk(KERN_INFO
"Gazel: config irq:%d ipac:0x%X cfg:0x%X\n",
cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg);
break;
}
return (0);
}
#endif /* CONFIG_PCI */
int setup_gazel(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_char val;
strcpy(tmp, gazel_revision);
printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_GAZEL)
return (0);
if (card->para[0]) {
if (setup_gazelisa(card, cs))
return (0);
} else {
#ifdef CONFIG_PCI
if (setup_gazelpci(cs))
return (0);
#else
printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n");
return (0);
#endif /* CONFIG_PCI */
}
if (reserve_regions(card, cs)) {
return (0);
}
if (reset_gazel(cs)) {
printk(KERN_WARNING "Gazel: wrong IRQ\n");
release_io_gazel(cs);
return (0);
}
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Gazel_card_msg;
switch (cs->subtyp) {
case R647:
case R685:
cs->irq_func = &gazel_interrupt;
ISACVersion(cs, "Gazel:");
if (HscxVersion(cs, "Gazel:")) {
printk(KERN_WARNING
"Gazel: wrong HSCX versions check IO address\n");
release_io_gazel(cs);
return (0);
}
break;
case R742:
case R753:
cs->irq_func = &gazel_interrupt_ipac;
val = ReadISAC(cs, IPAC_ID - 0x80);
printk(KERN_INFO "Gazel: IPAC version %x\n", val);
break;
}
return (1);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/***************************************************************/
/* $Id: hfc4s8s_l1.h,v 1.1 2005/02/02 17:28:55 martinb1 Exp $ */
/* */
/* This file is a minimal required extraction of hfc48scu.h */
/* (Genero 3.2, HFC XML 1.7a for HFC-E1, HFC-4S and HFC-8S) */
/* */
/* To get this complete register description contact */
/* Cologne Chip AG : */
/* Internet: http://www.colognechip.com/ */
/* E-Mail: info@colognechip.com */
/***************************************************************/
#ifndef _HFC4S8S_L1_H_
#define _HFC4S8S_L1_H_
/*
* include Genero generated HFC-4S/8S header file hfc48scu.h
* for complete register description. This will define _HFC48SCU_H_
* to prevent redefinitions
*/
// #include "hfc48scu.h"
#ifndef _HFC48SCU_H_
#define _HFC48SCU_H_
#ifndef PCI_VENDOR_ID_CCD
#define PCI_VENDOR_ID_CCD 0x1397
#endif
#define CHIP_ID_4S 0x0C
#define CHIP_ID_8S 0x08
#define PCI_DEVICE_ID_4S 0x08B4
#define PCI_DEVICE_ID_8S 0x16B8
#define R_IRQ_MISC 0x11
#define M_TI_IRQ 0x02
#define A_ST_RD_STA 0x30
#define A_ST_WR_STA 0x30
#define M_SET_G2_G3 0x80
#define A_ST_CTRL0 0x31
#define A_ST_CTRL2 0x33
#define A_ST_CLK_DLY 0x37
#define A_Z1 0x04
#define A_Z2 0x06
#define R_CIRM 0x00
#define M_SRES 0x08
#define R_CTRL 0x01
#define R_BRG_PCM_CFG 0x02
#define M_PCM_CLK 0x20
#define R_RAM_MISC 0x0C
#define M_FZ_MD 0x80
#define R_FIFO_MD 0x0D
#define A_INC_RES_FIFO 0x0E
#define R_FIFO 0x0F
#define A_F1 0x0C
#define A_F2 0x0D
#define R_IRQ_OVIEW 0x10
#define R_CHIP_ID 0x16
#define R_STATUS 0x1C
#define M_BUSY 0x01
#define M_MISC_IRQSTA 0x40
#define M_FR_IRQSTA 0x80
#define R_CHIP_RV 0x1F
#define R_IRQ_CTRL 0x13
#define M_FIFO_IRQ 0x01
#define M_GLOB_IRQ_EN 0x08
#define R_PCM_MD0 0x14
#define M_PCM_MD 0x01
#define A_FIFO_DATA0 0x80
#define R_TI_WD 0x1A
#define R_PWM1 0x39
#define R_PWM_MD 0x46
#define R_IRQ_FIFO_BL0 0xC8
#define A_CON_HDLC 0xFA
#define A_SUBCH_CFG 0xFB
#define A_IRQ_MSK 0xFF
#define R_SCI_MSK 0x12
#define R_ST_SEL 0x16
#define R_ST_SYNC 0x17
#define M_AUTO_SYNC 0x08
#define R_SCI 0x12
#define R_IRQMSK_MISC 0x11
#define M_TI_IRQMSK 0x02
#endif /* _HFC4S8S_L1_H_ */
#endif /* _HFC48SCU_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,128 +0,0 @@
/* $Id: hfc_2bds0.h,v 1.6.2.2 2004/01/12 22:52:26 keil Exp $
*
* specific defines for CCD's HFC 2BDS0
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define HFCD_CIRM 0x18
#define HFCD_CTMT 0x19
#define HFCD_INT_M1 0x1A
#define HFCD_INT_M2 0x1B
#define HFCD_INT_S1 0x1E
#define HFCD_STAT 0x1C
#define HFCD_STAT_DISB 0x1D
#define HFCD_STATES 0x30
#define HFCD_SCTRL 0x31
#define HFCD_TEST 0x32
#define HFCD_SQ 0x34
#define HFCD_CLKDEL 0x37
#define HFCD_MST_MODE 0x2E
#define HFCD_CONN 0x2F
#define HFCD_FIFO 0x80
#define HFCD_Z1 0x10
#define HFCD_Z2 0x18
#define HFCD_Z_LOW 0x00
#define HFCD_Z_HIGH 0x04
#define HFCD_F1_INC 0x12
#define HFCD_FIFO_IN 0x16
#define HFCD_F1 0x1a
#define HFCD_F2 0x1e
#define HFCD_F2_INC 0x22
#define HFCD_FIFO_OUT 0x26
#define HFCD_REC 0x01
#define HFCD_SEND 0x00
#define HFCB_FIFO 0x80
#define HFCB_Z1 0x00
#define HFCB_Z2 0x08
#define HFCB_Z_LOW 0x00
#define HFCB_Z_HIGH 0x04
#define HFCB_F1_INC 0x28
#define HFCB_FIFO_IN 0x2c
#define HFCB_F1 0x30
#define HFCB_F2 0x34
#define HFCB_F2_INC 0x38
#define HFCB_FIFO_OUT 0x3c
#define HFCB_REC 0x01
#define HFCB_SEND 0x00
#define HFCB_B1 0x00
#define HFCB_B2 0x02
#define HFCB_CHANNEL(ch) (ch ? HFCB_B2 : HFCB_B1)
#define HFCD_STATUS 0
#define HFCD_DATA 1
#define HFCD_DATA_NODEB 2
/* Status (READ) */
#define HFCD_BUSY 0x01
#define HFCD_BUSY_NBUSY 0x04
#define HFCD_TIMER_ELAP 0x10
#define HFCD_STATINT 0x20
#define HFCD_FRAMEINT 0x40
#define HFCD_ANYINT 0x80
/* CTMT (Write) */
#define HFCD_CLTIMER 0x80
#define HFCD_TIM25 0x00
#define HFCD_TIM50 0x08
#define HFCD_TIM400 0x10
#define HFCD_TIM800 0x18
#define HFCD_AUTO_TIMER 0x20
#define HFCD_TRANSB2 0x02
#define HFCD_TRANSB1 0x01
/* CIRM (Write) */
#define HFCD_RESET 0x08
#define HFCD_MEM8K 0x10
#define HFCD_INTA 0x01
#define HFCD_INTB 0x02
#define HFCD_INTC 0x03
#define HFCD_INTD 0x04
#define HFCD_INTE 0x05
#define HFCD_INTF 0x06
/* INT_M1;INT_S1 */
#define HFCD_INTS_B1TRANS 0x01
#define HFCD_INTS_B2TRANS 0x02
#define HFCD_INTS_DTRANS 0x04
#define HFCD_INTS_B1REC 0x08
#define HFCD_INTS_B2REC 0x10
#define HFCD_INTS_DREC 0x20
#define HFCD_INTS_L1STATE 0x40
#define HFCD_INTS_TIMER 0x80
/* INT_M2 */
#define HFCD_IRQ_ENABLE 0x08
/* STATES */
#define HFCD_LOAD_STATE 0x10
#define HFCD_ACTIVATE 0x20
#define HFCD_DO_ACTION 0x40
/* HFCD_MST_MODE */
#define HFCD_MASTER 0x01
/* HFCD_SCTRL */
#define SCTRL_B1_ENA 0x01
#define SCTRL_B2_ENA 0x02
#define SCTRL_LOW_PRIO 0x08
#define SCTRL_SQ_ENA 0x10
#define SCTRL_TEST 0x20
#define SCTRL_NONE_CAP 0x40
#define SCTRL_PWR_DOWN 0x80
/* HFCD_TEST */
#define HFCD_AUTO_AWAKE 0x01
extern void main_irq_2bds0(struct BCState *bcs);
extern void init2bds0(struct IsdnCardState *cs);
extern void release2bds0(struct IsdnCardState *cs);
extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val);
extern void set_cs_func(struct IsdnCardState *cs);

View File

@ -1,591 +0,0 @@
/* $Id: hfc_2bs0.c,v 1.20.2.6 2004/02/11 13:21:33 keil Exp $
*
* specific routines for CCD's HFC 2BS0
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "hfc_2bs0.h"
#include "isac.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
static inline int
WaitForBusy(struct IsdnCardState *cs)
{
int to = 130;
u_char val;
while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 |
(cs->hw.hfc.cip & 3));
udelay(1);
to--;
}
if (!to) {
printk(KERN_WARNING "HiSax: %s timeout\n", __func__);
return (0);
} else
return (to);
}
static inline int
WaitNoBusy(struct IsdnCardState *cs)
{
int to = 125;
while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) {
udelay(1);
to--;
}
if (!to) {
printk(KERN_WARNING "HiSax: waitforBusy timeout\n");
return (0);
} else
return (to);
}
static int
GetFreeFifoBytes(struct BCState *bcs)
{
int s;
if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2)
return (bcs->cs->hw.hfc.fifosize);
s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2];
if (s <= 0)
s += bcs->cs->hw.hfc.fifosize;
s = bcs->cs->hw.hfc.fifosize - s;
return (s);
}
static int
ReadZReg(struct BCState *bcs, u_char reg)
{
int val;
WaitNoBusy(bcs->cs);
val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH);
WaitNoBusy(bcs->cs);
val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW);
return (val);
}
static void
hfc_clear_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int idx, cnt;
int rcnt, z1, z2;
u_char cip, f1, f2;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hfc_clear_fifo");
cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
WaitForBusy(cs);
}
WaitNoBusy(cs);
f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
cnt = 32;
while (((f1 != f2) || (z1 != z2)) && cnt--) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc clear %d f1(%d) f2(%d)",
bcs->channel, f1, f2);
rcnt = z1 - z2;
if (rcnt < 0)
rcnt += cs->hw.hfc.fifosize;
if (rcnt)
rcnt++;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc clear %d z1(%x) z2(%x) cnt(%d)",
bcs->channel, z1, z2, rcnt);
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
idx = 0;
while ((idx < rcnt) && WaitNoBusy(cs)) {
cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
idx++;
}
if (f1 != f2) {
WaitNoBusy(cs);
cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
}
cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
}
return;
}
static struct sk_buff
*
hfc_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct sk_buff *skb;
struct IsdnCardState *cs = bcs->cs;
int idx;
int chksum;
u_char stat, cip;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hfc_empty_fifo");
idx = 0;
if (count > HSCX_BUFMAX + 3) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hfc_empty_fifo: incoming packet too large");
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
while ((idx++ < count) && WaitNoBusy(cs))
cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
return (NULL);
}
if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hfc_empty_fifo: incoming packet too small");
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
while ((idx++ < count) && WaitNoBusy(cs))
cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
#ifdef ERROR_STATISTIC
bcs->err_inv++;
#endif
return (NULL);
}
if (bcs->mode == L1_MODE_TRANS)
count -= 1;
else
count -= 3;
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HFC: receive out of memory\n");
else {
ptr = skb_put(skb, count);
idx = 0;
cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
while ((idx < count) && WaitNoBusy(cs)) {
*ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
idx++;
}
if (idx != count) {
debugl1(cs, "RFIFO BUSY error");
printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
dev_kfree_skb_any(skb);
if (bcs->mode != L1_MODE_TRANS) {
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
}
return (NULL);
}
if (bcs->mode != L1_MODE_TRANS) {
WaitNoBusy(cs);
chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8);
WaitNoBusy(cs);
chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip);
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, cip);
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x",
bcs->channel, chksum, stat);
if (stat) {
debugl1(cs, "FIFO CRC error");
dev_kfree_skb_any(skb);
skb = NULL;
#ifdef ERROR_STATISTIC
bcs->err_crc++;
#endif
}
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
HFC_CHANNEL(bcs->channel));
WaitForBusy(cs);
}
}
return (skb);
}
static void
hfc_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int idx, fcnt;
int count;
int z1, z2;
u_char cip;
if (!bcs->tx_skb)
return;
if (bcs->tx_skb->len <= 0)
return;
cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel);
if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
WaitForBusy(cs);
}
WaitNoBusy(cs);
if (bcs->mode != L1_MODE_TRANS) {
bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel));
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)",
bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2,
bcs->hw.hfc.send[bcs->hw.hfc.f1]);
fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2;
if (fcnt < 0)
fcnt += 32;
if (fcnt > 30) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo more as 30 frames");
return;
}
count = GetFreeFifoBytes(bcs);
}
else {
WaitForBusy(cs);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
count = z1 - z2;
if (count < 0)
count += cs->hw.hfc.fifosize;
} /* L1_MODE_TRANS */
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo %d count(%u/%d)",
bcs->channel, bcs->tx_skb->len,
count);
if (count < bcs->tx_skb->len) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc_fill_fifo no fifo mem");
return;
}
cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel);
idx = 0;
while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs))
cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]);
if (idx != bcs->tx_skb->len) {
debugl1(cs, "FIFO Send BUSY error");
printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
} else {
count = bcs->tx_skb->len;
bcs->tx_cnt -= count;
if (PACKET_NOACK == bcs->tx_skb->pkt_type)
count = -1;
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
if (bcs->mode != L1_MODE_TRANS) {
WaitForBusy(cs);
WaitNoBusy(cs);
cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel));
}
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(count >= 0)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
return;
}
void
main_irq_hfc(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int z1, z2, rcnt;
u_char f1, f2, cip;
int receive, transmit, count = 5;
struct sk_buff *skb;
Begin:
count--;
cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel);
if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) {
cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip);
WaitForBusy(cs);
}
WaitNoBusy(cs);
receive = 0;
if (bcs->mode == L1_MODE_HDLC) {
f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel);
WaitNoBusy(cs);
f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip);
if (f1 != f2) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc rec %d f1(%d) f2(%d)",
bcs->channel, f1, f2);
receive = 1;
}
}
if (receive || (bcs->mode == L1_MODE_TRANS)) {
WaitForBusy(cs);
z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel));
z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel));
rcnt = z1 - z2;
if (rcnt < 0)
rcnt += cs->hw.hfc.fifosize;
if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) {
rcnt++;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)",
bcs->channel, z1, z2, rcnt);
/* sti(); */
if ((skb = hfc_empty_fifo(bcs, rcnt))) {
skb_queue_tail(&bcs->rqueue, skb);
schedule_event(bcs, B_RCVBUFREADY);
}
}
receive = 1;
}
if (bcs->tx_skb) {
transmit = 1;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
hfc_fill_fifo(bcs);
if (test_bit(BC_FLG_BUSY, &bcs->Flag))
transmit = 0;
} else {
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
transmit = 1;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
hfc_fill_fifo(bcs);
if (test_bit(BC_FLG_BUSY, &bcs->Flag))
transmit = 0;
} else {
transmit = 0;
schedule_event(bcs, B_XMTBUFREADY);
}
}
if ((receive || transmit) && count)
goto Begin;
return;
}
static void
mode_hfc(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HFC 2BS0 mode %d bchan %d/%d",
mode, bc, bcs->channel);
bcs->mode = mode;
bcs->channel = bc;
switch (mode) {
case (L1_MODE_NULL):
if (bc) {
cs->hw.hfc.ctmt &= ~1;
cs->hw.hfc.isac_spcr &= ~0x03;
}
else {
cs->hw.hfc.ctmt &= ~2;
cs->hw.hfc.isac_spcr &= ~0x0c;
}
break;
case (L1_MODE_TRANS):
cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */
cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
hfc_clear_fifo(bcs); /* complete fifo clear */
if (bc) {
cs->hw.hfc.ctmt |= 1;
cs->hw.hfc.isac_spcr &= ~0x03;
cs->hw.hfc.isac_spcr |= 0x02;
} else {
cs->hw.hfc.ctmt |= 2;
cs->hw.hfc.isac_spcr &= ~0x0c;
cs->hw.hfc.isac_spcr |= 0x08;
}
break;
case (L1_MODE_HDLC):
if (bc) {
cs->hw.hfc.ctmt &= ~1;
cs->hw.hfc.isac_spcr &= ~0x03;
cs->hw.hfc.isac_spcr |= 0x02;
} else {
cs->hw.hfc.ctmt &= ~2;
cs->hw.hfc.isac_spcr &= ~0x0c;
cs->hw.hfc.isac_spcr |= 0x08;
}
break;
}
cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt);
cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr);
if (mode == L1_MODE_HDLC)
hfc_clear_fifo(bcs);
}
static void
hfc_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n");
} else {
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
mode_hfc(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
mode_hfc(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
static void
close_hfcstate(struct BCState *bcs)
{
mode_hfc(bcs, 0, bcs->channel);
if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
}
static int
open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->tx_cnt = 0;
return (0);
}
static int
setstack_hfc(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_hfcstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = hfc_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
static void
init_send(struct BCState *bcs)
{
int i;
bcs->hw.hfc.send = kmalloc_array(32, sizeof(unsigned int), GFP_ATOMIC);
if (!bcs->hw.hfc.send) {
printk(KERN_WARNING
"HiSax: No memory for hfc.send\n");
return;
}
for (i = 0; i < 32; i++)
bcs->hw.hfc.send[i] = 0x1fff;
}
void
inithfc(struct IsdnCardState *cs)
{
init_send(&cs->bcs[0]);
init_send(&cs->bcs[1]);
cs->BC_Send_Data = &hfc_fill_fifo;
cs->bcs[0].BC_SetStack = setstack_hfc;
cs->bcs[1].BC_SetStack = setstack_hfc;
cs->bcs[0].BC_Close = close_hfcstate;
cs->bcs[1].BC_Close = close_hfcstate;
mode_hfc(cs->bcs, 0, 0);
mode_hfc(cs->bcs + 1, 0, 0);
}
void
releasehfc(struct IsdnCardState *cs)
{
kfree(cs->bcs[0].hw.hfc.send);
cs->bcs[0].hw.hfc.send = NULL;
kfree(cs->bcs[1].hw.hfc.send);
cs->bcs[1].hw.hfc.send = NULL;
}

View File

@ -1,60 +0,0 @@
/* $Id: hfc_2bs0.h,v 1.5.2.2 2004/01/12 22:52:26 keil Exp $
*
* specific defines for CCD's HFC 2BS0
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define HFC_CTMT 0xe0
#define HFC_CIRM 0xc0
#define HFC_CIP 0x80
#define HFC_Z1 0x00
#define HFC_Z2 0x08
#define HFC_Z_LOW 0x00
#define HFC_Z_HIGH 0x04
#define HFC_F1_INC 0x28
#define HFC_FIFO_IN 0x2c
#define HFC_F1 0x30
#define HFC_F2 0x34
#define HFC_F2_INC 0x38
#define HFC_FIFO_OUT 0x3c
#define HFC_B1 0x00
#define HFC_B2 0x02
#define HFC_REC 0x01
#define HFC_SEND 0x00
#define HFC_CHANNEL(ch) (ch ? HFC_B2 : HFC_B1)
#define HFC_STATUS 0
#define HFC_DATA 1
#define HFC_DATA_NODEB 2
/* Status (READ) */
#define HFC_BUSY 0x01
#define HFC_TIMINT 0x02
#define HFC_EXTINT 0x04
/* CTMT (Write) */
#define HFC_CLTIMER 0x10
#define HFC_TIM50MS 0x08
#define HFC_TIMIRQE 0x04
#define HFC_TRANSB2 0x02
#define HFC_TRANSB1 0x01
/* CIRM (Write) */
#define HFC_RESET 0x08
#define HFC_MEM8K 0x10
#define HFC_INTA 0x01
#define HFC_INTB 0x02
#define HFC_INTC 0x03
#define HFC_INTD 0x04
#define HFC_INTE 0x05
#define HFC_INTF 0x06
extern void main_irq_hfc(struct BCState *bcs);
extern void inithfc(struct IsdnCardState *cs);
extern void releasehfc(struct IsdnCardState *cs);

File diff suppressed because it is too large Load Diff

View File

@ -1,235 +0,0 @@
/* $Id: hfc_pci.h,v 1.10.2.2 2004/01/12 22:52:26 keil Exp $
*
* specific defines for CCD's HFC 2BDS0 PCI chips
*
* Author Werner Cornelius
* Copyright by Werner Cornelius <werner@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/*********************************************/
/* thresholds for transparent B-channel mode */
/* change mask and threshold simultaneously */
/*********************************************/
#define HFCPCI_BTRANS_THRESHOLD 128
#define HFCPCI_BTRANS_THRESMASK 0x00
/* defines for PCI config */
#define PCI_ENA_MEMIO 0x02
#define PCI_ENA_MASTER 0x04
/* GCI/IOM bus monitor registers */
#define HCFPCI_C_I 0x08
#define HFCPCI_TRxR 0x0C
#define HFCPCI_MON1_D 0x28
#define HFCPCI_MON2_D 0x2C
/* GCI/IOM bus timeslot registers */
#define HFCPCI_B1_SSL 0x80
#define HFCPCI_B2_SSL 0x84
#define HFCPCI_AUX1_SSL 0x88
#define HFCPCI_AUX2_SSL 0x8C
#define HFCPCI_B1_RSL 0x90
#define HFCPCI_B2_RSL 0x94
#define HFCPCI_AUX1_RSL 0x98
#define HFCPCI_AUX2_RSL 0x9C
/* GCI/IOM bus data registers */
#define HFCPCI_B1_D 0xA0
#define HFCPCI_B2_D 0xA4
#define HFCPCI_AUX1_D 0xA8
#define HFCPCI_AUX2_D 0xAC
/* GCI/IOM bus configuration registers */
#define HFCPCI_MST_EMOD 0xB4
#define HFCPCI_MST_MODE 0xB8
#define HFCPCI_CONNECT 0xBC
/* Interrupt and status registers */
#define HFCPCI_FIFO_EN 0x44
#define HFCPCI_TRM 0x48
#define HFCPCI_B_MODE 0x4C
#define HFCPCI_CHIP_ID 0x58
#define HFCPCI_CIRM 0x60
#define HFCPCI_CTMT 0x64
#define HFCPCI_INT_M1 0x68
#define HFCPCI_INT_M2 0x6C
#define HFCPCI_INT_S1 0x78
#define HFCPCI_INT_S2 0x7C
#define HFCPCI_STATUS 0x70
/* S/T section registers */
#define HFCPCI_STATES 0xC0
#define HFCPCI_SCTRL 0xC4
#define HFCPCI_SCTRL_E 0xC8
#define HFCPCI_SCTRL_R 0xCC
#define HFCPCI_SQ 0xD0
#define HFCPCI_CLKDEL 0xDC
#define HFCPCI_B1_REC 0xF0
#define HFCPCI_B1_SEND 0xF0
#define HFCPCI_B2_REC 0xF4
#define HFCPCI_B2_SEND 0xF4
#define HFCPCI_D_REC 0xF8
#define HFCPCI_D_SEND 0xF8
#define HFCPCI_E_REC 0xFC
/* bits in status register (READ) */
#define HFCPCI_PCI_PROC 0x02
#define HFCPCI_NBUSY 0x04
#define HFCPCI_TIMER_ELAP 0x10
#define HFCPCI_STATINT 0x20
#define HFCPCI_FRAMEINT 0x40
#define HFCPCI_ANYINT 0x80
/* bits in CTMT (Write) */
#define HFCPCI_CLTIMER 0x80
#define HFCPCI_TIM3_125 0x04
#define HFCPCI_TIM25 0x10
#define HFCPCI_TIM50 0x14
#define HFCPCI_TIM400 0x18
#define HFCPCI_TIM800 0x1C
#define HFCPCI_AUTO_TIMER 0x20
#define HFCPCI_TRANSB2 0x02
#define HFCPCI_TRANSB1 0x01
/* bits in CIRM (Write) */
#define HFCPCI_AUX_MSK 0x07
#define HFCPCI_RESET 0x08
#define HFCPCI_B1_REV 0x40
#define HFCPCI_B2_REV 0x80
/* bits in INT_M1 and INT_S1 */
#define HFCPCI_INTS_B1TRANS 0x01
#define HFCPCI_INTS_B2TRANS 0x02
#define HFCPCI_INTS_DTRANS 0x04
#define HFCPCI_INTS_B1REC 0x08
#define HFCPCI_INTS_B2REC 0x10
#define HFCPCI_INTS_DREC 0x20
#define HFCPCI_INTS_L1STATE 0x40
#define HFCPCI_INTS_TIMER 0x80
/* bits in INT_M2 */
#define HFCPCI_PROC_TRANS 0x01
#define HFCPCI_GCI_I_CHG 0x02
#define HFCPCI_GCI_MON_REC 0x04
#define HFCPCI_IRQ_ENABLE 0x08
#define HFCPCI_PMESEL 0x80
/* bits in STATES */
#define HFCPCI_STATE_MSK 0x0F
#define HFCPCI_LOAD_STATE 0x10
#define HFCPCI_ACTIVATE 0x20
#define HFCPCI_DO_ACTION 0x40
#define HFCPCI_NT_G2_G3 0x80
/* bits in HFCD_MST_MODE */
#define HFCPCI_MASTER 0x01
#define HFCPCI_SLAVE 0x00
/* remaining bits are for codecs control */
/* bits in HFCD_SCTRL */
#define SCTRL_B1_ENA 0x01
#define SCTRL_B2_ENA 0x02
#define SCTRL_MODE_TE 0x00
#define SCTRL_MODE_NT 0x04
#define SCTRL_LOW_PRIO 0x08
#define SCTRL_SQ_ENA 0x10
#define SCTRL_TEST 0x20
#define SCTRL_NONE_CAP 0x40
#define SCTRL_PWR_DOWN 0x80
/* bits in SCTRL_E */
#define HFCPCI_AUTO_AWAKE 0x01
#define HFCPCI_DBIT_1 0x04
#define HFCPCI_IGNORE_COL 0x08
#define HFCPCI_CHG_B1_B2 0x80
/****************************/
/* bits in FIFO_EN register */
/****************************/
#define HFCPCI_FIFOEN_B1 0x03
#define HFCPCI_FIFOEN_B2 0x0C
#define HFCPCI_FIFOEN_DTX 0x10
#define HFCPCI_FIFOEN_B1TX 0x01
#define HFCPCI_FIFOEN_B1RX 0x02
#define HFCPCI_FIFOEN_B2TX 0x04
#define HFCPCI_FIFOEN_B2RX 0x08
/***********************************/
/* definitions of fifo memory area */
/***********************************/
#define MAX_D_FRAMES 15
#define MAX_B_FRAMES 31
#define B_SUB_VAL 0x200
#define B_FIFO_SIZE (0x2000 - B_SUB_VAL)
#define D_FIFO_SIZE 512
#define D_FREG_MASK 0xF
typedef struct {
unsigned short z1; /* Z1 pointer 16 Bit */
unsigned short z2; /* Z2 pointer 16 Bit */
} z_type;
typedef struct {
u_char data[D_FIFO_SIZE]; /* FIFO data space */
u_char fill1[0x20A0 - D_FIFO_SIZE]; /* reserved, do not use */
u_char f1, f2; /* f pointers */
u_char fill2[0x20C0 - 0x20A2]; /* reserved, do not use */
z_type za[MAX_D_FRAMES + 1]; /* mask index with D_FREG_MASK for access */
u_char fill3[0x4000 - 0x2100]; /* align 16K */
} dfifo_type;
typedef struct {
z_type za[MAX_B_FRAMES + 1]; /* only range 0x0..0x1F allowed */
u_char f1, f2; /* f pointers */
u_char fill[0x2100 - 0x2082]; /* alignment */
} bzfifo_type;
typedef union {
struct {
dfifo_type d_tx; /* D-send channel */
dfifo_type d_rx; /* D-receive channel */
} d_chan;
struct {
u_char fill1[0x200];
u_char txdat_b1[B_FIFO_SIZE];
bzfifo_type txbz_b1;
bzfifo_type txbz_b2;
u_char txdat_b2[B_FIFO_SIZE];
u_char fill2[D_FIFO_SIZE];
u_char rxdat_b1[B_FIFO_SIZE];
bzfifo_type rxbz_b1;
bzfifo_type rxbz_b2;
u_char rxdat_b2[B_FIFO_SIZE];
} b_chans;
u_char fill[32768];
} fifo_area;
#define Write_hfc(a, b, c) (writeb(c, (a->hw.hfcpci.pci_io) + b))
#define Read_hfc(a, b) (readb((a->hw.hfcpci.pci_io) + b))
extern void main_irq_hcpci(struct BCState *bcs);
extern void releasehfcpci(struct IsdnCardState *cs);

File diff suppressed because it is too large Load Diff

View File

@ -1,196 +0,0 @@
/* $Id: hfc_sx.h,v 1.2.6.1 2001/09/23 22:24:48 kai Exp $
*
* specific defines for CCD's HFC 2BDS0 S+,SP chips
*
* Author Werner Cornelius
* based on existing driver for CCD HFC PCI cards
* Copyright by Werner Cornelius <werner@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/*********************************************/
/* thresholds for transparent B-channel mode */
/* change mask and threshold simultaneously */
/*********************************************/
#define HFCSX_BTRANS_THRESHOLD 128
#define HFCSX_BTRANS_THRESMASK 0x00
/* GCI/IOM bus monitor registers */
#define HFCSX_C_I 0x02
#define HFCSX_TRxR 0x03
#define HFCSX_MON1_D 0x0A
#define HFCSX_MON2_D 0x0B
/* GCI/IOM bus timeslot registers */
#define HFCSX_B1_SSL 0x20
#define HFCSX_B2_SSL 0x21
#define HFCSX_AUX1_SSL 0x22
#define HFCSX_AUX2_SSL 0x23
#define HFCSX_B1_RSL 0x24
#define HFCSX_B2_RSL 0x25
#define HFCSX_AUX1_RSL 0x26
#define HFCSX_AUX2_RSL 0x27
/* GCI/IOM bus data registers */
#define HFCSX_B1_D 0x28
#define HFCSX_B2_D 0x29
#define HFCSX_AUX1_D 0x2A
#define HFCSX_AUX2_D 0x2B
/* GCI/IOM bus configuration registers */
#define HFCSX_MST_EMOD 0x2D
#define HFCSX_MST_MODE 0x2E
#define HFCSX_CONNECT 0x2F
/* Interrupt and status registers */
#define HFCSX_TRM 0x12
#define HFCSX_B_MODE 0x13
#define HFCSX_CHIP_ID 0x16
#define HFCSX_CIRM 0x18
#define HFCSX_CTMT 0x19
#define HFCSX_INT_M1 0x1A
#define HFCSX_INT_M2 0x1B
#define HFCSX_INT_S1 0x1E
#define HFCSX_INT_S2 0x1F
#define HFCSX_STATUS 0x1C
/* S/T section registers */
#define HFCSX_STATES 0x30
#define HFCSX_SCTRL 0x31
#define HFCSX_SCTRL_E 0x32
#define HFCSX_SCTRL_R 0x33
#define HFCSX_SQ 0x34
#define HFCSX_CLKDEL 0x37
#define HFCSX_B1_REC 0x3C
#define HFCSX_B1_SEND 0x3C
#define HFCSX_B2_REC 0x3D
#define HFCSX_B2_SEND 0x3D
#define HFCSX_D_REC 0x3E
#define HFCSX_D_SEND 0x3E
#define HFCSX_E_REC 0x3F
/****************/
/* FIFO section */
/****************/
#define HFCSX_FIF_SEL 0x10
#define HFCSX_FIF_Z1L 0x80
#define HFCSX_FIF_Z1H 0x84
#define HFCSX_FIF_Z2L 0x88
#define HFCSX_FIF_Z2H 0x8C
#define HFCSX_FIF_INCF1 0xA8
#define HFCSX_FIF_DWR 0xAC
#define HFCSX_FIF_F1 0xB0
#define HFCSX_FIF_F2 0xB4
#define HFCSX_FIF_INCF2 0xB8
#define HFCSX_FIF_DRD 0xBC
/* bits in status register (READ) */
#define HFCSX_SX_PROC 0x02
#define HFCSX_NBUSY 0x04
#define HFCSX_TIMER_ELAP 0x10
#define HFCSX_STATINT 0x20
#define HFCSX_FRAMEINT 0x40
#define HFCSX_ANYINT 0x80
/* bits in CTMT (Write) */
#define HFCSX_CLTIMER 0x80
#define HFCSX_TIM3_125 0x04
#define HFCSX_TIM25 0x10
#define HFCSX_TIM50 0x14
#define HFCSX_TIM400 0x18
#define HFCSX_TIM800 0x1C
#define HFCSX_AUTO_TIMER 0x20
#define HFCSX_TRANSB2 0x02
#define HFCSX_TRANSB1 0x01
/* bits in CIRM (Write) */
#define HFCSX_IRQ_SELMSK 0x07
#define HFCSX_IRQ_SELDIS 0x00
#define HFCSX_RESET 0x08
#define HFCSX_FIFO_RESET 0x80
/* bits in INT_M1 and INT_S1 */
#define HFCSX_INTS_B1TRANS 0x01
#define HFCSX_INTS_B2TRANS 0x02
#define HFCSX_INTS_DTRANS 0x04
#define HFCSX_INTS_B1REC 0x08
#define HFCSX_INTS_B2REC 0x10
#define HFCSX_INTS_DREC 0x20
#define HFCSX_INTS_L1STATE 0x40
#define HFCSX_INTS_TIMER 0x80
/* bits in INT_M2 */
#define HFCSX_PROC_TRANS 0x01
#define HFCSX_GCI_I_CHG 0x02
#define HFCSX_GCI_MON_REC 0x04
#define HFCSX_IRQ_ENABLE 0x08
/* bits in STATES */
#define HFCSX_STATE_MSK 0x0F
#define HFCSX_LOAD_STATE 0x10
#define HFCSX_ACTIVATE 0x20
#define HFCSX_DO_ACTION 0x40
#define HFCSX_NT_G2_G3 0x80
/* bits in HFCD_MST_MODE */
#define HFCSX_MASTER 0x01
#define HFCSX_SLAVE 0x00
/* remaining bits are for codecs control */
/* bits in HFCD_SCTRL */
#define SCTRL_B1_ENA 0x01
#define SCTRL_B2_ENA 0x02
#define SCTRL_MODE_TE 0x00
#define SCTRL_MODE_NT 0x04
#define SCTRL_LOW_PRIO 0x08
#define SCTRL_SQ_ENA 0x10
#define SCTRL_TEST 0x20
#define SCTRL_NONE_CAP 0x40
#define SCTRL_PWR_DOWN 0x80
/* bits in SCTRL_E */
#define HFCSX_AUTO_AWAKE 0x01
#define HFCSX_DBIT_1 0x04
#define HFCSX_IGNORE_COL 0x08
#define HFCSX_CHG_B1_B2 0x80
/**********************************/
/* definitions for FIFO selection */
/**********************************/
#define HFCSX_SEL_D_RX 5
#define HFCSX_SEL_D_TX 4
#define HFCSX_SEL_B1_RX 1
#define HFCSX_SEL_B1_TX 0
#define HFCSX_SEL_B2_RX 3
#define HFCSX_SEL_B2_TX 2
#define MAX_D_FRAMES 15
#define MAX_B_FRAMES 31
#define B_SUB_VAL_32K 0x0200
#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K)
#define B_SUB_VAL_8K 0x1A00
#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K)
#define D_FIFO_SIZE 512
#define D_FREG_MASK 0xF
/************************************************************/
/* structure holding additional dynamic data -> send marker */
/************************************************************/
struct hfcsx_extra {
unsigned short marker[2 * (MAX_B_FRAMES + 1) + (MAX_D_FRAMES + 1)];
};
extern void main_irq_hfcsx(struct BCState *bcs);
extern void releasehfcsx(struct IsdnCardState *cs);

File diff suppressed because it is too large Load Diff

View File

@ -1,208 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* hfc_usb.h
*
* $Id: hfc_usb.h,v 1.1.2.5 2007/08/20 14:36:03 mbachem Exp $
*/
#ifndef __HFC_USB_H__
#define __HFC_USB_H__
#define DRIVER_AUTHOR "Peter Sprenger (sprenger@moving-byters.de)"
#define DRIVER_DESC "HFC-S USB based HiSAX ISDN driver"
#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */
#define HFC_TIMER_T4 500 /* time for state change interval */
#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
#define HFCUSB_L1_DRX 1 /* D-frame received */
#define HFCUSB_L1_ERX 2 /* E-frame received */
#define HFCUSB_L1_DTX 4 /* D-frames completed */
#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
#define HFCUSB_CIRM 0x00 /* cirm register index */
#define HFCUSB_USB_SIZE 0x07 /* int length register */
#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
#define HFCUSB_F_CROSS 0x0b /* bit order register */
#define HFCUSB_CLKDEL 0x37 /* bit delay register */
#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
#define HFCUSB_HDLC_PAR 0xfb
#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
#define HFCUSB_F_THRES 0x0c /* threshold register */
#define HFCUSB_FIFO 0x0f /* fifo select register */
#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
#define HFCUSB_MST_MODE0 0x14
#define HFCUSB_MST_MODE1 0x15
#define HFCUSB_P_DATA 0x1f
#define HFCUSB_INC_RES_F 0x0e
#define HFCUSB_STATES 0x30
#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */
/* fifo registers */
#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
#define HFCUSB_B2_TX 2
#define HFCUSB_B2_RX 3
#define HFCUSB_D_TX 4
#define HFCUSB_D_RX 5
#define HFCUSB_PCM_TX 6
#define HFCUSB_PCM_RX 7
/*
* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
*/
#define USB_INT 0
#define USB_BULK 1
#define USB_ISOC 2
#define ISOC_PACKETS_D 8
#define ISOC_PACKETS_B 8
#define ISO_BUFFER_SIZE 128
/* Fifo flow Control for TX ISO */
#define SINK_MAX 68
#define SINK_MIN 48
#define SINK_DMIN 12
#define SINK_DMAX 18
#define BITLINE_INF (-64 * 8)
/* HFC-S USB register access by Control-URSs */
#define write_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), NULL, 0, HFC_CTRL_TIMEOUT)
#define read_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_in_pipe, 1, 0xC0, 0, (b), (c), 1, HFC_CTRL_TIMEOUT)
#define HFC_CTRL_BUFSIZE 32
/* entry and size of output/input control buffer */
typedef struct {
__u8 hfc_reg; /* register number */
__u8 reg_val; /* value to be written (or read) */
int action; /* data for action handler */
} ctrl_buft;
/* Debugging Flags */
#define HFCUSB_DBG_INIT 0x0001
#define HFCUSB_DBG_STATES 0x0002
#define HFCUSB_DBG_DCHANNEL 0x0080
#define HFCUSB_DBG_FIFO_ERR 0x4000
#define HFCUSB_DBG_VERBOSE_USB 0x8000
/*
* URB error codes:
* Used to represent a list of values and their respective symbolic names
*/
struct hfcusb_symbolic_list {
const int num;
const char *name;
};
static struct hfcusb_symbolic_list urb_errlist[] = {
{-ENOMEM, "No memory for allocation of internal structures"},
{-ENOSPC, "The host controller's bandwidth is already consumed"},
{-ENOENT, "URB was canceled by unlink_urb"},
{-EXDEV, "ISO transfer only partially completed"},
{-EAGAIN, "Too match scheduled for the future"},
{-ENXIO, "URB already queued"},
{-EFBIG, "Too much ISO frames requested"},
{-ENOSR, "Buffer error (overrun)"},
{-EPIPE, "Specified endpoint is stalled (device not responding)"},
{-EOVERFLOW, "Babble (bad cable?)"},
{-EPROTO, "Bit-stuff error (bad cable?)"},
{-EILSEQ, "CRC/Timeout"},
{-ETIMEDOUT, "NAK (device does not respond)"},
{-ESHUTDOWN, "Device unplugged"},
{-1, NULL}
};
/*
* device dependent information to support different
* ISDN Ta's using the HFC-S USB chip
*/
/* USB descriptor need to contain one of the following EndPoint combination: */
#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT
#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT
#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT
#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT
#define EP_NUL 1 // Endpoint at this position not allowed
#define EP_NOP 2 // all type of endpoints allowed at this position
#define EP_ISO 3 // Isochron endpoint mandatory at this position
#define EP_BLK 4 // Bulk endpoint mandatory at this position
#define EP_INT 5 // Interrupt endpoint mandatory at this position
/*
* List of all supported endpoint configuration sets, used to find the
* best matching endpoint configuration within a devices' USB descriptor.
* We need at least 3 RX endpoints, and 3 TX endpoints, either
* INT-in and ISO-out, or ISO-in and ISO-out)
* with 4 RX endpoints even E-Channel logging is possible
*/
static int validconf[][19] = {
// INT in, ISO out config
{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
CNF_4INT3ISO, 2, 1},
{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL,
EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
CNF_3INT3ISO, 2, 0},
// ISO in, ISO out config
{EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO,
CNF_4ISO3ISO, 2, 1},
{EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL,
CNF_3ISO3ISO, 2, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // EOL element
};
#ifdef CONFIG_HISAX_DEBUG
// string description of chosen config
static char *conf_str[] = {
"4 Interrupt IN + 3 Isochron OUT",
"3 Interrupt IN + 3 Isochron OUT",
"4 Isochron IN + 3 Isochron OUT",
"3 Isochron IN + 3 Isochron OUT"
};
#endif
typedef struct {
int vendor; // vendor id
int prod_id; // product id
char *vend_name; // vendor string
__u8 led_scheme; // led display scheme
signed short led_bits[8]; // array of 8 possible LED bitmask settings
} vendor_data;
#define LED_OFF 0 // no LED support
#define LED_SCHEME1 1 // LED standard scheme
#define LED_SCHEME2 2 // not used yet...
#define LED_POWER_ON 1
#define LED_POWER_OFF 2
#define LED_S0_ON 3
#define LED_S0_OFF 4
#define LED_B1_ON 5
#define LED_B1_OFF 6
#define LED_B1_DATA 7
#define LED_B2_ON 8
#define LED_B2_OFF 9
#define LED_B2_DATA 10
#define LED_NORMAL 0 // LEDs are normal
#define LED_INVERTED 1 // LEDs are inverted
#endif // __HFC_USB_H__

View File

@ -1,261 +0,0 @@
/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $
*
* low level stuff for hfcs based cards (Teles3c, ACER P10)
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include <linux/isapnp.h>
#include "hisax.h"
#include "hfc_2bds0.h"
#include "isdnl1.h"
static const char *hfcs_revision = "$Revision: 1.10.2.4 $";
static irqreturn_t
hfcs_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, stat;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) &
(stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) {
val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val);
hfc2bds0_interrupt(cs, val);
} else {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat);
}
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
hfcs_Timer(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, hw.hfcD.timer);
cs->hw.hfcD.timer.expires = jiffies + 75;
/* WD RESET */
/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80);
add_timer(&cs->hw.hfcD.timer);
*/
}
static void
release_io_hfcs(struct IsdnCardState *cs)
{
release2bds0(cs);
del_timer(&cs->hw.hfcD.timer);
if (cs->hw.hfcD.addr)
release_region(cs->hw.hfcD.addr, 2);
}
static void
reset_hfcs(struct IsdnCardState *cs)
{
printk(KERN_INFO "HFCS: resetting card\n");
cs->hw.hfcD.cirm = HFCD_RESET;
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_MEM8K;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */
mdelay(10);
cs->hw.hfcD.cirm = 0;
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_MEM8K;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */
mdelay(10);
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_INTB;
else if (cs->typ == ISDN_CTYPE_ACERP10)
cs->hw.hfcD.cirm |= HFCD_INTA;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */
cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE;
cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS |
HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC |
HFCD_INTS_DREC | HFCD_INTS_L1STATE;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */
udelay(10);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */
cs->hw.hfcD.mst_m = HFCD_MASTER;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */
cs->hw.hfcD.sctrl = 0;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
}
static int
hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
int delay;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "HFCS: card_msg %x", mt);
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_hfcs(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_hfcs(cs);
return (0);
case CARD_INIT:
delay = (75 * HZ) / 100 + 1;
mod_timer(&cs->hw.hfcD.timer, jiffies + delay);
spin_lock_irqsave(&cs->lock, flags);
reset_hfcs(cs);
init2bds0(cs);
spin_unlock_irqrestore(&cs->lock, flags);
delay = (80 * HZ) / 1000 + 1;
msleep(80);
spin_lock_irqsave(&cs->lock, flags);
cs->hw.hfcD.ctmt |= HFCD_TIM800;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
#ifdef __ISAPNP__
static struct isapnp_device_id hfc_ids[] = {
{ ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
(unsigned long) "Acer P10" },
{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
(unsigned long) "Billion 2" },
{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
(unsigned long) "Billion 1" },
{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
(unsigned long) "IStar PnP" },
{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
(unsigned long) "Teles 16.3c" },
{ ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
(unsigned long) "Tornado Tipa C" },
{ ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
(unsigned long) "Genius Speed Surfer" },
{ 0, }
};
static struct isapnp_device_id *ipid = &hfc_ids[0];
static struct pnp_card *pnp_c = NULL;
#endif
int setup_hfcs(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, hfcs_revision);
printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d;
while (ipid->card_vendor) {
if ((pnp_c = pnp_find_card(ipid->card_vendor,
ipid->card_device, pnp_c))) {
pnp_d = NULL;
if ((pnp_d = pnp_find_dev(pnp_c,
ipid->vendor, ipid->function, pnp_d))) {
int err;
printk(KERN_INFO "HiSax: %s detected\n",
(char *)ipid->driver_data);
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[0] = pnp_irq(pnp_d, 0);
if (card->para[0] == -1 || !card->para[1]) {
printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
return (0);
}
break;
} else {
printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
}
}
ipid++;
pnp_c = NULL;
}
if (!ipid->card_vendor) {
printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
return (0);
}
}
#endif
cs->hw.hfcD.addr = card->para[1] & 0xfffe;
cs->irq = card->para[0];
cs->hw.hfcD.cip = 0;
cs->hw.hfcD.int_s1 = 0;
cs->hw.hfcD.send = NULL;
cs->bcs[0].hw.hfc.send = NULL;
cs->bcs[1].hw.hfc.send = NULL;
cs->hw.hfcD.dfifosize = 512;
cs->dc.hfcd.ph_state = 0;
cs->hw.hfcD.fifo = 255;
if (cs->typ == ISDN_CTYPE_TELES3C) {
cs->hw.hfcD.bfifosize = 1024 + 512;
} else if (cs->typ == ISDN_CTYPE_ACERP10) {
cs->hw.hfcD.bfifosize = 7 * 1024 + 512;
} else
return (0);
if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
cs->hw.hfcD.addr,
cs->hw.hfcD.addr + 2);
return (0);
}
printk(KERN_INFO
"HFCS: defined at 0x%x IRQ %d HZ %d\n",
cs->hw.hfcD.addr,
cs->irq, HZ);
if (cs->typ == ISDN_CTYPE_TELES3C) {
/* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */
outb(0x00, cs->hw.hfcD.addr);
outb(0x56, cs->hw.hfcD.addr | 1);
} else if (cs->typ == ISDN_CTYPE_ACERP10) {
/* Acer P10 IO ADR is 0x300 */
outb(0x00, cs->hw.hfcD.addr);
outb(0x57, cs->hw.hfcD.addr | 1);
}
set_cs_func(cs);
timer_setup(&cs->hw.hfcD.timer, hfcs_Timer, 0);
cs->cardmsg = &hfcs_card_msg;
cs->irq_func = &hfcs_interrupt;
return (1);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
/* $Id: hisax_cfg.h,v 1.1.2.1 2004/01/24 20:47:23 keil Exp $
* define of the basic HiSax configuration structures
* and pcmcia interface
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#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_PNP 7
#define ISDN_CTYPE_TELESPCMCIA 8
#define ISDN_CTYPE_IX1MICROR2 9
#define ISDN_CTYPE_ELSA_PCMCIA 10
#define ISDN_CTYPE_DIEHLDIVA 11
#define ISDN_CTYPE_ASUSCOM 12
#define ISDN_CTYPE_TELEINT 13
#define ISDN_CTYPE_TELES3C 14
#define ISDN_CTYPE_SEDLBAUER 15
#define ISDN_CTYPE_SPORTSTER 16
#define ISDN_CTYPE_MIC 17
#define ISDN_CTYPE_ELSA_PCI 18
#define ISDN_CTYPE_COMPAQ_ISA 19
#define ISDN_CTYPE_NETJET_S 20
#define ISDN_CTYPE_TELESPCI 21
#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22
#define ISDN_CTYPE_AMD7930 23
#define ISDN_CTYPE_NICCY 24
#define ISDN_CTYPE_S0BOX 25
#define ISDN_CTYPE_A1_PCMCIA 26
#define ISDN_CTYPE_FRITZPCI 27
#define ISDN_CTYPE_SEDLBAUER_FAX 28
#define ISDN_CTYPE_ISURF 29
#define ISDN_CTYPE_ACERP10 30
#define ISDN_CTYPE_HSTSAPHIR 31
#define ISDN_CTYPE_BKM_A4T 32
#define ISDN_CTYPE_SCT_QUADRO 33
#define ISDN_CTYPE_GAZEL 34
#define ISDN_CTYPE_HFC_PCI 35
#define ISDN_CTYPE_W6692 36
#define ISDN_CTYPE_HFC_SX 37
#define ISDN_CTYPE_NETJET_U 38
#define ISDN_CTYPE_HFC_SP_PCMCIA 39
#define ISDN_CTYPE_DYNAMIC 40
#define ISDN_CTYPE_ENTERNOW 41
#define ISDN_CTYPE_COUNT 41
typedef struct IsdnCardState IsdnCardState_t;
typedef struct IsdnCard IsdnCard_t;
struct IsdnCard {
int typ;
int protocol; /* EDSS1, 1TR6 or NI1 */
unsigned long para[4];
IsdnCardState_t *cs;
};
typedef int (*hisax_setup_func_t)(struct IsdnCard *card);
extern void HiSax_closecard(int);
extern int hisax_init_pcmcia(void *, int *, IsdnCard_t *);

View File

@ -1,80 +0,0 @@
/*
* Common debugging macros for use with the hisax driver
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* How to use:
*
* Before including this file, you need to
* #define __debug_variable my_debug
* where my_debug is a variable in your code which
* determines the debug bitmask.
*
* If CONFIG_HISAX_DEBUG is not set, all macros evaluate to nothing
*
*/
#ifndef __HISAX_DEBUG_H__
#define __HISAX_DEBUG_H__
#ifdef CONFIG_HISAX_DEBUG
#define DBG(level, format, arg...) do { \
if (level & __debug_variable) \
printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \
} while (0)
#define DBG_PACKET(level, data, count) \
if (level & __debug_variable) dump_packet(__func__, data, count)
#define DBG_SKB(level, skb) \
if ((level & __debug_variable) && skb) dump_packet(__func__, skb->data, skb->len)
static void __attribute__((unused))
dump_packet(const char *name, const u_char *data, int pkt_len)
{
#define DUMP_HDR_SIZE 20
#define DUMP_TLR_SIZE 8
if (pkt_len) {
int i, len1, len2;
printk(KERN_DEBUG "%s: length=%d,data=", name, pkt_len);
if (pkt_len > DUMP_HDR_SIZE + DUMP_TLR_SIZE) {
len1 = DUMP_HDR_SIZE;
len2 = DUMP_TLR_SIZE;
} else {
len1 = pkt_len > DUMP_HDR_SIZE ? DUMP_HDR_SIZE : pkt_len;
len2 = 0;
}
for (i = 0; i < len1; ++i) {
printk("%.2x", data[i]);
}
if (len2) {
printk("..");
for (i = pkt_len-DUMP_TLR_SIZE; i < pkt_len; ++i) {
printk("%.2x", data[i]);
}
}
printk("\n");
}
#undef DUMP_HDR_SIZE
#undef DUMP_TLR_SIZE
}
#else
#define DBG(level, format, arg...) do {} while (0)
#define DBG_PACKET(level, data, count) do {} while (0)
#define DBG_SKB(level, skb) do {} while (0)
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include "hisax_if.h"
#include "hisax_isac.h"
#include <linux/pci.h>
#define HSCX_BUFMAX 4096
enum {
AVM_FRITZ_PCI,
AVM_FRITZ_PNP,
AVM_FRITZ_PCIV2,
};
struct hdlc_stat_reg {
#ifdef __BIG_ENDIAN
u_char fill;
u_char mode;
u_char xml;
u_char cmd;
#else
u_char cmd;
u_char xml;
u_char mode;
u_char fill;
#endif
} __attribute__((packed));
struct fritz_bcs {
struct hisax_b_if b_if;
struct fritz_adapter *adapter;
int mode;
int channel;
union {
u_int ctrl;
struct hdlc_stat_reg sr;
} ctrl;
u_int stat;
int rcvidx;
int fifo_size;
u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */
int tx_cnt; /* B-Channel transmit counter */
struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
};
struct fritz_adapter {
int type;
spinlock_t hw_lock;
unsigned int io;
unsigned int irq;
struct isac isac;
struct fritz_bcs bcs[2];
u32 (*read_hdlc_status) (struct fritz_adapter *adapter, int nr);
void (*write_ctrl) (struct fritz_bcs *bcs, int which);
};

View File

@ -1,66 +0,0 @@
/*
* Interface between low level (hardware) drivers and
* HiSax protocol stack
*
* Author Kai Germaschewski
* Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef __HISAX_IF_H__
#define __HISAX_IF_H__
#include <linux/skbuff.h>
#define REQUEST 0
#define CONFIRM 1
#define INDICATION 2
#define RESPONSE 3
#define PH_ACTIVATE 0x0100
#define PH_DEACTIVATE 0x0110
#define PH_DATA 0x0120
#define PH_PULL 0x0130
#define PH_DATA_E 0x0140
#define L1_MODE_NULL 0
#define L1_MODE_TRANS 1
#define L1_MODE_HDLC 2
#define L1_MODE_EXTRN 3
#define L1_MODE_HDLC_56K 4
#define L1_MODE_MODEM 7
#define L1_MODE_V32 8
#define L1_MODE_FAX 9
struct hisax_if {
void *priv; // private to driver
void (*l1l2)(struct hisax_if *, int pr, void *arg);
void (*l2l1)(struct hisax_if *, int pr, void *arg);
};
struct hisax_b_if {
struct hisax_if ifc;
// private to hisax
struct BCState *bcs;
};
struct hisax_d_if {
struct hisax_if ifc;
// private to hisax
struct module *owner;
struct IsdnCardState *cs;
struct hisax_b_if *b_if[2];
struct sk_buff_head erq;
unsigned long ph_state;
};
int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],
char *name, int protocol);
void hisax_unregister(struct hisax_d_if *hisax_if);
#endif

View File

@ -1,895 +0,0 @@
/*
* Driver for ISAC-S and ISAC-SX
* ISDN Subscriber Access Controller for Terminals
*
* Author Kai Germaschewski
* Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
* 2001 by Karsten Keil <keil@isdn4linux.de>
*
* based upon Karsten Keil's original isac.c driver
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Wizard Computersysteme GmbH, Bremervoerde and
* SoHaNet Technology GmbH, Berlin
* for supporting the development of this driver
*/
/* TODO:
* specifically handle level vs edge triggered?
*/
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include "hisax_isac.h"
// debugging cruft
#define __debug_variable debug
#include "hisax_debug.h"
#ifdef CONFIG_HISAX_DEBUG
static int debug = 1;
module_param(debug, int, 0);
static char *ISACVer[] = {
"2086/2186 V1.1",
"2085 B1",
"2085 B2",
"2085 V2.3"
};
#endif
MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
MODULE_LICENSE("GPL");
#define DBG_WARN 0x0001
#define DBG_IRQ 0x0002
#define DBG_L1M 0x0004
#define DBG_PR 0x0008
#define DBG_RFIFO 0x0100
#define DBG_RPACKET 0x0200
#define DBG_XFIFO 0x1000
#define DBG_XPACKET 0x2000
// we need to distinguish ISAC-S and ISAC-SX
#define TYPE_ISAC 0x00
#define TYPE_ISACSX 0x01
// registers etc.
#define ISAC_MASK 0x20
#define ISAC_ISTA 0x20
#define ISAC_ISTA_EXI 0x01
#define ISAC_ISTA_SIN 0x02
#define ISAC_ISTA_CISQ 0x04
#define ISAC_ISTA_XPR 0x10
#define ISAC_ISTA_RSC 0x20
#define ISAC_ISTA_RPF 0x40
#define ISAC_ISTA_RME 0x80
#define ISAC_STAR 0x21
#define ISAC_CMDR 0x21
#define ISAC_CMDR_XRES 0x01
#define ISAC_CMDR_XME 0x02
#define ISAC_CMDR_XTF 0x08
#define ISAC_CMDR_RRES 0x40
#define ISAC_CMDR_RMC 0x80
#define ISAC_EXIR 0x24
#define ISAC_EXIR_MOS 0x04
#define ISAC_EXIR_XDU 0x40
#define ISAC_EXIR_XMR 0x80
#define ISAC_ADF2 0x39
#define ISAC_SPCR 0x30
#define ISAC_ADF1 0x38
#define ISAC_CIR0 0x31
#define ISAC_CIX0 0x31
#define ISAC_CIR0_CIC0 0x02
#define ISAC_CIR0_CIC1 0x01
#define ISAC_CIR1 0x33
#define ISAC_CIX1 0x33
#define ISAC_STCR 0x37
#define ISAC_MODE 0x22
#define ISAC_RSTA 0x27
#define ISAC_RSTA_RDO 0x40
#define ISAC_RSTA_CRC 0x20
#define ISAC_RSTA_RAB 0x10
#define ISAC_RBCL 0x25
#define ISAC_RBCH 0x2A
#define ISAC_TIMR 0x23
#define ISAC_SQXR 0x3b
#define ISAC_MOSR 0x3a
#define ISAC_MOCR 0x3a
#define ISAC_MOR0 0x32
#define ISAC_MOX0 0x32
#define ISAC_MOR1 0x34
#define ISAC_MOX1 0x34
#define ISAC_RBCH_XAC 0x80
#define ISAC_CMD_TIM 0x0
#define ISAC_CMD_RES 0x1
#define ISAC_CMD_SSP 0x2
#define ISAC_CMD_SCP 0x3
#define ISAC_CMD_AR8 0x8
#define ISAC_CMD_AR10 0x9
#define ISAC_CMD_ARL 0xa
#define ISAC_CMD_DI 0xf
#define ISACSX_MASK 0x60
#define ISACSX_ISTA 0x60
#define ISACSX_ISTA_ICD 0x01
#define ISACSX_ISTA_CIC 0x10
#define ISACSX_MASKD 0x20
#define ISACSX_ISTAD 0x20
#define ISACSX_ISTAD_XDU 0x04
#define ISACSX_ISTAD_XMR 0x08
#define ISACSX_ISTAD_XPR 0x10
#define ISACSX_ISTAD_RFO 0x20
#define ISACSX_ISTAD_RPF 0x40
#define ISACSX_ISTAD_RME 0x80
#define ISACSX_CMDRD 0x21
#define ISACSX_CMDRD_XRES 0x01
#define ISACSX_CMDRD_XME 0x02
#define ISACSX_CMDRD_XTF 0x08
#define ISACSX_CMDRD_RRES 0x40
#define ISACSX_CMDRD_RMC 0x80
#define ISACSX_MODED 0x22
#define ISACSX_RBCLD 0x26
#define ISACSX_RSTAD 0x28
#define ISACSX_RSTAD_RAB 0x10
#define ISACSX_RSTAD_CRC 0x20
#define ISACSX_RSTAD_RDO 0x40
#define ISACSX_RSTAD_VFR 0x80
#define ISACSX_CIR0 0x2e
#define ISACSX_CIR0_CIC0 0x08
#define ISACSX_CIX0 0x2e
#define ISACSX_TR_CONF0 0x30
#define ISACSX_TR_CONF2 0x32
static struct Fsm l1fsm;
enum {
ST_L1_RESET,
ST_L1_F3_PDOWN,
ST_L1_F3_PUP,
ST_L1_F3_PEND_DEACT,
ST_L1_F4,
ST_L1_F5,
ST_L1_F6,
ST_L1_F7,
ST_L1_F8,
};
#define L1_STATE_COUNT (ST_L1_F8 + 1)
static char *strL1State[] =
{
"ST_L1_RESET",
"ST_L1_F3_PDOWN",
"ST_L1_F3_PUP",
"ST_L1_F3_PEND_DEACT",
"ST_L1_F4",
"ST_L1_F5",
"ST_L1_F6",
"ST_L1_F7",
"ST_L1_F8",
};
enum {
EV_PH_DR, // 0000
EV_PH_RES, // 0001
EV_PH_TMA, // 0010
EV_PH_SLD, // 0011
EV_PH_RSY, // 0100
EV_PH_DR6, // 0101
EV_PH_EI, // 0110
EV_PH_PU, // 0111
EV_PH_AR, // 1000
EV_PH_9, // 1001
EV_PH_ARL, // 1010
EV_PH_CVR, // 1011
EV_PH_AI8, // 1100
EV_PH_AI10, // 1101
EV_PH_AIL, // 1110
EV_PH_DC, // 1111
EV_PH_ACTIVATE_REQ,
EV_PH_DEACTIVATE_REQ,
EV_TIMER3,
};
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
static char *strL1Event[] =
{
"EV_PH_DR", // 0000
"EV_PH_RES", // 0001
"EV_PH_TMA", // 0010
"EV_PH_SLD", // 0011
"EV_PH_RSY", // 0100
"EV_PH_DR6", // 0101
"EV_PH_EI", // 0110
"EV_PH_PU", // 0111
"EV_PH_AR", // 1000
"EV_PH_9", // 1001
"EV_PH_ARL", // 1010
"EV_PH_CVR", // 1011
"EV_PH_AI8", // 1100
"EV_PH_AI10", // 1101
"EV_PH_AIL", // 1110
"EV_PH_DC", // 1111
"EV_PH_ACTIVATE_REQ",
"EV_PH_DEACTIVATE_REQ",
"EV_TIMER3",
};
static inline void D_L1L2(struct isac *isac, int pr, void *arg)
{
struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
DBG(DBG_PR, "pr %#x", pr);
ifc->l1l2(ifc, pr, arg);
}
static void ph_command(struct isac *isac, unsigned int command)
{
DBG(DBG_L1M, "ph_command %#x", command);
switch (isac->type) {
case TYPE_ISAC:
isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
break;
case TYPE_ISACSX:
isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
break;
}
}
// ----------------------------------------------------------------------
static void l1_di(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_RESET);
ph_command(isac, ISAC_CMD_DI);
}
static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_RESET);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
ph_command(isac, ISAC_CMD_DI);
}
static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F3_PDOWN);
}
static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
ph_command(isac, ISAC_CMD_DI);
}
static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
ph_command(isac, ISAC_CMD_DI);
}
static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F4);
}
static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F5);
}
static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F6);
}
static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_F6);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
}
static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmDelTimer(&isac->timer, 0);
FsmChangeState(fi, ST_L1_F7);
ph_command(isac, ISAC_CMD_AR8);
D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
}
static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F8);
}
static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmChangeState(fi, ST_L1_F8);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
}
static void l1_ar8(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
ph_command(isac, ISAC_CMD_AR8);
}
static void l1_timer3(struct FsmInst *fi, int event, void *arg)
{
struct isac *isac = fi->userdata;
ph_command(isac, ISAC_CMD_DI);
D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
}
// state machines according to data sheet PSB 2186 / 3186
static struct FsmNode L1FnList[] __initdata =
{
{ST_L1_RESET, EV_PH_RES, l1_di},
{ST_L1_RESET, EV_PH_EI, l1_di},
{ST_L1_RESET, EV_PH_DC, l1_go_f3pdown},
{ST_L1_RESET, EV_PH_AR, l1_go_f6},
{ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F3_PDOWN, EV_PH_RES, l1_di},
{ST_L1_F3_PDOWN, EV_PH_EI, l1_di},
{ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6},
{ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5},
{ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4},
{ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8},
{ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3},
{ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di},
{ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di},
{ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown},
{ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5},
{ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6},
{ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F4, EV_PH_RES, l1_di},
{ST_L1_F4, EV_PH_EI, l1_di},
{ST_L1_F4, EV_PH_RSY, l1_go_f5},
{ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F4, EV_TIMER3, l1_timer3},
{ST_L1_F4, EV_PH_DC, l1_go_f3pdown},
{ST_L1_F5, EV_PH_RES, l1_di},
{ST_L1_F5, EV_PH_EI, l1_di},
{ST_L1_F5, EV_PH_AR, l1_go_f6},
{ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F5, EV_TIMER3, l1_timer3},
{ST_L1_F5, EV_PH_DR, l1_go_f3pend},
{ST_L1_F5, EV_PH_DC, l1_go_f3pdown},
{ST_L1_F6, EV_PH_RES, l1_di},
{ST_L1_F6, EV_PH_EI, l1_di},
{ST_L1_F6, EV_PH_RSY, l1_go_f8},
{ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F6, EV_PH_DR6, l1_go_f3pend},
{ST_L1_F6, EV_TIMER3, l1_timer3},
{ST_L1_F6, EV_PH_DC, l1_go_f3pdown},
{ST_L1_F7, EV_PH_RES, l1_di_deact_ind},
{ST_L1_F7, EV_PH_EI, l1_di_deact_ind},
{ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind},
{ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind},
{ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind},
{ST_L1_F8, EV_PH_RES, l1_di},
{ST_L1_F8, EV_PH_EI, l1_di},
{ST_L1_F8, EV_PH_AR, l1_go_f6},
{ST_L1_F8, EV_PH_DR, l1_go_f3pend},
{ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind},
{ST_L1_F8, EV_TIMER3, l1_timer3},
{ST_L1_F8, EV_PH_DC, l1_go_f3pdown},
};
static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
char buf[256];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
DBG(DBG_L1M, "%s", buf);
va_end(args);
}
static void isac_version(struct isac *cs)
{
int val;
val = cs->read_isac(cs, ISAC_RBCH);
DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
}
static void isac_empty_fifo(struct isac *isac, int count)
{
// this also works for isacsx, since
// CMDR(D) register works the same
u_char *ptr;
DBG(DBG_IRQ, "count %d", count);
if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
isac->rcvidx = 0;
return;
}
ptr = isac->rcvbuf + isac->rcvidx;
isac->rcvidx += count;
isac->read_isac_fifo(isac, ptr, count);
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
DBG_PACKET(DBG_RFIFO, ptr, count);
}
static void isac_fill_fifo(struct isac *isac)
{
// this also works for isacsx, since
// CMDR(D) register works the same
int count;
unsigned char cmd;
u_char *ptr;
BUG_ON(!isac->tx_skb);
count = isac->tx_skb->len;
BUG_ON(count <= 0);
DBG(DBG_IRQ, "count %d", count);
if (count > 0x20) {
count = 0x20;
cmd = ISAC_CMDR_XTF;
} else {
cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
}
ptr = isac->tx_skb->data;
skb_pull(isac->tx_skb, count);
isac->tx_cnt += count;
DBG_PACKET(DBG_XFIFO, ptr, count);
isac->write_isac_fifo(isac, ptr, count);
isac->write_isac(isac, ISAC_CMDR, cmd);
}
static void isac_retransmit(struct isac *isac)
{
if (!isac->tx_skb) {
DBG(DBG_WARN, "no skb");
return;
}
skb_push(isac->tx_skb, isac->tx_cnt);
isac->tx_cnt = 0;
}
static inline void isac_cisq_interrupt(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISAC_CIR0);
DBG(DBG_IRQ, "CIR0 %#x", val);
if (val & ISAC_CIR0_CIC0) {
DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
}
if (val & ISAC_CIR0_CIC1) {
val = isac->read_isac(isac, ISAC_CIR1);
DBG(DBG_WARN, "ISAC CIR1 %#x", val);
}
}
static inline void isac_rme_interrupt(struct isac *isac)
{
unsigned char val;
int count;
struct sk_buff *skb;
val = isac->read_isac(isac, ISAC_RSTA);
if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB))
!= ISAC_RSTA_CRC) {
DBG(DBG_WARN, "RSTA %#x, dropped", val);
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
goto out;
}
count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
DBG(DBG_IRQ, "RBCL %#x", count);
if (count == 0)
count = 0x20;
isac_empty_fifo(isac, count);
count = isac->rcvidx;
if (count < 1) {
DBG(DBG_WARN, "count %d < 1", count);
goto out;
}
skb = alloc_skb(count, GFP_ATOMIC);
if (!skb) {
DBG(DBG_WARN, "no memory, dropping\n");
goto out;
}
skb_put_data(skb, isac->rcvbuf, count);
DBG_SKB(DBG_RPACKET, skb);
D_L1L2(isac, PH_DATA | INDICATION, skb);
out:
isac->rcvidx = 0;
}
static inline void isac_xpr_interrupt(struct isac *isac)
{
if (!isac->tx_skb)
return;
if (isac->tx_skb->len > 0) {
isac_fill_fifo(isac);
return;
}
dev_kfree_skb_irq(isac->tx_skb);
isac->tx_cnt = 0;
isac->tx_skb = NULL;
D_L1L2(isac, PH_DATA | CONFIRM, NULL);
}
static inline void isac_exi_interrupt(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISAC_EXIR);
DBG(2, "EXIR %#x", val);
if (val & ISAC_EXIR_XMR) {
DBG(DBG_WARN, "ISAC XMR");
isac_retransmit(isac);
}
if (val & ISAC_EXIR_XDU) {
DBG(DBG_WARN, "ISAC XDU");
isac_retransmit(isac);
}
if (val & ISAC_EXIR_MOS) { /* MOS */
DBG(DBG_WARN, "MOS");
val = isac->read_isac(isac, ISAC_MOSR);
DBG(2, "ISAC MOSR %#x", val);
}
}
void isac_irq(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISAC_ISTA);
DBG(DBG_IRQ, "ISTA %#x", val);
if (val & ISAC_ISTA_EXI) {
DBG(DBG_IRQ, "EXI");
isac_exi_interrupt(isac);
}
if (val & ISAC_ISTA_XPR) {
DBG(DBG_IRQ, "XPR");
isac_xpr_interrupt(isac);
}
if (val & ISAC_ISTA_RME) {
DBG(DBG_IRQ, "RME");
isac_rme_interrupt(isac);
}
if (val & ISAC_ISTA_RPF) {
DBG(DBG_IRQ, "RPF");
isac_empty_fifo(isac, 0x20);
}
if (val & ISAC_ISTA_CISQ) {
DBG(DBG_IRQ, "CISQ");
isac_cisq_interrupt(isac);
}
if (val & ISAC_ISTA_RSC) {
DBG(DBG_WARN, "RSC");
}
if (val & ISAC_ISTA_SIN) {
DBG(DBG_WARN, "SIN");
}
isac->write_isac(isac, ISAC_MASK, 0xff);
isac->write_isac(isac, ISAC_MASK, 0x00);
}
// ======================================================================
static inline void isacsx_cic_interrupt(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISACSX_CIR0);
DBG(DBG_IRQ, "CIR0 %#x", val);
if (val & ISACSX_CIR0_CIC0) {
DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
FsmEvent(&isac->l1m, val >> 4, NULL);
}
}
static inline void isacsx_rme_interrupt(struct isac *isac)
{
int count;
struct sk_buff *skb;
unsigned char val;
val = isac->read_isac(isac, ISACSX_RSTAD);
if ((val & (ISACSX_RSTAD_VFR |
ISACSX_RSTAD_RDO |
ISACSX_RSTAD_CRC |
ISACSX_RSTAD_RAB))
!= (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
DBG(DBG_WARN, "RSTAD %#x, dropped", val);
isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
goto out;
}
count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
DBG(DBG_IRQ, "RBCLD %#x", count);
if (count == 0)
count = 0x20;
isac_empty_fifo(isac, count);
// strip trailing status byte
count = isac->rcvidx - 1;
if (count < 1) {
DBG(DBG_WARN, "count %d < 1", count);
goto out;
}
skb = dev_alloc_skb(count);
if (!skb) {
DBG(DBG_WARN, "no memory, dropping");
goto out;
}
skb_put_data(skb, isac->rcvbuf, count);
DBG_SKB(DBG_RPACKET, skb);
D_L1L2(isac, PH_DATA | INDICATION, skb);
out:
isac->rcvidx = 0;
}
static inline void isacsx_xpr_interrupt(struct isac *isac)
{
if (!isac->tx_skb)
return;
if (isac->tx_skb->len > 0) {
isac_fill_fifo(isac);
return;
}
dev_kfree_skb_irq(isac->tx_skb);
isac->tx_skb = NULL;
isac->tx_cnt = 0;
D_L1L2(isac, PH_DATA | CONFIRM, NULL);
}
static inline void isacsx_icd_interrupt(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISACSX_ISTAD);
DBG(DBG_IRQ, "ISTAD %#x", val);
if (val & ISACSX_ISTAD_XDU) {
DBG(DBG_WARN, "ISTAD XDU");
isac_retransmit(isac);
}
if (val & ISACSX_ISTAD_XMR) {
DBG(DBG_WARN, "ISTAD XMR");
isac_retransmit(isac);
}
if (val & ISACSX_ISTAD_XPR) {
DBG(DBG_IRQ, "ISTAD XPR");
isacsx_xpr_interrupt(isac);
}
if (val & ISACSX_ISTAD_RFO) {
DBG(DBG_WARN, "ISTAD RFO");
isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
}
if (val & ISACSX_ISTAD_RME) {
DBG(DBG_IRQ, "ISTAD RME");
isacsx_rme_interrupt(isac);
}
if (val & ISACSX_ISTAD_RPF) {
DBG(DBG_IRQ, "ISTAD RPF");
isac_empty_fifo(isac, 0x20);
}
}
void isacsx_irq(struct isac *isac)
{
unsigned char val;
val = isac->read_isac(isac, ISACSX_ISTA);
DBG(DBG_IRQ, "ISTA %#x", val);
if (val & ISACSX_ISTA_ICD)
isacsx_icd_interrupt(isac);
if (val & ISACSX_ISTA_CIC)
isacsx_cic_interrupt(isac);
}
void isac_init(struct isac *isac)
{
isac->tx_skb = NULL;
isac->l1m.fsm = &l1fsm;
isac->l1m.state = ST_L1_RESET;
#ifdef CONFIG_HISAX_DEBUG
isac->l1m.debug = 1;
#else
isac->l1m.debug = 0;
#endif
isac->l1m.userdata = isac;
isac->l1m.printdebug = l1m_debug;
FsmInitTimer(&isac->l1m, &isac->timer);
}
void isac_setup(struct isac *isac)
{
int val, eval;
isac->type = TYPE_ISAC;
isac_version(isac);
ph_command(isac, ISAC_CMD_RES);
isac->write_isac(isac, ISAC_MASK, 0xff);
isac->mocr = 0xaa;
if (test_bit(ISAC_IOM1, &isac->flags)) {
/* IOM 1 Mode */
isac->write_isac(isac, ISAC_ADF2, 0x0);
isac->write_isac(isac, ISAC_SPCR, 0xa);
isac->write_isac(isac, ISAC_ADF1, 0x2);
isac->write_isac(isac, ISAC_STCR, 0x70);
isac->write_isac(isac, ISAC_MODE, 0xc9);
} else {
/* IOM 2 Mode */
if (!isac->adf2)
isac->adf2 = 0x80;
isac->write_isac(isac, ISAC_ADF2, isac->adf2);
isac->write_isac(isac, ISAC_SQXR, 0x2f);
isac->write_isac(isac, ISAC_SPCR, 0x00);
isac->write_isac(isac, ISAC_STCR, 0x70);
isac->write_isac(isac, ISAC_MODE, 0xc9);
isac->write_isac(isac, ISAC_TIMR, 0x00);
isac->write_isac(isac, ISAC_ADF1, 0x00);
}
val = isac->read_isac(isac, ISAC_STAR);
DBG(2, "ISAC STAR %x", val);
val = isac->read_isac(isac, ISAC_MODE);
DBG(2, "ISAC MODE %x", val);
val = isac->read_isac(isac, ISAC_ADF2);
DBG(2, "ISAC ADF2 %x", val);
val = isac->read_isac(isac, ISAC_ISTA);
DBG(2, "ISAC ISTA %x", val);
if (val & 0x01) {
eval = isac->read_isac(isac, ISAC_EXIR);
DBG(2, "ISAC EXIR %x", eval);
}
val = isac->read_isac(isac, ISAC_CIR0);
DBG(2, "ISAC CIR0 %x", val);
FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
isac->write_isac(isac, ISAC_MASK, 0x0);
// RESET Receiver and Transmitter
isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
}
void isacsx_setup(struct isac *isac)
{
isac->type = TYPE_ISACSX;
// clear LDD
isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
// enable transmitter
isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
// transparent mode 0, RAC, stop/go
isac->write_isac(isac, ISACSX_MODED, 0xc9);
// all HDLC IRQ unmasked
isac->write_isac(isac, ISACSX_MASKD, 0x03);
// unmask ICD, CID IRQs
isac->write_isac(isac, ISACSX_MASK,
~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
}
void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
{
struct isac *isac = hisax_d_if->priv;
struct sk_buff *skb = arg;
DBG(DBG_PR, "pr %#x", pr);
switch (pr) {
case PH_ACTIVATE | REQUEST:
FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
break;
case PH_DEACTIVATE | REQUEST:
FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
break;
case PH_DATA | REQUEST:
DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
DBG_SKB(DBG_XPACKET, skb);
if (isac->l1m.state != ST_L1_F7) {
DBG(1, "L1 wrong state %d\n", isac->l1m.state);
dev_kfree_skb(skb);
break;
}
BUG_ON(isac->tx_skb);
isac->tx_skb = skb;
isac_fill_fifo(isac);
break;
}
}
static int __init hisax_isac_init(void)
{
printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
l1fsm.state_count = L1_STATE_COUNT;
l1fsm.event_count = L1_EVENT_COUNT;
l1fsm.strState = strL1State;
l1fsm.strEvent = strL1Event;
return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
}
static void __exit hisax_isac_exit(void)
{
FsmFree(&l1fsm);
}
EXPORT_SYMBOL(isac_init);
EXPORT_SYMBOL(isac_d_l2l1);
EXPORT_SYMBOL(isacsx_setup);
EXPORT_SYMBOL(isacsx_irq);
EXPORT_SYMBOL(isac_setup);
EXPORT_SYMBOL(isac_irq);
module_init(hisax_isac_init);
module_exit(hisax_isac_exit);

View File

@ -1,46 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __HISAX_ISAC_H__
#define __HISAX_ISAC_H__
#include <linux/kernel.h>
#include "fsm.h"
#include "hisax_if.h"
#define TIMER3_VALUE 7000
#define MAX_DFRAME_LEN_L1 300
#define ISAC_IOM1 0
struct isac {
void *priv;
u_long flags;
struct hisax_d_if hisax_d_if;
struct FsmInst l1m;
struct FsmTimer timer;
u_char mocr;
u_char adf2;
int type;
u_char rcvbuf[MAX_DFRAME_LEN_L1];
int rcvidx;
struct sk_buff *tx_skb;
int tx_cnt;
u_char (*read_isac) (struct isac *, u_char);
void (*write_isac) (struct isac *, u_char, u_char);
void (*read_isac_fifo) (struct isac *, u_char *, int);
void (*write_isac_fifo)(struct isac *, u_char *, int);
};
void isac_init(struct isac *isac);
void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
void isac_setup(struct isac *isac);
void isac_irq(struct isac *isac);
void isacsx_setup(struct isac *isac);
void isacsx_irq(struct isac *isac);
#endif

View File

@ -1,277 +0,0 @@
/* $Id: hscx.c,v 1.24.2.4 2004/01/24 20:47:23 keil Exp $
*
* HSCX specific routines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "hscx.h"
#include "isac.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
static char *HSCXVer[] =
{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
"?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
int
HscxVersion(struct IsdnCardState *cs, char *s)
{
int verA, verB;
verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf;
verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf;
printk(KERN_INFO "%s HSCX version A: %s B: %s\n", s,
HSCXVer[verA], HSCXVer[verB]);
if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf))
return (1);
else
return (0);
}
void
modehscx(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
int hscx = bcs->hw.hscx.hscx;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "hscx %c mode %d ichan %d",
'A' + hscx, mode, bc);
bcs->mode = mode;
bcs->channel = bc;
cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF);
cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF);
cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF);
cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0);
cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0);
cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85);
cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30);
cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7);
cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7);
/* Switch IOM 1 SSI */
if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0))
bc = 1 - bc;
if (bc == 0) {
cs->BC_Write_Reg(cs, hscx, HSCX_TSAX,
test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
cs->BC_Write_Reg(cs, hscx, HSCX_TSAR,
test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0);
} else {
cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1);
cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1);
}
switch (mode) {
case (L1_MODE_NULL):
cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f);
cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f);
cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84);
break;
case (L1_MODE_TRANS):
cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4);
break;
case (L1_MODE_HDLC):
cs->BC_Write_Reg(cs, hscx, HSCX_CCR1,
test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d);
cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c);
break;
}
if (mode)
cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41);
cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00);
}
void
hscx_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
u_long flags;
struct sk_buff *skb = arg;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hscx.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
} else {
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->hw.hscx.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
modehscx(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
modehscx(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
static void
close_hscxstate(struct BCState *bcs)
{
modehscx(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
kfree(bcs->blog);
bcs->blog = NULL;
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
int
open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for hscx.rcvbuf\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
return (1);
}
if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for bcs->blog\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
return (2);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
return (0);
}
static int
setstack_hscx(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_hscxstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = hscx_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
void
clear_pending_hscx_ints(struct IsdnCardState *cs)
{
int val, eval;
val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA);
debugl1(cs, "HSCX B ISTA %x", val);
if (val & 0x01) {
eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR);
debugl1(cs, "HSCX B EXIR %x", eval);
}
if (val & 0x02) {
eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR);
debugl1(cs, "HSCX A EXIR %x", eval);
}
val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA);
debugl1(cs, "HSCX A ISTA %x", val);
val = cs->BC_Read_Reg(cs, 1, HSCX_STAR);
debugl1(cs, "HSCX B STAR %x", val);
val = cs->BC_Read_Reg(cs, 0, HSCX_STAR);
debugl1(cs, "HSCX A STAR %x", val);
/* disable all IRQ */
cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF);
cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
}
void
inithscx(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_hscx;
cs->bcs[1].BC_SetStack = setstack_hscx;
cs->bcs[0].BC_Close = close_hscxstate;
cs->bcs[1].BC_Close = close_hscxstate;
cs->bcs[0].hw.hscx.hscx = 0;
cs->bcs[1].hw.hscx.hscx = 1;
cs->bcs[0].hw.hscx.tsaxr0 = 0x2f;
cs->bcs[0].hw.hscx.tsaxr1 = 3;
cs->bcs[1].hw.hscx.tsaxr0 = 0x2f;
cs->bcs[1].hw.hscx.tsaxr1 = 3;
modehscx(cs->bcs, 0, 0);
modehscx(cs->bcs + 1, 0, 0);
}
void
inithscxisac(struct IsdnCardState *cs, int part)
{
if (part & 1) {
clear_pending_isac_ints(cs);
clear_pending_hscx_ints(cs);
initisac(cs);
inithscx(cs);
}
if (part & 2) {
/* Reenable all IRQ */
cs->writeisac(cs, ISAC_MASK, 0);
cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0);
cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0);
/* RESET Receiver and Transmitter */
cs->writeisac(cs, ISAC_CMDR, 0x41);
}
}

View File

@ -1,41 +0,0 @@
/* $Id: hscx.h,v 1.8.2.2 2004/01/12 22:52:26 keil Exp $
*
* HSCX specific defines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#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
extern int HscxVersion(struct IsdnCardState *cs, char *s);
extern void modehscx(struct BCState *bcs, int mode, int bc);
extern void clear_pending_hscx_ints(struct IsdnCardState *cs);
extern void inithscx(struct IsdnCardState *cs);
extern void inithscxisac(struct IsdnCardState *cs, int part);

View File

@ -1,294 +0,0 @@
/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $
*
* low level b-channel stuff for Siemens HSCX
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* This is an include file for fast inline IRQ stuff
*
*/
static inline void
waitforCEC(struct IsdnCardState *cs, int hscx)
{
int to = 50;
while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "HiSax: waitforCEC timeout\n");
}
static inline void
waitforXFW(struct IsdnCardState *cs, int hscx)
{
int to = 50;
while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "HiSax: waitforXFW timeout\n");
}
static inline void
WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
{
waitforCEC(cs, hscx);
WRITEHSCX(cs, hscx, HSCX_CMDR, data);
}
static void
hscx_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct IsdnCardState *cs = bcs->cs;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hscx_empty_fifo");
if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "hscx_empty_fifo: incoming packet too large");
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
bcs->hw.hscx.rcvidx = 0;
return;
}
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "hscx_empty_fifo %c cnt %d",
bcs->hw.hscx.hscx ? 'B' : 'A', count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
static void
hscx_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int more, count;
int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
u_char *ptr;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "hscx_fill_fifo");
if (!bcs->tx_skb)
return;
if (bcs->tx_skb->len <= 0)
return;
more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
if (bcs->tx_skb->len > fifo_size) {
more = !0;
count = fifo_size;
} else
count = bcs->tx_skb->len;
waitforXFW(cs, bcs->hw.hscx.hscx);
ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hscx.count += count;
WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "hscx_fill_fifo %c cnt %d",
bcs->hw.hscx.hscx ? 'B' : 'A', count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
static void
hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
{
u_char r;
struct BCState *bcs = cs->bcs + hscx;
struct sk_buff *skb;
int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32;
int count;
if (!test_bit(BC_FLG_INIT, &bcs->Flag))
return;
if (val & 0x80) { /* RME */
r = READHSCX(cs, hscx, HSCX_RSTA);
if ((r & 0xf0) != 0xa0) {
if (!(r & 0x80)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX invalid frame");
#ifdef ERROR_STATISTIC
bcs->err_inv++;
#endif
}
if ((r & 0x40) && bcs->mode) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX RDO mode=%d",
bcs->mode);
#ifdef ERROR_STATISTIC
bcs->err_rdo++;
#endif
}
if (!(r & 0x20)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX CRC error");
#ifdef ERROR_STATISTIC
bcs->err_crc++;
#endif
}
WriteHSCXCMDR(cs, hscx, 0x80);
} else {
count = READHSCX(cs, hscx, HSCX_RBCL) & (
test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f);
if (count == 0)
count = fifo_size;
hscx_empty_fifo(bcs, count);
if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
if (cs->debug & L1_DEB_HSCX_FIFO)
debugl1(cs, "HX Frame %d", count);
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HSCX: receive out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
count);
skb_queue_tail(&bcs->rqueue, skb);
}
}
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
if (val & 0x40) { /* RPF */
hscx_empty_fifo(bcs, fifo_size);
if (bcs->mode == L1_MODE_TRANS) {
/* receive audio data */
if (!(skb = dev_alloc_skb(fifo_size)))
printk(KERN_WARNING "HiSax: receive out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
fifo_size);
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
}
if (val & 0x10) { /* XPR */
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
hscx_fill_fifo(bcs);
return;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hscx.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hscx.count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
hscx_fill_fifo(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
}
static void
hscx_int_main(struct IsdnCardState *cs, u_char val)
{
u_char exval;
struct BCState *bcs;
if (val & 0x01) {
bcs = cs->bcs + 1;
exval = READHSCX(cs, 1, HSCX_EXIR);
if (exval & 0x40) {
if (bcs->mode == 1)
hscx_fill_fifo(bcs);
else {
#ifdef ERROR_STATISTIC
bcs->err_tx++;
#endif
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
bcs->tx_cnt += bcs->hw.hscx.count;
bcs->hw.hscx.count = 0;
}
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
}
} else if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX B EXIR %x", exval);
}
if (val & 0xf8) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX B interrupt %x", val);
hscx_interrupt(cs, val, 1);
}
if (val & 0x02) {
bcs = cs->bcs;
exval = READHSCX(cs, 0, HSCX_EXIR);
if (exval & 0x40) {
if (bcs->mode == L1_MODE_TRANS)
hscx_fill_fifo(bcs);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
#ifdef ERROR_STATISTIC
bcs->err_tx++;
#endif
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
bcs->tx_cnt += bcs->hw.hscx.count;
bcs->hw.hscx.count = 0;
}
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
}
} else if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX A EXIR %x", exval);
}
if (val & 0x04) {
exval = READHSCX(cs, 0, HSCX_ISTA);
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX A interrupt %x", exval);
hscx_interrupt(cs, exval, 0);
}
}

View File

@ -1,680 +0,0 @@
/* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $
*
* ICC specific routines
*
* Author Matt Henderson & Guy Ellis
* Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* 1999.6.25 Initial implementation of routines for Siemens ISDN
* Communication Controller PEB 2070 based on the ISAC routines
* written by Karsten Keil.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "icc.h"
// #include "arcofi.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
#define DBUSY_TIMER_VALUE 80
#define ARCOFI_USE 0
static char *ICCVer[] =
{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
void
ICCVersion(struct IsdnCardState *cs, char *s)
{
int val;
val = cs->readisac(cs, ICC_RBCH);
printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]);
}
static void
ph_command(struct IsdnCardState *cs, unsigned int command)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_command %x", command);
cs->writeisac(cs, ICC_CIX0, (command << 2) | 3);
}
static void
icc_new_ph(struct IsdnCardState *cs)
{
switch (cs->dc.icc.ph_state) {
case (ICC_IND_EI1):
ph_command(cs, ICC_CMD_DI);
l1_msg(cs, HW_RESET | INDICATION, NULL);
break;
case (ICC_IND_DC):
l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
break;
case (ICC_IND_DR):
l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
break;
case (ICC_IND_PU):
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
break;
case (ICC_IND_FJ):
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
break;
case (ICC_IND_AR):
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
break;
case (ICC_IND_AI):
l1_msg(cs, HW_INFO4 | INDICATION, NULL);
break;
default:
break;
}
}
static void
icc_bh(struct work_struct *work)
{
struct IsdnCardState *cs =
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
icc_new_ph(cs);
if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
DChannel_proc_rcv(cs);
if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
DChannel_proc_xmt(cs);
#if ARCOFI_USE
if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
return;
if (test_and_clear_bit(D_RX_MON1, &cs->event))
arcofi_fsm(cs, ARCOFI_RX_END, NULL);
if (test_and_clear_bit(D_TX_MON1, &cs->event))
arcofi_fsm(cs, ARCOFI_TX_END, NULL);
#endif
}
static void
icc_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "icc_empty_fifo");
if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "icc_empty_fifo overrun %d",
cs->rcvidx + count);
cs->writeisac(cs, ICC_CMDR, 0x80);
cs->rcvidx = 0;
return;
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, ICC_CMDR, 0x80);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "icc_empty_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
static void
icc_fill_fifo(struct IsdnCardState *cs)
{
int count, more;
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "icc_fill_fifo");
if (!cs->tx_skb)
return;
count = cs->tx_skb->len;
if (count <= 0)
return;
more = 0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
cs->writeisacfifo(cs, ptr, count);
cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "icc_fill_fifo dbusytimer running");
del_timer(&cs->dbusytimer);
}
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "icc_fill_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
void
icc_interrupt(struct IsdnCardState *cs, u_char val)
{
u_char exval, v1;
struct sk_buff *skb;
unsigned int count;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ICC interrupt %x", val);
if (val & 0x80) { /* RME */
exval = cs->readisac(cs, ICC_RSTA);
if ((exval & 0x70) != 0x20) {
if (exval & 0x40) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC RDO");
#ifdef ERROR_STATISTIC
cs->err_rx++;
#endif
}
if (!(exval & 0x20)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC CRC error");
#ifdef ERROR_STATISTIC
cs->err_crc++;
#endif
}
cs->writeisac(cs, ICC_CMDR, 0x80);
} else {
count = cs->readisac(cs, ICC_RBCL) & 0x1f;
if (count == 0)
count = 32;
icc_empty_fifo(cs, count);
if ((count = cs->rcvidx) > 0) {
cs->rcvidx = 0;
if (!(skb = alloc_skb(count, GFP_ATOMIC)))
printk(KERN_WARNING "HiSax: D receive out of memory\n");
else {
skb_put_data(skb, cs->rcvbuf, count);
skb_queue_tail(&cs->rq, skb);
}
}
}
cs->rcvidx = 0;
schedule_event(cs, D_RCVBUFREADY);
}
if (val & 0x40) { /* RPF */
icc_empty_fifo(cs, 32);
}
if (val & 0x20) { /* RSC */
/* never */
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC RSC interrupt");
}
if (val & 0x10) { /* XPR */
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->tx_skb->len) {
icc_fill_fifo(cs);
goto afterXPR;
} else {
dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
}
if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
cs->tx_cnt = 0;
icc_fill_fifo(cs);
} else
schedule_event(cs, D_XMTBUFREADY);
}
afterXPR:
if (val & 0x04) { /* CISQ */
exval = cs->readisac(cs, ICC_CIR0);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ICC CIR0 %02X", exval);
if (exval & 2) {
cs->dc.icc.ph_state = (exval >> 2) & 0xf;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
schedule_event(cs, D_L1STATECHANGE);
}
if (exval & 1) {
exval = cs->readisac(cs, ICC_CIR1);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ICC CIR1 %02X", exval);
}
}
if (val & 0x02) { /* SIN */
/* never */
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC SIN interrupt");
}
if (val & 0x01) { /* EXI */
exval = cs->readisac(cs, ICC_EXIR);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC EXIR %02x", exval);
if (exval & 0x80) { /* XMR */
debugl1(cs, "ICC XMR");
printk(KERN_WARNING "HiSax: ICC XMR\n");
}
if (exval & 0x40) { /* XDU */
debugl1(cs, "ICC XDU");
printk(KERN_WARNING "HiSax: ICC XDU\n");
#ifdef ERROR_STATISTIC
cs->err_tx++;
#endif
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) { /* Restart frame */
skb_push(cs->tx_skb, cs->tx_cnt);
cs->tx_cnt = 0;
icc_fill_fifo(cs);
} else {
printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
debugl1(cs, "ICC XDU no skb");
}
}
if (exval & 0x04) { /* MOS */
v1 = cs->readisac(cs, ICC_MOSR);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC MOSR %02x", v1);
#if ARCOFI_USE
if (v1 & 0x08) {
if (!cs->dc.icc.mon_rx) {
if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC MON RX out of memory!");
cs->dc.icc.mocr &= 0xf0;
cs->dc.icc.mocr |= 0x0a;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
goto afterMONR0;
} else
cs->dc.icc.mon_rxp = 0;
}
if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
cs->dc.icc.mocr &= 0xf0;
cs->dc.icc.mocr |= 0x0a;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mon_rxp = 0;
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC MON RX overflow!");
goto afterMONR0;
}
cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]);
if (cs->dc.icc.mon_rxp == 1) {
cs->dc.icc.mocr |= 0x04;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
}
}
afterMONR0:
if (v1 & 0x80) {
if (!cs->dc.icc.mon_rx) {
if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC MON RX out of memory!");
cs->dc.icc.mocr &= 0x0f;
cs->dc.icc.mocr |= 0xa0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
goto afterMONR1;
} else
cs->dc.icc.mon_rxp = 0;
}
if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
cs->dc.icc.mocr &= 0x0f;
cs->dc.icc.mocr |= 0xa0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mon_rxp = 0;
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ICC MON RX overflow!");
goto afterMONR1;
}
cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]);
cs->dc.icc.mocr |= 0x40;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
}
afterMONR1:
if (v1 & 0x04) {
cs->dc.icc.mocr &= 0xf0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mocr |= 0x0a;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
schedule_event(cs, D_RX_MON0);
}
if (v1 & 0x40) {
cs->dc.icc.mocr &= 0x0f;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mocr |= 0xa0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
schedule_event(cs, D_RX_MON1);
}
if (v1 & 0x02) {
if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
!(v1 & 0x08))) {
cs->dc.icc.mocr &= 0xf0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mocr |= 0x0a;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
if (cs->dc.icc.mon_txc &&
(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
schedule_event(cs, D_TX_MON0);
goto AfterMOX0;
}
if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
schedule_event(cs, D_TX_MON0);
goto AfterMOX0;
}
cs->writeisac(cs, ICC_MOX0,
cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
}
AfterMOX0:
if (v1 & 0x20) {
if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc &&
(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) &&
!(v1 & 0x80))) {
cs->dc.icc.mocr &= 0x0f;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
cs->dc.icc.mocr |= 0xa0;
cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
if (cs->dc.icc.mon_txc &&
(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
schedule_event(cs, D_TX_MON1);
goto AfterMOX1;
}
if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
schedule_event(cs, D_TX_MON1);
goto AfterMOX1;
}
cs->writeisac(cs, ICC_MOX1,
cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]);
}
AfterMOX1: ;
#endif
}
}
}
static void
ICC_l1hw(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
u_long flags;
int val;
switch (pr) {
case (PH_DATA | REQUEST):
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
skb_queue_tail(&cs->sq, skb);
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA Queued", 0);
#endif
} else {
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA", 0);
#endif
icc_fill_fifo(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
skb_queue_tail(&cs->sq, skb);
spin_unlock_irqrestore(&cs->lock, flags);
break;
}
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
#endif
icc_fill_fifo(cs);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | REQUEST):
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
debugl1(cs, "-> PH_REQUEST_PULL");
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
(cs->dc.icc.ph_state == ICC_IND_DR))
ph_command(cs, ICC_CMD_DI);
else
ph_command(cs, ICC_CMD_RES);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_ENABLE | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ICC_CMD_DI);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_INFO1 | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ICC_CMD_AR);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_INFO3 | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ICC_CMD_AI);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_TESTLOOP | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
val = 0;
if (1 & (long) arg)
val |= 0x0c;
if (2 & (long) arg)
val |= 0x3;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
if (!val) {
cs->writeisac(cs, ICC_SPCR, 0xa);
cs->writeisac(cs, ICC_ADF1, 0x2);
} else {
cs->writeisac(cs, ICC_SPCR, val);
cs->writeisac(cs, ICC_ADF1, 0xa);
}
} else {
/* IOM 2 Mode */
cs->writeisac(cs, ICC_SPCR, val);
if (val)
cs->writeisac(cs, ICC_ADF1, 0x8);
else
cs->writeisac(cs, ICC_ADF1, 0x0);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_DEACTIVATE | RESPONSE):
skb_queue_purge(&cs->rq);
skb_queue_purge(&cs->sq);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
break;
default:
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "icc_l1hw unknown %04x", pr);
break;
}
}
static void
setstack_icc(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = ICC_l1hw;
}
static void
DC_Close_icc(struct IsdnCardState *cs) {
kfree(cs->dc.icc.mon_rx);
cs->dc.icc.mon_rx = NULL;
kfree(cs->dc.icc.mon_tx);
cs->dc.icc.mon_tx = NULL;
}
static void
dbusy_timer_handler(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
struct PStack *stptr;
int rbch, star;
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
rbch = cs->readisac(cs, ICC_RBCH);
star = cs->readisac(cs, ICC_STAR);
if (cs->debug)
debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
rbch, star);
if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
/* discard frame; reset transceiver */
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
} else {
printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n");
debugl1(cs, "D-Channel Busy no skb");
}
cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
cs->irq_func(cs->irq, cs);
}
}
}
void
initicc(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_icc;
cs->DC_Close = DC_Close_icc;
cs->dc.icc.mon_tx = NULL;
cs->dc.icc.mon_rx = NULL;
cs->writeisac(cs, ICC_MASK, 0xff);
cs->dc.icc.mocr = 0xaa;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
cs->writeisac(cs, ICC_ADF2, 0x0);
cs->writeisac(cs, ICC_SPCR, 0xa);
cs->writeisac(cs, ICC_ADF1, 0x2);
cs->writeisac(cs, ICC_STCR, 0x70);
cs->writeisac(cs, ICC_MODE, 0xc9);
} else {
/* IOM 2 Mode */
if (!cs->dc.icc.adf2)
cs->dc.icc.adf2 = 0x80;
cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
cs->writeisac(cs, ICC_SQXR, 0xa0);
cs->writeisac(cs, ICC_SPCR, 0x20);
cs->writeisac(cs, ICC_STCR, 0x70);
cs->writeisac(cs, ICC_MODE, 0xca);
cs->writeisac(cs, ICC_TIMR, 0x00);
cs->writeisac(cs, ICC_ADF1, 0x20);
}
ph_command(cs, ICC_CMD_RES);
cs->writeisac(cs, ICC_MASK, 0x0);
ph_command(cs, ICC_CMD_DI);
}
void
clear_pending_icc_ints(struct IsdnCardState *cs)
{
int val, eval;
val = cs->readisac(cs, ICC_STAR);
debugl1(cs, "ICC STAR %x", val);
val = cs->readisac(cs, ICC_MODE);
debugl1(cs, "ICC MODE %x", val);
val = cs->readisac(cs, ICC_ADF2);
debugl1(cs, "ICC ADF2 %x", val);
val = cs->readisac(cs, ICC_ISTA);
debugl1(cs, "ICC ISTA %x", val);
if (val & 0x01) {
eval = cs->readisac(cs, ICC_EXIR);
debugl1(cs, "ICC EXIR %x", eval);
}
val = cs->readisac(cs, ICC_CIR0);
debugl1(cs, "ICC CIR0 %x", val);
cs->dc.icc.ph_state = (val >> 2) & 0xf;
schedule_event(cs, D_L1STATECHANGE);
/* Disable all IRQ */
cs->writeisac(cs, ICC_MASK, 0xFF);
}
void setup_icc(struct IsdnCardState *cs)
{
INIT_WORK(&cs->tqueue, icc_bh);
timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
}

View File

@ -1,72 +0,0 @@
/* $Id: icc.h,v 1.4.2.2 2004/01/12 22:52:26 keil Exp $
*
* ICC specific routines
*
* Author Matt Henderson & Guy Ellis
* Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* 1999.7.14 Initial implementation of routines for Siemens ISDN
* Communication Controller PEB 2070 based on the ISAC routines
* written by Karsten Keil.
*/
/* All Registers original Siemens Spec */
#define ICC_MASK 0x20
#define ICC_ISTA 0x20
#define ICC_STAR 0x21
#define ICC_CMDR 0x21
#define ICC_EXIR 0x24
#define ICC_ADF2 0x39
#define ICC_SPCR 0x30
#define ICC_ADF1 0x38
#define ICC_CIR0 0x31
#define ICC_CIX0 0x31
#define ICC_CIR1 0x33
#define ICC_CIX1 0x33
#define ICC_STCR 0x37
#define ICC_MODE 0x22
#define ICC_RSTA 0x27
#define ICC_RBCL 0x25
#define ICC_RBCH 0x2A
#define ICC_TIMR 0x23
#define ICC_SQXR 0x3b
#define ICC_MOSR 0x3a
#define ICC_MOCR 0x3a
#define ICC_MOR0 0x32
#define ICC_MOX0 0x32
#define ICC_MOR1 0x34
#define ICC_MOX1 0x34
#define ICC_RBCH_XAC 0x80
#define ICC_CMD_TIM 0x0
#define ICC_CMD_RES 0x1
#define ICC_CMD_DU 0x3
#define ICC_CMD_EI1 0x4
#define ICC_CMD_SSP 0x5
#define ICC_CMD_DT 0x6
#define ICC_CMD_AR 0x8
#define ICC_CMD_ARL 0xA
#define ICC_CMD_AI 0xC
#define ICC_CMD_DI 0xF
#define ICC_IND_DR 0x0
#define ICC_IND_FJ 0x2
#define ICC_IND_EI1 0x4
#define ICC_IND_INT 0x6
#define ICC_IND_PU 0x7
#define ICC_IND_AR 0x8
#define ICC_IND_ARL 0xA
#define ICC_IND_AI 0xC
#define ICC_IND_AIL 0xE
#define ICC_IND_DC 0xF
extern void ICCVersion(struct IsdnCardState *cs, char *s);
extern void initicc(struct IsdnCardState *cs);
extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
extern void clear_pending_icc_ints(struct IsdnCardState *cs);
extern void setup_icc(struct IsdnCardState *);

View File

@ -1,29 +0,0 @@
/* $Id: ipac.h,v 1.7.2.2 2004/01/12 22:52:26 keil Exp $
*
* IPAC specific defines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#define IPAC_CONF 0xC0
#define IPAC_MASK 0xC1
#define IPAC_ISTA 0xC1
#define IPAC_ID 0xC2
#define IPAC_ACFG 0xC3
#define IPAC_AOE 0xC4
#define IPAC_ARX 0xC5
#define IPAC_ATX 0xC5
#define IPAC_PITA1 0xC6
#define IPAC_PITA2 0xC7
#define IPAC_POTA1 0xC8
#define IPAC_POTA2 0xC9
#define IPAC_PCFG 0xCA
#define IPAC_SCFG 0xCB
#define IPAC_TIMR2 0xCC

View File

@ -1,913 +0,0 @@
/*
*
* IPACX specific routines
*
* Author Joerg Petersohn
* Derived from hisax_isac.c, isac.c, hscx.c and others
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include "hisax_if.h"
#include "hisax.h"
#include "isdnl1.h"
#include "ipacx.h"
#define DBUSY_TIMER_VALUE 80
#define TIMER3_VALUE 7000
#define MAX_DFRAME_LEN_L1 300
#define B_FIFO_SIZE 64
#define D_FIFO_SIZE 32
// ipacx interrupt mask values
#define _MASK_IMASK 0x2E // global mask
#define _MASKB_IMASK 0x0B
#define _MASKD_IMASK 0x03 // all on
//----------------------------------------------------------
// local function declarations
//----------------------------------------------------------
static void ph_command(struct IsdnCardState *cs, unsigned int command);
static inline void cic_int(struct IsdnCardState *cs);
static void dch_l2l1(struct PStack *st, int pr, void *arg);
static void dbusy_timer_handler(struct timer_list *t);
static void dch_empty_fifo(struct IsdnCardState *cs, int count);
static void dch_fill_fifo(struct IsdnCardState *cs);
static inline void dch_int(struct IsdnCardState *cs);
static void dch_setstack(struct PStack *st, struct IsdnCardState *cs);
static void dch_init(struct IsdnCardState *cs);
static void bch_l2l1(struct PStack *st, int pr, void *arg);
static void bch_empty_fifo(struct BCState *bcs, int count);
static void bch_fill_fifo(struct BCState *bcs);
static void bch_int(struct IsdnCardState *cs, u_char hscx);
static void bch_mode(struct BCState *bcs, int mode, int bc);
static void bch_close_state(struct BCState *bcs);
static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
static int bch_setstack(struct PStack *st, struct BCState *bcs);
static void bch_init(struct IsdnCardState *cs, int hscx);
static void clear_pending_ints(struct IsdnCardState *cs);
//----------------------------------------------------------
// Issue Layer 1 command to chip
//----------------------------------------------------------
static void
ph_command(struct IsdnCardState *cs, unsigned int command)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_command (%#x) in (%#x)", command,
cs->dc.isac.ph_state);
//###################################
// printk(KERN_INFO "ph_command (%#x)\n", command);
//###################################
cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
}
//----------------------------------------------------------
// Transceiver interrupt handler
//----------------------------------------------------------
static inline void
cic_int(struct IsdnCardState *cs)
{
u_char event;
event = cs->readisac(cs, IPACX_CIR0) >> 4;
if (cs->debug & L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
//#########################################
// printk(KERN_INFO "cic_int(%x)\n", event);
//#########################################
cs->dc.isac.ph_state = event;
schedule_event(cs, D_L1STATECHANGE);
}
//==========================================================
// D channel functions
//==========================================================
//----------------------------------------------------------
// Command entry point
//----------------------------------------------------------
static void
dch_l2l1(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
u_char cda1_cr;
switch (pr) {
case (PH_DATA | REQUEST):
if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
if (cs->tx_skb) {
skb_queue_tail(&cs->sq, skb);
#ifdef L2FRAME_DEBUG
if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
#endif
} else {
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG
if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
#endif
dch_fill_fifo(cs);
}
break;
case (PH_PULL | INDICATION):
if (cs->tx_skb) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
skb_queue_tail(&cs->sq, skb);
break;
}
if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG
if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
#endif
dch_fill_fifo(cs);
break;
case (PH_PULL | REQUEST):
#ifdef L2FRAME_DEBUG
if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
#endif
if (!cs->tx_skb) {
clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
case (HW_ENABLE | REQUEST):
if ((cs->dc.isac.ph_state == IPACX_IND_RES) ||
(cs->dc.isac.ph_state == IPACX_IND_DR) ||
(cs->dc.isac.ph_state == IPACX_IND_DC))
ph_command(cs, IPACX_CMD_TIM);
else
ph_command(cs, IPACX_CMD_RES);
break;
case (HW_INFO3 | REQUEST):
ph_command(cs, IPACX_CMD_AR8);
break;
case (HW_TESTLOOP | REQUEST):
cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
(void) cs->readisac(cs, IPACX_CDA2_CR);
if ((long)arg & 1) { // loop B1
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x0a);
}
else { // B1 off
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x0a);
}
if ((long)arg & 2) { // loop B2
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x14);
}
else { // B2 off
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x14);
}
break;
case (HW_DEACTIVATE | RESPONSE):
skb_queue_purge(&cs->rq);
skb_queue_purge(&cs->sq);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
break;
default:
if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);
break;
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
dbusy_timer_handler(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
struct PStack *st;
int rbchd, stard;
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
rbchd = cs->readisac(cs, IPACX_RBCHD);
stard = cs->readisac(cs, IPACX_STARD);
if (cs->debug)
debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
if (!(stard & 0x40)) { // D-Channel Busy
set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
for (st = cs->stlist; st; st = st->next) {
st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
}
} else {
// seems we lost an interrupt; reset transceiver */
clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
} else {
printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
debugl1(cs, "D-Channel Busy no skb");
}
cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
}
}
}
//----------------------------------------------------------
// Fill buffer from receive FIFO
//----------------------------------------------------------
static void
dch_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "dch_empty_fifo()");
// message too large, remove
if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "dch_empty_fifo() incoming message too large");
cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
cs->rcvidx = 0;
return;
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "dch_empty_fifo() cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
//----------------------------------------------------------
// Fill transmit FIFO
//----------------------------------------------------------
static void
dch_fill_fifo(struct IsdnCardState *cs)
{
int count;
u_char cmd, *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "dch_fill_fifo()");
if (!cs->tx_skb) return;
count = cs->tx_skb->len;
if (count <= 0) return;
if (count > D_FIFO_SIZE) {
count = D_FIFO_SIZE;
cmd = 0x08; // XTF
} else {
cmd = 0x0A; // XTF | XME
}
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
cs->writeisacfifo(cs, ptr, count);
cs->writeisac(cs, IPACX_CMDRD, cmd);
// set timeout for transmission contol
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "dch_fill_fifo dbusytimer running");
del_timer(&cs->dbusytimer);
}
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "dch_fill_fifo() cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
//----------------------------------------------------------
// D channel interrupt handler
//----------------------------------------------------------
static inline void
dch_int(struct IsdnCardState *cs)
{
struct sk_buff *skb;
u_char istad, rstad;
int count;
istad = cs->readisac(cs, IPACX_ISTAD);
//##############################################
// printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
//##############################################
if (istad & 0x80) { // RME
rstad = cs->readisac(cs, IPACX_RSTAD);
if ((rstad & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
if (!(rstad & 0x80))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "dch_int(): invalid frame");
if ((rstad & 0x40))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "dch_int(): RDO");
if (!(rstad & 0x20))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "dch_int(): CRC error");
cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
} else { // received frame ok
count = cs->readisac(cs, IPACX_RBCLD);
if (count) count--; // RSTAB is last byte
count &= D_FIFO_SIZE - 1;
if (count == 0) count = D_FIFO_SIZE;
dch_empty_fifo(cs, count);
if ((count = cs->rcvidx) > 0) {
cs->rcvidx = 0;
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
else {
skb_put_data(skb, cs->rcvbuf, count);
skb_queue_tail(&cs->rq, skb);
}
}
}
cs->rcvidx = 0;
schedule_event(cs, D_RCVBUFREADY);
}
if (istad & 0x40) { // RPF
dch_empty_fifo(cs, D_FIFO_SIZE);
}
if (istad & 0x20) { // RFO
if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
}
if (istad & 0x10) { // XPR
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->tx_skb->len) {
dch_fill_fifo(cs);
goto afterXPR;
}
else {
dev_kfree_skb_irq(cs->tx_skb);
cs->tx_skb = NULL;
cs->tx_cnt = 0;
}
}
if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
cs->tx_cnt = 0;
dch_fill_fifo(cs);
}
else {
schedule_event(cs, D_XMTBUFREADY);
}
}
afterXPR:
if (istad & 0x0C) { // XDU or XMR
if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
if (cs->tx_skb) {
skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
cs->tx_cnt = 0;
dch_fill_fifo(cs);
} else {
printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
debugl1(cs, "ISAC XDU no skb");
}
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
dch_setstack(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = dch_l2l1;
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
dch_init(struct IsdnCardState *cs)
{
printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
cs->setstack_d = dch_setstack;
timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD
cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter
cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go
cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel
}
//==========================================================
// B channel functions
//==========================================================
//----------------------------------------------------------
// Entry point for commands
//----------------------------------------------------------
static void
bch_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hscx.count = 0;
bch_fill_fifo(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
} else {
set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->hw.hscx.count = 0;
bch_fill_fifo(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
set_bit(BC_FLG_ACTIV, &bcs->Flag);
bch_mode(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
clear_bit(BC_FLG_ACTIV, &bcs->Flag);
clear_bit(BC_FLG_BUSY, &bcs->Flag);
bch_mode(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
//----------------------------------------------------------
// Read B channel fifo to receive buffer
//----------------------------------------------------------
static void
bch_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr, hscx;
struct IsdnCardState *cs;
int cnt;
cs = bcs->cs;
hscx = bcs->hw.hscx.hscx;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "bch_empty_fifo()");
// message too large, remove
if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_empty_fifo() incoming packet too large");
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
bcs->hw.hscx.rcvidx = 0;
return;
}
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
cnt = count;
while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
//----------------------------------------------------------
// Fill buffer to transmit FIFO
//----------------------------------------------------------
static void
bch_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs;
int more, count, cnt;
u_char *ptr, *p, hscx;
cs = bcs->cs;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "bch_fill_fifo()");
if (!bcs->tx_skb) return;
if (bcs->tx_skb->len <= 0) return;
hscx = bcs->hw.hscx.hscx;
more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
if (bcs->tx_skb->len > B_FIFO_SIZE) {
more = 1;
count = B_FIFO_SIZE;
} else {
count = bcs->tx_skb->len;
}
cnt = count;
p = ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hscx.count += count;
while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "%s() B-%d cnt %d", __func__, hscx, count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
//----------------------------------------------------------
// B channel interrupt handler
//----------------------------------------------------------
static void
bch_int(struct IsdnCardState *cs, u_char hscx)
{
u_char istab;
struct BCState *bcs;
struct sk_buff *skb;
int count;
u_char rstab;
bcs = cs->bcs + hscx;
istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
//##############################################
// printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
//##############################################
if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
if (istab & 0x80) { // RME
rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
if ((rstab & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
if (!(rstab & 0x80))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
if ((rstab & 0x40) && (bcs->mode != L1_MODE_NULL))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
if (!(rstab & 0x20))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: CRC error", hscx);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC
}
else { // received frame ok
count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) & (B_FIFO_SIZE - 1);
if (count == 0) count = B_FIFO_SIZE;
bch_empty_fifo(bcs, count);
if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
if (cs->debug & L1_DEB_HSCX_FIFO)
debugl1(cs, "bch_int Frame %d", count);
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
count);
skb_queue_tail(&bcs->rqueue, skb);
}
}
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
if (istab & 0x40) { // RPF
bch_empty_fifo(bcs, B_FIFO_SIZE);
if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
// receive transparent audio data
if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
B_FIFO_SIZE);
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
}
if (istab & 0x20) { // RFO
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: RFO error", hscx);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES
}
if (istab & 0x10) { // XPR
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
bch_fill_fifo(bcs);
goto afterXPR;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hscx.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
}
dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hscx.count = 0;
set_bit(BC_FLG_BUSY, &bcs->Flag);
bch_fill_fifo(bcs);
} else {
clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
afterXPR:
if (istab & 0x04) { // XDU
if (bcs->mode == L1_MODE_TRANS) {
bch_fill_fifo(bcs);
}
else {
if (bcs->tx_skb) { // restart transmitting the whole frame
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
bcs->tx_cnt += bcs->hw.hscx.count;
bcs->hw.hscx.count = 0;
}
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d XDU error", hscx);
}
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
bch_mode(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
int hscx = bcs->hw.hscx.hscx;
bc = bc ? 1 : 0; // in case bc is greater than 1
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "mode_bch() switch B-%d mode %d chan %d", hscx, mode, bc);
bcs->mode = mode;
bcs->channel = bc;
// map controller to according timeslot
if (!hscx)
{
cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
cs->writeisac(cs, IPACX_BCHA_CR, 0x88);
}
else
{
cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
cs->writeisac(cs, IPACX_BCHB_CR, 0x88);
}
switch (mode) {
case (L1_MODE_NULL):
cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off
cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj.
cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
break;
case (L1_MODE_TRANS):
cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode
cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
break;
case (L1_MODE_HDLC):
cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0
cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments
cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
break;
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
bch_close_state(struct BCState *bcs)
{
bch_mode(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
kfree(bcs->blog);
bcs->blog = NULL;
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
//----------------------------------------------------------
//----------------------------------------------------------
static int
bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
clear_bit(BC_FLG_INIT, &bcs->Flag);
return (1);
}
if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax open_bchstate: No memory for bcs->blog\n");
clear_bit(BC_FLG_INIT, &bcs->Flag);
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
return (2);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
return (0);
}
//----------------------------------------------------------
//----------------------------------------------------------
static int
bch_setstack(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (bch_open_state(st->l1.hardware, bcs)) return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = bch_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
//----------------------------------------------------------
//----------------------------------------------------------
static void
bch_init(struct IsdnCardState *cs, int hscx)
{
cs->bcs[hscx].BC_SetStack = bch_setstack;
cs->bcs[hscx].BC_Close = bch_close_state;
cs->bcs[hscx].hw.hscx.hscx = hscx;
cs->bcs[hscx].cs = cs;
bch_mode(cs->bcs + hscx, 0, hscx);
}
//==========================================================
// Shared functions
//==========================================================
//----------------------------------------------------------
// Main interrupt handler
//----------------------------------------------------------
void
interrupt_ipacx(struct IsdnCardState *cs)
{
u_char ista;
while ((ista = cs->readisac(cs, IPACX_ISTA))) {
//#################################################
// printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
//#################################################
if (ista & 0x80) bch_int(cs, 0); // B channel interrupts
if (ista & 0x40) bch_int(cs, 1);
if (ista & 0x01) dch_int(cs); // D channel
if (ista & 0x10) cic_int(cs); // Layer 1 state
}
}
//----------------------------------------------------------
// Clears chip interrupt status
//----------------------------------------------------------
static void
clear_pending_ints(struct IsdnCardState *cs)
{
int ista;
// all interrupts off
cs->writeisac(cs, IPACX_MASK, 0xff);
cs->writeisac(cs, IPACX_MASKD, 0xff);
cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
ista = cs->readisac(cs, IPACX_ISTA);
if (ista & 0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
if (ista & 0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
if (ista & 0x10) cs->readisac(cs, IPACX_CIR0);
if (ista & 0x01) cs->readisac(cs, IPACX_ISTAD);
}
//----------------------------------------------------------
// Does chip configuration work
// Work to do depends on bit mask in part
//----------------------------------------------------------
void
init_ipacx(struct IsdnCardState *cs, int part)
{
if (part & 1) { // initialise chip
//##################################################
// printk(KERN_INFO "init_ipacx(%x)\n", part);
//##################################################
clear_pending_ints(cs);
bch_init(cs, 0);
bch_init(cs, 1);
dch_init(cs);
}
if (part & 2) { // reenable all interrupts and start chip
cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
// reset HDLC Transmitters/receivers
cs->writeisac(cs, IPACX_CMDRD, 0x41);
cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
ph_command(cs, IPACX_CMD_RES);
}
}
//----------------- end of file -----------------------

View File

@ -1,162 +0,0 @@
/*
*
* IPACX specific defines
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#ifndef INCLUDE_IPACX_H
#define INCLUDE_IPACX_H
/* D-channel registers */
#define IPACX_RFIFOD 0x00 /* RD */
#define IPACX_XFIFOD 0x00 /* WR */
#define IPACX_ISTAD 0x20 /* RD */
#define IPACX_MASKD 0x20 /* WR */
#define IPACX_STARD 0x21 /* RD */
#define IPACX_CMDRD 0x21 /* WR */
#define IPACX_MODED 0x22 /* RD/WR */
#define IPACX_EXMD1 0x23 /* RD/WR */
#define IPACX_TIMR1 0x24 /* RD/WR */
#define IPACX_SAP1 0x25 /* WR */
#define IPACX_SAP2 0x26 /* WR */
#define IPACX_RBCLD 0x26 /* RD */
#define IPACX_RBCHD 0x27 /* RD */
#define IPACX_TEI1 0x27 /* WR */
#define IPACX_TEI2 0x28 /* WR */
#define IPACX_RSTAD 0x28 /* RD */
#define IPACX_TMD 0x29 /* RD/WR */
#define IPACX_CIR0 0x2E /* RD */
#define IPACX_CIX0 0x2E /* WR */
#define IPACX_CIR1 0x2F /* RD */
#define IPACX_CIX1 0x2F /* WR */
/* Transceiver registers */
#define IPACX_TR_CONF0 0x30 /* RD/WR */
#define IPACX_TR_CONF1 0x31 /* RD/WR */
#define IPACX_TR_CONF2 0x32 /* RD/WR */
#define IPACX_TR_STA 0x33 /* RD */
#define IPACX_TR_CMD 0x34 /* RD/WR */
#define IPACX_SQRR1 0x35 /* RD */
#define IPACX_SQXR1 0x35 /* WR */
#define IPACX_SQRR2 0x36 /* RD */
#define IPACX_SQXR2 0x36 /* WR */
#define IPACX_SQRR3 0x37 /* RD */
#define IPACX_SQXR3 0x37 /* WR */
#define IPACX_ISTATR 0x38 /* RD */
#define IPACX_MASKTR 0x39 /* RD/WR */
#define IPACX_TR_MODE 0x3A /* RD/WR */
#define IPACX_ACFG1 0x3C /* RD/WR */
#define IPACX_ACFG2 0x3D /* RD/WR */
#define IPACX_AOE 0x3E /* RD/WR */
#define IPACX_ARX 0x3F /* RD */
#define IPACX_ATX 0x3F /* WR */
/* IOM: Timeslot, DPS, CDA */
#define IPACX_CDA10 0x40 /* RD/WR */
#define IPACX_CDA11 0x41 /* RD/WR */
#define IPACX_CDA20 0x42 /* RD/WR */
#define IPACX_CDA21 0x43 /* RD/WR */
#define IPACX_CDA_TSDP10 0x44 /* RD/WR */
#define IPACX_CDA_TSDP11 0x45 /* RD/WR */
#define IPACX_CDA_TSDP20 0x46 /* RD/WR */
#define IPACX_CDA_TSDP21 0x47 /* RD/WR */
#define IPACX_BCHA_TSDP_BC1 0x48 /* RD/WR */
#define IPACX_BCHA_TSDP_BC2 0x49 /* RD/WR */
#define IPACX_BCHB_TSDP_BC1 0x4A /* RD/WR */
#define IPACX_BCHB_TSDP_BC2 0x4B /* RD/WR */
#define IPACX_TR_TSDP_BC1 0x4C /* RD/WR */
#define IPACX_TR_TSDP_BC2 0x4D /* RD/WR */
#define IPACX_CDA1_CR 0x4E /* RD/WR */
#define IPACX_CDA2_CR 0x4F /* RD/WR */
/* IOM: Contol, Sync transfer, Monitor */
#define IPACX_TR_CR 0x50 /* RD/WR */
#define IPACX_TRC_CR 0x50 /* RD/WR */
#define IPACX_BCHA_CR 0x51 /* RD/WR */
#define IPACX_BCHB_CR 0x52 /* RD/WR */
#define IPACX_DCI_CR 0x53 /* RD/WR */
#define IPACX_DCIC_CR 0x53 /* RD/WR */
#define IPACX_MON_CR 0x54 /* RD/WR */
#define IPACX_SDS1_CR 0x55 /* RD/WR */
#define IPACX_SDS2_CR 0x56 /* RD/WR */
#define IPACX_IOM_CR 0x57 /* RD/WR */
#define IPACX_STI 0x58 /* RD */
#define IPACX_ASTI 0x58 /* WR */
#define IPACX_MSTI 0x59 /* RD/WR */
#define IPACX_SDS_CONF 0x5A /* RD/WR */
#define IPACX_MCDA 0x5B /* RD */
#define IPACX_MOR 0x5C /* RD */
#define IPACX_MOX 0x5C /* WR */
#define IPACX_MOSR 0x5D /* RD */
#define IPACX_MOCR 0x5E /* RD/WR */
#define IPACX_MSTA 0x5F /* RD */
#define IPACX_MCONF 0x5F /* WR */
/* Interrupt and general registers */
#define IPACX_ISTA 0x60 /* RD */
#define IPACX_MASK 0x60 /* WR */
#define IPACX_AUXI 0x61 /* RD */
#define IPACX_AUXM 0x61 /* WR */
#define IPACX_MODE1 0x62 /* RD/WR */
#define IPACX_MODE2 0x63 /* RD/WR */
#define IPACX_ID 0x64 /* RD */
#define IPACX_SRES 0x64 /* WR */
#define IPACX_TIMR2 0x65 /* RD/WR */
/* B-channel registers */
#define IPACX_OFF_B1 0x70
#define IPACX_OFF_B2 0x80
#define IPACX_ISTAB 0x00 /* RD */
#define IPACX_MASKB 0x00 /* WR */
#define IPACX_STARB 0x01 /* RD */
#define IPACX_CMDRB 0x01 /* WR */
#define IPACX_MODEB 0x02 /* RD/WR */
#define IPACX_EXMB 0x03 /* RD/WR */
#define IPACX_RAH1 0x05 /* WR */
#define IPACX_RAH2 0x06 /* WR */
#define IPACX_RBCLB 0x06 /* RD */
#define IPACX_RBCHB 0x07 /* RD */
#define IPACX_RAL1 0x07 /* WR */
#define IPACX_RAL2 0x08 /* WR */
#define IPACX_RSTAB 0x08 /* RD */
#define IPACX_TMB 0x09 /* RD/WR */
#define IPACX_RFIFOB 0x0A /*- RD */
#define IPACX_XFIFOB 0x0A /*- WR */
/* Layer 1 Commands */
#define IPACX_CMD_TIM 0x0
#define IPACX_CMD_RES 0x1
#define IPACX_CMD_SSP 0x2
#define IPACX_CMD_SCP 0x3
#define IPACX_CMD_AR8 0x8
#define IPACX_CMD_AR10 0x9
#define IPACX_CMD_ARL 0xa
#define IPACX_CMD_DI 0xf
/* Layer 1 Indications */
#define IPACX_IND_DR 0x0
#define IPACX_IND_RES 0x1
#define IPACX_IND_TMA 0x2
#define IPACX_IND_SLD 0x3
#define IPACX_IND_RSY 0x4
#define IPACX_IND_DR6 0x5
#define IPACX_IND_PU 0x7
#define IPACX_IND_AR 0x8
#define IPACX_IND_ARL 0xa
#define IPACX_IND_CVR 0xb
#define IPACX_IND_AI8 0xc
#define IPACX_IND_AI10 0xd
#define IPACX_IND_AIL 0xe
#define IPACX_IND_DC 0xf
extern void init_ipacx(struct IsdnCardState *, int);
extern void interrupt_ipacx(struct IsdnCardState *);
extern void setup_isac(struct IsdnCardState *);
#endif

View File

@ -1,681 +0,0 @@
/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $
*
* ISAC specific routines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For changes and modifications please read
* Documentation/isdn/HiSax.cert
*
*/
#include "hisax.h"
#include "isac.h"
#include "arcofi.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/init.h>
#define DBUSY_TIMER_VALUE 80
#define ARCOFI_USE 1
static char *ISACVer[] =
{"2086/2186 V1.1", "2085 B1", "2085 B2",
"2085 V2.3"};
void ISACVersion(struct IsdnCardState *cs, char *s)
{
int val;
val = cs->readisac(cs, ISAC_RBCH);
printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]);
}
static void
ph_command(struct IsdnCardState *cs, unsigned int command)
{
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_command %x", command);
cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
}
static void
isac_new_ph(struct IsdnCardState *cs)
{
switch (cs->dc.isac.ph_state) {
case (ISAC_IND_RS):
case (ISAC_IND_EI):
ph_command(cs, ISAC_CMD_DUI);
l1_msg(cs, HW_RESET | INDICATION, NULL);
break;
case (ISAC_IND_DID):
l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
break;
case (ISAC_IND_DR):
l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
break;
case (ISAC_IND_PU):
l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
break;
case (ISAC_IND_RSY):
l1_msg(cs, HW_RSYNC | INDICATION, NULL);
break;
case (ISAC_IND_ARD):
l1_msg(cs, HW_INFO2 | INDICATION, NULL);
break;
case (ISAC_IND_AI8):
l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
break;
case (ISAC_IND_AI10):
l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
break;
default:
break;
}
}
static void
isac_bh(struct work_struct *work)
{
struct IsdnCardState *cs =
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
stptr = stptr->next;
}
}
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
isac_new_ph(cs);
if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
DChannel_proc_rcv(cs);
if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
DChannel_proc_xmt(cs);
#if ARCOFI_USE
if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
return;
if (test_and_clear_bit(D_RX_MON1, &cs->event))
arcofi_fsm(cs, ARCOFI_RX_END, NULL);
if (test_and_clear_bit(D_TX_MON1, &cs->event))
arcofi_fsm(cs, ARCOFI_TX_END, NULL);
#endif
}
static void
isac_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "isac_empty_fifo");
if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "isac_empty_fifo overrun %d",
cs->rcvidx + count);
cs->writeisac(cs, ISAC_CMDR, 0x80);
cs->rcvidx = 0;
return;
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, ISAC_CMDR, 0x80);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "isac_empty_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
static void
isac_fill_fifo(struct IsdnCardState *cs)
{
int count, more;
u_char *ptr;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "isac_fill_fifo");
if (!cs->tx_skb)
return;
count = cs->tx_skb->len;
if (count <= 0)
return;
more = 0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
cs->writeisacfifo(cs, ptr, count);
cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa);
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "isac_fill_fifo dbusytimer running");
del_timer(&cs->dbusytimer);
}
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
t += sprintf(t, "isac_fill_fifo cnt %d", count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", cs->dlog);
}
}
void
isac_interrupt(struct IsdnCardState *cs, u_char val)
{
u_char exval, v1;
struct sk_buff *skb;
unsigned int count;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC interrupt %x", val);
if (val & 0x80) { /* RME */
exval = cs->readisac(cs, ISAC_RSTA);
if ((exval & 0x70) != 0x20) {
if (exval & 0x40) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC RDO");
#ifdef ERROR_STATISTIC
cs->err_rx++;
#endif
}
if (!(exval & 0x20)) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC CRC error");
#ifdef ERROR_STATISTIC
cs->err_crc++;
#endif
}
cs->writeisac(cs, ISAC_CMDR, 0x80);
} else {
count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
if (count == 0)
count = 32;
isac_empty_fifo(cs, count);
count = cs->rcvidx;
if (count > 0) {
cs->rcvidx = 0;
skb = alloc_skb(count, GFP_ATOMIC);
if (!skb)
printk(KERN_WARNING "HiSax: D receive out of memory\n");
else {
skb_put_data(skb, cs->rcvbuf, count);
skb_queue_tail(&cs->rq, skb);
}
}
}
cs->rcvidx = 0;
schedule_event(cs, D_RCVBUFREADY);
}
if (val & 0x40) { /* RPF */
isac_empty_fifo(cs, 32);
}
if (val & 0x20) { /* RSC */
/* never */
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC RSC interrupt");
}
if (val & 0x10) { /* XPR */
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) {
if (cs->tx_skb->len) {
isac_fill_fifo(cs);
goto afterXPR;
} else {
dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
}
cs->tx_skb = skb_dequeue(&cs->sq);
if (cs->tx_skb) {
cs->tx_cnt = 0;
isac_fill_fifo(cs);
} else
schedule_event(cs, D_XMTBUFREADY);
}
afterXPR:
if (val & 0x04) { /* CISQ */
exval = cs->readisac(cs, ISAC_CIR0);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC CIR0 %02X", exval);
if (exval & 2) {
cs->dc.isac.ph_state = (exval >> 2) & 0xf;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
schedule_event(cs, D_L1STATECHANGE);
}
if (exval & 1) {
exval = cs->readisac(cs, ISAC_CIR1);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC CIR1 %02X", exval);
}
}
if (val & 0x02) { /* SIN */
/* never */
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC SIN interrupt");
}
if (val & 0x01) { /* EXI */
exval = cs->readisac(cs, ISAC_EXIR);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC EXIR %02x", exval);
if (exval & 0x80) { /* XMR */
debugl1(cs, "ISAC XMR");
printk(KERN_WARNING "HiSax: ISAC XMR\n");
}
if (exval & 0x40) { /* XDU */
debugl1(cs, "ISAC XDU");
printk(KERN_WARNING "HiSax: ISAC XDU\n");
#ifdef ERROR_STATISTIC
cs->err_tx++;
#endif
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
if (cs->tx_skb) { /* Restart frame */
skb_push(cs->tx_skb, cs->tx_cnt);
cs->tx_cnt = 0;
isac_fill_fifo(cs);
} else {
printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
debugl1(cs, "ISAC XDU no skb");
}
}
if (exval & 0x04) { /* MOS */
v1 = cs->readisac(cs, ISAC_MOSR);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC MOSR %02x", v1);
#if ARCOFI_USE
if (v1 & 0x08) {
if (!cs->dc.isac.mon_rx) {
cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
if (!cs->dc.isac.mon_rx) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON RX out of memory!");
cs->dc.isac.mocr &= 0xf0;
cs->dc.isac.mocr |= 0x0a;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
goto afterMONR0;
} else
cs->dc.isac.mon_rxp = 0;
}
if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
cs->dc.isac.mocr &= 0xf0;
cs->dc.isac.mocr |= 0x0a;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mon_rxp = 0;
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON RX overflow!");
goto afterMONR0;
}
cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]);
if (cs->dc.isac.mon_rxp == 1) {
cs->dc.isac.mocr |= 0x04;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
}
}
afterMONR0:
if (v1 & 0x80) {
if (!cs->dc.isac.mon_rx) {
cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
if (!cs->dc.isac.mon_rx) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON RX out of memory!");
cs->dc.isac.mocr &= 0x0f;
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
goto afterMONR1;
} else
cs->dc.isac.mon_rxp = 0;
}
if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
cs->dc.isac.mocr &= 0x0f;
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mon_rxp = 0;
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "ISAC MON RX overflow!");
goto afterMONR1;
}
cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]);
cs->dc.isac.mocr |= 0x40;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
}
afterMONR1:
if (v1 & 0x04) {
cs->dc.isac.mocr &= 0xf0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mocr |= 0x0a;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
schedule_event(cs, D_RX_MON0);
}
if (v1 & 0x40) {
cs->dc.isac.mocr &= 0x0f;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
schedule_event(cs, D_RX_MON1);
}
if (v1 & 0x02) {
if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
!(v1 & 0x08))) {
cs->dc.isac.mocr &= 0xf0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mocr |= 0x0a;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
if (cs->dc.isac.mon_txc &&
(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
schedule_event(cs, D_TX_MON0);
goto AfterMOX0;
}
if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
schedule_event(cs, D_TX_MON0);
goto AfterMOX0;
}
cs->writeisac(cs, ISAC_MOX0,
cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]);
}
AfterMOX0:
if (v1 & 0x20) {
if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
!(v1 & 0x80))) {
cs->dc.isac.mocr &= 0x0f;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
if (cs->dc.isac.mon_txc &&
(cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
schedule_event(cs, D_TX_MON1);
goto AfterMOX1;
}
if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
schedule_event(cs, D_TX_MON1);
goto AfterMOX1;
}
cs->writeisac(cs, ISAC_MOX1,
cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
if (cs->debug & L1_DEB_MONITOR)
debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]);
}
AfterMOX1:;
#endif
}
}
}
static void
ISAC_l1hw(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
u_long flags;
int val;
switch (pr) {
case (PH_DATA | REQUEST):
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
skb_queue_tail(&cs->sq, skb);
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA Queued", 0);
#endif
} else {
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA", 0);
#endif
isac_fill_fifo(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&cs->lock, flags);
if (cs->tx_skb) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
skb_queue_tail(&cs->sq, skb);
} else {
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 0);
cs->tx_skb = skb;
cs->tx_cnt = 0;
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
#endif
isac_fill_fifo(cs);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (PH_PULL | REQUEST):
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
debugl1(cs, "-> PH_REQUEST_PULL");
#endif
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
(cs->dc.isac.ph_state == ISAC_IND_DR) ||
(cs->dc.isac.ph_state == ISAC_IND_RS))
ph_command(cs, ISAC_CMD_TIM);
else
ph_command(cs, ISAC_CMD_RS);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_ENABLE | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ISAC_CMD_TIM);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_INFO3 | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
ph_command(cs, ISAC_CMD_AR8);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_TESTLOOP | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
val = 0;
if (1 & (long) arg)
val |= 0x0c;
if (2 & (long) arg)
val |= 0x3;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
if (!val) {
cs->writeisac(cs, ISAC_SPCR, 0xa);
cs->writeisac(cs, ISAC_ADF1, 0x2);
} else {
cs->writeisac(cs, ISAC_SPCR, val);
cs->writeisac(cs, ISAC_ADF1, 0xa);
}
} else {
/* IOM 2 Mode */
cs->writeisac(cs, ISAC_SPCR, val);
if (val)
cs->writeisac(cs, ISAC_ADF1, 0x8);
else
cs->writeisac(cs, ISAC_ADF1, 0x0);
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_DEACTIVATE | RESPONSE):
skb_queue_purge(&cs->rq);
skb_queue_purge(&cs->sq);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
del_timer(&cs->dbusytimer);
if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
schedule_event(cs, D_CLEARBUSY);
break;
default:
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "isac_l1hw unknown %04x", pr);
break;
}
}
static void
setstack_isac(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = ISAC_l1hw;
}
static void
DC_Close_isac(struct IsdnCardState *cs)
{
kfree(cs->dc.isac.mon_rx);
cs->dc.isac.mon_rx = NULL;
kfree(cs->dc.isac.mon_tx);
cs->dc.isac.mon_tx = NULL;
}
static void
dbusy_timer_handler(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
struct PStack *stptr;
int rbch, star;
if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
rbch = cs->readisac(cs, ISAC_RBCH);
star = cs->readisac(cs, ISAC_STAR);
if (cs->debug)
debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
rbch, star);
if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
stptr = cs->stlist;
while (stptr != NULL) {
stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
stptr = stptr->next;
}
} else {
/* discard frame; reset transceiver */
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
} else {
printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
debugl1(cs, "D-Channel Busy no skb");
}
cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
cs->irq_func(cs->irq, cs);
}
}
}
void initisac(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_isac;
cs->DC_Close = DC_Close_isac;
cs->dc.isac.mon_tx = NULL;
cs->dc.isac.mon_rx = NULL;
cs->writeisac(cs, ISAC_MASK, 0xff);
cs->dc.isac.mocr = 0xaa;
if (test_bit(HW_IOM1, &cs->HW_Flags)) {
/* IOM 1 Mode */
cs->writeisac(cs, ISAC_ADF2, 0x0);
cs->writeisac(cs, ISAC_SPCR, 0xa);
cs->writeisac(cs, ISAC_ADF1, 0x2);
cs->writeisac(cs, ISAC_STCR, 0x70);
cs->writeisac(cs, ISAC_MODE, 0xc9);
} else {
/* IOM 2 Mode */
if (!cs->dc.isac.adf2)
cs->dc.isac.adf2 = 0x80;
cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
cs->writeisac(cs, ISAC_SQXR, 0x2f);
cs->writeisac(cs, ISAC_SPCR, 0x00);
cs->writeisac(cs, ISAC_STCR, 0x70);
cs->writeisac(cs, ISAC_MODE, 0xc9);
cs->writeisac(cs, ISAC_TIMR, 0x00);
cs->writeisac(cs, ISAC_ADF1, 0x00);
}
ph_command(cs, ISAC_CMD_RS);
cs->writeisac(cs, ISAC_MASK, 0x0);
}
void clear_pending_isac_ints(struct IsdnCardState *cs)
{
int val, eval;
val = cs->readisac(cs, ISAC_STAR);
debugl1(cs, "ISAC STAR %x", val);
val = cs->readisac(cs, ISAC_MODE);
debugl1(cs, "ISAC MODE %x", val);
val = cs->readisac(cs, ISAC_ADF2);
debugl1(cs, "ISAC ADF2 %x", val);
val = cs->readisac(cs, ISAC_ISTA);
debugl1(cs, "ISAC ISTA %x", val);
if (val & 0x01) {
eval = cs->readisac(cs, ISAC_EXIR);
debugl1(cs, "ISAC EXIR %x", eval);
}
val = cs->readisac(cs, ISAC_CIR0);
debugl1(cs, "ISAC CIR0 %x", val);
cs->dc.isac.ph_state = (val >> 2) & 0xf;
schedule_event(cs, D_L1STATECHANGE);
/* Disable all IRQ */
cs->writeisac(cs, ISAC_MASK, 0xFF);
}
void setup_isac(struct IsdnCardState *cs)
{
INIT_WORK(&cs->tqueue, isac_bh);
timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
}

View File

@ -1,70 +0,0 @@
/* $Id: isac.h,v 1.9.2.2 2004/01/12 22:52:27 keil Exp $
*
* ISAC specific defines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#define ISAC_MASK 0x20
#define ISAC_ISTA 0x20
#define ISAC_STAR 0x21
#define ISAC_CMDR 0x21
#define ISAC_EXIR 0x24
#define ISAC_ADF2 0x39
#define ISAC_SPCR 0x30
#define ISAC_ADF1 0x38
#define ISAC_CIR0 0x31
#define ISAC_CIX0 0x31
#define ISAC_CIR1 0x33
#define ISAC_CIX1 0x33
#define ISAC_STCR 0x37
#define ISAC_MODE 0x22
#define ISAC_RSTA 0x27
#define ISAC_RBCL 0x25
#define ISAC_RBCH 0x2A
#define ISAC_TIMR 0x23
#define ISAC_SQXR 0x3b
#define ISAC_MOSR 0x3a
#define ISAC_MOCR 0x3a
#define ISAC_MOR0 0x32
#define ISAC_MOX0 0x32
#define ISAC_MOR1 0x34
#define ISAC_MOX1 0x34
#define ISAC_RBCH_XAC 0x80
#define ISAC_CMD_TIM 0x0
#define ISAC_CMD_RS 0x1
#define ISAC_CMD_SCZ 0x4
#define ISAC_CMD_SSZ 0x2
#define ISAC_CMD_AR8 0x8
#define ISAC_CMD_AR10 0x9
#define ISAC_CMD_ARL 0xA
#define ISAC_CMD_DUI 0xF
#define ISAC_IND_RS 0x1
#define ISAC_IND_PU 0x7
#define ISAC_IND_DR 0x0
#define ISAC_IND_SD 0x2
#define ISAC_IND_DIS 0x3
#define ISAC_IND_EI 0x6
#define ISAC_IND_RSY 0x4
#define ISAC_IND_ARD 0x8
#define ISAC_IND_TI 0xA
#define ISAC_IND_ATI 0xB
#define ISAC_IND_AI8 0xC
#define ISAC_IND_AI10 0xD
#define ISAC_IND_DID 0xF
extern void ISACVersion(struct IsdnCardState *, char *);
extern void setup_isac(struct IsdnCardState *);
extern void initisac(struct IsdnCardState *);
extern void isac_interrupt(struct IsdnCardState *, u_char);
extern void clear_pending_isac_ints(struct IsdnCardState *);

File diff suppressed because it is too large Load Diff

View File

@ -1,222 +0,0 @@
/* $Id: isar.h,v 1.11.2.2 2004/01/12 22:52:27 keil Exp $
*
* ISAR (Siemens PSB 7110) specific defines
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define ISAR_IRQMSK 0x04
#define ISAR_IRQSTA 0x04
#define ISAR_IRQBIT 0x75
#define ISAR_CTRL_H 0x61
#define ISAR_CTRL_L 0x60
#define ISAR_IIS 0x58
#define ISAR_IIA 0x58
#define ISAR_HIS 0x50
#define ISAR_HIA 0x50
#define ISAR_MBOX 0x4c
#define ISAR_WADR 0x4a
#define ISAR_RADR 0x48
#define ISAR_HIS_VNR 0x14
#define ISAR_HIS_DKEY 0x02
#define ISAR_HIS_FIRM 0x1e
#define ISAR_HIS_STDSP 0x08
#define ISAR_HIS_DIAG 0x05
#define ISAR_HIS_WAITSTATE 0x27
#define ISAR_HIS_TIMERIRQ 0x25
#define ISAR_HIS_P0CFG 0x3c
#define ISAR_HIS_P12CFG 0x24
#define ISAR_HIS_SARTCFG 0x25
#define ISAR_HIS_PUMPCFG 0x26
#define ISAR_HIS_PUMPCTRL 0x2a
#define ISAR_HIS_IOM2CFG 0x27
#define ISAR_HIS_IOM2REQ 0x07
#define ISAR_HIS_IOM2CTRL 0x2b
#define ISAR_HIS_BSTREQ 0x0c
#define ISAR_HIS_PSTREQ 0x0e
#define ISAR_HIS_SDATA 0x20
#define ISAR_HIS_DPS1 0x40
#define ISAR_HIS_DPS2 0x80
#define SET_DPS(x) ((x << 6) & 0xc0)
#define ISAR_CMD_TIMERIRQ_OFF 0x20
#define ISAR_CMD_TIMERIRQ_ON 0x21
#define ISAR_IIS_MSCMSD 0x3f
#define ISAR_IIS_VNR 0x15
#define ISAR_IIS_DKEY 0x03
#define ISAR_IIS_FIRM 0x1f
#define ISAR_IIS_STDSP 0x09
#define ISAR_IIS_DIAG 0x25
#define ISAR_IIS_GSTEV 0x00
#define ISAR_IIS_BSTEV 0x28
#define ISAR_IIS_BSTRSP 0x2c
#define ISAR_IIS_PSTRSP 0x2e
#define ISAR_IIS_PSTEV 0x2a
#define ISAR_IIS_IOM2RSP 0x27
#define ISAR_IIS_RDATA 0x20
#define ISAR_IIS_INVMSG 0x3f
#define ISAR_CTRL_SWVER 0x10
#define ISAR_CTRL_STST 0x40
#define ISAR_MSG_HWVER {0x20, 0, 1}
#define ISAR_DP1_USE 1
#define ISAR_DP2_USE 2
#define ISAR_RATE_REQ 3
#define PMOD_DISABLE 0
#define PMOD_FAX 1
#define PMOD_DATAMODEM 2
#define PMOD_HALFDUPLEX 3
#define PMOD_V110 4
#define PMOD_DTMF 5
#define PMOD_DTMF_TRANS 6
#define PMOD_BYPASS 7
#define PCTRL_ORIG 0x80
#define PV32P2_V23R 0x40
#define PV32P2_V22A 0x20
#define PV32P2_V22B 0x10
#define PV32P2_V22C 0x08
#define PV32P2_V21 0x02
#define PV32P2_BEL 0x01
// LSB MSB in ISAR doc wrong !!! Arghhh
#define PV32P3_AMOD 0x80
#define PV32P3_V32B 0x02
#define PV32P3_V23B 0x01
#define PV32P4_48 0x11
#define PV32P5_48 0x05
#define PV32P4_UT48 0x11
#define PV32P5_UT48 0x0d
#define PV32P4_96 0x11
#define PV32P5_96 0x03
#define PV32P4_UT96 0x11
#define PV32P5_UT96 0x0f
#define PV32P4_B96 0x91
#define PV32P5_B96 0x0b
#define PV32P4_UTB96 0xd1
#define PV32P5_UTB96 0x0f
#define PV32P4_120 0xb1
#define PV32P5_120 0x09
#define PV32P4_UT120 0xf1
#define PV32P5_UT120 0x0f
#define PV32P4_144 0x99
#define PV32P5_144 0x09
#define PV32P4_UT144 0xf9
#define PV32P5_UT144 0x0f
#define PV32P6_CTN 0x01
#define PV32P6_ATN 0x02
#define PFAXP2_CTN 0x01
#define PFAXP2_ATN 0x04
#define PSEV_10MS_TIMER 0x02
#define PSEV_CON_ON 0x18
#define PSEV_CON_OFF 0x19
#define PSEV_V24_OFF 0x20
#define PSEV_CTS_ON 0x21
#define PSEV_CTS_OFF 0x22
#define PSEV_DCD_ON 0x23
#define PSEV_DCD_OFF 0x24
#define PSEV_DSR_ON 0x25
#define PSEV_DSR_OFF 0x26
#define PSEV_REM_RET 0xcc
#define PSEV_REM_REN 0xcd
#define PSEV_GSTN_CLR 0xd4
#define PSEV_RSP_READY 0xbc
#define PSEV_LINE_TX_H 0xb3
#define PSEV_LINE_TX_B 0xb2
#define PSEV_LINE_RX_H 0xb1
#define PSEV_LINE_RX_B 0xb0
#define PSEV_RSP_CONN 0xb5
#define PSEV_RSP_DISC 0xb7
#define PSEV_RSP_FCERR 0xb9
#define PSEV_RSP_SILDET 0xbe
#define PSEV_RSP_SILOFF 0xab
#define PSEV_FLAGS_DET 0xba
#define PCTRL_CMD_FTH 0xa7
#define PCTRL_CMD_FRH 0xa5
#define PCTRL_CMD_FTM 0xa8
#define PCTRL_CMD_FRM 0xa6
#define PCTRL_CMD_SILON 0xac
#define PCTRL_CMD_CONT 0xa2
#define PCTRL_CMD_ESC 0xa4
#define PCTRL_CMD_SILOFF 0xab
#define PCTRL_CMD_HALT 0xa9
#define PCTRL_LOC_RET 0xcf
#define PCTRL_LOC_REN 0xce
#define SMODE_DISABLE 0
#define SMODE_V14 2
#define SMODE_HDLC 3
#define SMODE_BINARY 4
#define SMODE_FSK_V14 5
#define SCTRL_HDMC_BOTH 0x00
#define SCTRL_HDMC_DTX 0x80
#define SCTRL_HDMC_DRX 0x40
#define S_P1_OVSP 0x40
#define S_P1_SNP 0x20
#define S_P1_EOP 0x10
#define S_P1_EDP 0x08
#define S_P1_NSB 0x04
#define S_P1_CHS_8 0x03
#define S_P1_CHS_7 0x02
#define S_P1_CHS_6 0x01
#define S_P1_CHS_5 0x00
#define S_P2_BFT_DEF 0x10
#define IOM_CTRL_ENA 0x80
#define IOM_CTRL_NOPCM 0x00
#define IOM_CTRL_ALAW 0x02
#define IOM_CTRL_ULAW 0x04
#define IOM_CTRL_RCV 0x01
#define IOM_P1_TXD 0x10
#define HDLC_FED 0x40
#define HDLC_FSD 0x20
#define HDLC_FST 0x20
#define HDLC_ERROR 0x1c
#define HDLC_ERR_FAD 0x10
#define HDLC_ERR_RER 0x08
#define HDLC_ERR_CER 0x04
#define SART_NMD 0x01
#define BSTAT_RDM0 0x1
#define BSTAT_RDM1 0x2
#define BSTAT_RDM2 0x4
#define BSTAT_RDM3 0x8
#define BSTEV_TBO 0x1f
#define BSTEV_RBO 0x2f
/* FAX State Machine */
#define STFAX_NULL 0
#define STFAX_READY 1
#define STFAX_LINE 2
#define STFAX_CONT 3
#define STFAX_ACTIV 4
#define STFAX_ESCAPE 5
#define STFAX_SILDET 6
#define ISDN_FAXPUMP_HALT 100
extern int ISARVersion(struct IsdnCardState *cs, char *s);
extern void isar_int_main(struct IsdnCardState *cs);
extern void initisar(struct IsdnCardState *cs);
extern void isar_fill_fifo(struct BCState *bcs);
extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic);

View File

@ -1,930 +0,0 @@
/* $Id: isdnl1.c,v 2.46.2.5 2004/02/11 13:21:34 keil Exp $
*
* common low level stuff for Siemens Chipsetbased isdn cards
*
* Author Karsten Keil
* based on the teles driver from Jan den Ouden
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For changes and modifications please read
* Documentation/isdn/HiSax.cert
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
*/
#include <linux/init.h>
#include <linux/gfp.h>
#include "hisax.h"
#include "isdnl1.h"
const char *l1_revision = "$Revision: 2.46.2.5 $";
#define TIMER3_VALUE 7000
static struct Fsm l1fsm_b;
static struct Fsm l1fsm_s;
enum {
ST_L1_F2,
ST_L1_F3,
ST_L1_F4,
ST_L1_F5,
ST_L1_F6,
ST_L1_F7,
ST_L1_F8,
};
#define L1S_STATE_COUNT (ST_L1_F8 + 1)
static char *strL1SState[] =
{
"ST_L1_F2",
"ST_L1_F3",
"ST_L1_F4",
"ST_L1_F5",
"ST_L1_F6",
"ST_L1_F7",
"ST_L1_F8",
};
#ifdef HISAX_UINTERFACE
static
struct Fsm l1fsm_u =
{NULL, 0, 0, NULL, NULL};
enum {
ST_L1_RESET,
ST_L1_DEACT,
ST_L1_SYNC2,
ST_L1_TRANS,
};
#define L1U_STATE_COUNT (ST_L1_TRANS + 1)
static char *strL1UState[] =
{
"ST_L1_RESET",
"ST_L1_DEACT",
"ST_L1_SYNC2",
"ST_L1_TRANS",
};
#endif
enum {
ST_L1_NULL,
ST_L1_WAIT_ACT,
ST_L1_WAIT_DEACT,
ST_L1_ACTIV,
};
#define L1B_STATE_COUNT (ST_L1_ACTIV + 1)
static char *strL1BState[] =
{
"ST_L1_NULL",
"ST_L1_WAIT_ACT",
"ST_L1_WAIT_DEACT",
"ST_L1_ACTIV",
};
enum {
EV_PH_ACTIVATE,
EV_PH_DEACTIVATE,
EV_RESET_IND,
EV_DEACT_CNF,
EV_DEACT_IND,
EV_POWER_UP,
EV_RSYNC_IND,
EV_INFO2_IND,
EV_INFO4_IND,
EV_TIMER_DEACT,
EV_TIMER_ACT,
EV_TIMER3,
};
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
static char *strL1Event[] =
{
"EV_PH_ACTIVATE",
"EV_PH_DEACTIVATE",
"EV_RESET_IND",
"EV_DEACT_CNF",
"EV_DEACT_IND",
"EV_POWER_UP",
"EV_RSYNC_IND",
"EV_INFO2_IND",
"EV_INFO4_IND",
"EV_TIMER_DEACT",
"EV_TIMER_ACT",
"EV_TIMER3",
};
void
debugl1(struct IsdnCardState *cs, char *fmt, ...)
{
va_list args;
char tmp[8];
va_start(args, fmt);
sprintf(tmp, "Card%d ", cs->cardnr + 1);
VHiSax_putstatus(cs, tmp, fmt, args);
va_end(args);
}
static void
l1m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
struct PStack *st = fi->userdata;
struct IsdnCardState *cs = st->l1.hardware;
char tmp[8];
va_start(args, fmt);
sprintf(tmp, "Card%d ", cs->cardnr + 1);
VHiSax_putstatus(cs, tmp, fmt, args);
va_end(args);
}
static void
L1activated(struct IsdnCardState *cs)
{
struct PStack *st;
st = cs->stlist;
while (st) {
if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
else
st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL);
st = st->next;
}
}
static void
L1deactivated(struct IsdnCardState *cs)
{
struct PStack *st;
st = cs->stlist;
while (st) {
if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL);
st = st->next;
}
test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
}
void
DChannel_proc_xmt(struct IsdnCardState *cs)
{
struct PStack *stptr;
if (cs->tx_skb)
return;
stptr = cs->stlist;
while (stptr != NULL) {
if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) {
stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL);
break;
} else
stptr = stptr->next;
}
}
void
DChannel_proc_rcv(struct IsdnCardState *cs)
{
struct sk_buff *skb, *nskb;
struct PStack *stptr = cs->stlist;
int found, tei, sapi;
if (stptr)
if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags))
FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL);
while ((skb = skb_dequeue(&cs->rq))) {
#ifdef L2FRAME_DEBUG /* psa */
if (cs->debug & L1_DEB_LAPD)
Logl2Frame(cs, skb, "PH_DATA", 1);
#endif
stptr = cs->stlist;
if (skb->len < 3) {
debugl1(cs, "D-channel frame too short(%d)", skb->len);
dev_kfree_skb(skb);
return;
}
if ((skb->data[0] & 1) || !(skb->data[1] & 1)) {
debugl1(cs, "D-channel frame wrong EA0/EA1");
dev_kfree_skb(skb);
return;
}
sapi = skb->data[0] >> 2;
tei = skb->data[1] >> 1;
if (cs->debug & DEB_DLOG_HEX)
LogFrame(cs, skb->data, skb->len);
if (cs->debug & DEB_DLOG_VERBOSE)
dlogframe(cs, skb, 1);
if (tei == GROUP_TEI) {
if (sapi == CTRL_SAPI) { /* sapi 0 */
while (stptr != NULL) {
if ((nskb = skb_clone(skb, GFP_ATOMIC)))
stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb);
else
printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
stptr = stptr->next;
}
} else if (sapi == TEI_SAPI) {
while (stptr != NULL) {
if ((nskb = skb_clone(skb, GFP_ATOMIC)))
stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb);
else
printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n");
stptr = stptr->next;
}
}
dev_kfree_skb(skb);
} else if (sapi == CTRL_SAPI) { /* sapi 0 */
found = 0;
while (stptr != NULL)
if (tei == stptr->l2.tei) {
stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb);
found = !0;
break;
} else
stptr = stptr->next;
if (!found)
dev_kfree_skb(skb);
} else
dev_kfree_skb(skb);
}
}
static void
BChannel_proc_xmt(struct BCState *bcs)
{
struct PStack *st = bcs->st;
if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
debugl1(bcs->cs, "BC_BUSY Error");
return;
}
if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
if (!test_bit(BC_FLG_BUSY, &bcs->Flag) &&
skb_queue_empty(&bcs->squeue)) {
st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
}
}
}
static void
BChannel_proc_rcv(struct BCState *bcs)
{
struct sk_buff *skb;
if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) {
FsmDelTimer(&bcs->st->l1.timer, 4);
FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL);
}
while ((skb = skb_dequeue(&bcs->rqueue))) {
bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb);
}
}
static void
BChannel_proc_ack(struct BCState *bcs)
{
u_long flags;
int ack;
spin_lock_irqsave(&bcs->aclock, flags);
ack = bcs->ackcnt;
bcs->ackcnt = 0;
spin_unlock_irqrestore(&bcs->aclock, flags);
if (ack)
lli_writewakeup(bcs->st, ack);
}
void
BChannel_bh(struct work_struct *work)
{
struct BCState *bcs = container_of(work, struct BCState, tqueue);
if (!bcs)
return;
if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event))
BChannel_proc_rcv(bcs);
if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event))
BChannel_proc_xmt(bcs);
if (test_and_clear_bit(B_ACKPENDING, &bcs->event))
BChannel_proc_ack(bcs);
}
void
HiSax_addlist(struct IsdnCardState *cs,
struct PStack *st)
{
st->next = cs->stlist;
cs->stlist = st;
}
void
HiSax_rmlist(struct IsdnCardState *cs,
struct PStack *st)
{
struct PStack *p;
FsmDelTimer(&st->l1.timer, 0);
if (cs->stlist == st)
cs->stlist = st->next;
else {
p = cs->stlist;
while (p)
if (p->next == st) {
p->next = st->next;
return;
} else
p = p->next;
}
}
void
init_bcstate(struct IsdnCardState *cs, int bc)
{
struct BCState *bcs = cs->bcs + bc;
bcs->cs = cs;
bcs->channel = bc;
INIT_WORK(&bcs->tqueue, BChannel_bh);
spin_lock_init(&bcs->aclock);
bcs->BC_SetStack = NULL;
bcs->BC_Close = NULL;
bcs->Flag = 0;
}
#ifdef L2FRAME_DEBUG /* psa */
static 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 tmpdeb[32];
static char *
l2frames(u_char *ptr)
{
switch (ptr[2] & ~0x10) {
case 1:
case 5:
case 9:
sprintf(tmpdeb, "%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(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4);
break;
default:
if (!(ptr[2] & 1)) {
sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1);
break;
} else
return "invalid command";
}
return tmpdeb;
}
void
Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir)
{
u_char *ptr;
ptr = skb->data;
if (ptr[0] & 1 || !(ptr[1] & 1))
debugl1(cs, "Address not LAPD");
else
debugl1(cs, "%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);
}
#endif
static void
l1_reset(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F3);
}
static void
l1_deact_cnf(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_F3);
if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
}
static void
l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_F3);
FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
}
static void
l1_power_up_s(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) {
FsmChangeState(fi, ST_L1_F4);
st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
} else
FsmChangeState(fi, ST_L1_F3);
}
static void
l1_go_F5(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F5);
}
static void
l1_go_F8(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_F8);
}
static void
l1_info2_ind(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
#ifdef HISAX_UINTERFACE
if (test_bit(FLG_L1_UINT, &st->l1.Flags))
FsmChangeState(fi, ST_L1_SYNC2);
else
#endif
FsmChangeState(fi, ST_L1_F6);
st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
}
static void
l1_info4_ind(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
#ifdef HISAX_UINTERFACE
if (test_bit(FLG_L1_UINT, &st->l1.Flags))
FsmChangeState(fi, ST_L1_TRANS);
else
#endif
FsmChangeState(fi, ST_L1_F7);
st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags))
FsmDelTimer(&st->l1.timer, 4);
if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) {
if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags))
FsmDelTimer(&st->l1.timer, 3);
FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2);
test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
}
}
static void
l1_timer3(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);
if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
L1deactivated(st->l1.hardware);
#ifdef HISAX_UINTERFACE
if (!test_bit(FLG_L1_UINT, &st->l1.Flags))
#endif
if (st->l1.l1m.state != ST_L1_F6) {
FsmChangeState(fi, ST_L1_F3);
st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
}
}
static void
l1_timer_act(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags);
test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
L1activated(st->l1.hardware);
}
static void
l1_timer_deact(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags);
L1deactivated(st->l1.hardware);
st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL);
}
static void
l1_activate_s(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
st->l1.l1hw(st, HW_RESET | REQUEST, NULL);
}
static void
l1_activate_no(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) {
test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
L1deactivated(st->l1.hardware);
}
}
static struct FsmNode L1SFnList[] __initdata =
{
{ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},
{ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
{ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},
{ST_L1_F3, EV_RESET_IND, l1_reset},
{ST_L1_F4, EV_RESET_IND, l1_reset},
{ST_L1_F5, EV_RESET_IND, l1_reset},
{ST_L1_F6, EV_RESET_IND, l1_reset},
{ST_L1_F7, EV_RESET_IND, l1_reset},
{ST_L1_F8, EV_RESET_IND, l1_reset},
{ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf},
{ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf},
{ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf},
{ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},
{ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},
{ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},
{ST_L1_F6, EV_DEACT_IND, l1_deact_req_s},
{ST_L1_F7, EV_DEACT_IND, l1_deact_req_s},
{ST_L1_F8, EV_DEACT_IND, l1_deact_req_s},
{ST_L1_F3, EV_POWER_UP, l1_power_up_s},
{ST_L1_F4, EV_RSYNC_IND, l1_go_F5},
{ST_L1_F6, EV_RSYNC_IND, l1_go_F8},
{ST_L1_F7, EV_RSYNC_IND, l1_go_F8},
{ST_L1_F3, EV_INFO2_IND, l1_info2_ind},
{ST_L1_F4, EV_INFO2_IND, l1_info2_ind},
{ST_L1_F5, EV_INFO2_IND, l1_info2_ind},
{ST_L1_F7, EV_INFO2_IND, l1_info2_ind},
{ST_L1_F8, EV_INFO2_IND, l1_info2_ind},
{ST_L1_F3, EV_INFO4_IND, l1_info4_ind},
{ST_L1_F4, EV_INFO4_IND, l1_info4_ind},
{ST_L1_F5, EV_INFO4_IND, l1_info4_ind},
{ST_L1_F6, EV_INFO4_IND, l1_info4_ind},
{ST_L1_F8, EV_INFO4_IND, l1_info4_ind},
{ST_L1_F3, EV_TIMER3, l1_timer3},
{ST_L1_F4, EV_TIMER3, l1_timer3},
{ST_L1_F5, EV_TIMER3, l1_timer3},
{ST_L1_F6, EV_TIMER3, l1_timer3},
{ST_L1_F8, EV_TIMER3, l1_timer3},
{ST_L1_F7, EV_TIMER_ACT, l1_timer_act},
{ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact},
{ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact},
{ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact},
{ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact},
{ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact},
{ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
};
#ifdef HISAX_UINTERFACE
static void
l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_RESET);
FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
}
static void
l1_power_up_u(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
}
static void
l1_info0_ind(struct FsmInst *fi, int event, void *arg)
{
FsmChangeState(fi, ST_L1_DEACT);
}
static void
l1_activate_u(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL);
}
static struct FsmNode L1UFnList[] __initdata =
{
{ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u},
{ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u},
{ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u},
{ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u},
{ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u},
{ST_L1_DEACT, EV_POWER_UP, l1_power_up_u},
{ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind},
{ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind},
{ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind},
{ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind},
{ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind},
{ST_L1_RESET, EV_INFO4_IND, l1_info4_ind},
{ST_L1_DEACT, EV_TIMER3, l1_timer3},
{ST_L1_SYNC2, EV_TIMER3, l1_timer3},
{ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act},
{ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact},
{ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact},
{ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact},
};
#endif
static void
l1b_activate(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_WAIT_ACT);
FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2);
}
static void
l1b_deactivate(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_WAIT_DEACT);
FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2);
}
static void
l1b_timer_act(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_ACTIV);
st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
}
static void
l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L1_NULL);
st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
}
static struct FsmNode L1BFnList[] __initdata =
{
{ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate},
{ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act},
{ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate},
{ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact},
};
int __init
Isdnl1New(void)
{
int retval;
l1fsm_s.state_count = L1S_STATE_COUNT;
l1fsm_s.event_count = L1_EVENT_COUNT;
l1fsm_s.strEvent = strL1Event;
l1fsm_s.strState = strL1SState;
retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList));
if (retval)
return retval;
l1fsm_b.state_count = L1B_STATE_COUNT;
l1fsm_b.event_count = L1_EVENT_COUNT;
l1fsm_b.strEvent = strL1Event;
l1fsm_b.strState = strL1BState;
retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList));
if (retval) {
FsmFree(&l1fsm_s);
return retval;
}
#ifdef HISAX_UINTERFACE
l1fsm_u.state_count = L1U_STATE_COUNT;
l1fsm_u.event_count = L1_EVENT_COUNT;
l1fsm_u.strEvent = strL1Event;
l1fsm_u.strState = strL1UState;
retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList));
if (retval) {
FsmFree(&l1fsm_s);
FsmFree(&l1fsm_b);
return retval;
}
#endif
return 0;
}
void Isdnl1Free(void)
{
#ifdef HISAX_UINTERFACE
FsmFree(&l1fsm_u);
#endif
FsmFree(&l1fsm_s);
FsmFree(&l1fsm_b);
}
static void
dch_l2l1(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
switch (pr) {
case (PH_DATA | REQUEST):
case (PH_PULL | REQUEST):
case (PH_PULL | INDICATION):
st->l1.l1hw(st, pr, arg);
break;
case (PH_ACTIVATE | REQUEST):
if (cs->debug)
debugl1(cs, "PH_ACTIVATE_REQ %s",
st->l1.l1m.fsm->strState[st->l1.l1m.state]);
if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
else {
test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags);
FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg);
}
break;
case (PH_TESTLOOP | REQUEST):
if (1 & (long) arg)
debugl1(cs, "PH_TEST_LOOP B1");
if (2 & (long) arg)
debugl1(cs, "PH_TEST_LOOP B2");
if (!(3 & (long) arg))
debugl1(cs, "PH_TEST_LOOP DISABLED");
st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg);
break;
default:
if (cs->debug)
debugl1(cs, "dch_l2l1 msg %04X unhandled", pr);
break;
}
}
void
l1_msg(struct IsdnCardState *cs, int pr, void *arg) {
struct PStack *st;
st = cs->stlist;
while (st) {
switch (pr) {
case (HW_RESET | INDICATION):
FsmEvent(&st->l1.l1m, EV_RESET_IND, arg);
break;
case (HW_DEACTIVATE | CONFIRM):
FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg);
break;
case (HW_DEACTIVATE | INDICATION):
FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg);
break;
case (HW_POWERUP | CONFIRM):
FsmEvent(&st->l1.l1m, EV_POWER_UP, arg);
break;
case (HW_RSYNC | INDICATION):
FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg);
break;
case (HW_INFO2 | INDICATION):
FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg);
break;
case (HW_INFO4_P8 | INDICATION):
case (HW_INFO4_P10 | INDICATION):
FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg);
break;
default:
if (cs->debug)
debugl1(cs, "%s %04X unhandled", __func__, pr);
break;
}
st = st->next;
}
}
void
l1_msg_b(struct PStack *st, int pr, void *arg) {
switch (pr) {
case (PH_ACTIVATE | REQUEST):
FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL);
break;
case (PH_DEACTIVATE | REQUEST):
FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL);
break;
}
}
void
setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.hardware = cs;
st->protocol = cs->protocol;
st->l1.l1m.fsm = &l1fsm_s;
st->l1.l1m.state = ST_L1_F3;
st->l1.Flags = 0;
#ifdef HISAX_UINTERFACE
if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) {
st->l1.l1m.fsm = &l1fsm_u;
st->l1.l1m.state = ST_L1_RESET;
st->l1.Flags = FLG_L1_UINT;
}
#endif
st->l1.l1m.debug = cs->debug;
st->l1.l1m.userdata = st;
st->l1.l1m.userint = 0;
st->l1.l1m.printdebug = l1m_debug;
FsmInitTimer(&st->l1.l1m, &st->l1.timer);
setstack_tei(st);
setstack_manager(st);
st->l1.stlistp = &(cs->stlist);
st->l2.l2l1 = dch_l2l1;
if (cs->setstack_d)
cs->setstack_d(st, cs);
}
void
setstack_l1_B(struct PStack *st)
{
struct IsdnCardState *cs = st->l1.hardware;
st->l1.l1m.fsm = &l1fsm_b;
st->l1.l1m.state = ST_L1_NULL;
st->l1.l1m.debug = cs->debug;
st->l1.l1m.userdata = st;
st->l1.l1m.userint = 0;
st->l1.l1m.printdebug = l1m_debug;
st->l1.Flags = 0;
FsmInitTimer(&st->l1.l1m, &st->l1.timer);
}

View File

@ -1,32 +0,0 @@
/* $Id: isdnl1.h,v 2.12.2.3 2004/02/11 13:21:34 keil Exp $
*
* Layer 1 defines
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define D_RCVBUFREADY 0
#define D_XMTBUFREADY 1
#define D_L1STATECHANGE 2
#define D_CLEARBUSY 3
#define D_RX_MON0 4
#define D_RX_MON1 5
#define D_TX_MON0 6
#define D_TX_MON1 7
#define E_RCVBUFREADY 8
#define B_RCVBUFREADY 0
#define B_XMTBUFREADY 1
#define B_ACKPENDING 2
__printf(2, 3)
void debugl1(struct IsdnCardState *cs, char *fmt, ...);
void DChannel_proc_xmt(struct IsdnCardState *cs);
void DChannel_proc_rcv(struct IsdnCardState *cs);
void l1_msg(struct IsdnCardState *cs, int pr, void *arg);
void l1_msg_b(struct PStack *st, int pr, void *arg);
void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf,
int dir);
void BChannel_bh(struct work_struct *work);

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
/* $Id: isdnl2.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $
*
* Layer 2 defines
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#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

View File

@ -1,594 +0,0 @@
/* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $
*
* Author Karsten Keil
* based on the teles driver from Jan den Ouden
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For changes and modifications please read
* Documentation/isdn/HiSax.cert
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
*/
#include <linux/init.h>
#include <linux/slab.h>
#include "hisax.h"
#include "isdnl3.h"
const char *l3_revision = "$Revision: 2.22.2.3 $";
static struct Fsm l3fsm;
enum {
ST_L3_LC_REL,
ST_L3_LC_ESTAB_WAIT,
ST_L3_LC_REL_DELAY,
ST_L3_LC_REL_WAIT,
ST_L3_LC_ESTAB,
};
#define L3_STATE_COUNT (ST_L3_LC_ESTAB + 1)
static char *strL3State[] =
{
"ST_L3_LC_REL",
"ST_L3_LC_ESTAB_WAIT",
"ST_L3_LC_REL_DELAY",
"ST_L3_LC_REL_WAIT",
"ST_L3_LC_ESTAB",
};
enum {
EV_ESTABLISH_REQ,
EV_ESTABLISH_IND,
EV_ESTABLISH_CNF,
EV_RELEASE_REQ,
EV_RELEASE_CNF,
EV_RELEASE_IND,
EV_TIMEOUT,
};
#define L3_EVENT_COUNT (EV_TIMEOUT + 1)
static char *strL3Event[] =
{
"EV_ESTABLISH_REQ",
"EV_ESTABLISH_IND",
"EV_ESTABLISH_CNF",
"EV_RELEASE_REQ",
"EV_RELEASE_CNF",
"EV_RELEASE_IND",
"EV_TIMEOUT",
};
static __printf(2, 3) void
l3m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
struct PStack *st = fi->userdata;
va_start(args, fmt);
VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args);
va_end(args);
}
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)
{ /* improved length check (Werner Cornelius) */
if ((pend - p) < 2)
return (NULL);
if (*(p + 1) > (pend - (p + 2)))
return (NULL);
return (p);
}
if (*p > ie)
return (NULL);
}
p++;
l = *p++;
p += l;
codeset = maincodeset;
}
}
return (NULL);
}
int
getcallref(u_char *p)
{
int l, cr = 0;
p++; /* prot discr */
if (*p & 0xfe) /* wrong callref BRI only 1 octet*/
return (-2);
l = 0xf & *p++; /* callref length */
if (!l) /* dummy CallRef */
return (-1);
cr = *p++;
return (cr);
}
static int OrigCallRef = 0;
int
newcallref(void)
{
if (OrigCallRef == 127)
OrigCallRef = 1;
else
OrigCallRef++;
return (OrigCallRef);
}
void
newl3state(struct l3_process *pc, int state)
{
if (pc->debug & L3_DEB_STATE)
l3_debug(pc->st, "%s cr %d %d --> %d", __func__,
pc->callref & 0x7F,
pc->state, state);
pc->state = state;
}
static void
L3ExpireTimer(struct timer_list *timer)
{
struct L3Timer *t = from_timer(t, timer, tl);
t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc);
}
void
L3InitTimer(struct l3_process *pc, struct L3Timer *t)
{
t->pc = pc;
timer_setup(&t->tl, L3ExpireTimer, 0);
}
void
L3DelTimer(struct L3Timer *t)
{
del_timer(&t->tl);
}
int
L3AddTimer(struct L3Timer *t,
int millisec, int event)
{
if (timer_pending(&t->tl)) {
printk(KERN_WARNING "L3AddTimer: timer already active!\n");
return -1;
}
t->event = event;
t->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&t->tl);
return 0;
}
void
StopAllL3Timer(struct l3_process *pc)
{
L3DelTimer(&pc->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);
}
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;
HiSax_putstatus(st->l1.hardware, "L3", "no D protocol");
if (skb) {
dev_kfree_skb(skb);
}
}
static int
no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
{
printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n", ic->arg & 0xFF);
return (-1);
}
struct l3_process
*getl3proc(struct PStack *st, int cr)
{
struct l3_process *p = st->l3.proc;
while (p)
if (p->callref == cr)
return (p);
else
p = p->next;
return (NULL);
}
struct l3_process
*new_l3_process(struct PStack *st, int cr)
{
struct l3_process *p, *np;
if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr);
return (NULL);
}
if (!st->l3.proc)
st->l3.proc = p;
else {
np = st->l3.proc;
while (np->next)
np = np->next;
np->next = p;
}
p->next = NULL;
p->debug = st->l3.debug;
p->callref = cr;
p->state = 0;
p->chan = NULL;
p->st = st;
p->N303 = st->l3.N303;
L3InitTimer(p, &p->timer);
return (p);
};
void
release_l3_process(struct l3_process *p)
{
struct l3_process *np, *pp = NULL;
if (!p)
return;
np = p->st->l3.proc;
while (np) {
if (np == p) {
StopAllL3Timer(p);
if (pp)
pp->next = np->next;
else if (!(p->st->l3.proc = np->next) &&
!test_bit(FLG_PTP, &p->st->l2.flag)) {
if (p->debug)
l3_debug(p->st, "release_l3_process: last process");
if (skb_queue_empty(&p->st->l3.squeue)) {
if (p->debug)
l3_debug(p->st, "release_l3_process: release link");
if (p->st->protocol != ISDN_PTYPE_NI1)
FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
else
FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL);
} else {
if (p->debug)
l3_debug(p->st, "release_l3_process: not release link");
}
}
kfree(p);
return;
}
pp = np;
np = np->next;
}
printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref);
l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref);
};
static void
l3ml3p(struct PStack *st, int pr)
{
struct l3_process *p = st->l3.proc;
struct l3_process *np;
while (p) {
/* p might be kfreed under us, so we need to save where we want to go on */
np = p->next;
st->l3.l3ml3(st, pr, p);
p = np;
}
}
void
setstack_l3dc(struct PStack *st, struct Channel *chanp)
{
char tmp[64];
st->l3.proc = NULL;
st->l3.global = NULL;
skb_queue_head_init(&st->l3.squeue);
st->l3.l3m.fsm = &l3fsm;
st->l3.l3m.state = ST_L3_LC_REL;
st->l3.l3m.debug = 1;
st->l3.l3m.userdata = st;
st->l3.l3m.userint = 0;
st->l3.l3m.printdebug = l3m_debug;
FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer);
strcpy(st->l3.debug_id, "L3DC ");
st->lli.l4l3_proto = no_l3_proto_spec;
#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->lli.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
st->l3.l3ml3 = no_l3_proto;
printk(KERN_INFO "HiSax: Leased line mode\n");
} else {
st->lli.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
st->l3.l3ml3 = 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);
st->protocol = -1;
}
}
static void
isdnl3_trans(struct PStack *st, int pr, void *arg) {
st->l3.l3l2(st, pr, arg);
}
void
releasestack_isdnl3(struct PStack *st)
{
while (st->l3.proc)
release_l3_process(st->l3.proc);
if (st->l3.global) {
StopAllL3Timer(st->l3.global);
kfree(st->l3.global);
st->l3.global = NULL;
}
FsmDelTimer(&st->l3.l3m_timer, 54);
skb_queue_purge(&st->l3.squeue);
}
void
setstack_l3bc(struct PStack *st, struct Channel *chanp)
{
st->l3.proc = NULL;
st->l3.global = NULL;
skb_queue_head_init(&st->l3.squeue);
st->l3.l3m.fsm = &l3fsm;
st->l3.l3m.state = ST_L3_LC_REL;
st->l3.l3m.debug = 1;
st->l3.l3m.userdata = st;
st->l3.l3m.userint = 0;
st->l3.l3m.printdebug = l3m_debug;
strcpy(st->l3.debug_id, "L3BC ");
st->lli.l4l3 = isdnl3_trans;
}
#define DREL_TIMER_VALUE 40000
static void
lc_activate(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT);
st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL);
}
static void
lc_connect(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
int dequeued = 0;
FsmChangeState(fi, ST_L3_LC_ESTAB);
while ((skb = skb_dequeue(&st->l3.squeue))) {
st->l3.l3l2(st, DL_DATA | REQUEST, skb);
dequeued++;
}
if ((!st->l3.proc) && dequeued) {
if (st->l3.debug)
l3_debug(st, "lc_connect: release link");
FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
} else
l3ml3p(st, DL_ESTABLISH | INDICATION);
}
static void
lc_connected(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
int dequeued = 0;
FsmDelTimer(&st->l3.l3m_timer, 51);
FsmChangeState(fi, ST_L3_LC_ESTAB);
while ((skb = skb_dequeue(&st->l3.squeue))) {
st->l3.l3l2(st, DL_DATA | REQUEST, skb);
dequeued++;
}
if ((!st->l3.proc) && dequeued) {
if (st->l3.debug)
l3_debug(st, "lc_connected: release link");
FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
} else
l3ml3p(st, DL_ESTABLISH | CONFIRM);
}
static void
lc_start_delay(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L3_LC_REL_DELAY);
FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
}
static void
lc_start_delay_check(struct FsmInst *fi, int event, void *arg)
/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L3_LC_REL_DELAY);
/* 19/09/00 - GE timer not user for NI-1 */
if (st->protocol != ISDN_PTYPE_NI1)
FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
}
static void
lc_release_req(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
if (test_bit(FLG_L2BLOCK, &st->l2.flag)) {
if (st->l3.debug)
l3_debug(st, "lc_release_req: l2 blocked");
/* restart release timer */
FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51);
} else {
FsmChangeState(fi, ST_L3_LC_REL_WAIT);
st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL);
}
}
static void
lc_release_ind(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmDelTimer(&st->l3.l3m_timer, 52);
FsmChangeState(fi, ST_L3_LC_REL);
skb_queue_purge(&st->l3.squeue);
l3ml3p(st, DL_RELEASE | INDICATION);
}
static void
lc_release_cnf(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
FsmChangeState(fi, ST_L3_LC_REL);
skb_queue_purge(&st->l3.squeue);
l3ml3p(st, DL_RELEASE | CONFIRM);
}
/* *INDENT-OFF* */
static struct FsmNode L3FnList[] __initdata =
{
{ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate},
{ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect},
{ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect},
{ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected},
{ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay},
{ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind},
{ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind},
{ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay_check},
{ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind},
{ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected},
{ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req},
{ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf},
{ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate},
};
/* *INDENT-ON* */
void
l3_msg(struct PStack *st, int pr, void *arg)
{
switch (pr) {
case (DL_DATA | REQUEST):
if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
st->l3.l3l2(st, pr, arg);
} else {
struct sk_buff *skb = arg;
skb_queue_tail(&st->l3.squeue, skb);
FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
}
break;
case (DL_ESTABLISH | REQUEST):
FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL);
break;
case (DL_ESTABLISH | CONFIRM):
FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL);
break;
case (DL_ESTABLISH | INDICATION):
FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL);
break;
case (DL_RELEASE | INDICATION):
FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL);
break;
case (DL_RELEASE | CONFIRM):
FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL);
break;
case (DL_RELEASE | REQUEST):
FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL);
break;
}
}
int __init
Isdnl3New(void)
{
l3fsm.state_count = L3_STATE_COUNT;
l3fsm.event_count = L3_EVENT_COUNT;
l3fsm.strEvent = strL3Event;
l3fsm.strState = strL3State;
return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList));
}
void
Isdnl3Free(void)
{
FsmFree(&l3fsm);
}

View File

@ -1,42 +0,0 @@
/* $Id: isdnl3.h,v 2.6.6.2 2001/09/23 22:24:49 kai Exp $
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define SBIT(state) (1 << state)
#define ALL_STATES 0x03ffffff
#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
#define L3_DEB_CHECK 0x10
#define L3_DEB_SI 0x20
struct stateentry {
int state;
int primitive;
void (*rout) (struct l3_process *, u8, void *);
};
#define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args)
struct PStack;
void newl3state(struct l3_process *pc, int state);
void L3InitTimer(struct l3_process *pc, struct L3Timer *t);
void L3DelTimer(struct L3Timer *t);
int L3AddTimer(struct L3Timer *t, int millisec, int event);
void StopAllL3Timer(struct l3_process *pc);
struct sk_buff *l3_alloc_skb(int len);
struct l3_process *new_l3_process(struct PStack *st, int cr);
void release_l3_process(struct l3_process *p);
struct l3_process *getl3proc(struct PStack *st, int cr);
void l3_msg(struct PStack *st, int pr, void *arg);
void setstack_dss1(struct PStack *st);
void setstack_ni1(struct PStack *st);
void setstack_1tr6(struct PStack *st);

View File

@ -1,305 +0,0 @@
/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $
*
* low level stuff for Siemens I-Surf/I-Talk cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "isar.h"
#include "isdnl1.h"
#include <linux/isapnp.h>
static const char *ISurf_revision = "$Revision: 1.12.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define ISURF_ISAR_RESET 1
#define ISURF_ISAC_RESET 2
#define ISURF_ISAR_EA 4
#define ISURF_ARCOFI_RESET 8
#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
#define ISURF_ISAR_OFFSET 0
#define ISURF_ISAC_OFFSET 0x100
#define ISURF_IOMEM_SIZE 0x400
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readb(cs->hw.isurf.isac + offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writeb(value, cs->hw.isurf.isac + offset); mb();
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
register int i;
for (i = 0; i < size; i++)
data[i] = readb(cs->hw.isurf.isac);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
register int i;
for (i = 0; i < size; i++) {
writeb(data[i], cs->hw.isurf.isac); mb();
}
}
/* ISAR access routines
* mode = 0 access with IRQ on
* mode = 1 access with IRQ off
* mode = 2 access with IRQ off and using last offset
*/
static u_char
ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
{
return (readb(cs->hw.isurf.isar + offset));
}
static void
WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
{
writeb(value, cs->hw.isurf.isar + offset); mb();
}
static irqreturn_t
isurf_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
int cnt = 5;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
Start_ISAR:
if (val & ISAR_IRQSTA)
isar_int_main(cs);
val = readb(cs->hw.isurf.isac + ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
if ((val & ISAR_IRQSTA) && --cnt) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "ISAR IntStat after IntRoutine");
goto Start_ISAR;
}
val = readb(cs->hw.isurf.isac + ISAC_ISTA);
if (val && --cnt) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (!cnt)
printk(KERN_WARNING "ISurf IRQ LOOP\n");
writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK); mb();
writeb(0, cs->hw.isurf.isac + ISAC_MASK); mb();
writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_isurf(struct IsdnCardState *cs)
{
release_region(cs->hw.isurf.reset, 1);
iounmap(cs->hw.isurf.isar);
release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
}
static void
reset_isurf(struct IsdnCardState *cs, u_char chips)
{
printk(KERN_INFO "ISurf: resetting card\n");
byteout(cs->hw.isurf.reset, chips); /* Reset On */
mdelay(10);
byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
mdelay(10);
}
static int
ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_isurf(cs, ISURF_RESET);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_isurf(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
reset_isurf(cs, ISURF_RESET);
clear_pending_isac_ints(cs);
writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
initisac(cs);
initisar(cs);
/* Reenable ISAC IRQ */
cs->writeisac(cs, ISAC_MASK, 0);
/* RESET Receiver and Transmitter */
cs->writeisac(cs, ISAC_CMDR, 0x41);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int
isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
int ret;
u_long flags;
if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
ret = isar_auxcmd(cs, ic);
spin_lock_irqsave(&cs->lock, flags);
if (!ret) {
reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
ISURF_ARCOFI_RESET);
initisac(cs);
cs->writeisac(cs, ISAC_MASK, 0);
cs->writeisac(cs, ISAC_CMDR, 0x41);
}
spin_unlock_irqrestore(&cs->lock, flags);
return (ret);
}
return (isar_auxcmd(cs, ic));
}
#ifdef __ISAPNP__
static struct pnp_card *pnp_c = NULL;
#endif
int setup_isurf(struct IsdnCard *card)
{
int ver;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, ISurf_revision);
printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_ISURF)
return (0);
if (card->para[1] && card->para[2]) {
cs->hw.isurf.reset = card->para[1];
cs->hw.isurf.phymem = card->para[2];
cs->irq = card->para[0];
} else {
#ifdef __ISAPNP__
if (isapnp_present()) {
struct pnp_dev *pnp_d = NULL;
int err;
cs->subtyp = 0;
if ((pnp_c = pnp_find_card(
ISAPNP_VENDOR('S', 'I', 'E'),
ISAPNP_FUNCTION(0x0010), pnp_c))) {
if (!(pnp_d = pnp_find_dev(pnp_c,
ISAPNP_VENDOR('S', 'I', 'E'),
ISAPNP_FUNCTION(0x0010), pnp_d))) {
printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
return (0);
}
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
pr_warn("%s: pnp_activate_dev ret=%d\n",
__func__, err);
return 0;
}
cs->hw.isurf.reset = pnp_port_start(pnp_d, 0);
cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1);
cs->irq = pnp_irq(pnp_d, 0);
if (cs->irq == -1 || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
pnp_disable_dev(pnp_d);
return (0);
}
} else {
printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
return (0);
}
} else {
printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
return (0);
}
#else
printk(KERN_WARNING "HiSax: Siemens I-Surf port/mem not set\n");
return (0);
#endif
}
if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) {
printk(KERN_WARNING
"HiSax: Siemens I-Surf config port %x already in use\n",
cs->hw.isurf.reset);
return (0);
}
if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) {
printk(KERN_WARNING "HiSax: Siemens I-Surf memory region "
"%lx-%lx already in use\n",
cs->hw.isurf.phymem,
cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
release_region(cs->hw.isurf.reset, 1);
return (0);
}
cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
printk(KERN_INFO
"ISurf: defined at 0x%x 0x%lx IRQ %d\n",
cs->hw.isurf.reset,
cs->hw.isurf.phymem,
cs->irq);
setup_isac(cs);
cs->cardmsg = &ISurf_card_msg;
cs->irq_func = &isurf_interrupt;
cs->auxcmd = &isurf_auxcmd;
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
test_and_set_bit(HW_ISAR, &cs->HW_Flags);
ISACVersion(cs, "ISurf:");
cs->BC_Read_Reg = &ReadISAR;
cs->BC_Write_Reg = &WriteISAR;
cs->BC_Send_Data = &isar_fill_fifo;
ver = ISARVersion(cs, "ISurf:");
if (ver < 0) {
printk(KERN_WARNING
"ISurf: wrong ISAR version (ret = %d)\n", ver);
release_io_isurf(cs);
return (0);
}
return (1);
}

View File

@ -1,316 +0,0 @@
/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for ITK ix1-micro Rev.2 isdn cards
* derived from the original file teles3.c from Karsten Keil
*
* Author Klaus-Peter Nischke
* Copyright by Klaus-Peter Nischke, ITK AG
* <klaus@nischke.do.eunet.de>
* by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Klaus-Peter Nischke
* Deusener Str. 287
* 44369 Dortmund
* Germany
*/
#include <linux/init.h>
#include <linux/isapnp.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *ix1_revision = "$Revision: 2.12.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(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 TIMEOUT 50
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.ix1.hscx_ale,
cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.ix1.hscx_ale,
cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
}
#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
ix1micro_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_ix1micro(struct IsdnCardState *cs)
{
if (cs->hw.ix1.cfg_reg)
release_region(cs->hw.ix1.cfg_reg, 4);
}
static void
ix1_reset(struct IsdnCardState *cs)
{
int cnt;
/* reset isac */
cnt = 3 * (HZ / 10) + 1;
while (cnt--) {
byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
HZDELAY(1); /* wait >=10 ms */
}
byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
}
static int
ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
ix1_reset(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_ix1micro(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
ix1_reset(cs);
inithscxisac(cs, 3);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
#ifdef __ISAPNP__
static struct isapnp_device_id itk_ids[] = {
{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
(unsigned long) "ITK micro 2" },
{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
(unsigned long) "ITK micro 2." },
{ 0, }
};
static struct isapnp_device_id *ipid = &itk_ids[0];
static struct pnp_card *pnp_c = NULL;
#endif
int setup_ix1micro(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, ix1_revision);
printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_IX1MICROR2)
return (0);
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d;
while (ipid->card_vendor) {
if ((pnp_c = pnp_find_card(ipid->card_vendor,
ipid->card_device, pnp_c))) {
pnp_d = NULL;
if ((pnp_d = pnp_find_dev(pnp_c,
ipid->vendor, ipid->function, pnp_d))) {
int err;
printk(KERN_INFO "HiSax: %s detected\n",
(char *)ipid->driver_data);
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[0] = pnp_irq(pnp_d, 0);
if (card->para[0] == -1 || !card->para[1]) {
printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
return (0);
}
break;
} else {
printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
}
}
ipid++;
pnp_c = NULL;
}
if (!ipid->card_vendor) {
printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
return (0);
}
}
#endif
/* IO-Ports */
cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
cs->hw.ix1.cfg_reg = card->para[1];
cs->irq = card->para[0];
if (cs->hw.ix1.cfg_reg) {
if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) {
printk(KERN_WARNING
"HiSax: ITK ix1-micro Rev.2 config port "
"%x-%x already in use\n",
cs->hw.ix1.cfg_reg,
cs->hw.ix1.cfg_reg + 4);
return (0);
}
}
printk(KERN_INFO "HiSax: ITK ix1-micro Rev.2 config irq:%d io:0x%X\n",
cs->irq, cs->hw.ix1.cfg_reg);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &ix1_card_msg;
cs->irq_func = &ix1micro_interrupt;
ISACVersion(cs, "ix1-Micro:");
if (HscxVersion(cs, "ix1-Micro:")) {
printk(KERN_WARNING
"ix1-Micro: wrong HSCX versions check IO address\n");
release_io_ix1micro(cs);
return (0);
}
return (1);
}

View File

@ -1,305 +0,0 @@
/* $Id: jade.c,v 1.9.2.4 2004/01/14 16:04:48 keil Exp $
*
* JADE stuff (derived from original hscx.c)
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "hscx.h"
#include "jade.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/slab.h>
int
JadeVersion(struct IsdnCardState *cs, char *s)
{
int ver;
int to = 50;
cs->BC_Write_Reg(cs, -1, 0x50, 0x19);
while (to) {
udelay(1);
ver = cs->BC_Read_Reg(cs, -1, 0x60);
to--;
if (ver)
break;
if (!to) {
printk(KERN_INFO "%s JADE version not obtainable\n", s);
return (0);
}
}
/* Wait for the JADE */
udelay(10);
/* Read version */
ver = cs->BC_Read_Reg(cs, -1, 0x60);
printk(KERN_INFO "%s JADE version: %d\n", s, ver);
return (1);
}
/* Write to indirect accessible jade register set */
static void
jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
{
int to = 50;
u_char ret;
/* Write the data */
cs->BC_Write_Reg(cs, -1, COMM_JADE + 1, value);
/* Say JADE we wanna write indirect reg 'reg' */
cs->BC_Write_Reg(cs, -1, COMM_JADE, reg);
to = 50;
/* Wait for RDY goes high */
while (to) {
udelay(1);
ret = cs->BC_Read_Reg(cs, -1, COMM_JADE);
to--;
if (ret & 1)
/* Got acknowledge */
break;
if (!to) {
printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value);
return;
}
}
}
static void
modejade(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
int jade = bcs->hw.hscx.hscx;
if (cs->debug & L1_DEB_HSCX) {
debugl1(cs, "jade %c mode %d ichan %d", 'A' + jade, mode, bc);
}
bcs->mode = mode;
bcs->channel = bc;
cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO : 0x00));
cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU | jadeCCR0_ITF));
cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00);
jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08);
jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08);
jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00);
jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00);
cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07);
cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07);
if (bc == 0) {
cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00);
cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00);
} else {
cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04);
cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04);
}
switch (mode) {
case (L1_MODE_NULL):
cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO);
break;
case (L1_MODE_TRANS):
cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO | jadeMODE_RAC | jadeMODE_XAC));
break;
case (L1_MODE_HDLC):
cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC | jadeMODE_XAC));
break;
}
if (mode) {
cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES | jadeRCMD_RMC));
cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES);
/* Unmask ints */
cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8);
}
else
/* Mask ints */
cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00);
}
static void
jade_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.hscx.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n");
} else {
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->tx_skb = skb;
bcs->hw.hscx.count = 0;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
modejade(bcs, st->l1.mode, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
modejade(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
static void
close_jadestate(struct BCState *bcs)
{
modejade(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
kfree(bcs->blog);
bcs->blog = NULL;
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
static int
open_jadestate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for hscx.rcvbuf\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
return (1);
}
if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for bcs->blog\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
return (2);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
return (0);
}
static int
setstack_jade(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_jadestate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = jade_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
void
clear_pending_jade_ints(struct IsdnCardState *cs)
{
int val;
cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR);
debugl1(cs, "jade B ISTA %x", val);
val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR);
debugl1(cs, "jade A ISTA %x", val);
val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR);
debugl1(cs, "jade B STAR %x", val);
val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR);
debugl1(cs, "jade A STAR %x", val);
/* Unmask ints */
cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8);
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
}
void
initjade(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_jade;
cs->bcs[1].BC_SetStack = setstack_jade;
cs->bcs[0].BC_Close = close_jadestate;
cs->bcs[1].BC_Close = close_jadestate;
cs->bcs[0].hw.hscx.hscx = 0;
cs->bcs[1].hw.hscx.hscx = 1;
/* Stop DSP audio tx/rx */
jade_write_indirect(cs, 0x11, 0x0f);
jade_write_indirect(cs, 0x17, 0x2f);
/* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */
cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO);
cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO);
/* Power down, 1-Idle, RxTx least significant bit first */
cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00);
cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00);
/* Mask all interrupts */
cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
/* Setup host access to hdlc controller */
jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1 | jadeINDIRECT_HAH2));
/* Unmask HDLC int (don't forget DSP int later on)*/
cs->BC_Write_Reg(cs, -1, jade_INT, (jadeINT_HDLC1 | jadeINT_HDLC2));
/* once again TRANSPARENT */
modejade(cs->bcs, 0, 0);
modejade(cs->bcs + 1, 0, 0);
}

View File

@ -1,134 +0,0 @@
/* $Id: jade.h,v 1.5.2.3 2004/01/14 16:04:48 keil Exp $
*
* JADE specific defines
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/* All Registers original Siemens Spec */
#ifndef __JADE_H__
#define __JADE_H__
/* Special registers for access to indirect accessible JADE regs */
#define DIRECT_IO_JADE 0x0000 /* Jade direct io access area */
#define COMM_JADE 0x0040 /* Jade communication area */
/********************************************************************/
/* JADE-HDLC registers */
/********************************************************************/
#define jade_HDLC_RFIFO 0x00 /* R */
#define jade_HDLC_XFIFO 0x00 /* W */
#define jade_HDLC_STAR 0x20 /* R */
#define jadeSTAR_XDOV 0x80
#define jadeSTAR_XFW 0x40 /* Does not work*/
#define jadeSTAR_XCEC 0x20
#define jadeSTAR_RCEC 0x10
#define jadeSTAR_BSY 0x08
#define jadeSTAR_RNA 0x04
#define jadeSTAR_STR 0x02
#define jadeSTAR_STX 0x01
#define jade_HDLC_XCMD 0x20 /* W */
#define jadeXCMD_XF 0x80
#define jadeXCMD_XME 0x40
#define jadeXCMD_XRES 0x20
#define jadeXCMD_STX 0x01
#define jade_HDLC_RSTA 0x21 /* R */
#define jadeRSTA_VFR 0x80
#define jadeRSTA_RDO 0x40
#define jadeRSTA_CRC 0x20
#define jadeRSTA_RAB 0x10
#define jadeRSTA_MASK 0xF0
#define jade_HDLC_MODE 0x22 /* RW*/
#define jadeMODE_TMO 0x80
#define jadeMODE_RAC 0x40
#define jadeMODE_XAC 0x20
#define jadeMODE_TLP 0x10
#define jadeMODE_ERFS 0x02
#define jadeMODE_ETFS 0x01
#define jade_HDLC_RBCH 0x24 /* R */
#define jade_HDLC_RBCL 0x25 /* R */
#define jade_HDLC_RCMD 0x25 /* W */
#define jadeRCMD_RMC 0x80
#define jadeRCMD_RRES 0x40
#define jadeRCMD_RMD 0x20
#define jadeRCMD_STR 0x02
#define jade_HDLC_CCR0 0x26 /* RW*/
#define jadeCCR0_PU 0x80
#define jadeCCR0_ITF 0x40
#define jadeCCR0_C32 0x20
#define jadeCCR0_CRL 0x10
#define jadeCCR0_RCRC 0x08
#define jadeCCR0_XCRC 0x04
#define jadeCCR0_RMSB 0x02
#define jadeCCR0_XMSB 0x01
#define jade_HDLC_CCR1 0x27 /* RW*/
#define jadeCCR1_RCS0 0x80
#define jadeCCR1_RCONT 0x40
#define jadeCCR1_RFDIS 0x20
#define jadeCCR1_XCS0 0x10
#define jadeCCR1_XCONT 0x08
#define jadeCCR1_XFDIS 0x04
#define jade_HDLC_TSAR 0x28 /* RW*/
#define jade_HDLC_TSAX 0x29 /* RW*/
#define jade_HDLC_RCCR 0x2A /* RW*/
#define jade_HDLC_XCCR 0x2B /* RW*/
#define jade_HDLC_ISR 0x2C /* R */
#define jade_HDLC_IMR 0x2C /* W */
#define jadeISR_RME 0x80
#define jadeISR_RPF 0x40
#define jadeISR_RFO 0x20
#define jadeISR_XPR 0x10
#define jadeISR_XDU 0x08
#define jadeISR_ALLS 0x04
#define jade_INT 0x75
#define jadeINT_HDLC1 0x02
#define jadeINT_HDLC2 0x01
#define jadeINT_DSP 0x04
#define jade_INTR 0x70
/********************************************************************/
/* Indirect accessible JADE registers of common interest */
/********************************************************************/
#define jade_CHIPVERSIONNR 0x00 /* Does not work*/
#define jade_HDLCCNTRACCESS 0x10
#define jadeINDIRECT_HAH1 0x02
#define jadeINDIRECT_HAH2 0x01
#define jade_HDLC1SERRXPATH 0x1D
#define jade_HDLC1SERTXPATH 0x1E
#define jade_HDLC2SERRXPATH 0x1F
#define jade_HDLC2SERTXPATH 0x20
#define jadeINDIRECT_SLIN1 0x10
#define jadeINDIRECT_SLIN0 0x08
#define jadeINDIRECT_LMOD1 0x04
#define jadeINDIRECT_LMOD0 0x02
#define jadeINDIRECT_HHR 0x01
#define jadeINDIRECT_HHX 0x01
#define jade_RXAUDIOCH1CFG 0x11
#define jade_RXAUDIOCH2CFG 0x14
#define jade_TXAUDIOCH1CFG 0x17
#define jade_TXAUDIOCH2CFG 0x1A
extern int JadeVersion(struct IsdnCardState *cs, char *s);
extern void clear_pending_jade_ints(struct IsdnCardState *cs);
extern void initjade(struct IsdnCardState *cs);
#endif /* __JADE_H__ */

View File

@ -1,238 +0,0 @@
/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $
*
* Low level JADE IRQ stuff (derived from original hscx_irq.c)
*
* Author Roland Klabunde
* Copyright by Roland Klabunde <R.Klabunde@Berkom.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
static inline void
waitforCEC(struct IsdnCardState *cs, int jade, int reg)
{
int to = 50;
int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n");
}
static inline void
waitforXFW(struct IsdnCardState *cs, int jade)
{
/* Does not work on older jade versions, don't care */
}
static inline void
WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
{
waitforCEC(cs, jade, reg);
WRITEJADE(cs, jade, reg, data);
}
static void
jade_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct IsdnCardState *cs = bcs->cs;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "jade_empty_fifo");
if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "jade_empty_fifo: incoming packet too large");
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
bcs->hw.hscx.rcvidx = 0;
return;
}
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "jade_empty_fifo %c cnt %d",
bcs->hw.hscx.hscx ? 'B' : 'A', count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
static void
jade_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int more, count;
int fifo_size = 32;
u_char *ptr;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "jade_fill_fifo");
if (!bcs->tx_skb)
return;
if (bcs->tx_skb->len <= 0)
return;
more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
if (bcs->tx_skb->len > fifo_size) {
more = !0;
count = fifo_size;
} else
count = bcs->tx_skb->len;
waitforXFW(cs, bcs->hw.hscx.hscx);
ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hscx.count += count;
WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF | jadeXCMD_XME));
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "jade_fill_fifo %c cnt %d",
bcs->hw.hscx.hscx ? 'B' : 'A', count);
QuickHex(t, ptr, count);
debugl1(cs, "%s", bcs->blog);
}
}
static void
jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
{
u_char r;
struct BCState *bcs = cs->bcs + jade;
struct sk_buff *skb;
int fifo_size = 32;
int count;
int i_jade = (int) jade; /* To satisfy the compiler */
if (!test_bit(BC_FLG_INIT, &bcs->Flag))
return;
if (val & 0x80) { /* RME */
r = READJADE(cs, i_jade, jade_HDLC_RSTA);
if ((r & 0xf0) != 0xa0) {
if (!(r & 0x80))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %s invalid frame", (jade ? "B" : "A"));
if ((r & 0x40) && bcs->mode)
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c RDO mode=%d", 'A' + jade, bcs->mode);
if (!(r & 0x20))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c CRC error", 'A' + jade);
WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
} else {
count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
if (count == 0)
count = fifo_size;
jade_empty_fifo(bcs, count);
if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
if (cs->debug & L1_DEB_HSCX_FIFO)
debugl1(cs, "HX Frame %d", count);
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B" : "A"));
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
count);
skb_queue_tail(&bcs->rqueue, skb);
}
}
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
if (val & 0x40) { /* RPF */
jade_empty_fifo(bcs, fifo_size);
if (bcs->mode == L1_MODE_TRANS) {
/* receive audio data */
if (!(skb = dev_alloc_skb(fifo_size)))
printk(KERN_WARNING "HiSax: receive out of memory\n");
else {
skb_put_data(skb, bcs->hw.hscx.rcvbuf,
fifo_size);
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->hw.hscx.rcvidx = 0;
schedule_event(bcs, B_RCVBUFREADY);
}
}
if (val & 0x10) { /* XPR */
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
jade_fill_fifo(bcs);
return;
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->hw.hscx.count;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hscx.count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
jade_fill_fifo(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
}
static inline void
jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
{
struct BCState *bcs;
bcs = cs->bcs + jade;
if (val & jadeISR_RFO) {
/* handled with RDO */
val &= ~jadeISR_RFO;
}
if (val & jadeISR_XDU) {
/* relevant in HDLC mode only */
/* don't reset XPR here */
if (bcs->mode == 1)
jade_fill_fifo(bcs);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
bcs->tx_cnt += bcs->hw.hscx.count;
bcs->hw.hscx.count = 0;
}
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c EXIR %x Lost TX", 'A' + jade, val);
}
}
if (val & (jadeISR_RME | jadeISR_RPF | jadeISR_XPR)) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "JADE %c interrupt %x", 'A' + jade, val);
jade_interrupt(cs, val, jade);
}
}

View File

@ -1,932 +0,0 @@
/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $
*
* German 1TR6 D-channel protocol
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For changes and modifications please read
* Documentation/isdn/HiSax.cert
*
*/
#include "hisax.h"
#include "l3_1tr6.h"
#include "isdnl3.h"
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
*ptr++ = 0x1; \
*ptr++ = cref ^ 0x80; \
*ptr++ = mty
static void
l3_1TR6_message(struct l3_process *pc, 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, pc->callref, mt, pd);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
}
static void
l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg)
{
StopAllL3Timer(pc);
newl3state(pc, 19);
l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
L3AddTimer(&pc->timer, T308, CC_T308_1);
}
static void
l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
dev_kfree_skb(skb);
l3_1tr6_release_req(pc, 0, NULL);
}
static void
l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
{
dev_kfree_skb(skb);
if (pc->st->l3.debug & L3_DEB_WARN)
l3_debug(pc->st, "%s", msg);
l3_1tr6_release_req(pc, 0, NULL);
}
static void
l3_1tr6_setup_req(struct l3_process *pc, 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;
MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1);
teln = pc->para.setup.phone;
pc->para.spv = 0;
if (!isdigit(*teln)) {
switch (0x5f & *teln) {
case 'S':
pc->para.spv = 1;
break;
case 'C':
channel = 0x08;
/* fall through */
case 'P':
channel |= 0x80;
teln++;
if (*teln == '1')
channel |= 0x01;
else
channel |= 0x02;
break;
default:
if (pc->st->l3.debug & L3_DEB_WARN)
l3_debug(pc->st, "Wrong MSN Code");
break;
}
teln++;
}
if (channel) {
*p++ = 0x18; /* channel indicator */
*p++ = 1;
*p++ = channel;
}
if (pc->para.spv) { /* SPV ? */
/* NSF SPV */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_SPV; /* SPV */
*p++ = pc->para.setup.si1; /* 0 for all Services */
*p++ = pc->para.setup.si2; /* 0 for all Services */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_Activate; /* aktiviere SPV (default) */
*p++ = pc->para.setup.si1; /* 0 for all Services */
*p++ = pc->para.setup.si2; /* 0 for all Services */
}
eaz = pc->para.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++ = pc->para.setup.si1;
*p++ = pc->para.setup.si2;
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
skb_put_data(skb, tmp, l);
L3DelTimer(&pc->timer);
L3AddTimer(&pc->timer, T303, CC_T303);
newl3state(pc, 1);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
}
static void
l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
int bcfound = 0;
struct sk_buff *skb = arg;
/* Channel Identification */
p = findie(skb->data, skb->len, WE0_chanID, 0);
if (p) {
if (p[1] != 1) {
l3_1tr6_error(pc, "setup wrong chanID len", skb);
return;
}
if ((p[2] & 0xf4) != 0x80) {
l3_1tr6_error(pc, "setup wrong WE0_chanID", skb);
return;
}
if ((pc->para.bchannel = p[2] & 0x3))
bcfound++;
} else {
l3_1tr6_error(pc, "missing setup chanID", skb);
return;
}
p = skb->data;
if ((p = findie(p, skb->len, WE6_serviceInd, 6))) {
pc->para.setup.si1 = p[2];
pc->para.setup.si2 = p[3];
} else {
l3_1tr6_error(pc, "missing setup SI", skb);
return;
}
p = skb->data;
if ((p = findie(p, skb->len, WE0_destAddr, 0)))
iecpy(pc->para.setup.eazmsn, p, 1);
else
pc->para.setup.eazmsn[0] = 0;
p = skb->data;
if ((p = findie(p, skb->len, WE0_origAddr, 0))) {
iecpy(pc->para.setup.phone, p, 1);
} else
pc->para.setup.phone[0] = 0;
p = skb->data;
pc->para.spv = 0;
if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) {
if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
pc->para.spv = 1;
}
dev_kfree_skb(skb);
/* Signal all services, linklevel takes care of Service-Indicator */
if (bcfound) {
if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) {
l3_debug(pc->st, "non-digital call: %s -> %s",
pc->para.setup.phone,
pc->para.setup.eazmsn);
}
newl3state(pc, 6);
pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
} else
release_l3_process(pc);
}
static void
l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
L3DelTimer(&pc->timer);
p = skb->data;
newl3state(pc, 2);
if ((p = findie(p, skb->len, WE0_chanID, 0))) {
if (p[1] != 1) {
l3_1tr6_error(pc, "setup_ack wrong chanID len", skb);
return;
}
if ((p[2] & 0xf4) != 0x80) {
l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb);
return;
}
pc->para.bchannel = p[2] & 0x3;
} else {
l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb);
return;
}
dev_kfree_skb(skb);
L3AddTimer(&pc->timer, T304, CC_T304);
pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
}
static void
l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
struct sk_buff *skb = arg;
L3DelTimer(&pc->timer);
p = skb->data;
if ((p = findie(p, skb->len, WE0_chanID, 0))) {
if (p[1] != 1) {
l3_1tr6_error(pc, "call sent wrong chanID len", skb);
return;
}
if ((p[2] & 0xf4) != 0x80) {
l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb);
return;
}
if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) {
l3_1tr6_error(pc, "call sent wrong chanID value", skb);
return;
}
pc->para.bchannel = p[2] & 0x3;
} else {
l3_1tr6_error(pc, "missing call sent WE0_chanID", skb);
return;
}
dev_kfree_skb(skb);
L3AddTimer(&pc->timer, T310, CC_T310);
newl3state(pc, 3);
pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
}
static void
l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
dev_kfree_skb(skb);
L3DelTimer(&pc->timer); /* T304 */
newl3state(pc, 4);
pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
}
static void
l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
{
u_char *p;
int i, tmpcharge = 0;
char a_charge[8];
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 > pc->para.chargeinfo) {
pc->para.chargeinfo = tmpcharge;
pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
}
if (pc->st->l3.debug & L3_DEB_CHARGE) {
l3_debug(pc->st, "charging info %d",
pc->para.chargeinfo);
}
} else if (pc->st->l3.debug & L3_DEB_CHARGE)
l3_debug(pc->st, "charging info not found");
dev_kfree_skb(skb);
}
static void
l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
dev_kfree_skb(skb);
}
static void
l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
L3DelTimer(&pc->timer); /* T310 */
if (!findie(skb->data, skb->len, WE6_date, 6)) {
l3_1tr6_error(pc, "missing connect date", skb);
return;
}
newl3state(pc, 10);
dev_kfree_skb(skb);
pc->para.chargeinfo = 0;
pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
}
static void
l3_1tr6_rel(struct l3_process *pc, 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) {
pc->para.cause = p[2];
if (p[1] > 1)
pc->para.loc = p[3];
else
pc->para.loc = 0;
} else {
pc->para.cause = 0;
pc->para.loc = 0;
}
} else {
pc->para.cause = NO_CAUSE;
l3_1tr6_error(pc, "missing REL cause", skb);
return;
}
dev_kfree_skb(skb);
StopAllL3Timer(pc);
newl3state(pc, 0);
l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1);
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
static void
l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
dev_kfree_skb(skb);
StopAllL3Timer(pc);
newl3state(pc, 0);
pc->para.cause = NO_CAUSE;
pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
release_l3_process(pc);
}
static void
l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
u_char *p;
int i, tmpcharge = 0;
char a_charge[8];
StopAllL3Timer(pc);
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 > pc->para.chargeinfo) {
pc->para.chargeinfo = tmpcharge;
pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
}
if (pc->st->l3.debug & L3_DEB_CHARGE) {
l3_debug(pc->st, "charging info %d",
pc->para.chargeinfo);
}
} else if (pc->st->l3.debug & L3_DEB_CHARGE)
l3_debug(pc->st, "charging info not found");
p = skb->data;
if ((p = findie(p, skb->len, WE0_cause, 0))) {
if (p[1] > 0) {
pc->para.cause = p[2];
if (p[1] > 1)
pc->para.loc = p[3];
else
pc->para.loc = 0;
} else {
pc->para.cause = 0;
pc->para.loc = 0;
}
} else {
if (pc->st->l3.debug & L3_DEB_WARN)
l3_debug(pc->st, "cause not found");
pc->para.cause = NO_CAUSE;
}
if (!findie(skb->data, skb->len, WE6_date, 6)) {
l3_1tr6_error(pc, "missing connack date", skb);
return;
}
dev_kfree_skb(skb);
newl3state(pc, 12);
pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
}
static void
l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb = arg;
if (!findie(skb->data, skb->len, WE6_date, 6)) {
l3_1tr6_error(pc, "missing connack date", skb);
return;
}
dev_kfree_skb(skb);
newl3state(pc, 10);
pc->para.chargeinfo = 0;
L3DelTimer(&pc->timer);
pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
}
static void
l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg)
{
newl3state(pc, 7);
l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1);
}
static void
l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg)
{
struct sk_buff *skb;
u_char tmp[24];
u_char *p = tmp;
int l;
MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1);
if (pc->para.spv) { /* SPV ? */
/* NSF SPV */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_SPV; /* SPV */
*p++ = pc->para.setup.si1;
*p++ = pc->para.setup.si2;
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_Activate; /* aktiviere SPV */
*p++ = pc->para.setup.si1;
*p++ = pc->para.setup.si2;
}
newl3state(pc, 8);
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
skb_put_data(skb, tmp, l);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
L3DelTimer(&pc->timer);
L3AddTimer(&pc->timer, T313, CC_T313);
}
static void
l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg)
{
release_l3_process(pc);
}
static void
l3_1tr6_disconnect_req(struct l3_process *pc, 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 (pc->para.cause > 0)
cause = pc->para.cause;
/* Map DSS1 causes */
switch (cause & 0x7f) {
case 0x10:
clen = 0;
break;
case 0x11:
cause = CAUSE_UserBusy;
break;
case 0x15:
cause = CAUSE_CallRejected;
break;
}
StopAllL3Timer(pc);
MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1);
*p++ = WE0_cause;
*p++ = clen; /* Laenge */
if (clen)
*p++ = cause | 0x80;
newl3state(pc, 11);
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
skb_put_data(skb, tmp, l);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
L3AddTimer(&pc->timer, T305, CC_T305);
}
static void
l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg)
{
if (pc->N303 > 0) {
pc->N303--;
L3DelTimer(&pc->timer);
l3_1tr6_setup_req(pc, pr, arg);
} else {
L3DelTimer(&pc->timer);
pc->para.cause = 0;
l3_1tr6_disconnect_req(pc, 0, NULL);
}
}
static void
l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
pc->para.cause = 0xE6;
l3_1tr6_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
}
static void
l3_1tr6_t305(struct l3_process *pc, 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(&pc->timer);
if (pc->para.cause != NO_CAUSE)
cause = pc->para.cause;
/* Map DSS1 causes */
switch (cause & 0x7f) {
case 0x10:
clen = 0;
break;
case 0x15:
cause = CAUSE_CallRejected;
break;
}
MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1);
*p++ = WE0_cause;
*p++ = clen; /* Laenge */
if (clen)
*p++ = cause;
newl3state(pc, 19);
l = p - tmp;
if (!(skb = l3_alloc_skb(l)))
return;
skb_put_data(skb, tmp, l);
l3_msg(pc->st, DL_DATA | REQUEST, skb);
L3AddTimer(&pc->timer, T308, CC_T308_1);
}
static void
l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
pc->para.cause = 0xE6;
l3_1tr6_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
}
static void
l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
pc->para.cause = 0xE6;
l3_1tr6_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
}
static void
l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1);
L3AddTimer(&pc->timer, T308, CC_T308_2);
newl3state(pc, 19);
}
static void
l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg)
{
L3DelTimer(&pc->timer);
pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
release_l3_process(pc);
}
static void
l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg)
{
pc->para.cause = CAUSE_LocalProcErr;
l3_1tr6_disconnect_req(pc, pr, NULL);
pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
}
static void
l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg)
{
newl3state(pc, 0);
pc->para.cause = 0x1b; /* Destination out of order */
pc->para.loc = 0;
pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
release_l3_process(pc);
}
/* *INDENT-OFF* */
static struct stateentry downstl[] =
{
{SBIT(0),
CC_SETUP | REQUEST, l3_1tr6_setup_req},
{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) |
SBIT(10),
CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req},
{SBIT(12),
CC_RELEASE | REQUEST, l3_1tr6_release_req},
{SBIT(6),
CC_IGNORE | REQUEST, l3_1tr6_reset},
{SBIT(6),
CC_REJECT | REQUEST, l3_1tr6_disconnect_req},
{SBIT(6),
CC_ALERTING | REQUEST, l3_1tr6_alert_req},
{SBIT(6) | SBIT(7),
CC_SETUP | RESPONSE, 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 struct stateentry datastln1[] =
{
{SBIT(0),
MT_N1_INVALID, l3_1tr6_invalid},
{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),
MT_N1_REL, l3_1tr6_rel},
{SBIT(19),
MT_N1_REL, l3_1tr6_rel_ack},
{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) |
SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17),
MT_N1_REL_ACK, l3_1tr6_invalid},
{SBIT(19),
MT_N1_REL_ACK, l3_1tr6_rel_ack}
};
static struct stateentry manstatelist[] =
{
{SBIT(2),
DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset},
{ALL_STATES,
DL_RELEASE | INDICATION, l3_1tr6_dl_release},
};
/* *INDENT-ON* */
static void
up1tr6(struct PStack *st, int pr, void *arg)
{
int i, mt, cr;
struct l3_process *proc;
struct sk_buff *skb = arg;
switch (pr) {
case (DL_DATA | INDICATION):
case (DL_UNIT_DATA | INDICATION):
break;
case (DL_ESTABLISH | CONFIRM):
case (DL_ESTABLISH | INDICATION):
case (DL_RELEASE | INDICATION):
case (DL_RELEASE | CONFIRM):
l3_msg(st, pr, arg);
return;
break;
}
if (skb->len < 4) {
if (st->l3.debug & L3_DEB_PROTERR) {
l3_debug(st, "up1tr6 len only %d", skb->len);
}
dev_kfree_skb(skb);
return;
}
if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
if (st->l3.debug & L3_DEB_PROTERR) {
l3_debug(st, "up1tr6%sunexpected discriminator %x message len %d",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
skb->data[0], skb->len);
}
dev_kfree_skb(skb);
return;
}
if (skb->data[1] != 1) {
if (st->l3.debug & L3_DEB_PROTERR) {
l3_debug(st, "up1tr6 CR len not 1");
}
dev_kfree_skb(skb);
return;
}
cr = skb->data[2];
mt = skb->data[3];
if (skb->data[0] == PROTO_DIS_N0) {
dev_kfree_skb(skb);
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "up1tr6%s N0 mt %x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt);
}
} else if (skb->data[0] == PROTO_DIS_N1) {
if (!(proc = getl3proc(st, cr))) {
if (mt == MT_N1_SETUP) {
if (cr < 128) {
if (!(proc = new_l3_process(st, cr))) {
if (st->l3.debug & L3_DEB_PROTERR) {
l3_debug(st, "up1tr6 no roc mem");
}
dev_kfree_skb(skb);
return;
}
} else {
dev_kfree_skb(skb);
return;
}
} else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) ||
(mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) ||
(mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) ||
(mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) ||
(mt == MT_N1_INFO)) {
dev_kfree_skb(skb);
return;
} else {
if (!(proc = new_l3_process(st, cr))) {
if (st->l3.debug & L3_DEB_PROTERR) {
l3_debug(st, "up1tr6 no roc mem");
}
dev_kfree_skb(skb);
return;
}
mt = MT_N1_INVALID;
}
}
for (i = 0; i < ARRAY_SIZE(datastln1); i++)
if ((mt == datastln1[i].primitive) &&
((1 << proc->state) & datastln1[i].state))
break;
if (i == ARRAY_SIZE(datastln1)) {
dev_kfree_skb(skb);
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "up1tr6%sstate %d mt %x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
proc->state, mt);
}
return;
} else {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "up1tr6%sstate %d mt %x",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
proc->state, mt);
}
datastln1[i].rout(proc, pr, skb);
}
}
}
static void
down1tr6(struct PStack *st, int pr, void *arg)
{
int i, cr;
struct l3_process *proc;
struct Channel *chan;
if ((DL_ESTABLISH | REQUEST) == pr) {
l3_msg(st, pr, NULL);
return;
} else if ((CC_SETUP | REQUEST) == pr) {
chan = arg;
cr = newcallref();
cr |= 0x80;
if (!(proc = new_l3_process(st, cr))) {
return;
} else {
proc->chan = chan;
chan->proc = proc;
memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
proc->callref = cr;
}
} else {
proc = arg;
}
for (i = 0; i < ARRAY_SIZE(downstl); i++)
if ((pr == downstl[i].primitive) &&
((1 << proc->state) & downstl[i].state))
break;
if (i == ARRAY_SIZE(downstl)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "down1tr6 state %d prim %d unhandled",
proc->state, pr);
}
} else {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "down1tr6 state %d prim %d",
proc->state, pr);
}
downstl[i].rout(proc, pr, arg);
}
}
static void
man1tr6(struct PStack *st, int pr, void *arg)
{
int i;
struct l3_process *proc = arg;
if (!proc) {
printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr);
return;
}
for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
if ((pr == manstatelist[i].primitive) &&
((1 << proc->state) & manstatelist[i].state))
break;
if (i == ARRAY_SIZE(manstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled",
proc->callref & 0x7f, proc->state, pr);
}
} else {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "cr %d man1tr6 state %d prim %d",
proc->callref & 0x7f, proc->state, pr);
}
manstatelist[i].rout(proc, pr, arg);
}
}
void
setstack_1tr6(struct PStack *st)
{
char tmp[64];
st->lli.l4l3 = down1tr6;
st->l2.l2l3 = up1tr6;
st->l3.l3ml3 = man1tr6;
st->l3.N303 = 0;
strcpy(tmp, l3_1tr6_revision);
printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp));
}

View File

@ -1,164 +0,0 @@
/* $Id: l3_1tr6.h,v 2.2.6.2 2001/09/23 22:24:49 kai Exp $
*
* German 1TR6 D-channel protocol defines
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#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
#define MT_N1_INVALID 0
/*
* 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
#define T303 4000
#define T304 20000
#define T305 4000
#define T308 4000
#define T310 120000
#define T313 4000
#define T318 4000
#define T319 4000
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +0,0 @@
/* $Id: l3dss1.h,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $
*
* DSS1 (Euro) D-channel protocol defines
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef l3dss1_process
#define T302 15000
#define T303 4000
#define T304 30000
#define T305 30000
#define T308 4000
/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
/* This makes some tests easier and quicker */
#define T309 40000
#define T310 30000
#define T313 4000
#define T318 4000
#define T319 4000
/*
* 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_SEGMENT 0x00
#define IE_BEARER 0x04
#define IE_CAUSE 0x08
#define IE_CALL_ID 0x10
#define IE_CALL_STATE 0x14
#define IE_CHANNEL_ID 0x18
#define IE_FACILITY 0x1c
#define IE_PROGRESS 0x1e
#define IE_NET_FAC 0x20
#define IE_NOTIFY 0x27
#define IE_DISPLAY 0x28
#define IE_DATE 0x29
#define IE_KEYPAD 0x2c
#define IE_SIGNAL 0x34
#define IE_INFORATE 0x40
#define IE_E2E_TDELAY 0x42
#define IE_TDELAY_SEL 0x43
#define IE_PACK_BINPARA 0x44
#define IE_PACK_WINSIZE 0x45
#define IE_PACK_SIZE 0x46
#define IE_CUG 0x47
#define IE_REV_CHARGE 0x4a
#define IE_CONNECT_PN 0x4c
#define IE_CONNECT_SUB 0x4d
#define IE_CALLING_PN 0x6c
#define IE_CALLING_SUB 0x6d
#define IE_CALLED_PN 0x70
#define IE_CALLED_SUB 0x71
#define IE_REDIR_NR 0x74
#define IE_TRANS_SEL 0x78
#define IE_RESTART_IND 0x79
#define IE_LLC 0x7c
#define IE_HLC 0x7d
#define IE_USER_USER 0x7e
#define IE_ESCAPE 0x7f
#define IE_SHIFT 0x90
#define IE_MORE_DATA 0xa0
#define IE_COMPLETE 0xa1
#define IE_CONGESTION 0xb0
#define IE_REPEAT 0xd0
#define IE_MANDATORY 0x0100
/* mandatory not in every case */
#define IE_MANDATORY_1 0x0200
#define ERR_IE_COMPREHENSION 1
#define ERR_IE_UNRECOGNIZED -1
#define ERR_IE_LENGTH -2
#define ERR_IE_SEQUENCE -3
#else /* only l3dss1_process */
/* l3dss1 specific data in l3 process */
typedef struct
{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
ulong ll_id; /* remebered ll id */
u8 remote_operation; /* handled remote operation, 0 = not active */
int proc; /* rememered procedure */
ulong remote_result; /* result of remote operation for statcallb */
char uus1_data[35]; /* data send during alerting or disconnect */
} dss1_proc_priv;
/* l3dss1 specific data in protocol stack */
typedef struct
{ unsigned char last_invoke_id; /* last used value for invoking */
unsigned char invoke_used[32]; /* 256 bits for 256 values */
} dss1_stk_priv;
#endif /* only l3dss1_process */

File diff suppressed because it is too large Load Diff

View File

@ -1,136 +0,0 @@
/* $Id: l3ni1.h,v 2.3.6.2 2001/09/23 22:24:50 kai Exp $
*
* NI1 D-channel protocol
*
* Author Matt Henderson & Guy Ellis
* Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* 2000.6.6 Initial implementation of routines for US NI1
* Layer 3 protocol based on the EURO/DSS1 D-channel protocol
* driver written by Karsten Keil et al. Thanks also for the
* code provided by Ragnar Paulson.
*
*/
#ifndef l3ni1_process
#define T302 15000
#define T303 4000
#define T304 30000
#define T305 30000
#define T308 4000
/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
/* This makes some tests easier and quicker */
#define T309 40000
#define T310 30000
#define T313 4000
#define T318 4000
#define T319 4000
#define TSPID 5000 /* was 2000 - Guy Ellis */
/*
* 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 MT_DL_ESTABLISHED 0xfe
#define IE_SEGMENT 0x00
#define IE_BEARER 0x04
#define IE_CAUSE 0x08
#define IE_CALL_ID 0x10
#define IE_CALL_STATE 0x14
#define IE_CHANNEL_ID 0x18
#define IE_FACILITY 0x1c
#define IE_PROGRESS 0x1e
#define IE_NET_FAC 0x20
#define IE_NOTIFY 0x27
#define IE_DISPLAY 0x28
#define IE_DATE 0x29
#define IE_KEYPAD 0x2c
#define IE_SIGNAL 0x34
#define IE_SPID 0x3a
#define IE_ENDPOINT_ID 0x3b
#define IE_INFORATE 0x40
#define IE_E2E_TDELAY 0x42
#define IE_TDELAY_SEL 0x43
#define IE_PACK_BINPARA 0x44
#define IE_PACK_WINSIZE 0x45
#define IE_PACK_SIZE 0x46
#define IE_CUG 0x47
#define IE_REV_CHARGE 0x4a
#define IE_CONNECT_PN 0x4c
#define IE_CONNECT_SUB 0x4d
#define IE_CALLING_PN 0x6c
#define IE_CALLING_SUB 0x6d
#define IE_CALLED_PN 0x70
#define IE_CALLED_SUB 0x71
#define IE_REDIR_NR 0x74
#define IE_TRANS_SEL 0x78
#define IE_RESTART_IND 0x79
#define IE_LLC 0x7c
#define IE_HLC 0x7d
#define IE_USER_USER 0x7e
#define IE_ESCAPE 0x7f
#define IE_SHIFT 0x90
#define IE_MORE_DATA 0xa0
#define IE_COMPLETE 0xa1
#define IE_CONGESTION 0xb0
#define IE_REPEAT 0xd0
#define IE_MANDATORY 0x0100
/* mandatory not in every case */
#define IE_MANDATORY_1 0x0200
#define ERR_IE_COMPREHENSION 1
#define ERR_IE_UNRECOGNIZED -1
#define ERR_IE_LENGTH -2
#define ERR_IE_SEQUENCE -3
#else /* only l3ni1_process */
/* l3ni1 specific data in l3 process */
typedef struct
{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
ulong ll_id; /* remebered ll id */
u8 remote_operation; /* handled remote operation, 0 = not active */
int proc; /* rememered procedure */
ulong remote_result; /* result of remote operation for statcallb */
char uus1_data[35]; /* data send during alerting or disconnect */
} ni1_proc_priv;
/* l3dni1 specific data in protocol stack */
typedef struct
{ unsigned char last_invoke_id; /* last used value for invoking */
unsigned char invoke_used[32]; /* 256 bits for 256 values */
} ni1_stk_priv;
#endif /* only l3dni1_process */

View File

@ -1,50 +0,0 @@
/* $Id: lmgr.c,v 1.7.6.2 2001/09/23 22:24:50 kai Exp $
*
* Layermanagement module
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include "hisax.h"
static void
error_handling_dchan(struct PStack *st, int Error)
{
switch (Error) {
case 'C':
case 'D':
case 'G':
case 'H':
st->l2.l2tei(st, MDL_ERROR | REQUEST, NULL);
break;
}
}
static void
hisax_manager(struct PStack *st, int pr, void *arg)
{
long Code;
switch (pr) {
case (MDL_ERROR | INDICATION):
Code = (long) arg;
HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR",
" %c %s", (char)Code,
test_bit(FLG_LAPD, &st->l2.flag) ?
"D-channel" : "B-channel");
if (test_bit(FLG_LAPD, &st->l2.flag))
error_handling_dchan(st, Code);
break;
}
}
void
setstack_manager(struct PStack *st)
{
st->ma.layer = hisax_manager;
}

View File

@ -1,235 +0,0 @@
/* $Id: mic.c,v 1.12.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for mic cards
*
* Author Stephan von Krawczynski
* Copyright by Stephan von Krawczynski <skraw@ithnet.com>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *mic_revision = "$Revision: 1.12.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define MIC_ISAC 2
#define MIC_HSCX 1
#define MIC_ADR 7
/* CARD_ADR (Write) */
#define MIC_RESET 0x3 /* same as DOS driver */
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.mic.adr,
cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.mic.adr,
cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \
cs->hw.mic.hscx, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \
cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \
cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \
cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
mic_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF);
writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0);
writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_mic(struct IsdnCardState *cs)
{
int bytecnt = 8;
if (cs->hw.mic.cfg_reg)
release_region(cs->hw.mic.cfg_reg, bytecnt);
}
static int
mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
return (0);
case CARD_RELEASE:
release_io_mic(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscx(cs); /* /RTSA := ISAC RST */
inithscxisac(cs, 3);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
int setup_mic(struct IsdnCard *card)
{
int bytecnt;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, mic_revision);
printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_MIC)
return (0);
bytecnt = 8;
cs->hw.mic.cfg_reg = card->para[1];
cs->irq = card->para[0];
cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) {
printk(KERN_WARNING
"HiSax: ith mic config port %x-%x already in use\n",
cs->hw.mic.cfg_reg,
cs->hw.mic.cfg_reg + bytecnt);
return (0);
}
printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n",
cs->hw.mic.cfg_reg, cs->irq);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &mic_card_msg;
cs->irq_func = &mic_interrupt;
ISACVersion(cs, "mic:");
if (HscxVersion(cs, "mic:")) {
printk(KERN_WARNING
"mic: wrong HSCX versions check IO address\n");
release_io_mic(cs);
return (0);
}
return (1);
}

View File

@ -1,985 +0,0 @@
/* $Id: netjet.c,v 1.29.2.4 2004/02/11 13:21:34 keil Exp $
*
* low level stuff for Traverse Technologie NETJet ISDN cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Traverse Technologies Australia for documents and information
*
* 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au)
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
#include <linux/slab.h>
#include <asm/io.h>
#include "netjet.h"
/* Interface functions */
u_char
NETjet_ReadIC(struct IsdnCardState *cs, u_char offset)
{
u_char ret;
cs->hw.njet.auxd &= 0xfc;
cs->hw.njet.auxd |= (offset >> 4) & 3;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
ret = bytein(cs->hw.njet.isac + ((offset & 0xf) << 2));
return (ret);
}
void
NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value)
{
cs->hw.njet.auxd &= 0xfc;
cs->hw.njet.auxd |= (offset >> 4) & 3;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
byteout(cs->hw.njet.isac + ((offset & 0xf) << 2), value);
}
void
NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size)
{
cs->hw.njet.auxd &= 0xfc;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
insb(cs->hw.njet.isac, data, size);
}
void
NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size)
{
cs->hw.njet.auxd &= 0xfc;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
outsb(cs->hw.njet.isac, data, size);
}
static void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
{
u_int mask = 0x000000ff, val = 0, *p = pos;
u_int i;
val |= fill;
if (chan) {
val <<= 8;
mask <<= 8;
}
mask ^= 0xffffffff;
for (i = 0; i < cnt; i++) {
*p &= mask;
*p++ |= val;
if (p > bcs->hw.tiger.s_end)
p = bcs->hw.tiger.send;
}
}
static void
mode_tiger(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
u_char led;
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "Tiger mode %d bchan %d/%d",
mode, bc, bcs->channel);
bcs->mode = mode;
bcs->channel = bc;
switch (mode) {
case (L1_MODE_NULL):
fill_mem(bcs, bcs->hw.tiger.send,
NETJET_DMA_TXSIZE, bc, 0xff);
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "Tiger stat rec %d/%d send %d",
bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err,
bcs->hw.tiger.s_tot);
if ((cs->bcs[0].mode == L1_MODE_NULL) &&
(cs->bcs[1].mode == L1_MODE_NULL)) {
cs->hw.njet.dmactrl = 0;
byteout(cs->hw.njet.base + NETJET_DMACTRL,
cs->hw.njet.dmactrl);
byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
}
if (cs->typ == ISDN_CTYPE_NETJET_S)
{
// led off
led = bc & 0x01;
led = 0x01 << (6 + led); // convert to mask
led = ~led;
cs->hw.njet.auxd &= led;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
}
break;
case (L1_MODE_TRANS):
break;
case (L1_MODE_HDLC_56K):
case (L1_MODE_HDLC):
fill_mem(bcs, bcs->hw.tiger.send,
NETJET_DMA_TXSIZE, bc, 0xff);
bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH;
bcs->hw.tiger.r_tot = 0;
bcs->hw.tiger.r_bitcnt = 0;
bcs->hw.tiger.r_one = 0;
bcs->hw.tiger.r_err = 0;
bcs->hw.tiger.s_tot = 0;
if (!cs->hw.njet.dmactrl) {
fill_mem(bcs, bcs->hw.tiger.send,
NETJET_DMA_TXSIZE, !bc, 0xff);
cs->hw.njet.dmactrl = 1;
byteout(cs->hw.njet.base + NETJET_DMACTRL,
cs->hw.njet.dmactrl);
byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x0f);
/* was 0x3f now 0x0f for TJ300 and TJ320 GE 13/07/00 */
}
bcs->hw.tiger.sendp = bcs->hw.tiger.send;
bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
if (cs->typ == ISDN_CTYPE_NETJET_S)
{
// led on
led = bc & 0x01;
led = 0x01 << (6 + led); // convert to mask
cs->hw.njet.auxd |= led;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
}
break;
}
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "tiger: set %x %x %x %x/%x pulse=%d",
bytein(cs->hw.njet.base + NETJET_DMACTRL),
bytein(cs->hw.njet.base + NETJET_IRQMASK0),
bytein(cs->hw.njet.base + NETJET_IRQSTAT0),
inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
}
static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) {
char tmp[128];
char *t = tmp;
int i = count, j;
u_char *p = buf;
t += sprintf(t, "tiger %s(%4d)", s, count);
while (i > 0) {
if (i > 16)
j = 16;
else
j = i;
QuickHex(t, p, j);
debugl1(cs, "%s", tmp);
p += j;
i -= j;
t = tmp;
t += sprintf(t, "tiger %s ", s);
}
}
// macro for 64k
#define MAKE_RAW_BYTE for (j = 0; j < 8; j++) { \
bitcnt++; \
s_val >>= 1; \
if (val & 1) { \
s_one++; \
s_val |= 0x80; \
} else { \
s_one = 0; \
s_val &= 0x7f; \
} \
if (bitcnt == 8) { \
bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \
bitcnt = 0; \
} \
if (s_one == 5) { \
s_val >>= 1; \
s_val &= 0x7f; \
bitcnt++; \
s_one = 0; \
} \
if (bitcnt == 8) { \
bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \
bitcnt = 0; \
} \
val >>= 1; \
}
static int make_raw_data(struct BCState *bcs) {
// this make_raw is for 64k
register u_int i, s_cnt = 0;
register u_char j;
register u_char val;
register u_char s_one = 0;
register u_char s_val = 0;
register u_char bitcnt = 0;
u_int fcs;
if (!bcs->tx_skb) {
debugl1(bcs->cs, "tiger make_raw: NULL skb");
return (1);
}
bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE;
fcs = PPP_INITFCS;
for (i = 0; i < bcs->tx_skb->len; i++) {
val = bcs->tx_skb->data[i];
fcs = PPP_FCS(fcs, val);
MAKE_RAW_BYTE;
}
fcs ^= 0xffff;
val = fcs & 0xff;
MAKE_RAW_BYTE;
val = (fcs >> 8) & 0xff;
MAKE_RAW_BYTE;
val = HDLC_FLAG_VALUE;
for (j = 0; j < 8; j++) {
bitcnt++;
s_val >>= 1;
if (val & 1)
s_val |= 0x80;
else
s_val &= 0x7f;
if (bitcnt == 8) {
bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
bitcnt = 0;
}
val >>= 1;
}
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger make_raw: in %u out %d.%d",
bcs->tx_skb->len, s_cnt, bitcnt);
if (bitcnt) {
while (8 > bitcnt++) {
s_val >>= 1;
s_val |= 0x80;
}
bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix
}
bcs->hw.tiger.sendcnt = s_cnt;
bcs->tx_cnt -= bcs->tx_skb->len;
bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
return (0);
}
// macro for 56k
#define MAKE_RAW_BYTE_56K for (j = 0; j < 8; j++) { \
bitcnt++; \
s_val >>= 1; \
if (val & 1) { \
s_one++; \
s_val |= 0x80; \
} else { \
s_one = 0; \
s_val &= 0x7f; \
} \
if (bitcnt == 7) { \
s_val >>= 1; \
s_val |= 0x80; \
bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \
bitcnt = 0; \
} \
if (s_one == 5) { \
s_val >>= 1; \
s_val &= 0x7f; \
bitcnt++; \
s_one = 0; \
} \
if (bitcnt == 7) { \
s_val >>= 1; \
s_val |= 0x80; \
bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \
bitcnt = 0; \
} \
val >>= 1; \
}
static int make_raw_data_56k(struct BCState *bcs) {
// this make_raw is for 56k
register u_int i, s_cnt = 0;
register u_char j;
register u_char val;
register u_char s_one = 0;
register u_char s_val = 0;
register u_char bitcnt = 0;
u_int fcs;
if (!bcs->tx_skb) {
debugl1(bcs->cs, "tiger make_raw_56k: NULL skb");
return (1);
}
val = HDLC_FLAG_VALUE;
for (j = 0; j < 8; j++) {
bitcnt++;
s_val >>= 1;
if (val & 1)
s_val |= 0x80;
else
s_val &= 0x7f;
if (bitcnt == 7) {
s_val >>= 1;
s_val |= 0x80;
bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
bitcnt = 0;
}
val >>= 1;
}
fcs = PPP_INITFCS;
for (i = 0; i < bcs->tx_skb->len; i++) {
val = bcs->tx_skb->data[i];
fcs = PPP_FCS(fcs, val);
MAKE_RAW_BYTE_56K;
}
fcs ^= 0xffff;
val = fcs & 0xff;
MAKE_RAW_BYTE_56K;
val = (fcs >> 8) & 0xff;
MAKE_RAW_BYTE_56K;
val = HDLC_FLAG_VALUE;
for (j = 0; j < 8; j++) {
bitcnt++;
s_val >>= 1;
if (val & 1)
s_val |= 0x80;
else
s_val &= 0x7f;
if (bitcnt == 7) {
s_val >>= 1;
s_val |= 0x80;
bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
bitcnt = 0;
}
val >>= 1;
}
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger make_raw_56k: in %u out %d.%d",
bcs->tx_skb->len, s_cnt, bitcnt);
if (bitcnt) {
while (8 > bitcnt++) {
s_val >>= 1;
s_val |= 0x80;
}
bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix
}
bcs->hw.tiger.sendcnt = s_cnt;
bcs->tx_cnt -= bcs->tx_skb->len;
bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
return (0);
}
static void got_frame(struct BCState *bcs, int count) {
struct sk_buff *skb;
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "TIGER: receive out of memory\n");
else {
skb_put_data(skb, bcs->hw.tiger.rcvbuf, count);
skb_queue_tail(&bcs->rqueue, skb);
}
test_and_set_bit(B_RCVBUFREADY, &bcs->event);
schedule_work(&bcs->tqueue);
if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME)
printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec");
}
static void read_raw(struct BCState *bcs, u_int *buf, int cnt) {
int i;
register u_char j;
register u_char val;
u_int *pend = bcs->hw.tiger.rec + NETJET_DMA_RXSIZE - 1;
register u_char state = bcs->hw.tiger.r_state;
register u_char r_one = bcs->hw.tiger.r_one;
register u_char r_val = bcs->hw.tiger.r_val;
register u_int bitcnt = bcs->hw.tiger.r_bitcnt;
u_int *p = buf;
int bits;
u_char mask;
if (bcs->mode == L1_MODE_HDLC) { // it's 64k
mask = 0xff;
bits = 8;
}
else { // it's 56K
mask = 0x7f;
bits = 7;
}
for (i = 0; i < cnt; i++) {
val = bcs->channel ? ((*p >> 8) & 0xff) : (*p & 0xff);
p++;
if (p > pend)
p = bcs->hw.tiger.rec;
if ((val & mask) == mask) {
state = HDLC_ZERO_SEARCH;
bcs->hw.tiger.r_tot++;
bitcnt = 0;
r_one = 0;
continue;
}
for (j = 0; j < bits; j++) {
if (state == HDLC_ZERO_SEARCH) {
if (val & 1) {
r_one++;
} else {
r_one = 0;
state = HDLC_FLAG_SEARCH;
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger read_raw: zBit(%d,%d,%d) %x",
bcs->hw.tiger.r_tot, i, j, val);
}
} else if (state == HDLC_FLAG_SEARCH) {
if (val & 1) {
r_one++;
if (r_one > 6) {
state = HDLC_ZERO_SEARCH;
}
} else {
if (r_one == 6) {
bitcnt = 0;
r_val = 0;
state = HDLC_FLAG_FOUND;
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger read_raw: flag(%d,%d,%d) %x",
bcs->hw.tiger.r_tot, i, j, val);
}
r_one = 0;
}
} else if (state == HDLC_FLAG_FOUND) {
if (val & 1) {
r_one++;
if (r_one > 6) {
state = HDLC_ZERO_SEARCH;
} else {
r_val >>= 1;
r_val |= 0x80;
bitcnt++;
}
} else {
if (r_one == 6) {
bitcnt = 0;
r_val = 0;
r_one = 0;
val >>= 1;
continue;
} else if (r_one != 5) {
r_val >>= 1;
r_val &= 0x7f;
bitcnt++;
}
r_one = 0;
}
if ((state != HDLC_ZERO_SEARCH) &&
!(bitcnt & 7)) {
state = HDLC_FRAME_FOUND;
bcs->hw.tiger.r_fcs = PPP_INITFCS;
bcs->hw.tiger.rcvbuf[0] = r_val;
bcs->hw.tiger.r_fcs = PPP_FCS(bcs->hw.tiger.r_fcs, r_val);
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x",
bcs->hw.tiger.r_tot, i, j, r_val, val,
bcs->cs->hw.njet.irqstat0);
}
} else if (state == HDLC_FRAME_FOUND) {
if (val & 1) {
r_one++;
if (r_one > 6) {
state = HDLC_ZERO_SEARCH;
bitcnt = 0;
} else {
r_val >>= 1;
r_val |= 0x80;
bitcnt++;
}
} else {
if (r_one == 6) {
r_val = 0;
r_one = 0;
bitcnt++;
if (bitcnt & 7) {
debugl1(bcs->cs, "tiger: frame not byte aligned");
state = HDLC_FLAG_SEARCH;
bcs->hw.tiger.r_err++;
#ifdef ERROR_STATISTIC
bcs->err_inv++;
#endif
} else {
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger frame end(%d,%d): fcs(%x) i %x",
i, j, bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0);
if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) {
got_frame(bcs, (bitcnt >> 3) - 3);
} else {
if (bcs->cs->debug) {
debugl1(bcs->cs, "tiger FCS error");
printframe(bcs->cs, bcs->hw.tiger.rcvbuf,
(bitcnt >> 3) - 1, "rec");
bcs->hw.tiger.r_err++;
}
#ifdef ERROR_STATISTIC
bcs->err_crc++;
#endif
}
state = HDLC_FLAG_FOUND;
}
bitcnt = 0;
} else if (r_one == 5) {
val >>= 1;
r_one = 0;
continue;
} else {
r_val >>= 1;
r_val &= 0x7f;
bitcnt++;
}
r_one = 0;
}
if ((state == HDLC_FRAME_FOUND) &&
!(bitcnt & 7)) {
if ((bitcnt >> 3) >= HSCX_BUFMAX) {
debugl1(bcs->cs, "tiger: frame too big");
r_val = 0;
state = HDLC_FLAG_SEARCH;
bcs->hw.tiger.r_err++;
#ifdef ERROR_STATISTIC
bcs->err_inv++;
#endif
} else {
bcs->hw.tiger.rcvbuf[(bitcnt >> 3) - 1] = r_val;
bcs->hw.tiger.r_fcs =
PPP_FCS(bcs->hw.tiger.r_fcs, r_val);
}
}
}
val >>= 1;
}
bcs->hw.tiger.r_tot++;
}
bcs->hw.tiger.r_state = state;
bcs->hw.tiger.r_one = r_one;
bcs->hw.tiger.r_val = r_val;
bcs->hw.tiger.r_bitcnt = bitcnt;
}
void read_tiger(struct IsdnCardState *cs) {
u_int *p;
int cnt = NETJET_DMA_RXSIZE / 2;
if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) {
debugl1(cs, "tiger warn read double dma %x/%x",
cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
#ifdef ERROR_STATISTIC
if (cs->bcs[0].mode)
cs->bcs[0].err_rdo++;
if (cs->bcs[1].mode)
cs->bcs[1].err_rdo++;
#endif
return;
} else {
cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ;
cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ);
}
if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1)
p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1;
else
p = cs->bcs[0].hw.tiger.rec + cnt - 1;
if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K))
read_raw(cs->bcs, p, cnt);
if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K))
read_raw(cs->bcs + 1, p, cnt);
cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ;
}
static void write_raw(struct BCState *bcs, u_int *buf, int cnt);
void netjet_fill_dma(struct BCState *bcs)
{
register u_int *p, *sp;
register int cnt;
if (!bcs->tx_skb)
return;
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger fill_dma1: c%d %4lx", bcs->channel,
bcs->Flag);
if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
return;
if (bcs->mode == L1_MODE_HDLC) { // it's 64k
if (make_raw_data(bcs))
return;
}
else { // it's 56k
if (make_raw_data_56k(bcs))
return;
}
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger fill_dma2: c%d %4lx", bcs->channel,
bcs->Flag);
if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
} else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
sp = bcs->hw.tiger.sendp;
if (p == bcs->hw.tiger.s_end)
p = bcs->hw.tiger.send - 1;
if (sp == bcs->hw.tiger.s_end)
sp = bcs->hw.tiger.send - 1;
cnt = p - sp;
if (cnt < 0) {
write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
} else {
p++;
cnt++;
if (p > bcs->hw.tiger.s_end)
p = bcs->hw.tiger.send;
p++;
cnt++;
if (p > bcs->hw.tiger.s_end)
p = bcs->hw.tiger.send;
write_raw(bcs, p, bcs->hw.tiger.free - cnt);
}
} else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) {
p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR));
cnt = bcs->hw.tiger.s_end - p;
if (cnt < 2) {
p = bcs->hw.tiger.send + 1;
cnt = NETJET_DMA_TXSIZE / 2 - 2;
} else {
p++;
p++;
if (cnt <= (NETJET_DMA_TXSIZE / 2))
cnt += NETJET_DMA_TXSIZE / 2;
cnt--;
cnt--;
}
write_raw(bcs, p, cnt);
}
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger fill_dma3: c%d %4lx", bcs->channel,
bcs->Flag);
}
static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
u_int mask, val, *p = buf;
u_int i, s_cnt;
if (cnt <= 0)
return;
if (test_bit(BC_FLG_BUSY, &bcs->Flag)) {
if (bcs->hw.tiger.sendcnt > cnt) {
s_cnt = cnt;
bcs->hw.tiger.sendcnt -= cnt;
} else {
s_cnt = bcs->hw.tiger.sendcnt;
bcs->hw.tiger.sendcnt = 0;
}
if (bcs->channel)
mask = 0xffff00ff;
else
mask = 0xffffff00;
for (i = 0; i < s_cnt; i++) {
val = bcs->channel ? ((bcs->hw.tiger.sp[i] << 8) & 0xff00) :
(bcs->hw.tiger.sp[i]);
*p &= mask;
*p++ |= val;
if (p > bcs->hw.tiger.s_end)
p = bcs->hw.tiger.send;
}
bcs->hw.tiger.s_tot += s_cnt;
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger write_raw: c%d %p-%p %d/%d %d %x", bcs->channel,
buf, p, s_cnt, cnt,
bcs->hw.tiger.sendcnt, bcs->cs->hw.njet.irqstat0);
if (bcs->cs->debug & L1_DEB_HSCX_FIFO)
printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd");
bcs->hw.tiger.sp += s_cnt;
bcs->hw.tiger.sendp = p;
if (!bcs->hw.tiger.sendcnt) {
if (!bcs->tx_skb) {
debugl1(bcs->cs, "tiger write_raw: NULL skb s_cnt %d", s_cnt);
} else {
if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
bcs->ackcnt += bcs->tx_skb->len;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
}
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->hw.tiger.free = cnt - s_cnt;
if (bcs->hw.tiger.free > (NETJET_DMA_TXSIZE / 2))
test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
else {
test_and_clear_bit(BC_FLG_HALF, &bcs->Flag);
test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag);
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
netjet_fill_dma(bcs);
} else {
mask ^= 0xffffffff;
if (s_cnt < cnt) {
for (i = s_cnt; i < cnt; i++) {
*p++ |= mask;
if (p > bcs->hw.tiger.s_end)
p = bcs->hw.tiger.send;
}
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger write_raw: fill rest %d",
cnt - s_cnt);
}
test_and_set_bit(B_XMTBUFREADY, &bcs->event);
schedule_work(&bcs->tqueue);
}
}
} else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
test_and_set_bit(BC_FLG_HALF, &bcs->Flag);
fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
bcs->hw.tiger.free += cnt;
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger write_raw: fill half");
} else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) {
test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
fill_mem(bcs, buf, cnt, bcs->channel, 0xff);
if (bcs->cs->debug & L1_DEB_HSCX)
debugl1(bcs->cs, "tiger write_raw: fill full");
}
}
void write_tiger(struct IsdnCardState *cs) {
u_int *p, cnt = NETJET_DMA_TXSIZE / 2;
if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
debugl1(cs, "tiger warn write double dma %x/%x",
cs->hw.njet.irqstat0, cs->hw.njet.last_is0);
#ifdef ERROR_STATISTIC
if (cs->bcs[0].mode)
cs->bcs[0].err_tx++;
if (cs->bcs[1].mode)
cs->bcs[1].err_tx++;
#endif
return;
} else {
cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE;
cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE);
}
if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1)
p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
else
p = cs->bcs[0].hw.tiger.send + cnt - 1;
if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K))
write_raw(cs->bcs, p, cnt);
if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K))
write_raw(cs->bcs + 1, p, cnt);
cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE;
}
static void
tiger_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
struct sk_buff *skb = arg;
u_long flags;
switch (pr) {
case (PH_DATA | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
skb_queue_tail(&bcs->squeue, skb);
} else {
bcs->tx_skb = skb;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | INDICATION):
spin_lock_irqsave(&bcs->cs->lock, flags);
if (bcs->tx_skb) {
printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n");
} else {
bcs->tx_skb = skb;
bcs->cs->BC_Send_Data(bcs);
}
spin_unlock_irqrestore(&bcs->cs->lock, flags);
break;
case (PH_PULL | REQUEST):
if (!bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag);
mode_tiger(bcs, st->l1.mode, st->l1.bc);
/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
spin_unlock_irqrestore(&bcs->cs->lock, flags);
bcs->cs->cardmsg(bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
bcs->cs->cardmsg(bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
spin_lock_irqsave(&bcs->cs->lock, flags);
test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
mode_tiger(bcs, 0, st->l1.bc);
spin_unlock_irqrestore(&bcs->cs->lock, flags);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
static void
close_tigerstate(struct BCState *bcs)
{
mode_tiger(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
kfree(bcs->hw.tiger.rcvbuf);
bcs->hw.tiger.rcvbuf = NULL;
kfree(bcs->hw.tiger.sendbuf);
bcs->hw.tiger.sendbuf = NULL;
skb_queue_purge(&bcs->rqueue);
skb_queue_purge(&bcs->squeue);
if (bcs->tx_skb) {
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
static int
open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for tiger.rcvbuf\n");
return (1);
}
if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for tiger.sendbuf\n");
return (1);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
bcs->hw.tiger.sendcnt = 0;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->tx_cnt = 0;
return (0);
}
static int
setstack_tiger(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_tigerstate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = tiger_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
void
inittiger(struct IsdnCardState *cs)
{
cs->bcs[0].hw.tiger.send = kmalloc_array(NETJET_DMA_TXSIZE,
sizeof(unsigned int),
GFP_KERNEL | GFP_DMA);
if (!cs->bcs[0].hw.tiger.send) {
printk(KERN_WARNING
"HiSax: No memory for tiger.send\n");
return;
}
cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE / 2 - 1;
cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send;
cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq;
cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end;
memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int));
debugl1(cs, "tiger: send buf %p - %p", cs->bcs[0].hw.tiger.send,
cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1);
outl(virt_to_bus(cs->bcs[0].hw.tiger.send),
cs->hw.njet.base + NETJET_DMA_READ_START);
outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq),
cs->hw.njet.base + NETJET_DMA_READ_IRQ);
outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end),
cs->hw.njet.base + NETJET_DMA_READ_END);
cs->bcs[0].hw.tiger.rec = kmalloc_array(NETJET_DMA_RXSIZE,
sizeof(unsigned int),
GFP_KERNEL | GFP_DMA);
if (!cs->bcs[0].hw.tiger.rec) {
printk(KERN_WARNING
"HiSax: No memory for tiger.rec\n");
return;
}
debugl1(cs, "tiger: rec buf %p - %p", cs->bcs[0].hw.tiger.rec,
cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1);
cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec;
memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * sizeof(unsigned int));
outl(virt_to_bus(cs->bcs[0].hw.tiger.rec),
cs->hw.njet.base + NETJET_DMA_WRITE_START);
outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE / 2 - 1),
cs->hw.njet.base + NETJET_DMA_WRITE_IRQ);
outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1),
cs->hw.njet.base + NETJET_DMA_WRITE_END);
debugl1(cs, "tiger: dmacfg %x/%x pulse=%d",
inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
cs->hw.njet.last_is0 = 0;
cs->bcs[0].BC_SetStack = setstack_tiger;
cs->bcs[1].BC_SetStack = setstack_tiger;
cs->bcs[0].BC_Close = close_tigerstate;
cs->bcs[1].BC_Close = close_tigerstate;
}
static void
releasetiger(struct IsdnCardState *cs)
{
kfree(cs->bcs[0].hw.tiger.send);
cs->bcs[0].hw.tiger.send = NULL;
cs->bcs[1].hw.tiger.send = NULL;
kfree(cs->bcs[0].hw.tiger.rec);
cs->bcs[0].hw.tiger.rec = NULL;
cs->bcs[1].hw.tiger.rec = NULL;
}
void
release_io_netjet(struct IsdnCardState *cs)
{
byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0);
releasetiger(cs);
release_region(cs->hw.njet.base, 256);
}

View File

@ -1,69 +0,0 @@
/* $Id: netjet.h,v 2.8.2.2 2004/01/12 22:52:28 keil Exp $
*
* NETjet common header file
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
* by Matt Henderson,
* Traverse Technologies P/L www.traverse.com.au
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define NETJET_CTRL 0x00
#define NETJET_DMACTRL 0x01
#define NETJET_AUXCTRL 0x02
#define NETJET_AUXDATA 0x03
#define NETJET_IRQMASK0 0x04
#define NETJET_IRQMASK1 0x05
#define NETJET_IRQSTAT0 0x06
#define NETJET_IRQSTAT1 0x07
#define NETJET_DMA_READ_START 0x08
#define NETJET_DMA_READ_IRQ 0x0c
#define NETJET_DMA_READ_END 0x10
#define NETJET_DMA_READ_ADR 0x14
#define NETJET_DMA_WRITE_START 0x18
#define NETJET_DMA_WRITE_IRQ 0x1c
#define NETJET_DMA_WRITE_END 0x20
#define NETJET_DMA_WRITE_ADR 0x24
#define NETJET_PULSE_CNT 0x28
#define NETJET_ISAC_OFF 0xc0
#define NETJET_ISACIRQ 0x10
#define NETJET_IRQM0_READ 0x0c
#define NETJET_IRQM0_READ_1 0x04
#define NETJET_IRQM0_READ_2 0x08
#define NETJET_IRQM0_WRITE 0x03
#define NETJET_IRQM0_WRITE_1 0x01
#define NETJET_IRQM0_WRITE_2 0x02
#define NETJET_DMA_TXSIZE 512
#define NETJET_DMA_RXSIZE 128
#define HDLC_ZERO_SEARCH 0
#define HDLC_FLAG_SEARCH 1
#define HDLC_FLAG_FOUND 2
#define HDLC_FRAME_FOUND 3
#define HDLC_NULL 4
#define HDLC_PART 5
#define HDLC_FULL 6
#define HDLC_FLAG_VALUE 0x7e
u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset);
void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value);
void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size);
void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size);
void read_tiger(struct IsdnCardState *cs);
void write_tiger(struct IsdnCardState *cs);
void netjet_fill_dma(struct BCState *bcs);
void netjet_interrupt(int intno, void *dev_id);
void inittiger(struct IsdnCardState *cs);
void release_io_netjet(struct IsdnCardState *cs);

View File

@ -1,380 +0,0 @@
/* $Id: niccy.c,v 1.21.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
* compatible (SAGEM cybermodem)
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Dr. Neuhaus and SAGEM for information
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include <linux/isapnp.h>
static const char *niccy_revision = "$Revision: 1.21.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define ISAC_PCI_DATA 0
#define HSCX_PCI_DATA 1
#define ISAC_PCI_ADDR 2
#define HSCX_PCI_ADDR 3
#define ISAC_PNP 0
#define HSCX_PNP 1
/* SUB Types */
#define NICCY_PNP 1
#define NICCY_PCI 2
/* PCI stuff */
#define PCI_IRQ_CTRL_REG 0x38
#define PCI_IRQ_ENABLE 0x1f00
#define PCI_IRQ_DISABLE 0xff0000
#define PCI_IRQ_ASSERT 0x800000
static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
return ret;
}
static inline void readfifo(unsigned int ale, unsigned int adr, u_char off,
u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
static inline void writereg(unsigned int ale, unsigned int adr, u_char off,
u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
static inline void writefifo(unsigned int ale, unsigned int adr, u_char off,
u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
}
/* Interface functions */
static u_char ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset);
}
static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
}
static void ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
}
static void WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
}
static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return readreg(cs->hw.niccy.hscx_ale,
cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0));
}
static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset,
u_char value)
{
writereg(cs->hw.niccy.hscx_ale,
cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
}
#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \
cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \
cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \
cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \
cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t niccy_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
if (cs->subtyp == NICCY_PCI) {
int ival;
ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
}
val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
HSCX_ISTA + 0x40);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,
0xFF);
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void release_io_niccy(struct IsdnCardState *cs)
{
if (cs->subtyp == NICCY_PCI) {
int val;
val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
val &= PCI_IRQ_DISABLE;
outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
release_region(cs->hw.niccy.cfg_reg, 0x40);
release_region(cs->hw.niccy.isac, 4);
} else {
release_region(cs->hw.niccy.isac, 2);
release_region(cs->hw.niccy.isac_ale, 2);
}
}
static void niccy_reset(struct IsdnCardState *cs)
{
if (cs->subtyp == NICCY_PCI) {
int val;
val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
val |= PCI_IRQ_ENABLE;
outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
}
inithscxisac(cs, 3);
}
static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
niccy_reset(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return 0;
case CARD_RELEASE:
release_io_niccy(cs);
return 0;
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
niccy_reset(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return 0;
case CARD_TEST:
return 0;
}
return 0;
}
#ifdef __ISAPNP__
static struct pnp_card *pnp_c = NULL;
#endif
int setup_niccy(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, niccy_revision);
printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_NICCY)
return 0;
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d = NULL;
int err;
pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'),
ISAPNP_FUNCTION(0x0150), pnp_c);
if (pnp_c) {
pnp_d = pnp_find_dev(pnp_c,
ISAPNP_VENDOR('S', 'D', 'A'),
ISAPNP_FUNCTION(0x0150), pnp_d);
if (!pnp_d) {
printk(KERN_ERR "NiccyPnP: PnP error card "
"found, no device\n");
return 0;
}
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev "
"ret(%d)\n", __func__, err);
return 0;
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[2] = pnp_port_start(pnp_d, 1);
card->para[0] = pnp_irq(pnp_d, 0);
if (card->para[0] == -1 || !card->para[1] ||
!card->para[2]) {
printk(KERN_ERR "NiccyPnP:some resources are "
"missing %ld/%lx/%lx\n",
card->para[0], card->para[1],
card->para[2]);
pnp_disable_dev(pnp_d);
return 0;
}
} else
printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
}
#endif
if (card->para[1]) {
cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP;
cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP;
cs->hw.niccy.cfg_reg = 0;
cs->subtyp = NICCY_PNP;
cs->irq = card->para[0];
if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) {
printk(KERN_WARNING "HiSax: NICCY data port %x-%x "
"already in use\n",
cs->hw.niccy.isac, cs->hw.niccy.isac + 1);
return 0;
}
if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) {
printk(KERN_WARNING "HiSax: NICCY address port %x-%x "
"already in use\n",
cs->hw.niccy.isac_ale,
cs->hw.niccy.isac_ale + 1);
release_region(cs->hw.niccy.isac, 2);
return 0;
}
} else {
#ifdef CONFIG_PCI
static struct pci_dev *niccy_dev;
u_int pci_ioaddr;
cs->subtyp = 0;
if ((niccy_dev = hisax_find_pci_device(PCI_VENDOR_ID_SATSAGEM,
PCI_DEVICE_ID_SATSAGEM_NICCY,
niccy_dev))) {
if (pci_enable_device(niccy_dev))
return 0;
/* get IRQ */
if (!niccy_dev->irq) {
printk(KERN_WARNING
"Niccy: No IRQ for PCI card found\n");
return 0;
}
cs->irq = niccy_dev->irq;
cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
if (!cs->hw.niccy.cfg_reg) {
printk(KERN_WARNING
"Niccy: No IO-Adr for PCI cfg found\n");
return 0;
}
pci_ioaddr = pci_resource_start(niccy_dev, 1);
if (!pci_ioaddr) {
printk(KERN_WARNING
"Niccy: No IO-Adr for PCI card found\n");
return 0;
}
cs->subtyp = NICCY_PCI;
} else {
printk(KERN_WARNING "Niccy: No PCI card found\n");
return 0;
}
cs->irq_flags |= IRQF_SHARED;
cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
if (!request_region(cs->hw.niccy.isac, 4, "niccy")) {
printk(KERN_WARNING
"HiSax: NICCY data port %x-%x already in use\n",
cs->hw.niccy.isac, cs->hw.niccy.isac + 4);
return 0;
}
if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) {
printk(KERN_WARNING
"HiSax: NICCY pci port %x-%x already in use\n",
cs->hw.niccy.cfg_reg,
cs->hw.niccy.cfg_reg + 0x40);
release_region(cs->hw.niccy.isac, 4);
return 0;
}
#else
printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
return 0;
#endif /* CONFIG_PCI */
}
printk(KERN_INFO "HiSax: NICCY %s config irq:%d data:0x%X ale:0x%X\n",
(cs->subtyp == 1) ? "PnP" : "PCI",
cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &niccy_card_msg;
cs->irq_func = &niccy_interrupt;
ISACVersion(cs, "Niccy:");
if (HscxVersion(cs, "Niccy:")) {
printk(KERN_WARNING "Niccy: wrong HSCX versions check IO "
"address\n");
release_io_niccy(cs);
return 0;
}
return 1;
}

View File

@ -1,294 +0,0 @@
/* $Id: nj_s.c,v 2.13.2.4 2004/01/16 01:53:48 keil Exp $
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
#include "netjet.h"
static const char *NETjet_S_revision = "$Revision: 2.13.2.4 $";
static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
{
return (5);
}
static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
{
}
static irqreturn_t
netjet_s_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, s1val, s0val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
s1val = bytein(cs->hw.njet.base + NETJET_IRQSTAT1);
if (!(s1val & NETJET_ISACIRQ)) {
val = NETjet_ReadIC(cs, ISAC_ISTA);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "tiger: i1 %x %x", s1val, val);
if (val) {
isac_interrupt(cs, val);
NETjet_WriteIC(cs, ISAC_MASK, 0xFF);
NETjet_WriteIC(cs, ISAC_MASK, 0x0);
}
s1val = 1;
} else
s1val = 0;
/*
* read/write stat0 is better, because lower IRQ rate
* Note the IRQ is on for 125 us if a condition match
* thats long on modern CPU and so the IRQ is reentered
* all the time.
*/
s0val = bytein(cs->hw.njet.base + NETJET_IRQSTAT0);
if ((s0val | s1val) == 0) { // shared IRQ
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
if (s0val)
byteout(cs->hw.njet.base + NETJET_IRQSTAT0, s0val);
/* start new code 13/07/00 GE */
/* set bits in sval to indicate which page is free */
if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
/* the 2nd write page is free */
s0val = 0x08;
else /* the 1st write page is free */
s0val = 0x04;
if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
/* the 2nd read page is free */
s0val |= 0x02;
else /* the 1st read page is free */
s0val |= 0x01;
if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */
{
if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n",
cs->hw.njet.last_is0, s0val);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
cs->hw.njet.irqstat0 = s0val;
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
/* we have a read dma int */
read_tiger(cs);
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
/* we have a write dma int */
write_tiger(cs);
/* end new code 13/07/00 GE */
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
}
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
reset_netjet_s(struct IsdnCardState *cs)
{
cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
mdelay(10);
/* now edge triggered for TJ320 GE 13/07/00 */
/* see comment in IRQ function */
if (cs->subtyp) /* TJ320 */
cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */
else
cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
mdelay(10);
cs->hw.njet.auxd = 0;
cs->hw.njet.dmactrl = 0;
byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
}
static int
NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_netjet_s(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_netjet(cs);
return (0);
case CARD_INIT:
reset_netjet_s(cs);
inittiger(cs);
spin_lock_irqsave(&cs->lock, flags);
clear_pending_isac_ints(cs);
initisac(cs);
/* Reenable all IRQ */
cs->writeisac(cs, ISAC_MASK, 0);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int njs_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
{
u32 cfg;
if (pci_enable_device(dev_netjet))
return (0);
pci_set_master(dev_netjet);
cs->irq = dev_netjet->irq;
if (!cs->irq) {
printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
return (0);
}
cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
if (!cs->hw.njet.base) {
printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
return (0);
}
/* the TJ300 and TJ320 must be detected, the IRQ handling is different
* unfortunately the chips use the same device ID, but the TJ320 has
* the bit20 in status PCI cfg register set
*/
pci_read_config_dword(dev_netjet, 0x04, &cfg);
if (cfg & 0x00100000)
cs->subtyp = 1; /* TJ320 */
else
cs->subtyp = 0; /* TJ300 */
/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
if ((dev_netjet->subsystem_vendor == 0x55) &&
(dev_netjet->subsystem_device == 0x02)) {
printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
return (0);
}
/* end new code */
return (1);
}
static int njs_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
{
cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
mdelay(10);
cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
mdelay(10);
cs->hw.njet.auxd = 0xC0;
cs->hw.njet.dmactrl = 0;
byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
switch (((NETjet_ReadIC(cs, ISAC_RBCH) >> 5) & 3))
{
case 0:
return 1; /* end loop */
case 3:
printk(KERN_WARNING "NETjet-S: NETspider-U PCI card found\n");
return -1; /* continue looping */
default:
printk(KERN_WARNING "NETjet-S: No PCI card found\n");
return 0; /* end loop & function */
}
return 1; /* end loop */
}
static int njs_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
{
const int bytecnt = 256;
printk(KERN_INFO
"NETjet-S: %s card configured at %#lx IRQ %d\n",
cs->subtyp ? "TJ320" : "TJ300", cs->hw.njet.base, cs->irq);
if (!request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn")) {
printk(KERN_WARNING
"HiSax: NETjet-S config port %#lx-%#lx already in use\n",
cs->hw.njet.base,
cs->hw.njet.base + bytecnt);
return (0);
}
cs->readisac = &NETjet_ReadIC;
cs->writeisac = &NETjet_WriteIC;
cs->readisacfifo = &NETjet_ReadICfifo;
cs->writeisacfifo = &NETjet_WriteICfifo;
cs->BC_Read_Reg = &dummyrr;
cs->BC_Write_Reg = &dummywr;
cs->BC_Send_Data = &netjet_fill_dma;
setup_isac(cs);
cs->cardmsg = &NETjet_S_card_msg;
cs->irq_func = &netjet_s_interrupt;
cs->irq_flags |= IRQF_SHARED;
ISACVersion(cs, "NETjet-S:");
return (1);
}
static struct pci_dev *dev_netjet = NULL;
int setup_netjet_s(struct IsdnCard *card)
{
int ret;
struct IsdnCardState *cs = card->cs;
char tmp[64];
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
strcpy(tmp, NETjet_S_revision);
printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_NETJET_S)
return (0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
for (;;)
{
if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
ret = njs_pci_probe(dev_netjet, cs);
if (!ret)
return (0);
} else {
printk(KERN_WARNING "NETjet-S: No PCI card found\n");
return (0);
}
ret = njs_cs_init(card, cs);
if (!ret)
return (0);
if (ret > 0)
break;
/* otherwise, ret < 0, continue looping */
}
return njs_cs_init_rest(card, cs);
}

View File

@ -1,258 +0,0 @@
/* $Id: nj_u.c,v 2.14.2.3 2004/01/13 14:31:26 keil Exp $
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "icc.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
#include "netjet.h"
static const char *NETjet_U_revision = "$Revision: 2.14.2.3 $";
static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
{
return (5);
}
static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
{
}
static irqreturn_t
netjet_u_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
NETJET_ISACIRQ)) {
val = NETjet_ReadIC(cs, ICC_ISTA);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "tiger: i1 %x %x", sval, val);
if (val) {
icc_interrupt(cs, val);
NETjet_WriteIC(cs, ICC_MASK, 0xFF);
NETjet_WriteIC(cs, ICC_MASK, 0x0);
}
}
/* start new code 13/07/00 GE */
/* set bits in sval to indicate which page is free */
if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
/* the 2nd write page is free */
sval = 0x08;
else /* the 1st write page is free */
sval = 0x04;
if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
/* the 2nd read page is free */
sval = sval | 0x02;
else /* the 1st read page is free */
sval = sval | 0x01;
if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
{
if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
cs->hw.njet.irqstat0 = sval;
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
/* we have a read dma int */
read_tiger(cs);
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
/* we have a write dma int */
write_tiger(cs);
/* end new code 13/07/00 GE */
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
}
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
reset_netjet_u(struct IsdnCardState *cs)
{
cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
mdelay(10);
cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */
/* now edge triggered for TJ320 GE 13/07/00 */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
mdelay(10);
cs->hw.njet.auxd = 0xC0;
cs->hw.njet.dmactrl = 0;
byteout(cs->hw.njet.auxa, 0);
byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
}
static int
NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_netjet_u(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_netjet(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inittiger(cs);
reset_netjet_u(cs);
clear_pending_icc_ints(cs);
initicc(cs);
/* Reenable all IRQ */
cs->writeisac(cs, ICC_MASK, 0);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int nju_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
{
if (pci_enable_device(dev_netjet))
return (0);
pci_set_master(dev_netjet);
cs->irq = dev_netjet->irq;
if (!cs->irq) {
printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
return (0);
}
cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
if (!cs->hw.njet.base) {
printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
return (0);
}
return (1);
}
static int nju_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
{
cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
mdelay(10);
cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
mdelay(10);
cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
mdelay(10);
cs->hw.njet.auxd = 0xC0;
cs->hw.njet.dmactrl = 0;
byteout(cs->hw.njet.auxa, 0);
byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
switch (((NETjet_ReadIC(cs, ICC_RBCH) >> 5) & 3))
{
case 3:
return 1; /* end loop */
case 0:
printk(KERN_WARNING "NETspider-U: NETjet-S PCI card found\n");
return -1; /* continue looping */
default:
printk(KERN_WARNING "NETspider-U: No PCI card found\n");
return 0; /* end loop & function */
}
return 1; /* end loop */
}
static int nju_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
{
const int bytecnt = 256;
printk(KERN_INFO
"NETspider-U: PCI card configured at %#lx IRQ %d\n",
cs->hw.njet.base, cs->irq);
if (!request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn")) {
printk(KERN_WARNING
"HiSax: NETspider-U config port %#lx-%#lx "
"already in use\n",
cs->hw.njet.base,
cs->hw.njet.base + bytecnt);
return (0);
}
setup_icc(cs);
cs->readisac = &NETjet_ReadIC;
cs->writeisac = &NETjet_WriteIC;
cs->readisacfifo = &NETjet_ReadICfifo;
cs->writeisacfifo = &NETjet_WriteICfifo;
cs->BC_Read_Reg = &dummyrr;
cs->BC_Write_Reg = &dummywr;
cs->BC_Send_Data = &netjet_fill_dma;
cs->cardmsg = &NETjet_U_card_msg;
cs->irq_func = &netjet_u_interrupt;
cs->irq_flags |= IRQF_SHARED;
ICCVersion(cs, "NETspider-U:");
return (1);
}
static struct pci_dev *dev_netjet = NULL;
int setup_netjet_u(struct IsdnCard *card)
{
int ret;
struct IsdnCardState *cs = card->cs;
char tmp[64];
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
strcpy(tmp, NETjet_U_revision);
printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_NETJET_U)
return (0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
for (;;)
{
if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
ret = nju_pci_probe(dev_netjet, cs);
if (!ret)
return (0);
} else {
printk(KERN_WARNING "NETspider-U: No PCI card found\n");
return (0);
}
ret = nju_cs_init(card, cs);
if (!ret)
return (0);
if (ret > 0)
break;
/* ret < 0 == continue looping */
}
return nju_cs_init_rest(card, cs);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,260 +0,0 @@
/* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for Creatix S0BOX
*
* Author Enrik Berkhan
* Copyright by Enrik Berkhan <enrik@starfleet.inka.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *s0box_revision = "$Revision: 2.6.2.4 $";
static inline void
writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
outb_p(0x1c, padr + 2);
outb_p(0x14, padr + 2);
outb_p((addr + off) & 0x7f, padr);
outb_p(0x16, padr + 2);
outb_p(val, padr);
outb_p(0x17, padr + 2);
outb_p(0x14, padr + 2);
outb_p(0x1c, padr + 2);
}
static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
0, 0, 0, 0, 0, 0, 0, 0,
0, 8, 4, 0xc, 2, 0xa, 6, 0xe };
static inline u_char
readreg(unsigned int padr, signed int addr, u_char off) {
register u_char n1, n2;
outb_p(0x1c, padr + 2);
outb_p(0x14, padr + 2);
outb_p((addr + off) | 0x80, padr);
outb_p(0x16, padr + 2);
outb_p(0x17, padr + 2);
n1 = (inb_p(padr + 1) >> 3) & 0x17;
outb_p(0x16, padr + 2);
n2 = (inb_p(padr + 1) >> 3) & 0x17;
outb_p(0x14, padr + 2);
outb_p(0x1c, padr + 2);
return nibtab[n1] | (nibtab[n2] << 4);
}
static inline void
read_fifo(unsigned int padr, signed int adr, u_char *data, int size)
{
int i;
register u_char n1, n2;
outb_p(0x1c, padr + 2);
outb_p(0x14, padr + 2);
outb_p(adr | 0x80, padr);
outb_p(0x16, padr + 2);
for (i = 0; i < size; i++) {
outb_p(0x17, padr + 2);
n1 = (inb_p(padr + 1) >> 3) & 0x17;
outb_p(0x16, padr + 2);
n2 = (inb_p(padr + 1) >> 3) & 0x17;
*(data++) = nibtab[n1] | (nibtab[n2] << 4);
}
outb_p(0x14, padr + 2);
outb_p(0x1c, padr + 2);
return;
}
static inline void
write_fifo(unsigned int padr, signed int adr, u_char *data, int size)
{
int i;
outb_p(0x1c, padr + 2);
outb_p(0x14, padr + 2);
outb_p(adr & 0x7f, padr);
for (i = 0; i < size; i++) {
outb_p(0x16, padr + 2);
outb_p(*(data++), padr);
outb_p(0x17, padr + 2);
}
outb_p(0x14, padr + 2);
outb_p(0x1c, padr + 2);
return;
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg)
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
s0box_interrupt(int intno, void *dev_id)
{
#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
int count = 0;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
count++;
val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
if (val && count < MAXCOUNT) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
if (val && count < MAXCOUNT) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (count >= MAXCOUNT)
printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count);
writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_s0box(struct IsdnCardState *cs)
{
release_region(cs->hw.teles3.cfg_reg, 8);
}
static int
S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
break;
case CARD_RELEASE:
release_io_s0box(cs);
break;
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscxisac(cs, 3);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case CARD_TEST:
break;
}
return (0);
}
int setup_s0box(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, s0box_revision);
printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_S0BOX)
return (0);
cs->hw.teles3.cfg_reg = card->para[1];
cs->hw.teles3.hscx[0] = -0x20;
cs->hw.teles3.hscx[1] = 0x0;
cs->hw.teles3.isac = 0x20;
cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
cs->irq = card->para[0];
if (!request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O")) {
printk(KERN_WARNING "HiSax: S0Box ports %x-%x already in use\n",
cs->hw.teles3.cfg_reg,
cs->hw.teles3.cfg_reg + 7);
return 0;
}
printk(KERN_INFO "HiSax: S0Box config irq:%d isac:0x%x cfg:0x%x\n",
cs->irq,
cs->hw.teles3.isac, cs->hw.teles3.cfg_reg);
printk(KERN_INFO "HiSax: hscx A:0x%x hscx B:0x%x\n",
cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &S0Box_card_msg;
cs->irq_func = &s0box_interrupt;
ISACVersion(cs, "S0Box:");
if (HscxVersion(cs, "S0Box:")) {
printk(KERN_WARNING
"S0Box: wrong HSCX versions check IO address\n");
release_io_s0box(cs);
return (0);
}
return (1);
}

View File

@ -1,296 +0,0 @@
/* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for HST Saphir 1
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to HST High Soft Tech GmbH
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
static char *saphir_rev = "$Revision: 1.10.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define ISAC_DATA 0
#define HSCX_DATA 1
#define ADDRESS_REG 2
#define IRQ_REG 3
#define SPARE_REG 4
#define RESET_REG 5
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
offset + (hscx ? 0x40 : 0), value);
}
#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \
cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \
cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \
cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \
cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
saphir_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
/* Watchdog */
if (cs->hw.saphir.timer.function)
mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ);
else
printk(KERN_WARNING "saphir: Spurious timer!\n");
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0);
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0);
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
SaphirWatchDog(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, hw.saphir.timer);
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
/* 5 sec WatchDog, so read at least every 4 sec */
cs->readisac(cs, ISAC_RBCH);
spin_unlock_irqrestore(&cs->lock, flags);
mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ);
}
static void
release_io_saphir(struct IsdnCardState *cs)
{
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
del_timer(&cs->hw.saphir.timer);
cs->hw.saphir.timer.function = NULL;
if (cs->hw.saphir.cfg_reg)
release_region(cs->hw.saphir.cfg_reg, 6);
}
static int
saphir_reset(struct IsdnCardState *cs)
{
u_char irq_val;
switch (cs->irq) {
case 5: irq_val = 0;
break;
case 3: irq_val = 1;
break;
case 11:
irq_val = 2;
break;
case 12:
irq_val = 3;
break;
case 15:
irq_val = 4;
break;
default:
printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n",
cs->irq);
return (1);
}
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
mdelay(10);
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
mdelay(10);
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
return (0);
}
static int
saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
saphir_reset(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_saphir(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscxisac(cs, 3);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
int setup_saphir(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, saphir_rev);
printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_HSTSAPHIR)
return (0);
/* IO-Ports */
cs->hw.saphir.cfg_reg = card->para[1];
cs->hw.saphir.isac = card->para[1] + ISAC_DATA;
cs->hw.saphir.hscx = card->para[1] + HSCX_DATA;
cs->hw.saphir.ale = card->para[1] + ADDRESS_REG;
cs->irq = card->para[0];
if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) {
printk(KERN_WARNING
"HiSax: HST Saphir config port %x-%x already in use\n",
cs->hw.saphir.cfg_reg,
cs->hw.saphir.cfg_reg + 5);
return (0);
}
printk(KERN_INFO "HiSax: HST Saphir config irq:%d io:0x%X\n",
cs->irq, cs->hw.saphir.cfg_reg);
setup_isac(cs);
timer_setup(&cs->hw.saphir.timer, SaphirWatchDog, 0);
cs->hw.saphir.timer.expires = jiffies + 4 * HZ;
add_timer(&cs->hw.saphir.timer);
if (saphir_reset(cs)) {
release_io_saphir(cs);
return (0);
}
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &saphir_card_msg;
cs->irq_func = &saphir_interrupt;
ISACVersion(cs, "saphir:");
if (HscxVersion(cs, "saphir:")) {
printk(KERN_WARNING
"saphir: wrong HSCX versions check IO address\n");
release_io_saphir(cs);
return (0);
}
return (1);
}

View File

@ -1,873 +0,0 @@
/* $Id: sedlbauer.c,v 1.34.2.6 2004/01/24 20:47:24 keil Exp $
*
* low level stuff for Sedlbauer cards
* includes support for the Sedlbauer speed star (speed star II),
* support for the Sedlbauer speed fax+,
* support for the Sedlbauer ISDN-Controller PC/104 and
* support for the Sedlbauer speed pci
* derived from the original file asuscom.c from Karsten Keil
*
* Author Marcus Niemann
* Copyright by Marcus Niemann <niemann@www-bib.fh-bielefeld.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Karsten Keil
* Sedlbauer AG for informations
* Edgar Toernig
*
*/
/* Supported cards:
* Card: Chip: Configuration: Comment:
* ---------------------------------------------------------------------
* Speed Card ISAC_HSCX DIP-SWITCH
* Speed Win ISAC_HSCX ISAPNP
* Speed Fax+ ISAC_ISAR ISAPNP Full analog support
* Speed Star ISAC_HSCX CARDMGR
* Speed Win2 IPAC ISAPNP
* ISDN PC/104 IPAC DIP-SWITCH
* Speed Star2 IPAC CARDMGR
* Speed PCI IPAC PCI PNP
* Speed Fax+ ISAC_ISAR PCI PNP Full analog support
*
* Important:
* For the sedlbauer speed fax+ to work properly you have to download
* the firmware onto the card.
* For example: hisaxctrl <DriverID> 9 ISAR.BIN
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "ipac.h"
#include "hscx.h"
#include "isar.h"
#include "isdnl1.h"
#include <linux/pci.h>
#include <linux/isapnp.h>
static const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
static const char *Sedlbauer_Types[] =
{"None", "speed card/win", "speed star", "speed fax+",
"speed win II / ISDN PC/104", "speed star II", "speed pci",
"speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"};
#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
#define PCI_SUBVENDOR_HST_SAPHIR3 0x52
#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
#define PCI_SUB_ID_SEDLBAUER 0x01
#define SEDL_SPEED_CARD_WIN 1
#define SEDL_SPEED_STAR 2
#define SEDL_SPEED_FAX 3
#define SEDL_SPEED_WIN2_PC104 4
#define SEDL_SPEED_STAR2 5
#define SEDL_SPEED_PCI 6
#define SEDL_SPEEDFAX_PYRAMID 7
#define SEDL_SPEEDFAX_PCI 8
#define HST_SAPHIR3 9
#define SEDL_CHIP_TEST 0
#define SEDL_CHIP_ISAC_HSCX 1
#define SEDL_CHIP_ISAC_ISAR 2
#define SEDL_CHIP_IPAC 3
#define SEDL_BUS_ISA 1
#define SEDL_BUS_PCI 2
#define SEDL_BUS_PCMCIA 3
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define SEDL_HSCX_ISA_RESET_ON 0
#define SEDL_HSCX_ISA_RESET_OFF 1
#define SEDL_HSCX_ISA_ISAC 2
#define SEDL_HSCX_ISA_HSCX 3
#define SEDL_HSCX_ISA_ADR 4
#define SEDL_HSCX_PCMCIA_RESET 0
#define SEDL_HSCX_PCMCIA_ISAC 1
#define SEDL_HSCX_PCMCIA_HSCX 2
#define SEDL_HSCX_PCMCIA_ADR 4
#define SEDL_ISAR_ISA_ISAC 4
#define SEDL_ISAR_ISA_ISAR 6
#define SEDL_ISAR_ISA_ADR 8
#define SEDL_ISAR_ISA_ISAR_RESET_ON 10
#define SEDL_ISAR_ISA_ISAR_RESET_OFF 12
#define SEDL_IPAC_ANY_ADR 0
#define SEDL_IPAC_ANY_IPAC 2
#define SEDL_IPAC_PCI_BASE 0
#define SEDL_IPAC_PCI_ADR 0xc0
#define SEDL_IPAC_PCI_IPAC 0xc8
#define SEDL_ISAR_PCI_ADR 0xc8
#define SEDL_ISAR_PCI_ISAC 0xd0
#define SEDL_ISAR_PCI_ISAR 0xe0
#define SEDL_ISAR_PCI_ISAR_RESET_ON 0x01
#define SEDL_ISAR_PCI_ISAR_RESET_OFF 0x18
#define SEDL_ISAR_PCI_LED1 0x08
#define SEDL_ISAR_PCI_LED2 0x10
#define SEDL_RESET 0x3 /* same as DOS driver */
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size);
}
static u_char
ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset | 0x80));
}
static void
WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset | 0x80, value);
}
static void
ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
{
readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
}
static void
WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size)
{
writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.sedl.adr,
cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.sedl.adr,
cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value);
}
/* ISAR access routines
* mode = 0 access with IRQ on
* mode = 1 access with IRQ off
* mode = 2 access with IRQ off and using last offset
*/
static u_char
ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
{
if (mode == 0)
return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset));
else if (mode == 1)
byteout(cs->hw.sedl.adr, offset);
return (bytein(cs->hw.sedl.hscx));
}
static void
WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
{
if (mode == 0)
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value);
else {
if (mode == 1)
byteout(cs->hw.sedl.adr, offset);
byteout(cs->hw.sedl.hscx, value);
}
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \
cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \
cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \
cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \
cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
sedlbauer_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) {
/* The card tends to generate interrupts while being removed
causing us to just crash the kernel. bad. */
spin_unlock_irqrestore(&cs->lock, flags);
printk(KERN_WARNING "Sedlbauer: card not available!\n");
return IRQ_NONE;
}
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t
sedlbauer_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
Start_IPAC:
if (cs->debug & L1_DEB_IPAC)
debugl1(cs, "IPAC ISTA %02X", ista);
if (ista & 0x0f) {
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
if (ista & 0x01)
val |= 0x01;
if (ista & 0x04)
val |= 0x02;
if (ista & 0x08)
val |= 0x04;
if (val)
hscx_int_main(cs, val);
}
if (ista & 0x20) {
val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80);
if (val) {
isac_interrupt(cs, val);
}
}
if (ista & 0x10) {
val = 0x01;
isac_interrupt(cs, val);
}
ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA);
if ((ista & 0x3f) && icnt) {
icnt--;
goto Start_IPAC;
}
if (!icnt)
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Sedlbauer IRQ LOOP");
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static irqreturn_t
sedlbauer_interrupt_isar(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
int cnt = 5;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
Start_ISAR:
if (val & ISAR_IRQSTA)
isar_int_main(cs);
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT);
if ((val & ISAR_IRQSTA) && --cnt) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "ISAR IntStat after IntRoutine");
goto Start_ISAR;
}
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA);
if (val && --cnt) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (!cnt)
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Sedlbauer IRQ LOOP");
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_sedlbauer(struct IsdnCardState *cs)
{
int bytecnt = 8;
if (cs->subtyp == SEDL_SPEED_FAX) {
bytecnt = 16;
} else if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
bytecnt = 256;
}
if (cs->hw.sedl.cfg_reg)
release_region(cs->hw.sedl.cfg_reg, bytecnt);
}
static void
reset_sedlbauer(struct IsdnCardState *cs)
{
printk(KERN_INFO "Sedlbauer: resetting card\n");
if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) &&
(cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) {
if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
mdelay(2);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
mdelay(10);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
} else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) &&
(cs->hw.sedl.bus == SEDL_BUS_PCI)) {
byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_on);
mdelay(2);
byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off);
mdelay(10);
} else {
byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */
mdelay(2);
byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */
mdelay(10);
}
}
}
static int
Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_sedlbauer(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
if (cs->hw.sedl.bus == SEDL_BUS_PCI)
/* disable all IRQ */
byteout(cs->hw.sedl.cfg_reg + 5, 0);
if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
spin_lock_irqsave(&cs->lock, flags);
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
ISAR_IRQBIT, 0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
ISAC_MASK, 0xFF);
reset_sedlbauer(cs);
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
ISAR_IRQBIT, 0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac,
ISAC_MASK, 0xFF);
spin_unlock_irqrestore(&cs->lock, flags);
}
release_io_sedlbauer(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
if (cs->hw.sedl.bus == SEDL_BUS_PCI)
/* enable all IRQ */
byteout(cs->hw.sedl.cfg_reg + 5, 0x02);
reset_sedlbauer(cs);
if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
clear_pending_isac_ints(cs);
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
ISAR_IRQBIT, 0);
initisac(cs);
initisar(cs);
/* Reenable all IRQ */
cs->writeisac(cs, ISAC_MASK, 0);
/* RESET Receiver and Transmitter */
cs->writeisac(cs, ISAC_CMDR, 0x41);
} else {
inithscxisac(cs, 3);
}
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
case MDL_INFO_CONN:
if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
return (0);
spin_lock_irqsave(&cs->lock, flags);
if ((long) arg)
cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
else
cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1;
byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off);
spin_unlock_irqrestore(&cs->lock, flags);
break;
case MDL_INFO_REL:
if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
return (0);
spin_lock_irqsave(&cs->lock, flags);
if ((long) arg)
cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2;
else
cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1;
byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off);
spin_unlock_irqrestore(&cs->lock, flags);
break;
}
return (0);
}
#ifdef __ISAPNP__
static struct isapnp_device_id sedl_ids[] = {
{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
(unsigned long) "Speed win" },
{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
(unsigned long) "Speed Fax+" },
{ 0, }
};
static struct isapnp_device_id *ipid = &sedl_ids[0];
static struct pnp_card *pnp_c = NULL;
static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
{
struct IsdnCardState *cs = card->cs;
struct pnp_dev *pnp_d;
if (!isapnp_present())
return -1;
while (ipid->card_vendor) {
if ((pnp_c = pnp_find_card(ipid->card_vendor,
ipid->card_device, pnp_c))) {
pnp_d = NULL;
if ((pnp_d = pnp_find_dev(pnp_c,
ipid->vendor, ipid->function, pnp_d))) {
int err;
printk(KERN_INFO "HiSax: %s detected\n",
(char *)ipid->driver_data);
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[0] = pnp_irq(pnp_d, 0);
if (card->para[0] == -1 || !card->para[1]) {
printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
return (0);
}
cs->hw.sedl.cfg_reg = card->para[1];
cs->irq = card->para[0];
if (ipid->function == ISAPNP_FUNCTION(0x2)) {
cs->subtyp = SEDL_SPEED_FAX;
cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
*bytecnt = 16;
} else {
cs->subtyp = SEDL_SPEED_CARD_WIN;
cs->hw.sedl.chip = SEDL_CHIP_TEST;
}
return (1);
} else {
printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
return (0);
}
}
ipid++;
pnp_c = NULL;
}
printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
return -1;
}
#else
static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
{
return -1;
}
#endif /* __ISAPNP__ */
#ifdef CONFIG_PCI
static struct pci_dev *dev_sedl = NULL;
static int setup_sedlbauer_pci(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
u16 sub_vendor_id, sub_id;
if ((dev_sedl = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET,
PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
if (pci_enable_device(dev_sedl))
return (0);
cs->irq = dev_sedl->irq;
if (!cs->irq) {
printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
return (0);
}
cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
} else {
printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
return (0);
}
cs->irq_flags |= IRQF_SHARED;
cs->hw.sedl.bus = SEDL_BUS_PCI;
sub_vendor_id = dev_sedl->subsystem_vendor;
sub_id = dev_sedl->subsystem_device;
printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
sub_vendor_id, sub_id);
printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
cs->hw.sedl.cfg_reg);
if (sub_id != PCI_SUB_ID_SEDLBAUER) {
printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
return (0);
}
if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
} else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
cs->subtyp = SEDL_SPEEDFAX_PCI;
} else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
cs->hw.sedl.chip = SEDL_CHIP_IPAC;
cs->subtyp = HST_SAPHIR3;
} else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
cs->hw.sedl.chip = SEDL_CHIP_IPAC;
cs->subtyp = SEDL_SPEED_PCI;
} else {
printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
sub_vendor_id);
return (0);
}
cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
byteout(cs->hw.sedl.cfg_reg, 0xff);
byteout(cs->hw.sedl.cfg_reg, 0x00);
byteout(cs->hw.sedl.cfg_reg + 2, 0xdd);
byteout(cs->hw.sedl.cfg_reg + 5, 0); /* disable all IRQ */
byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_on);
mdelay(2);
byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off);
mdelay(10);
return (1);
}
#else
static int setup_sedlbauer_pci(struct IsdnCard *card)
{
return (1);
}
#endif /* CONFIG_PCI */
int setup_sedlbauer(struct IsdnCard *card)
{
int bytecnt = 8, ver, val, rc;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, Sedlbauer_revision);
printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ == ISDN_CTYPE_SEDLBAUER) {
cs->subtyp = SEDL_SPEED_CARD_WIN;
cs->hw.sedl.bus = SEDL_BUS_ISA;
cs->hw.sedl.chip = SEDL_CHIP_TEST;
} else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) {
cs->subtyp = SEDL_SPEED_STAR;
cs->hw.sedl.bus = SEDL_BUS_PCMCIA;
cs->hw.sedl.chip = SEDL_CHIP_TEST;
} else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) {
cs->subtyp = SEDL_SPEED_FAX;
cs->hw.sedl.bus = SEDL_BUS_ISA;
cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
} else
return (0);
bytecnt = 8;
if (card->para[1]) {
cs->hw.sedl.cfg_reg = card->para[1];
cs->irq = card->para[0];
if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
bytecnt = 16;
}
} else {
rc = setup_sedlbauer_isapnp(card, &bytecnt);
if (!rc)
return (0);
if (rc > 0)
goto ready;
/* Probe for Sedlbauer speed pci */
rc = setup_sedlbauer_pci(card);
if (!rc)
return (0);
bytecnt = 256;
}
ready:
/* In case of the sedlbauer pcmcia card, this region is in use,
* reserved for us by the card manager. So we do not check it
* here, it would fail.
*/
if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA &&
!request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn")) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
cs->hw.sedl.cfg_reg,
cs->hw.sedl.cfg_reg + bytecnt);
return (0);
}
printk(KERN_INFO
"Sedlbauer: defined at 0x%x-0x%x IRQ %d\n",
cs->hw.sedl.cfg_reg,
cs->hw.sedl.cfg_reg + bytecnt,
cs->irq);
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Sedl_card_msg;
/*
* testing ISA and PCMCIA Cards for IPAC, default is ISAC
* do not test for PCI card, because ports are different
* and PCI card uses only IPAC (for the moment)
*/
if (cs->hw.sedl.bus != SEDL_BUS_PCI) {
val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR,
cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID);
printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val);
if ((val == 1) || (val == 2)) {
/* IPAC */
cs->subtyp = SEDL_SPEED_WIN2_PC104;
if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
cs->subtyp = SEDL_SPEED_STAR2;
}
cs->hw.sedl.chip = SEDL_CHIP_IPAC;
} else {
/* ISAC_HSCX oder ISAC_ISAR */
if (cs->hw.sedl.chip == SEDL_CHIP_TEST) {
cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX;
}
}
}
/*
* hw.sedl.chip is now properly set
*/
printk(KERN_INFO "Sedlbauer: %s detected\n",
Sedlbauer_Types[cs->subtyp]);
setup_isac(cs);
if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR;
cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
} else {
cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR;
cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC;
}
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
cs->readisac = &ReadISAC_IPAC;
cs->writeisac = &WriteISAC_IPAC;
cs->readisacfifo = &ReadISACfifo_IPAC;
cs->writeisacfifo = &WriteISACfifo_IPAC;
cs->irq_func = &sedlbauer_interrupt_ipac;
val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID);
printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val);
} else {
/* ISAC_HSCX oder ISAC_ISAR */
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
SEDL_ISAR_PCI_ADR;
cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
SEDL_ISAR_PCI_ISAC;
cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
SEDL_ISAR_PCI_ISAR;
} else {
cs->hw.sedl.adr = cs->hw.sedl.cfg_reg +
SEDL_ISAR_ISA_ADR;
cs->hw.sedl.isac = cs->hw.sedl.cfg_reg +
SEDL_ISAR_ISA_ISAC;
cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg +
SEDL_ISAR_ISA_ISAR;
cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg +
SEDL_ISAR_ISA_ISAR_RESET_ON;
cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg +
SEDL_ISAR_ISA_ISAR_RESET_OFF;
}
cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar;
cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar;
test_and_set_bit(HW_ISAR, &cs->HW_Flags);
cs->irq_func = &sedlbauer_interrupt_isar;
cs->auxcmd = &isar_auxcmd;
ISACVersion(cs, "Sedlbauer:");
cs->BC_Read_Reg = &ReadISAR;
cs->BC_Write_Reg = &WriteISAR;
cs->BC_Send_Data = &isar_fill_fifo;
bytecnt = 3;
while (bytecnt) {
ver = ISARVersion(cs, "Sedlbauer:");
if (ver < 0)
printk(KERN_WARNING
"Sedlbauer: wrong ISAR version (ret = %d)\n", ver);
else
break;
reset_sedlbauer(cs);
bytecnt--;
}
if (!bytecnt) {
release_io_sedlbauer(cs);
return (0);
}
} else {
if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) {
cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR;
cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC;
cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX;
cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
cs->irq_flags |= IRQF_SHARED;
} else {
cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR;
cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC;
cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX;
cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON;
cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF;
}
cs->irq_func = &sedlbauer_interrupt;
ISACVersion(cs, "Sedlbauer:");
if (HscxVersion(cs, "Sedlbauer:")) {
printk(KERN_WARNING
"Sedlbauer: wrong HSCX versions check IO address\n");
release_io_sedlbauer(cs);
return (0);
}
}
}
return (1);
}

View File

@ -1,209 +0,0 @@
/*======================================================================
A Sedlbauer PCMCIA client driver
This driver is for the Sedlbauer Speed Star and Speed Star II,
which are ISDN PCMCIA Cards.
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The initial developer of the original code is David A. Hinds
<dahinds@users.sourceforge.net>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann
<maniemann@users.sourceforge.net>. All Rights Reserved.
Alternatively, the contents of this file may be used under the
terms of the GNU General Public License version 2 (the "GPL"), in
which case the provisions of the GPL are applicable instead of the
above. If you wish to allow the use of your version of this file
only under the terms of the GPL and not to allow others to use
your version of this file under the MPL, indicate your decision
by deleting the provisions above and replace them with the notice
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
======================================================================*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#include "hisax_cfg.h"
MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards");
MODULE_AUTHOR("Marcus Niemann");
MODULE_LICENSE("Dual MPL/GPL");
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int protocol = 2; /* EURO-ISDN Default */
module_param(protocol, int, 0);
static int sedlbauer_config(struct pcmcia_device *link);
static void sedlbauer_release(struct pcmcia_device *link);
static void sedlbauer_detach(struct pcmcia_device *p_dev);
typedef struct local_info_t {
struct pcmcia_device *p_dev;
int stop;
int cardnr;
} local_info_t;
static int sedlbauer_probe(struct pcmcia_device *link)
{
local_info_t *local;
dev_dbg(&link->dev, "sedlbauer_attach()\n");
/* Allocate space for private device-specific data */
local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
local->cardnr = -1;
local->p_dev = link;
link->priv = local;
return sedlbauer_config(link);
} /* sedlbauer_attach */
static void sedlbauer_detach(struct pcmcia_device *link)
{
dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link);
((local_info_t *)link->priv)->stop = 1;
sedlbauer_release(link);
/* This points to the parent local_info_t struct */
kfree(link->priv);
} /* sedlbauer_detach */
static int sedlbauer_config_check(struct pcmcia_device *p_dev, void *priv_data)
{
if (p_dev->config_index == 0)
return -EINVAL;
p_dev->io_lines = 3;
return pcmcia_request_io(p_dev);
}
static int sedlbauer_config(struct pcmcia_device *link)
{
int ret;
IsdnCard_t icard;
dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link);
link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
ret = pcmcia_loop_config(link, sedlbauer_config_check, NULL);
if (ret)
goto failed;
ret = pcmcia_enable_device(link);
if (ret)
goto failed;
icard.para[0] = link->irq;
icard.para[1] = link->resource[0]->start;
icard.protocol = protocol;
icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
ret = hisax_init_pcmcia(link,
&(((local_info_t *)link->priv)->stop), &icard);
if (ret < 0) {
printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d with %pR\n",
ret, link->resource[0]);
sedlbauer_release(link);
return -ENODEV;
} else
((local_info_t *)link->priv)->cardnr = ret;
return 0;
failed:
sedlbauer_release(link);
return -ENODEV;
} /* sedlbauer_config */
static void sedlbauer_release(struct pcmcia_device *link)
{
local_info_t *local = link->priv;
dev_dbg(&link->dev, "sedlbauer_release(0x%p)\n", link);
if (local) {
if (local->cardnr >= 0) {
/* no unregister function with hisax */
HiSax_closecard(local->cardnr);
}
}
pcmcia_disable_device(link);
} /* sedlbauer_release */
static int sedlbauer_suspend(struct pcmcia_device *link)
{
local_info_t *dev = link->priv;
dev->stop = 1;
return 0;
}
static int sedlbauer_resume(struct pcmcia_device *link)
{
local_info_t *dev = link->priv;
dev->stop = 0;
return 0;
}
static const struct pcmcia_device_id sedlbauer_ids[] = {
PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
/* PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
static struct pcmcia_driver sedlbauer_driver = {
.owner = THIS_MODULE,
.name = "sedlbauer_cs",
.probe = sedlbauer_probe,
.remove = sedlbauer_detach,
.id_table = sedlbauer_ids,
.suspend = sedlbauer_suspend,
.resume = sedlbauer_resume,
};
module_pcmcia_driver(sedlbauer_driver);

View File

@ -1,267 +0,0 @@
/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for USR Sportster internal TA
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
*
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *sportster_revision = "$Revision: 1.16.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
#define SPORTSTER_ISAC 0xC000
#define SPORTSTER_HSCXA 0x0000
#define SPORTSTER_HSCXB 0x4000
#define SPORTSTER_RES_IRQ 0x8000
#define SPORTSTER_RESET 0x80
#define SPORTSTER_INTE 0x40
static inline int
calc_off(unsigned int base, unsigned int off)
{
return (base + ((off & 0xfc) << 8) + ((off & 3) << 1));
}
static inline void
read_fifo(unsigned int adr, u_char *data, int size)
{
insb(adr, data, size);
}
static void
write_fifo(unsigned int adr, u_char *data, int size)
{
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (bytein(calc_off(cs->hw.spt.isac, offset)));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
byteout(calc_off(cs->hw.spt.isac, offset), value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
read_fifo(cs->hw.spt.isac, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
write_fifo(cs->hw.spt.isac, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg))
#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
sportster_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = READHSCX(cs, 1, HSCX_ISTA);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = ReadISAC(cs, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = READHSCX(cs, 1, HSCX_ISTA);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = ReadISAC(cs, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
/* get a new irq impulse if there any pending */
bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ + 1);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_sportster(struct IsdnCardState *cs)
{
int i, adr;
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0);
for (i = 0; i < 64; i++) {
adr = cs->hw.spt.cfg_reg + i * 1024;
release_region(adr, 8);
}
}
static void
reset_sportster(struct IsdnCardState *cs)
{
cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
mdelay(10);
cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
mdelay(10);
}
static int
Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_sportster(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_sportster(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
reset_sportster(cs);
inithscxisac(cs, 1);
cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
inithscxisac(cs, 2);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
static int get_io_range(struct IsdnCardState *cs)
{
int i, j, adr;
for (i = 0; i < 64; i++) {
adr = cs->hw.spt.cfg_reg + i * 1024;
if (!request_region(adr, 8, "sportster")) {
printk(KERN_WARNING "HiSax: USR Sportster config port "
"%x-%x already in use\n",
adr, adr + 8);
break;
}
}
if (i == 64)
return (1);
else {
for (j = 0; j < i; j++) {
adr = cs->hw.spt.cfg_reg + j * 1024;
release_region(adr, 8);
}
return (0);
}
}
int setup_sportster(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, sportster_revision);
printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_SPORTSTER)
return (0);
cs->hw.spt.cfg_reg = card->para[1];
cs->irq = card->para[0];
if (!get_io_range(cs))
return (0);
cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC;
cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA;
cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB;
switch (cs->irq) {
case 5: cs->hw.spt.res_irq = 1;
break;
case 7: cs->hw.spt.res_irq = 2;
break;
case 10:cs->hw.spt.res_irq = 3;
break;
case 11:cs->hw.spt.res_irq = 4;
break;
case 12:cs->hw.spt.res_irq = 5;
break;
case 14:cs->hw.spt.res_irq = 6;
break;
case 15:cs->hw.spt.res_irq = 7;
break;
default:release_io_sportster(cs);
printk(KERN_WARNING "Sportster: wrong IRQ\n");
return (0);
}
printk(KERN_INFO "HiSax: USR Sportster config irq:%d cfg:0x%X\n",
cs->irq, cs->hw.spt.cfg_reg);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Sportster_card_msg;
cs->irq_func = &sportster_interrupt;
ISACVersion(cs, "Sportster:");
if (HscxVersion(cs, "Sportster:")) {
printk(KERN_WARNING
"Sportster: wrong HSCX versions check IO address\n");
release_io_sportster(cs);
return (0);
}
return (1);
}

View File

@ -1,529 +0,0 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#ifndef _ST5481_H_
#define _ST5481_H_
// USB IDs, the Product Id is in the range 0x4810-0x481F
#define ST_VENDOR_ID 0x0483
#define ST5481_PRODUCT_ID 0x4810
#define ST5481_PRODUCT_ID_MASK 0xFFF0
// ST5481 endpoints when using alternative setting 3 (2B+D).
// To get the endpoint address, OR with 0x80 for IN endpoints.
#define EP_CTRL 0x00U /* Control endpoint */
#define EP_INT 0x01U /* Interrupt endpoint */
#define EP_B1_OUT 0x02U /* B1 channel out */
#define EP_B1_IN 0x03U /* B1 channel in */
#define EP_B2_OUT 0x04U /* B2 channel out */
#define EP_B2_IN 0x05U /* B2 channel in */
#define EP_D_OUT 0x06U /* D channel out */
#define EP_D_IN 0x07U /* D channel in */
// Number of isochronous packets. With 20 packets we get
// 50 interrupts/sec for each endpoint.
#define NUM_ISO_PACKETS_D 20
#define NUM_ISO_PACKETS_B 20
// Size of each isochronous packet.
// In outgoing direction we need to match ISDN data rates:
// D: 2 bytes / msec -> 16 kbit / s
// B: 16 bytes / msec -> 64 kbit / s
#define SIZE_ISO_PACKETS_D_IN 16
#define SIZE_ISO_PACKETS_D_OUT 2
#define SIZE_ISO_PACKETS_B_IN 32
#define SIZE_ISO_PACKETS_B_OUT 8
// If we overrun/underrun, we send one packet with +/- 2 bytes
#define B_FLOW_ADJUST 2
// Registers that are written using vendor specific device request
// on endpoint 0.
#define LBA 0x02 /* S loopback */
#define SET_DEFAULT 0x06 /* Soft reset */
#define LBB 0x1D /* S maintenance loopback */
#define STT 0x1e /* S force transmission signals */
#define SDA_MIN 0x20 /* SDA-sin minimal value */
#define SDA_MAX 0x21 /* SDA-sin maximal value */
#define SDELAY_VALUE 0x22 /* Delay between Tx and Rx clock */
#define IN_D_COUNTER 0x36 /* D receive channel fifo counter */
#define OUT_D_COUNTER 0x37 /* D transmit channel fifo counter */
#define IN_B1_COUNTER 0x38 /* B1 receive channel fifo counter */
#define OUT_B1_COUNTER 0x39 /* B1 transmit channel fifo counter */
#define IN_B2_COUNTER 0x3a /* B2 receive channel fifo counter */
#define OUT_B2_COUNTER 0x3b /* B2 transmit channel fifo counter */
#define FFCTRL_IN_D 0x3C /* D receive channel fifo threshold low */
#define FFCTRH_IN_D 0x3D /* D receive channel fifo threshold high */
#define FFCTRL_OUT_D 0x3E /* D transmit channel fifo threshold low */
#define FFCTRH_OUT_D 0x3F /* D transmit channel fifo threshold high */
#define FFCTRL_IN_B1 0x40 /* B1 receive channel fifo threshold low */
#define FFCTRH_IN_B1 0x41 /* B1 receive channel fifo threshold high */
#define FFCTRL_OUT_B1 0x42 /* B1 transmit channel fifo threshold low */
#define FFCTRH_OUT_B1 0x43 /* B1 transmit channel fifo threshold high */
#define FFCTRL_IN_B2 0x44 /* B2 receive channel fifo threshold low */
#define FFCTRH_IN_B2 0x45 /* B2 receive channel fifo threshold high */
#define FFCTRL_OUT_B2 0x46 /* B2 transmit channel fifo threshold low */
#define FFCTRH_OUT_B2 0x47 /* B2 transmit channel fifo threshold high */
#define MPMSK 0x4A /* Multi purpose interrupt MASK register */
#define FFMSK_D 0x4c /* D fifo interrupt MASK register */
#define FFMSK_B1 0x4e /* B1 fifo interrupt MASK register */
#define FFMSK_B2 0x50 /* B2 fifo interrupt MASK register */
#define GPIO_DIR 0x52 /* GPIO pins direction registers */
#define GPIO_OUT 0x53 /* GPIO pins output register */
#define GPIO_IN 0x54 /* GPIO pins input register */
#define TXCI 0x56 /* CI command to be transmitted */
// Format of the interrupt packet received on endpoint 1:
//
// +--------+--------+--------+--------+--------+--------+
// !MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT!
// +--------+--------+--------+--------+--------+--------+
// Offsets in the interrupt packet
#define MPINT 0
#define FFINT_D 1
#define FFINT_B1 2
#define FFINT_B2 3
#define CCIST 4
#define GPIO_INT 5
#define INT_PKT_SIZE 6
// MPINT
#define LSD_INT 0x80 /* S line activity detected */
#define RXCI_INT 0x40 /* Indicate primitive arrived */
#define DEN_INT 0x20 /* Signal enabling data out of D Tx fifo */
#define DCOLL_INT 0x10 /* D channel collision */
#define AMIVN_INT 0x04 /* AMI violation number reached 2 */
#define INFOI_INT 0x04 /* INFOi changed */
#define DRXON_INT 0x02 /* Reception channel active */
#define GPCHG_INT 0x01 /* GPIO pin value changed */
// FFINT_x
#define IN_OVERRUN 0x80 /* In fifo overrun */
#define OUT_UNDERRUN 0x40 /* Out fifo underrun */
#define IN_UP 0x20 /* In fifo thresholdh up-crossed */
#define IN_DOWN 0x10 /* In fifo thresholdl down-crossed */
#define OUT_UP 0x08 /* Out fifo thresholdh up-crossed */
#define OUT_DOWN 0x04 /* Out fifo thresholdl down-crossed */
#define IN_COUNTER_ZEROED 0x02 /* In down-counter reached 0 */
#define OUT_COUNTER_ZEROED 0x01 /* Out down-counter reached 0 */
#define ANY_REC_INT (IN_OVERRUN + IN_UP + IN_DOWN + IN_COUNTER_ZEROED)
#define ANY_XMIT_INT (OUT_UNDERRUN + OUT_UP + OUT_DOWN + OUT_COUNTER_ZEROED)
// Level 1 commands that are sent using the TXCI device request
#define ST5481_CMD_DR 0x0 /* Deactivation Request */
#define ST5481_CMD_RES 0x1 /* state machine RESet */
#define ST5481_CMD_TM1 0x2 /* Test Mode 1 */
#define ST5481_CMD_TM2 0x3 /* Test Mode 2 */
#define ST5481_CMD_PUP 0x7 /* Power UP */
#define ST5481_CMD_AR8 0x8 /* Activation Request class 1 */
#define ST5481_CMD_AR10 0x9 /* Activation Request class 2 */
#define ST5481_CMD_ARL 0xA /* Activation Request Loopback */
#define ST5481_CMD_PDN 0xF /* Power DoWn */
// Turn on/off the LEDs using the GPIO device request.
// To use the B LEDs, number_of_leds must be set to 4
#define B1_LED 0x10U
#define B2_LED 0x20U
#define GREEN_LED 0x40U
#define RED_LED 0x80U
// D channel out states
enum {
ST_DOUT_NONE,
ST_DOUT_SHORT_INIT,
ST_DOUT_SHORT_WAIT_DEN,
ST_DOUT_LONG_INIT,
ST_DOUT_LONG_WAIT_DEN,
ST_DOUT_NORMAL,
ST_DOUT_WAIT_FOR_UNDERRUN,
ST_DOUT_WAIT_FOR_NOT_BUSY,
ST_DOUT_WAIT_FOR_STOP,
ST_DOUT_WAIT_FOR_RESET,
};
#define DOUT_STATE_COUNT (ST_DOUT_WAIT_FOR_RESET + 1)
// D channel out events
enum {
EV_DOUT_START_XMIT,
EV_DOUT_COMPLETE,
EV_DOUT_DEN,
EV_DOUT_RESETED,
EV_DOUT_STOPPED,
EV_DOUT_COLL,
EV_DOUT_UNDERRUN,
};
#define DOUT_EVENT_COUNT (EV_DOUT_UNDERRUN + 1)
// ----------------------------------------------------------------------
enum {
ST_L1_F3,
ST_L1_F4,
ST_L1_F6,
ST_L1_F7,
ST_L1_F8,
};
#define L1_STATE_COUNT (ST_L1_F8 + 1)
// The first 16 entries match the Level 1 indications that
// are found at offset 4 (CCIST) in the interrupt packet
enum {
EV_IND_DP, // 0000 Deactivation Pending
EV_IND_1, // 0001
EV_IND_2, // 0010
EV_IND_3, // 0011
EV_IND_RSY, // 0100 ReSYnchronizing
EV_IND_5, // 0101
EV_IND_6, // 0110
EV_IND_7, // 0111
EV_IND_AP, // 1000 Activation Pending
EV_IND_9, // 1001
EV_IND_10, // 1010
EV_IND_11, // 1011
EV_IND_AI8, // 1100 Activation Indication class 8
EV_IND_AI10,// 1101 Activation Indication class 10
EV_IND_AIL, // 1110 Activation Indication Loopback
EV_IND_DI, // 1111 Deactivation Indication
EV_PH_ACTIVATE_REQ,
EV_PH_DEACTIVATE_REQ,
EV_TIMER3,
};
#define L1_EVENT_COUNT (EV_TIMER3 + 1)
#define ERR(format, arg...) \
printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
#define WARNING(format, arg...) \
printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
#define INFO(format, arg...) \
printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
#include <linux/isdn/hdlc.h>
#include "fsm.h"
#include "hisax_if.h"
#include <linux/skbuff.h>
/* ======================================================================
* FIFO handling
*/
/* Generic FIFO structure */
struct fifo {
u_char r, w, count, size;
spinlock_t lock;
};
/*
* Init an FIFO
*/
static inline void fifo_init(struct fifo *fifo, int size)
{
fifo->r = fifo->w = fifo->count = 0;
fifo->size = size;
spin_lock_init(&fifo->lock);
}
/*
* Add an entry to the FIFO
*/
static inline int fifo_add(struct fifo *fifo)
{
unsigned long flags;
int index;
if (!fifo) {
return -1;
}
spin_lock_irqsave(&fifo->lock, flags);
if (fifo->count == fifo->size) {
// FIFO full
index = -1;
} else {
// Return index where to get the next data to add to the FIFO
index = fifo->w++ & (fifo->size - 1);
fifo->count++;
}
spin_unlock_irqrestore(&fifo->lock, flags);
return index;
}
/*
* Remove an entry from the FIFO with the index returned.
*/
static inline int fifo_remove(struct fifo *fifo)
{
unsigned long flags;
int index;
if (!fifo) {
return -1;
}
spin_lock_irqsave(&fifo->lock, flags);
if (!fifo->count) {
// FIFO empty
index = -1;
} else {
// Return index where to get the next data from the FIFO
index = fifo->r++ & (fifo->size - 1);
fifo->count--;
}
spin_unlock_irqrestore(&fifo->lock, flags);
return index;
}
/* ======================================================================
* control pipe
*/
typedef void (*ctrl_complete_t)(void *);
typedef struct ctrl_msg {
struct usb_ctrlrequest dr;
ctrl_complete_t complete;
void *context;
} ctrl_msg;
/* FIFO of ctrl messages waiting to be sent */
#define MAX_EP0_MSG 16
struct ctrl_msg_fifo {
struct fifo f;
struct ctrl_msg data[MAX_EP0_MSG];
};
#define MAX_DFRAME_LEN_L1 300
#define HSCX_BUFMAX 4096
struct st5481_ctrl {
struct ctrl_msg_fifo msg_fifo;
unsigned long busy;
struct urb *urb;
};
struct st5481_intr {
// struct evt_fifo evt_fifo;
struct urb *urb;
};
struct st5481_d_out {
struct isdnhdlc_vars hdlc_state;
struct urb *urb[2]; /* double buffering */
unsigned long busy;
struct sk_buff *tx_skb;
struct FsmInst fsm;
};
struct st5481_b_out {
struct isdnhdlc_vars hdlc_state;
struct urb *urb[2]; /* double buffering */
u_char flow_event;
u_long busy;
struct sk_buff *tx_skb;
};
struct st5481_in {
struct isdnhdlc_vars hdlc_state;
struct urb *urb[2]; /* double buffering */
int mode;
int bufsize;
unsigned int num_packets;
unsigned int packet_size;
unsigned char ep, counter;
unsigned char *rcvbuf;
struct st5481_adapter *adapter;
struct hisax_if *hisax_if;
};
int st5481_setup_in(struct st5481_in *in);
void st5481_release_in(struct st5481_in *in);
void st5481_in_mode(struct st5481_in *in, int mode);
struct st5481_bcs {
struct hisax_b_if b_if;
struct st5481_adapter *adapter;
struct st5481_in b_in;
struct st5481_b_out b_out;
int channel;
int mode;
};
struct st5481_adapter {
int number_of_leds;
struct usb_device *usb_dev;
struct hisax_d_if hisax_d_if;
struct st5481_ctrl ctrl;
struct st5481_intr intr;
struct st5481_in d_in;
struct st5481_d_out d_out;
unsigned char leds;
unsigned int led_counter;
unsigned long event;
struct FsmInst l1m;
struct FsmTimer timer;
struct st5481_bcs bcs[2];
};
#define TIMER3_VALUE 7000
/* ======================================================================
*
*/
/*
* Submit an URB with error reporting. This is a macro so
* the __func__ returns the caller function name.
*/
#define SUBMIT_URB(urb, mem_flags) \
({ \
int status; \
if ((status = usb_submit_urb(urb, mem_flags)) < 0) { \
WARNING("usb_submit_urb failed,status=%d", status); \
} \
status; \
})
/*
* USB double buffering, return the URB index (0 or 1).
*/
static inline int get_buf_nr(struct urb *urbs[], struct urb *urb)
{
return (urbs[0] == urb ? 0 : 1);
}
/* ---------------------------------------------------------------------- */
/* B Channel */
int st5481_setup_b(struct st5481_bcs *bcs);
void st5481_release_b(struct st5481_bcs *bcs);
void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
/* D Channel */
int st5481_setup_d(struct st5481_adapter *adapter);
void st5481_release_d(struct st5481_adapter *adapter);
void st5481_b_l2l1(struct hisax_if *b_if, int pr, void *arg);
int st5481_d_init(void);
void st5481_d_exit(void);
/* USB */
void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command);
int st5481_setup_isocpipes(struct urb *urb[2], struct usb_device *dev,
unsigned int pipe, int num_packets,
int packet_size, int buf_size,
usb_complete_t complete, void *context);
void st5481_release_isocpipes(struct urb *urb[2]);
void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
u_char pipe, ctrl_complete_t complete, void *context);
void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
u8 request, u16 value,
ctrl_complete_t complete, void *context);
int st5481_setup_usb(struct st5481_adapter *adapter);
void st5481_release_usb(struct st5481_adapter *adapter);
void st5481_start(struct st5481_adapter *adapter);
void st5481_stop(struct st5481_adapter *adapter);
// ----------------------------------------------------------------------
// debugging macros
#define __debug_variable st5481_debug
#include "hisax_debug.h"
extern int st5481_debug;
#ifdef CONFIG_HISAX_DEBUG
#define DBG_ISO_PACKET(level, urb) \
if (level & __debug_variable) dump_iso_packet(__func__, urb)
static void __attribute__((unused))
dump_iso_packet(const char *name, struct urb *urb)
{
int i, j;
int len, ofs;
u_char *data;
printk(KERN_DEBUG "%s: packets=%d,errors=%d\n",
name, urb->number_of_packets, urb->error_count);
for (i = 0; i < urb->number_of_packets; ++i) {
if (urb->pipe & USB_DIR_IN) {
len = urb->iso_frame_desc[i].actual_length;
} else {
len = urb->iso_frame_desc[i].length;
}
ofs = urb->iso_frame_desc[i].offset;
printk(KERN_DEBUG "len=%.2d,ofs=%.3d ", len, ofs);
if (len) {
data = urb->transfer_buffer + ofs;
for (j = 0; j < len; j++) {
printk("%.2x", data[j]);
}
}
printk("\n");
}
}
static inline const char *ST5481_CMD_string(int evt)
{
static char s[16];
switch (evt) {
case ST5481_CMD_DR: return "DR";
case ST5481_CMD_RES: return "RES";
case ST5481_CMD_TM1: return "TM1";
case ST5481_CMD_TM2: return "TM2";
case ST5481_CMD_PUP: return "PUP";
case ST5481_CMD_AR8: return "AR8";
case ST5481_CMD_AR10: return "AR10";
case ST5481_CMD_ARL: return "ARL";
case ST5481_CMD_PDN: return "PDN";
}
sprintf(s, "0x%x", evt);
return s;
}
#else
#define DBG_ISO_PACKET(level, urb) do {} while (0)
#endif
#endif

View File

@ -1,380 +0,0 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include <linux/gfp.h>
#include <linux/usb.h>
#include <linux/netdevice.h>
#include <linux/bitrev.h>
#include "st5481.h"
static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg)
{
struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
ifc->l1l2(ifc, pr, arg);
}
/*
* Encode and transmit next frame.
*/
static void usb_b_out(struct st5481_bcs *bcs, int buf_nr)
{
struct st5481_b_out *b_out = &bcs->b_out;
struct st5481_adapter *adapter = bcs->adapter;
struct urb *urb;
unsigned int packet_size, offset;
int len, buf_size, bytes_sent;
int i;
struct sk_buff *skb;
if (test_and_set_bit(buf_nr, &b_out->busy)) {
DBG(4, "ep %d urb %d busy", (bcs->channel + 1) * 2, buf_nr);
return;
}
urb = b_out->urb[buf_nr];
// Adjust isoc buffer size according to flow state
if (b_out->flow_event & (OUT_DOWN | OUT_UNDERRUN)) {
buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
packet_size = SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
DBG(4, "B%d,adjust flow,add %d bytes", bcs->channel + 1, B_FLOW_ADJUST);
} else if (b_out->flow_event & OUT_UP) {
buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
packet_size = SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
DBG(4, "B%d,adjust flow,remove %d bytes", bcs->channel + 1, B_FLOW_ADJUST);
} else {
buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT;
packet_size = 8;
}
b_out->flow_event = 0;
len = 0;
while (len < buf_size) {
if ((skb = b_out->tx_skb)) {
DBG_SKB(0x100, skb);
DBG(4, "B%d,len=%d", bcs->channel + 1, skb->len);
if (bcs->mode == L1_MODE_TRANS) {
bytes_sent = buf_size - len;
if (skb->len < bytes_sent)
bytes_sent = skb->len;
{ /* swap tx bytes to get hearable audio data */
register unsigned char *src = skb->data;
register unsigned char *dest = urb->transfer_buffer + len;
register unsigned int count;
for (count = 0; count < bytes_sent; count++)
*dest++ = bitrev8(*src++);
}
len += bytes_sent;
} else {
len += isdnhdlc_encode(&b_out->hdlc_state,
skb->data, skb->len, &bytes_sent,
urb->transfer_buffer + len, buf_size-len);
}
skb_pull(skb, bytes_sent);
if (!skb->len) {
// Frame sent
b_out->tx_skb = NULL;
B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long) skb->truesize);
dev_kfree_skb_any(skb);
/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
/* st5481B_sched_event(bcs, B_XMTBUFREADY); */
/* } */
}
} else {
if (bcs->mode == L1_MODE_TRANS) {
memset(urb->transfer_buffer + len, 0xff, buf_size-len);
len = buf_size;
} else {
// Send flags
len += isdnhdlc_encode(&b_out->hdlc_state,
NULL, 0, &bytes_sent,
urb->transfer_buffer + len, buf_size-len);
}
}
}
// Prepare the URB
for (i = 0, offset = 0; offset < len; i++) {
urb->iso_frame_desc[i].offset = offset;
urb->iso_frame_desc[i].length = packet_size;
offset += packet_size;
packet_size = SIZE_ISO_PACKETS_B_OUT;
}
urb->transfer_buffer_length = len;
urb->number_of_packets = i;
urb->dev = adapter->usb_dev;
DBG_ISO_PACKET(0x200, urb);
SUBMIT_URB(urb, GFP_NOIO);
}
/*
* Start transferring (flags or data) on the B channel, since
* FIFO counters has been set to a non-zero value.
*/
static void st5481B_start_xfer(void *context)
{
struct st5481_bcs *bcs = context;
DBG(4, "B%d", bcs->channel + 1);
// Start transmitting (flags or data) on B channel
usb_b_out(bcs, 0);
usb_b_out(bcs, 1);
}
/*
* If the adapter has only 2 LEDs, the green
* LED will blink with a rate depending
* on the number of channels opened.
*/
static void led_blink(struct st5481_adapter *adapter)
{
u_char leds = adapter->leds;
// 50 frames/sec for each channel
if (++adapter->led_counter % 50) {
return;
}
if (adapter->led_counter % 100) {
leds |= GREEN_LED;
} else {
leds &= ~GREEN_LED;
}
st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL);
}
static void usb_b_out_complete(struct urb *urb)
{
struct st5481_bcs *bcs = urb->context;
struct st5481_b_out *b_out = &bcs->b_out;
struct st5481_adapter *adapter = bcs->adapter;
int buf_nr;
buf_nr = get_buf_nr(b_out->urb, urb);
test_and_clear_bit(buf_nr, &b_out->busy);
if (unlikely(urb->status < 0)) {
switch (urb->status) {
case -ENOENT:
case -ESHUTDOWN:
case -ECONNRESET:
DBG(4, "urb killed status %d", urb->status);
return; // Give up
default:
WARNING("urb status %d", urb->status);
if (b_out->busy == 0) {
st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2 | USB_DIR_OUT, NULL, NULL);
}
break;
}
}
usb_b_out(bcs, buf_nr);
if (adapter->number_of_leds == 2)
led_blink(adapter);
}
/*
* Start or stop the transfer on the B channel.
*/
static void st5481B_mode(struct st5481_bcs *bcs, int mode)
{
struct st5481_b_out *b_out = &bcs->b_out;
struct st5481_adapter *adapter = bcs->adapter;
DBG(4, "B%d,mode=%d", bcs->channel + 1, mode);
if (bcs->mode == mode)
return;
bcs->mode = mode;
// Cancel all USB transfers on this B channel
usb_unlink_urb(b_out->urb[0]);
usb_unlink_urb(b_out->urb[1]);
b_out->busy = 0;
st5481_in_mode(&bcs->b_in, mode);
if (bcs->mode != L1_MODE_NULL) {
// Open the B channel
if (bcs->mode != L1_MODE_TRANS) {
u32 features = HDLC_BITREVERSE;
if (bcs->mode == L1_MODE_HDLC_56K)
features |= HDLC_56KBIT;
isdnhdlc_out_init(&b_out->hdlc_state, features);
}
st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2, NULL, NULL);
// Enable B channel interrupts
st5481_usb_device_ctrl_msg(adapter, FFMSK_B1 + (bcs->channel * 2),
OUT_UP + OUT_DOWN + OUT_UNDERRUN, NULL, NULL);
// Enable B channel FIFOs
st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 32, st5481B_start_xfer, bcs);
if (adapter->number_of_leds == 4) {
if (bcs->channel == 0) {
adapter->leds |= B1_LED;
} else {
adapter->leds |= B2_LED;
}
}
} else {
// Disable B channel interrupts
st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel * 2), 0, NULL, NULL);
// Disable B channel FIFOs
st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 0, NULL, NULL);
if (adapter->number_of_leds == 4) {
if (bcs->channel == 0) {
adapter->leds &= ~B1_LED;
} else {
adapter->leds &= ~B2_LED;
}
} else {
st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
}
if (b_out->tx_skb) {
dev_kfree_skb_any(b_out->tx_skb);
b_out->tx_skb = NULL;
}
}
}
static int st5481_setup_b_out(struct st5481_bcs *bcs)
{
struct usb_device *dev = bcs->adapter->usb_dev;
struct usb_interface *intf;
struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
struct st5481_b_out *b_out = &bcs->b_out;
DBG(4, "");
intf = usb_ifnum_to_if(dev, 0);
if (intf)
altsetting = usb_altnum_to_altsetting(intf, 3);
if (!altsetting)
return -ENXIO;
// Allocate URBs and buffers for the B channel out
endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2];
DBG(4, "endpoint address=%02x,packet size=%d",
endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize));
// Allocate memory for 8000bytes/sec + extra bytes if underrun
return st5481_setup_isocpipes(b_out->urb, dev,
usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress),
NUM_ISO_PACKETS_B, SIZE_ISO_PACKETS_B_OUT,
NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST,
usb_b_out_complete, bcs);
}
static void st5481_release_b_out(struct st5481_bcs *bcs)
{
struct st5481_b_out *b_out = &bcs->b_out;
DBG(4, "");
st5481_release_isocpipes(b_out->urb);
}
int st5481_setup_b(struct st5481_bcs *bcs)
{
int retval;
DBG(4, "");
retval = st5481_setup_b_out(bcs);
if (retval)
goto err;
bcs->b_in.bufsize = HSCX_BUFMAX;
bcs->b_in.num_packets = NUM_ISO_PACKETS_B;
bcs->b_in.packet_size = SIZE_ISO_PACKETS_B_IN;
bcs->b_in.ep = (bcs->channel ? EP_B2_IN : EP_B1_IN) | USB_DIR_IN;
bcs->b_in.counter = bcs->channel ? IN_B2_COUNTER : IN_B1_COUNTER;
bcs->b_in.adapter = bcs->adapter;
bcs->b_in.hisax_if = &bcs->b_if.ifc;
retval = st5481_setup_in(&bcs->b_in);
if (retval)
goto err_b_out;
return 0;
err_b_out:
st5481_release_b_out(bcs);
err:
return retval;
}
/*
* Release buffers and URBs for the B channels
*/
void st5481_release_b(struct st5481_bcs *bcs)
{
DBG(4, "");
st5481_release_in(&bcs->b_in);
st5481_release_b_out(bcs);
}
/*
* st5481_b_l2l1 is the entry point for upper layer routines that want to
* transmit on the B channel. PH_DATA | REQUEST is a normal packet that
* we either start transmitting (if idle) or queue (if busy).
* PH_PULL | REQUEST can be called to request a callback message
* (PH_PULL | CONFIRM)
* once the link is idle. After a "pull" callback, the upper layer
* routines can use PH_PULL | INDICATION to send data.
*/
void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
{
struct st5481_bcs *bcs = ifc->priv;
struct sk_buff *skb = arg;
long mode;
DBG(4, "");
switch (pr) {
case PH_DATA | REQUEST:
BUG_ON(bcs->b_out.tx_skb);
bcs->b_out.tx_skb = skb;
break;
case PH_ACTIVATE | REQUEST:
mode = (long) arg;
DBG(4, "B%d,PH_ACTIVATE_REQUEST %ld", bcs->channel + 1, mode);
st5481B_mode(bcs, mode);
B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
break;
case PH_DEACTIVATE | REQUEST:
DBG(4, "B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
st5481B_mode(bcs, L1_MODE_NULL);
B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
break;
default:
WARNING("pr %#x\n", pr);
}
}

View File

@ -1,780 +0,0 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include <linux/gfp.h>
#include <linux/usb.h>
#include <linux/netdevice.h>
#include "st5481.h"
static void ph_connect(struct st5481_adapter *adapter);
static void ph_disconnect(struct st5481_adapter *adapter);
static struct Fsm l1fsm;
static char *strL1State[] =
{
"ST_L1_F3",
"ST_L1_F4",
"ST_L1_F6",
"ST_L1_F7",
"ST_L1_F8",
};
static char *strL1Event[] =
{
"EV_IND_DP",
"EV_IND_1",
"EV_IND_2",
"EV_IND_3",
"EV_IND_RSY",
"EV_IND_5",
"EV_IND_6",
"EV_IND_7",
"EV_IND_AP",
"EV_IND_9",
"EV_IND_10",
"EV_IND_11",
"EV_IND_AI8",
"EV_IND_AI10",
"EV_IND_AIL",
"EV_IND_DI",
"EV_PH_ACTIVATE_REQ",
"EV_PH_DEACTIVATE_REQ",
"EV_TIMER3",
};
static inline void D_L1L2(struct st5481_adapter *adapter, int pr, void *arg)
{
struct hisax_if *ifc = (struct hisax_if *) &adapter->hisax_d_if;
ifc->l1l2(ifc, pr, arg);
}
static void
l1_go_f3(struct FsmInst *fi, int event, void *arg)
{
struct st5481_adapter *adapter = fi->userdata;
if (fi->state == ST_L1_F7)
ph_disconnect(adapter);
FsmChangeState(fi, ST_L1_F3);
D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
}
static void
l1_go_f6(struct FsmInst *fi, int event, void *arg)
{
struct st5481_adapter *adapter = fi->userdata;
if (fi->state == ST_L1_F7)
ph_disconnect(adapter);
FsmChangeState(fi, ST_L1_F6);
}
static void
l1_go_f7(struct FsmInst *fi, int event, void *arg)
{
struct st5481_adapter *adapter = fi->userdata;
FsmDelTimer(&adapter->timer, 0);
ph_connect(adapter);
FsmChangeState(fi, ST_L1_F7);
D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL);
}
static void
l1_go_f8(struct FsmInst *fi, int event, void *arg)
{
struct st5481_adapter *adapter = fi->userdata;
if (fi->state == ST_L1_F7)
ph_disconnect(adapter);
FsmChangeState(fi, ST_L1_F8);
}
static void
l1_timer3(struct FsmInst *fi, int event, void *arg)
{
struct st5481_adapter *adapter = fi->userdata;
st5481_ph_command(adapter, ST5481_CMD_DR);
FsmChangeState(fi, ST_L1_F3);
D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
}
static void
l1_ignore(struct FsmInst *fi, int event, void *arg)
{
}
static void
l1_activate(struct FsmInst *fi, int event, void *arg)
{
struct st5481_adapter *adapter = fi->userdata;
st5481_ph_command(adapter, ST5481_CMD_DR);
st5481_ph_command(adapter, ST5481_CMD_PUP);
FsmRestartTimer(&adapter->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
st5481_ph_command(adapter, ST5481_CMD_AR8);
FsmChangeState(fi, ST_L1_F4);
}
static struct FsmNode L1FnList[] __initdata =
{
{ST_L1_F3, EV_IND_DP, l1_ignore},
{ST_L1_F3, EV_IND_AP, l1_go_f6},
{ST_L1_F3, EV_IND_AI8, l1_go_f7},
{ST_L1_F3, EV_IND_AI10, l1_go_f7},
{ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_activate},
{ST_L1_F4, EV_TIMER3, l1_timer3},
{ST_L1_F4, EV_IND_DP, l1_go_f3},
{ST_L1_F4, EV_IND_AP, l1_go_f6},
{ST_L1_F4, EV_IND_AI8, l1_go_f7},
{ST_L1_F4, EV_IND_AI10, l1_go_f7},
{ST_L1_F6, EV_TIMER3, l1_timer3},
{ST_L1_F6, EV_IND_DP, l1_go_f3},
{ST_L1_F6, EV_IND_AP, l1_ignore},
{ST_L1_F6, EV_IND_AI8, l1_go_f7},
{ST_L1_F6, EV_IND_AI10, l1_go_f7},
{ST_L1_F7, EV_IND_RSY, l1_go_f8},
{ST_L1_F7, EV_IND_DP, l1_go_f3},
{ST_L1_F7, EV_IND_AP, l1_go_f6},
{ST_L1_F7, EV_IND_AI8, l1_ignore},
{ST_L1_F7, EV_IND_AI10, l1_ignore},
{ST_L1_F7, EV_IND_RSY, l1_go_f8},
{ST_L1_F8, EV_TIMER3, l1_timer3},
{ST_L1_F8, EV_IND_DP, l1_go_f3},
{ST_L1_F8, EV_IND_AP, l1_go_f6},
{ST_L1_F8, EV_IND_AI8, l1_go_f8},
{ST_L1_F8, EV_IND_AI10, l1_go_f8},
{ST_L1_F8, EV_IND_RSY, l1_ignore},
};
static __printf(2, 3)
void l1m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
char buf[256];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
DBG(8, "%s", buf);
va_end(args);
}
/* ======================================================================
* D-Channel out
*/
/*
D OUT state machine:
====================
Transmit short frame (< 16 bytes of encoded data):
L1 FRAME D_OUT_STATE USB D CHANNEL
-------- ----------- --- ---------
FIXME
-> [xx..xx] SHORT_INIT -> [7Exx..xxC1C27EFF]
SHORT_WAIT_DEN <> OUT_D_COUNTER=16
END_OF_SHORT <- DEN_EVENT -> 7Exx
xxxx
xxxx
xxxx
xxxx
xxxx
C1C1
7EFF
WAIT_FOR_RESET_IDLE <- D_UNDERRUN <- (8ms)
IDLE <> Reset pipe
Transmit long frame (>= 16 bytes of encoded data):
L1 FRAME D_OUT_STATE USB D CHANNEL
-------- ----------- --- ---------
-> [xx...xx] IDLE
WAIT_FOR_STOP <> OUT_D_COUNTER=0
WAIT_FOR_RESET <> Reset pipe
STOP
INIT_LONG_FRAME -> [7Exx..xx]
WAIT_DEN <> OUT_D_COUNTER=16
OUT_NORMAL <- DEN_EVENT -> 7Exx
END_OF_FRAME_BUSY -> [xxxx] xxxx
END_OF_FRAME_NOT_BUSY -> [xxxx] xxxx
-> [xxxx] xxxx
-> [C1C2] xxxx
-> [7EFF] xxxx
xxxx
xxxx
....
xxxx
C1C2
7EFF
<- D_UNDERRUN <- (> 8ms)
WAIT_FOR_STOP <> OUT_D_COUNTER=0
WAIT_FOR_RESET <> Reset pipe
STOP
*/
static struct Fsm dout_fsm;
static char *strDoutState[] =
{
"ST_DOUT_NONE",
"ST_DOUT_SHORT_INIT",
"ST_DOUT_SHORT_WAIT_DEN",
"ST_DOUT_LONG_INIT",
"ST_DOUT_LONG_WAIT_DEN",
"ST_DOUT_NORMAL",
"ST_DOUT_WAIT_FOR_UNDERRUN",
"ST_DOUT_WAIT_FOR_NOT_BUSY",
"ST_DOUT_WAIT_FOR_STOP",
"ST_DOUT_WAIT_FOR_RESET",
};
static char *strDoutEvent[] =
{
"EV_DOUT_START_XMIT",
"EV_DOUT_COMPLETE",
"EV_DOUT_DEN",
"EV_DOUT_RESETED",
"EV_DOUT_STOPPED",
"EV_DOUT_COLL",
"EV_DOUT_UNDERRUN",
};
static __printf(2, 3)
void dout_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
char buf[256];
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
DBG(0x2, "%s", buf);
va_end(args);
}
static void dout_stop_event(void *context)
{
struct st5481_adapter *adapter = context;
FsmEvent(&adapter->d_out.fsm, EV_DOUT_STOPPED, NULL);
}
/*
* Start the transfer of a D channel frame.
*/
static void usb_d_out(struct st5481_adapter *adapter, int buf_nr)
{
struct st5481_d_out *d_out = &adapter->d_out;
struct urb *urb;
unsigned int num_packets, packet_offset;
int len, buf_size, bytes_sent;
struct sk_buff *skb;
struct usb_iso_packet_descriptor *desc;
if (d_out->fsm.state != ST_DOUT_NORMAL)
return;
if (test_and_set_bit(buf_nr, &d_out->busy)) {
DBG(2, "ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
return;
}
urb = d_out->urb[buf_nr];
skb = d_out->tx_skb;
buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
if (skb) {
len = isdnhdlc_encode(&d_out->hdlc_state,
skb->data, skb->len, &bytes_sent,
urb->transfer_buffer, buf_size);
skb_pull(skb, bytes_sent);
} else {
// Send flags or idle
len = isdnhdlc_encode(&d_out->hdlc_state,
NULL, 0, &bytes_sent,
urb->transfer_buffer, buf_size);
}
if (len < buf_size) {
FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
}
if (skb && !skb->len) {
d_out->tx_skb = NULL;
D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
dev_kfree_skb_any(skb);
}
// Prepare the URB
urb->transfer_buffer_length = len;
num_packets = 0;
packet_offset = 0;
while (packet_offset < len) {
desc = &urb->iso_frame_desc[num_packets];
desc->offset = packet_offset;
desc->length = SIZE_ISO_PACKETS_D_OUT;
if (len - packet_offset < desc->length)
desc->length = len - packet_offset;
num_packets++;
packet_offset += desc->length;
}
urb->number_of_packets = num_packets;
// Prepare the URB
urb->dev = adapter->usb_dev;
// Need to transmit the next buffer 2ms after the DEN_EVENT
urb->transfer_flags = 0;
urb->start_frame = usb_get_current_frame_number(adapter->usb_dev) + 2;
DBG_ISO_PACKET(0x20, urb);
if (usb_submit_urb(urb, GFP_KERNEL) < 0) {
// There is another URB queued up
urb->transfer_flags = URB_ISO_ASAP;
SUBMIT_URB(urb, GFP_KERNEL);
}
}
static void fifo_reseted(void *context)
{
struct st5481_adapter *adapter = context;
FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL);
}
static void usb_d_out_complete(struct urb *urb)
{
struct st5481_adapter *adapter = urb->context;
struct st5481_d_out *d_out = &adapter->d_out;
long buf_nr;
DBG(2, "");
buf_nr = get_buf_nr(d_out->urb, urb);
test_and_clear_bit(buf_nr, &d_out->busy);
if (unlikely(urb->status < 0)) {
switch (urb->status) {
case -ENOENT:
case -ESHUTDOWN:
case -ECONNRESET:
DBG(1, "urb killed status %d", urb->status);
break;
default:
WARNING("urb status %d", urb->status);
if (d_out->busy == 0) {
st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
}
break;
}
return; // Give up
}
FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr);
}
/* ====================================================================== */
static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
{
// FIXME unify?
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
struct urb *urb;
int len, bytes_sent;
struct sk_buff *skb;
int buf_nr = 0;
skb = d_out->tx_skb;
DBG(2, "len=%d", skb->len);
isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE);
if (test_and_set_bit(buf_nr, &d_out->busy)) {
WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
return;
}
urb = d_out->urb[buf_nr];
DBG_SKB(0x10, skb);
len = isdnhdlc_encode(&d_out->hdlc_state,
skb->data, skb->len, &bytes_sent,
urb->transfer_buffer, 16);
skb_pull(skb, bytes_sent);
if (len < 16)
FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_INIT);
else
FsmChangeState(&d_out->fsm, ST_DOUT_LONG_INIT);
if (skb->len == 0) {
d_out->tx_skb = NULL;
D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
dev_kfree_skb_any(skb);
}
// Prepare the URB
urb->transfer_buffer_length = len;
urb->iso_frame_desc[0].offset = 0;
urb->iso_frame_desc[0].length = len;
urb->number_of_packets = 1;
// Prepare the URB
urb->dev = adapter->usb_dev;
urb->transfer_flags = URB_ISO_ASAP;
DBG_ISO_PACKET(0x20, urb);
SUBMIT_URB(urb, GFP_KERNEL);
}
static void dout_short_fifo(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_WAIT_DEN);
st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL);
}
static void dout_end_short_frame(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
}
static void dout_long_enable_fifo(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL);
FsmChangeState(&d_out->fsm, ST_DOUT_LONG_WAIT_DEN);
}
static void dout_long_den(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
FsmChangeState(&d_out->fsm, ST_DOUT_NORMAL);
usb_d_out(adapter, 0);
usb_d_out(adapter, 1);
}
static void dout_reset(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_RESET);
st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
}
static void dout_stop(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_STOP);
st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 0, dout_stop_event, adapter);
}
static void dout_underrun(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
if (test_bit(0, &d_out->busy) || test_bit(1, &d_out->busy)) {
FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_NOT_BUSY);
} else {
dout_stop(fsm, event, arg);
}
}
static void dout_check_busy(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
if (!test_bit(0, &d_out->busy) && !test_bit(1, &d_out->busy))
dout_stop(fsm, event, arg);
}
static void dout_reseted(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
struct st5481_d_out *d_out = &adapter->d_out;
FsmChangeState(&d_out->fsm, ST_DOUT_NONE);
// FIXME locking
if (d_out->tx_skb)
FsmEvent(&d_out->fsm, EV_DOUT_START_XMIT, NULL);
}
static void dout_complete(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
long buf_nr = (long) arg;
usb_d_out(adapter, buf_nr);
}
static void dout_ignore(struct FsmInst *fsm, int event, void *arg)
{
}
static struct FsmNode DoutFnList[] __initdata =
{
{ST_DOUT_NONE, EV_DOUT_START_XMIT, dout_start_xmit},
{ST_DOUT_SHORT_INIT, EV_DOUT_COMPLETE, dout_short_fifo},
{ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_DEN, dout_end_short_frame},
{ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
{ST_DOUT_LONG_INIT, EV_DOUT_COMPLETE, dout_long_enable_fifo},
{ST_DOUT_LONG_WAIT_DEN, EV_DOUT_DEN, dout_long_den},
{ST_DOUT_LONG_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
{ST_DOUT_NORMAL, EV_DOUT_UNDERRUN, dout_underrun},
{ST_DOUT_NORMAL, EV_DOUT_COMPLETE, dout_complete},
{ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_UNDERRUN, dout_underrun},
{ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_COMPLETE, dout_ignore},
{ST_DOUT_WAIT_FOR_NOT_BUSY, EV_DOUT_COMPLETE, dout_check_busy},
{ST_DOUT_WAIT_FOR_STOP, EV_DOUT_STOPPED, dout_reset},
{ST_DOUT_WAIT_FOR_RESET, EV_DOUT_RESETED, dout_reseted},
};
void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
{
struct st5481_adapter *adapter = hisax_d_if->priv;
struct sk_buff *skb = arg;
switch (pr) {
case PH_ACTIVATE | REQUEST:
FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL);
break;
case PH_DEACTIVATE | REQUEST:
FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL);
break;
case PH_DATA | REQUEST:
DBG(2, "PH_DATA REQUEST len %d", skb->len);
BUG_ON(adapter->d_out.tx_skb);
adapter->d_out.tx_skb = skb;
FsmEvent(&adapter->d_out.fsm, EV_DOUT_START_XMIT, NULL);
break;
default:
WARNING("pr %#x\n", pr);
break;
}
}
/* ======================================================================
*/
/*
* Start receiving on the D channel since entered state F7.
*/
static void ph_connect(struct st5481_adapter *adapter)
{
struct st5481_d_out *d_out = &adapter->d_out;
struct st5481_in *d_in = &adapter->d_in;
DBG(8, "");
FsmChangeState(&d_out->fsm, ST_DOUT_NONE);
// st5481_usb_device_ctrl_msg(adapter, FFMSK_D, OUT_UNDERRUN, NULL, NULL);
st5481_usb_device_ctrl_msg(adapter, FFMSK_D, 0xfc, NULL, NULL);
st5481_in_mode(d_in, L1_MODE_HDLC);
#ifdef LOOPBACK
// Turn loopback on (data sent on B and D looped back)
st5481_usb_device_ctrl_msg(cs, LBB, 0x04, NULL, NULL);
#endif
st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, NULL, NULL);
// Turn on the green LED to tell that we are in state F7
adapter->leds |= GREEN_LED;
st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
}
/*
* Stop receiving on the D channel since not in state F7.
*/
static void ph_disconnect(struct st5481_adapter *adapter)
{
DBG(8, "");
st5481_in_mode(&adapter->d_in, L1_MODE_NULL);
// Turn off the green LED to tell that we left state F7
adapter->leds &= ~GREEN_LED;
st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
}
static int st5481_setup_d_out(struct st5481_adapter *adapter)
{
struct usb_device *dev = adapter->usb_dev;
struct usb_interface *intf;
struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
struct st5481_d_out *d_out = &adapter->d_out;
DBG(2, "");
intf = usb_ifnum_to_if(dev, 0);
if (intf)
altsetting = usb_altnum_to_altsetting(intf, 3);
if (!altsetting)
return -ENXIO;
// Allocate URBs and buffers for the D channel out
endpoint = &altsetting->endpoint[EP_D_OUT-1];
DBG(2, "endpoint address=%02x,packet size=%d",
endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize));
return st5481_setup_isocpipes(d_out->urb, dev,
usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress),
NUM_ISO_PACKETS_D, SIZE_ISO_PACKETS_D_OUT,
NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT,
usb_d_out_complete, adapter);
}
static void st5481_release_d_out(struct st5481_adapter *adapter)
{
struct st5481_d_out *d_out = &adapter->d_out;
DBG(2, "");
st5481_release_isocpipes(d_out->urb);
}
int st5481_setup_d(struct st5481_adapter *adapter)
{
int retval;
DBG(2, "");
retval = st5481_setup_d_out(adapter);
if (retval)
goto err;
adapter->d_in.bufsize = MAX_DFRAME_LEN_L1;
adapter->d_in.num_packets = NUM_ISO_PACKETS_D;
adapter->d_in.packet_size = SIZE_ISO_PACKETS_D_IN;
adapter->d_in.ep = EP_D_IN | USB_DIR_IN;
adapter->d_in.counter = IN_D_COUNTER;
adapter->d_in.adapter = adapter;
adapter->d_in.hisax_if = &adapter->hisax_d_if.ifc;
retval = st5481_setup_in(&adapter->d_in);
if (retval)
goto err_d_out;
adapter->l1m.fsm = &l1fsm;
adapter->l1m.state = ST_L1_F3;
adapter->l1m.debug = st5481_debug & 0x100;
adapter->l1m.userdata = adapter;
adapter->l1m.printdebug = l1m_debug;
FsmInitTimer(&adapter->l1m, &adapter->timer);
adapter->d_out.fsm.fsm = &dout_fsm;
adapter->d_out.fsm.state = ST_DOUT_NONE;
adapter->d_out.fsm.debug = st5481_debug & 0x100;
adapter->d_out.fsm.userdata = adapter;
adapter->d_out.fsm.printdebug = dout_debug;
return 0;
err_d_out:
st5481_release_d_out(adapter);
err:
return retval;
}
void st5481_release_d(struct st5481_adapter *adapter)
{
DBG(2, "");
st5481_release_in(&adapter->d_in);
st5481_release_d_out(adapter);
}
/* ======================================================================
* init / exit
*/
int __init st5481_d_init(void)
{
int retval;
l1fsm.state_count = L1_STATE_COUNT;
l1fsm.event_count = L1_EVENT_COUNT;
l1fsm.strEvent = strL1Event;
l1fsm.strState = strL1State;
retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
if (retval)
goto err;
dout_fsm.state_count = DOUT_STATE_COUNT;
dout_fsm.event_count = DOUT_EVENT_COUNT;
dout_fsm.strEvent = strDoutEvent;
dout_fsm.strState = strDoutState;
retval = FsmNew(&dout_fsm, DoutFnList, ARRAY_SIZE(DoutFnList));
if (retval)
goto err_l1;
return 0;
err_l1:
FsmFree(&l1fsm);
err:
return retval;
}
// can't be __exit
void st5481_d_exit(void)
{
FsmFree(&l1fsm);
FsmFree(&dout_fsm);
}

View File

@ -1,221 +0,0 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
/*
* TODO:
*
* b layer1 delay?
* hotplug / unregister issues
* mod_inc/dec_use_count
* unify parts of d/b channel usb handling
* file header
* avoid copy to isoc buffer?
* improve usb delay?
* merge l1 state machines?
* clean up debug
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/slab.h>
#include "st5481.h"
MODULE_DESCRIPTION("ISDN4Linux: driver for ST5481 USB ISDN adapter");
MODULE_AUTHOR("Frode Isaksen");
MODULE_LICENSE("GPL");
static int protocol = 2; /* EURO-ISDN Default */
module_param(protocol, int, 0);
static int number_of_leds = 2; /* 2 LEDs on the adpater default */
module_param(number_of_leds, int, 0);
#ifdef CONFIG_HISAX_DEBUG
static int debug = 0;
module_param(debug, int, 0);
#endif
int st5481_debug;
/* ======================================================================
* registration/deregistration with the USB layer
*/
/*
* This function will be called when the adapter is plugged
* into the USB bus.
*/
static int probe_st5481(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct st5481_adapter *adapter;
struct hisax_b_if *b_if[2];
int retval, i;
printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct),
number_of_leds);
adapter = kzalloc(sizeof(struct st5481_adapter), GFP_KERNEL);
if (!adapter)
return -ENOMEM;
adapter->number_of_leds = number_of_leds;
adapter->usb_dev = dev;
adapter->hisax_d_if.owner = THIS_MODULE;
adapter->hisax_d_if.ifc.priv = adapter;
adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1;
for (i = 0; i < 2; i++) {
adapter->bcs[i].adapter = adapter;
adapter->bcs[i].channel = i;
adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1;
}
retval = st5481_setup_usb(adapter);
if (retval < 0)
goto err;
retval = st5481_setup_d(adapter);
if (retval < 0)
goto err_usb;
retval = st5481_setup_b(&adapter->bcs[0]);
if (retval < 0)
goto err_d;
retval = st5481_setup_b(&adapter->bcs[1]);
if (retval < 0)
goto err_b;
for (i = 0; i < 2; i++)
b_if[i] = &adapter->bcs[i].b_if;
if (hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb",
protocol) != 0)
goto err_b1;
st5481_start(adapter);
usb_set_intfdata(intf, adapter);
return 0;
err_b1:
st5481_release_b(&adapter->bcs[1]);
err_b:
st5481_release_b(&adapter->bcs[0]);
err_d:
st5481_release_d(adapter);
err_usb:
st5481_release_usb(adapter);
err:
kfree(adapter);
return -EIO;
}
/*
* This function will be called when the adapter is removed
* from the USB bus.
*/
static void disconnect_st5481(struct usb_interface *intf)
{
struct st5481_adapter *adapter = usb_get_intfdata(intf);
DBG(1, "");
usb_set_intfdata(intf, NULL);
if (!adapter)
return;
st5481_stop(adapter);
st5481_release_b(&adapter->bcs[1]);
st5481_release_b(&adapter->bcs[0]);
st5481_release_d(adapter);
// we would actually better wait for completion of outstanding urbs
mdelay(2);
st5481_release_usb(adapter);
hisax_unregister(&adapter->hisax_d_if);
kfree(adapter);
}
/*
* The last 4 bits in the Product Id is set with 4 pins on the chip.
*/
static struct usb_device_id st5481_ids[] = {
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x0) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x1) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x2) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x3) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x4) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x5) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x6) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x7) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x8) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x9) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xA) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xB) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xC) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xD) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xE) },
{ USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xF) },
{ }
};
MODULE_DEVICE_TABLE(usb, st5481_ids);
static struct usb_driver st5481_usb_driver = {
.name = "st5481_usb",
.probe = probe_st5481,
.disconnect = disconnect_st5481,
.id_table = st5481_ids,
.disable_hub_initiated_lpm = 1,
};
static int __init st5481_usb_init(void)
{
int retval;
#ifdef CONFIG_HISAX_DEBUG
st5481_debug = debug;
#endif
printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n");
retval = st5481_d_init();
if (retval < 0)
goto out;
retval = usb_register(&st5481_usb_driver);
if (retval < 0)
goto out_d_exit;
return 0;
out_d_exit:
st5481_d_exit();
out:
return retval;
}
static void __exit st5481_usb_exit(void)
{
usb_deregister(&st5481_usb_driver);
st5481_d_exit();
}
module_init(st5481_usb_init);
module_exit(st5481_usb_exit);

View File

@ -1,659 +0,0 @@
/*
* Driver for ST5481 USB ISDN modem
*
* Author Frode Isaksen
* Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
* 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/slab.h>
#include "st5481.h"
static int st5481_isoc_flatten(struct urb *urb);
/* ======================================================================
* control pipe
*/
/*
* Send the next endpoint 0 request stored in the FIFO.
* Called either by the completion or by usb_ctrl_msg.
*/
static void usb_next_ctrl_msg(struct urb *urb,
struct st5481_adapter *adapter)
{
struct st5481_ctrl *ctrl = &adapter->ctrl;
int r_index;
if (test_and_set_bit(0, &ctrl->busy)) {
return;
}
if ((r_index = fifo_remove(&ctrl->msg_fifo.f)) < 0) {
test_and_clear_bit(0, &ctrl->busy);
return;
}
urb->setup_packet =
(unsigned char *)&ctrl->msg_fifo.data[r_index];
DBG(1, "request=0x%02x,value=0x%04x,index=%x",
((struct ctrl_msg *)urb->setup_packet)->dr.bRequest,
((struct ctrl_msg *)urb->setup_packet)->dr.wValue,
((struct ctrl_msg *)urb->setup_packet)->dr.wIndex);
// Prepare the URB
urb->dev = adapter->usb_dev;
SUBMIT_URB(urb, GFP_ATOMIC);
}
/*
* Asynchronous endpoint 0 request (async version of usb_control_msg).
* The request will be queued up in a FIFO if the endpoint is busy.
*/
static void usb_ctrl_msg(struct st5481_adapter *adapter,
u8 request, u8 requesttype, u16 value, u16 index,
ctrl_complete_t complete, void *context)
{
struct st5481_ctrl *ctrl = &adapter->ctrl;
int w_index;
struct ctrl_msg *ctrl_msg;
if ((w_index = fifo_add(&ctrl->msg_fifo.f)) < 0) {
WARNING("control msg FIFO full");
return;
}
ctrl_msg = &ctrl->msg_fifo.data[w_index];
ctrl_msg->dr.bRequestType = requesttype;
ctrl_msg->dr.bRequest = request;
ctrl_msg->dr.wValue = cpu_to_le16p(&value);
ctrl_msg->dr.wIndex = cpu_to_le16p(&index);
ctrl_msg->dr.wLength = 0;
ctrl_msg->complete = complete;
ctrl_msg->context = context;
usb_next_ctrl_msg(ctrl->urb, adapter);
}
/*
* Asynchronous endpoint 0 device request.
*/
void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
u8 request, u16 value,
ctrl_complete_t complete, void *context)
{
usb_ctrl_msg(adapter, request,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, 0, complete, context);
}
/*
* Asynchronous pipe reset (async version of usb_clear_halt).
*/
void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
u_char pipe,
ctrl_complete_t complete, void *context)
{
DBG(1, "pipe=%02x", pipe);
usb_ctrl_msg(adapter,
USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RECIP_ENDPOINT,
0, pipe, complete, context);
}
/*
Physical level functions
*/
void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command)
{
DBG(8, "command=%s", ST5481_CMD_string(command));
st5481_usb_device_ctrl_msg(adapter, TXCI, command, NULL, NULL);
}
/*
* The request on endpoint 0 has completed.
* Call the user provided completion routine and try
* to send the next request.
*/
static void usb_ctrl_complete(struct urb *urb)
{
struct st5481_adapter *adapter = urb->context;
struct st5481_ctrl *ctrl = &adapter->ctrl;
struct ctrl_msg *ctrl_msg;
if (unlikely(urb->status < 0)) {
switch (urb->status) {
case -ENOENT:
case -ESHUTDOWN:
case -ECONNRESET:
DBG(1, "urb killed status %d", urb->status);
return; // Give up
default:
WARNING("urb status %d", urb->status);
break;
}
}
ctrl_msg = (struct ctrl_msg *)urb->setup_packet;
if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) {
/* Special case handling for pipe reset */
le16_to_cpus(&ctrl_msg->dr.wIndex);
usb_reset_endpoint(adapter->usb_dev, ctrl_msg->dr.wIndex);
}
if (ctrl_msg->complete)
ctrl_msg->complete(ctrl_msg->context);
clear_bit(0, &ctrl->busy);
// Try to send next control message
usb_next_ctrl_msg(urb, adapter);
return;
}
/* ======================================================================
* interrupt pipe
*/
/*
* The interrupt endpoint will be called when any
* of the 6 registers changes state (depending on masks).
* Decode the register values and schedule a private event.
* Called at interrupt.
*/
static void usb_int_complete(struct urb *urb)
{
u8 *data = urb->transfer_buffer;
u8 irqbyte;
struct st5481_adapter *adapter = urb->context;
int j;
int status;
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
DBG(2, "urb shutting down with status: %d", urb->status);
return;
default:
WARNING("nonzero urb status received: %d", urb->status);
goto exit;
}
DBG_PACKET(2, data, INT_PKT_SIZE);
if (urb->actual_length == 0) {
goto exit;
}
irqbyte = data[MPINT];
if (irqbyte & DEN_INT)
FsmEvent(&adapter->d_out.fsm, EV_DOUT_DEN, NULL);
if (irqbyte & DCOLL_INT)
FsmEvent(&adapter->d_out.fsm, EV_DOUT_COLL, NULL);
irqbyte = data[FFINT_D];
if (irqbyte & OUT_UNDERRUN)
FsmEvent(&adapter->d_out.fsm, EV_DOUT_UNDERRUN, NULL);
if (irqbyte & OUT_DOWN)
;// printk("OUT_DOWN\n");
irqbyte = data[MPINT];
if (irqbyte & RXCI_INT)
FsmEvent(&adapter->l1m, data[CCIST] & 0x0f, NULL);
for (j = 0; j < 2; j++)
adapter->bcs[j].b_out.flow_event |= data[FFINT_B1 + j];
urb->actual_length = 0;
exit:
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
WARNING("usb_submit_urb failed with result %d", status);
}
/* ======================================================================
* initialization
*/
int st5481_setup_usb(struct st5481_adapter *adapter)
{
struct usb_device *dev = adapter->usb_dev;
struct st5481_ctrl *ctrl = &adapter->ctrl;
struct st5481_intr *intr = &adapter->intr;
struct usb_interface *intf;
struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
int status;
struct urb *urb;
u8 *buf;
DBG(2, "");
if ((status = usb_reset_configuration(dev)) < 0) {
WARNING("reset_configuration failed,status=%d", status);
return status;
}
intf = usb_ifnum_to_if(dev, 0);
if (intf)
altsetting = usb_altnum_to_altsetting(intf, 3);
if (!altsetting)
return -ENXIO;
// Check if the config is sane
if (altsetting->desc.bNumEndpoints != 7) {
WARNING("expecting 7 got %d endpoints!", altsetting->desc.bNumEndpoints);
return -EINVAL;
}
// The descriptor is wrong for some early samples of the ST5481 chip
altsetting->endpoint[3].desc.wMaxPacketSize = cpu_to_le16(32);
altsetting->endpoint[4].desc.wMaxPacketSize = cpu_to_le16(32);
// Use alternative setting 3 on interface 0 to have 2B+D
if ((status = usb_set_interface(dev, 0, 3)) < 0) {
WARNING("usb_set_interface failed,status=%d", status);
return status;
}
// Allocate URB for control endpoint
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
return -ENOMEM;
}
ctrl->urb = urb;
// Fill the control URB
usb_fill_control_urb(urb, dev,
usb_sndctrlpipe(dev, 0),
NULL, NULL, 0, usb_ctrl_complete, adapter);
fifo_init(&ctrl->msg_fifo.f, ARRAY_SIZE(ctrl->msg_fifo.data));
// Allocate URBs and buffers for interrupt endpoint
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
goto err1;
}
intr->urb = urb;
buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL);
if (!buf) {
goto err2;
}
endpoint = &altsetting->endpoint[EP_INT-1];
// Fill the interrupt URB
usb_fill_int_urb(urb, dev,
usb_rcvintpipe(dev, endpoint->desc.bEndpointAddress),
buf, INT_PKT_SIZE,
usb_int_complete, adapter,
endpoint->desc.bInterval);
return 0;
err2:
usb_free_urb(intr->urb);
intr->urb = NULL;
err1:
usb_free_urb(ctrl->urb);
ctrl->urb = NULL;
return -ENOMEM;
}
/*
* Release buffers and URBs for the interrupt and control
* endpoint.
*/
void st5481_release_usb(struct st5481_adapter *adapter)
{
struct st5481_intr *intr = &adapter->intr;
struct st5481_ctrl *ctrl = &adapter->ctrl;
DBG(1, "");
// Stop and free Control and Interrupt URBs
usb_kill_urb(ctrl->urb);
kfree(ctrl->urb->transfer_buffer);
usb_free_urb(ctrl->urb);
ctrl->urb = NULL;
usb_kill_urb(intr->urb);
kfree(intr->urb->transfer_buffer);
usb_free_urb(intr->urb);
intr->urb = NULL;
}
/*
* Initialize the adapter.
*/
void st5481_start(struct st5481_adapter *adapter)
{
static const u8 init_cmd_table[] = {
SET_DEFAULT, 0,
STT, 0,
SDA_MIN, 0x0d,
SDA_MAX, 0x29,
SDELAY_VALUE, 0x14,
GPIO_DIR, 0x01,
GPIO_OUT, RED_LED,
// FFCTRL_OUT_D,4,
// FFCTRH_OUT_D,12,
FFCTRL_OUT_B1, 6,
FFCTRH_OUT_B1, 20,
FFCTRL_OUT_B2, 6,
FFCTRH_OUT_B2, 20,
MPMSK, RXCI_INT + DEN_INT + DCOLL_INT,
0
};
struct st5481_intr *intr = &adapter->intr;
int i = 0;
u8 request, value;
DBG(8, "");
adapter->leds = RED_LED;
// Start receiving on the interrupt endpoint
SUBMIT_URB(intr->urb, GFP_KERNEL);
while ((request = init_cmd_table[i++])) {
value = init_cmd_table[i++];
st5481_usb_device_ctrl_msg(adapter, request, value, NULL, NULL);
}
st5481_ph_command(adapter, ST5481_CMD_PUP);
}
/*
* Reset the adapter to default values.
*/
void st5481_stop(struct st5481_adapter *adapter)
{
DBG(8, "");
st5481_usb_device_ctrl_msg(adapter, SET_DEFAULT, 0, NULL, NULL);
}
/* ======================================================================
* isochronous USB helpers
*/
static void
fill_isoc_urb(struct urb *urb, struct usb_device *dev,
unsigned int pipe, void *buf, int num_packets,
int packet_size, usb_complete_t complete,
void *context)
{
int k;
usb_fill_int_urb(urb, dev, pipe, buf, num_packets * packet_size,
complete, context, 1);
urb->number_of_packets = num_packets;
urb->transfer_flags = URB_ISO_ASAP;
for (k = 0; k < num_packets; k++) {
urb->iso_frame_desc[k].offset = packet_size * k;
urb->iso_frame_desc[k].length = packet_size;
urb->iso_frame_desc[k].actual_length = 0;
}
}
int
st5481_setup_isocpipes(struct urb *urb[2], struct usb_device *dev,
unsigned int pipe, int num_packets,
int packet_size, int buf_size,
usb_complete_t complete, void *context)
{
int j, retval;
unsigned char *buf;
for (j = 0; j < 2; j++) {
retval = -ENOMEM;
urb[j] = usb_alloc_urb(num_packets, GFP_KERNEL);
if (!urb[j])
goto err;
// Allocate memory for 2000bytes/sec (16Kb/s)
buf = kmalloc(buf_size, GFP_KERNEL);
if (!buf)
goto err;
// Fill the isochronous URB
fill_isoc_urb(urb[j], dev, pipe, buf,
num_packets, packet_size, complete,
context);
}
return 0;
err:
for (j = 0; j < 2; j++) {
if (urb[j]) {
kfree(urb[j]->transfer_buffer);
urb[j]->transfer_buffer = NULL;
usb_free_urb(urb[j]);
urb[j] = NULL;
}
}
return retval;
}
void st5481_release_isocpipes(struct urb *urb[2])
{
int j;
for (j = 0; j < 2; j++) {
usb_kill_urb(urb[j]);
kfree(urb[j]->transfer_buffer);
usb_free_urb(urb[j]);
urb[j] = NULL;
}
}
/*
* Decode frames received on the B/D channel.
* Note that this function will be called continuously
* with 64Kbit/s / 16Kbit/s of data and hence it will be
* called 50 times per second with 20 ISOC descriptors.
* Called at interrupt.
*/
static void usb_in_complete(struct urb *urb)
{
struct st5481_in *in = urb->context;
unsigned char *ptr;
struct sk_buff *skb;
int len, count, status;
if (unlikely(urb->status < 0)) {
switch (urb->status) {
case -ENOENT:
case -ESHUTDOWN:
case -ECONNRESET:
DBG(1, "urb killed status %d", urb->status);
return; // Give up
default:
WARNING("urb status %d", urb->status);
break;
}
}
DBG_ISO_PACKET(0x80, urb);
len = st5481_isoc_flatten(urb);
ptr = urb->transfer_buffer;
while (len > 0) {
if (in->mode == L1_MODE_TRANS) {
memcpy(in->rcvbuf, ptr, len);
status = len;
len = 0;
} else {
status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count,
in->rcvbuf, in->bufsize);
ptr += count;
len -= count;
}
if (status > 0) {
// Good frame received
DBG(4, "count=%d", status);
DBG_PACKET(0x400, in->rcvbuf, status);
if (!(skb = dev_alloc_skb(status))) {
WARNING("receive out of memory\n");
break;
}
skb_put_data(skb, in->rcvbuf, status);
in->hisax_if->l1l2(in->hisax_if, PH_DATA | INDICATION, skb);
} else if (status == -HDLC_CRC_ERROR) {
INFO("CRC error");
} else if (status == -HDLC_FRAMING_ERROR) {
INFO("framing error");
} else if (status == -HDLC_LENGTH_ERROR) {
INFO("length error");
}
}
// Prepare URB for next transfer
urb->dev = in->adapter->usb_dev;
urb->actual_length = 0;
SUBMIT_URB(urb, GFP_ATOMIC);
}
int st5481_setup_in(struct st5481_in *in)
{
struct usb_device *dev = in->adapter->usb_dev;
int retval;
DBG(4, "");
in->rcvbuf = kmalloc(in->bufsize, GFP_KERNEL);
retval = -ENOMEM;
if (!in->rcvbuf)
goto err;
retval = st5481_setup_isocpipes(in->urb, dev,
usb_rcvisocpipe(dev, in->ep),
in->num_packets, in->packet_size,
in->num_packets * in->packet_size,
usb_in_complete, in);
if (retval)
goto err_free;
return 0;
err_free:
kfree(in->rcvbuf);
err:
return retval;
}
void st5481_release_in(struct st5481_in *in)
{
DBG(2, "");
st5481_release_isocpipes(in->urb);
}
/*
* Make the transfer_buffer contiguous by
* copying from the iso descriptors if necessary.
*/
static int st5481_isoc_flatten(struct urb *urb)
{
struct usb_iso_packet_descriptor *pipd, *pend;
unsigned char *src, *dst;
unsigned int len;
if (urb->status < 0) {
return urb->status;
}
for (pipd = &urb->iso_frame_desc[0],
pend = &urb->iso_frame_desc[urb->number_of_packets],
dst = urb->transfer_buffer;
pipd < pend;
pipd++) {
if (pipd->status < 0) {
return (pipd->status);
}
len = pipd->actual_length;
pipd->actual_length = 0;
src = urb->transfer_buffer + pipd->offset;
if (src != dst) {
// Need to copy since isoc buffers not full
while (len--) {
*dst++ = *src++;
}
} else {
// No need to copy, just update destination buffer
dst += len;
}
}
// Return size of flattened buffer
return (dst - (unsigned char *)urb->transfer_buffer);
}
static void st5481_start_rcv(void *context)
{
struct st5481_in *in = context;
struct st5481_adapter *adapter = in->adapter;
DBG(4, "");
in->urb[0]->dev = adapter->usb_dev;
SUBMIT_URB(in->urb[0], GFP_KERNEL);
in->urb[1]->dev = adapter->usb_dev;
SUBMIT_URB(in->urb[1], GFP_KERNEL);
}
void st5481_in_mode(struct st5481_in *in, int mode)
{
if (in->mode == mode)
return;
in->mode = mode;
usb_unlink_urb(in->urb[0]);
usb_unlink_urb(in->urb[1]);
if (in->mode != L1_MODE_NULL) {
if (in->mode != L1_MODE_TRANS) {
u32 features = HDLC_BITREVERSE;
if (in->mode == L1_MODE_HDLC_56K)
features |= HDLC_56KBIT;
isdnhdlc_rcv_init(&in->hdlc_state, features);
}
st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
st5481_usb_device_ctrl_msg(in->adapter, in->counter,
in->packet_size,
NULL, NULL);
st5481_start_rcv(in);
} else {
st5481_usb_device_ctrl_msg(in->adapter, in->counter,
0, NULL, NULL);
}
}

View File

@ -1,465 +0,0 @@
/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $
*
* Author Karsten Keil
* based on the teles driver from Jan den Ouden
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For changes and modifications please read
* Documentation/isdn/HiSax.cert
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
*/
#include "hisax.h"
#include "isdnl2.h"
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/random.h>
const char *tei_revision = "$Revision: 2.20.2.3 $";
#define ID_REQUEST 1
#define ID_ASSIGNED 2
#define ID_DENIED 3
#define ID_CHK_REQ 4
#define ID_CHK_RES 5
#define ID_REMOVE 6
#define ID_VERIFY 7
#define TEI_ENTITY_ID 0xf
static struct Fsm teifsm;
void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
enum {
ST_TEI_NOP,
ST_TEI_IDREQ,
ST_TEI_IDVERIFY,
};
#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1)
static char *strTeiState[] =
{
"ST_TEI_NOP",
"ST_TEI_IDREQ",
"ST_TEI_IDVERIFY",
};
enum {
EV_IDREQ,
EV_ASSIGN,
EV_DENIED,
EV_CHKREQ,
EV_REMOVE,
EV_VERIFY,
EV_T202,
};
#define TEI_EVENT_COUNT (EV_T202 + 1)
static char *strTeiEvent[] =
{
"EV_IDREQ",
"EV_ASSIGN",
"EV_DENIED",
"EV_CHKREQ",
"EV_REMOVE",
"EV_VERIFY",
"EV_T202",
};
static unsigned int
random_ri(void)
{
unsigned int x;
get_random_bytes(&x, sizeof(x));
return (x & 0xffff);
}
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
put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei)
{
struct sk_buff *skb;
u_char *bp;
if (!(skb = alloc_skb(8, GFP_ATOMIC))) {
printk(KERN_WARNING "HiSax: No skb for TEI manager\n");
return;
}
bp = skb_put(skb, 3);
bp[0] = (TEI_SAPI << 2);
bp[1] = (GROUP_TEI << 1) | 0x1;
bp[2] = UI;
bp = skb_put(skb, 5);
bp[0] = TEI_ENTITY_ID;
bp[1] = ri >> 8;
bp[2] = ri & 0xff;
bp[3] = m_id;
bp[4] = (tei << 1) | 1;
st->l2.l2l1(st, PH_DATA | REQUEST, skb);
}
static void
tei_id_request(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
if (st->l2.tei != -1) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"assign request for already assigned tei %d",
st->l2.tei);
return;
}
st->ma.ri = random_ri();
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"assign request ri %d", st->ma.ri);
put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ);
FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1);
st->ma.N202 = 3;
}
static void
tei_id_assign(struct FsmInst *fi, int event, void *arg)
{
struct PStack *ost, *st = fi->userdata;
struct sk_buff *skb = arg;
struct IsdnCardState *cs;
int ri, tei;
ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
tei = skb->data[4] >> 1;
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"identity assign ri %d tei %d", ri, tei);
if ((ost = findtei(st, tei))) { /* same tei is in use */
if (ri != ost->ma.ri) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"possible duplicate assignment tei %d", tei);
ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL);
}
} else if (ri == st->ma.ri) {
FsmDelTimer(&st->ma.t202, 1);
FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
}
}
static void
tei_id_test_dup(struct FsmInst *fi, int event, void *arg)
{
struct PStack *ost, *st = fi->userdata;
struct sk_buff *skb = arg;
int tei, ri;
ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
tei = skb->data[4] >> 1;
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"foreign identity assign ri %d tei %d", ri, tei);
if ((ost = findtei(st, tei))) { /* same tei is in use */
if (ri != ost->ma.ri) { /* and it wasn't our request */
st->ma.tei_m.printdebug(&st->ma.tei_m,
"possible duplicate assignment tei %d", tei);
FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
}
}
}
static void
tei_id_denied(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
int ri, tei;
ri = ((unsigned int) skb->data[1] << 8) + skb->data[2];
tei = skb->data[4] >> 1;
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"identity denied ri %d tei %d", ri, tei);
}
static void
tei_id_chk_req(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
int tei;
tei = skb->data[4] >> 1;
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"identity check req tei %d", tei);
if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
FsmDelTimer(&st->ma.t202, 4);
FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei);
}
}
static void
tei_id_remove(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct sk_buff *skb = arg;
struct IsdnCardState *cs;
int tei;
tei = skb->data[4] >> 1;
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"identity remove tei %d", tei);
if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) {
FsmDelTimer(&st->ma.t202, 5);
FsmChangeState(&st->ma.tei_m, ST_TEI_NOP);
st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
}
}
static void
tei_id_verify(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"id verify request for tei %d", st->l2.tei);
put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY);
FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2);
st->ma.N202 = 2;
}
static void
tei_id_req_tout(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct IsdnCardState *cs;
if (--st->ma.N202) {
st->ma.ri = random_ri();
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"assign req(%d) ri %d", 4 - st->ma.N202,
st->ma.ri);
put_tei_msg(st, ID_REQUEST, st->ma.ri, 127);
FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3);
} else {
st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed");
st->l3.l3l2(st, MDL_ERROR | RESPONSE, NULL);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
FsmChangeState(fi, ST_TEI_NOP);
}
}
static void
tei_id_ver_tout(struct FsmInst *fi, int event, void *arg)
{
struct PStack *st = fi->userdata;
struct IsdnCardState *cs;
if (--st->ma.N202) {
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"id verify req(%d) for tei %d",
3 - st->ma.N202, st->l2.tei);
put_tei_msg(st, ID_VERIFY, 0, st->l2.tei);
FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4);
} else {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"verify req for tei %d failed", st->l2.tei);
st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL);
FsmChangeState(fi, ST_TEI_NOP);
}
}
static void
tei_l1l2(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
int mt;
if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
dev_kfree_skb(skb);
return;
}
if (pr == (PH_DATA | INDICATION)) {
if (skb->len < 3) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"short mgr frame %ld/3", skb->len);
} else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) ||
(skb->data[1] != ((GROUP_TEI << 1) | 1))) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"wrong mgr sapi/tei %x/%x",
skb->data[0], skb->data[1]);
} else if ((skb->data[2] & 0xef) != UI) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"mgr frame is not ui %x", skb->data[2]);
} else {
skb_pull(skb, 3);
if (skb->len < 5) {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"short mgr frame %ld/5", skb->len);
} else if (skb->data[0] != TEI_ENTITY_ID) {
/* wrong management entity identifier, ignore */
st->ma.tei_m.printdebug(&st->ma.tei_m,
"tei handler wrong entity id %x",
skb->data[0]);
} else {
mt = skb->data[3];
if (mt == ID_ASSIGNED)
FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb);
else if (mt == ID_DENIED)
FsmEvent(&st->ma.tei_m, EV_DENIED, skb);
else if (mt == ID_CHK_REQ)
FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb);
else if (mt == ID_REMOVE)
FsmEvent(&st->ma.tei_m, EV_REMOVE, skb);
else {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"tei handler wrong mt %x\n", mt);
}
}
}
} else {
st->ma.tei_m.printdebug(&st->ma.tei_m,
"tei handler wrong pr %x\n", pr);
}
dev_kfree_skb(skb);
}
static void
tei_l2tei(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs;
if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) {
if (pr == (MDL_ASSIGN | INDICATION)) {
if (st->ma.debug)
st->ma.tei_m.printdebug(&st->ma.tei_m,
"fixed assign tei %d", st->l2.tei);
st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei);
cs = (struct IsdnCardState *) st->l1.hardware;
cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL);
}
return;
}
switch (pr) {
case (MDL_ASSIGN | INDICATION):
FsmEvent(&st->ma.tei_m, EV_IDREQ, arg);
break;
case (MDL_ERROR | REQUEST):
FsmEvent(&st->ma.tei_m, EV_VERIFY, arg);
break;
default:
break;
}
}
static void
tei_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
struct PStack *st = fi->userdata;
va_start(args, fmt);
VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args);
va_end(args);
}
void
setstack_tei(struct PStack *st)
{
st->l2.l2tei = tei_l2tei;
st->ma.T202 = 2000; /* T202 2000 milliseconds */
st->l1.l1tei = tei_l1l2;
st->ma.debug = 1;
st->ma.tei_m.fsm = &teifsm;
st->ma.tei_m.state = ST_TEI_NOP;
st->ma.tei_m.debug = 1;
st->ma.tei_m.userdata = st;
st->ma.tei_m.userint = 0;
st->ma.tei_m.printdebug = tei_debug;
FsmInitTimer(&st->ma.tei_m, &st->ma.t202);
}
void
init_tei(struct IsdnCardState *cs, int protocol)
{
}
void
release_tei(struct IsdnCardState *cs)
{
struct PStack *st = cs->stlist;
while (st) {
FsmDelTimer(&st->ma.t202, 1);
st = st->next;
}
}
static struct FsmNode TeiFnList[] __initdata =
{
{ST_TEI_NOP, EV_IDREQ, tei_id_request},
{ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
{ST_TEI_NOP, EV_VERIFY, tei_id_verify},
{ST_TEI_NOP, EV_REMOVE, tei_id_remove},
{ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req},
{ST_TEI_IDREQ, EV_T202, tei_id_req_tout},
{ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign},
{ST_TEI_IDREQ, EV_DENIED, tei_id_denied},
{ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout},
{ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove},
{ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
};
int __init
TeiNew(void)
{
teifsm.state_count = TEI_STATE_COUNT;
teifsm.event_count = TEI_EVENT_COUNT;
teifsm.strEvent = strTeiEvent;
teifsm.strState = strTeiState;
return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList));
}
void
TeiFree(void)
{
FsmFree(&teifsm);
}

View File

@ -1,334 +0,0 @@
/* $Id: teleint.c,v 1.16.2.5 2004/01/19 15:31:50 keil Exp $
*
* low level stuff for TeleInt isdn cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
#include "hfc_2bs0.h"
#include "isdnl1.h"
static const char *TeleInt_revision = "$Revision: 1.16.2.5 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
int max_delay = 2000;
byteout(ale, off);
ret = HFC_BUSY & bytein(ale);
while (ret && --max_delay)
ret = HFC_BUSY & bytein(ale);
if (!max_delay) {
printk(KERN_WARNING "TeleInt Busy not inactive\n");
return (0);
}
ret = bytein(adr);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
register u_char ret;
register int max_delay = 20000;
register int i;
byteout(ale, off);
for (i = 0; i < size; i++) {
ret = HFC_BUSY & bytein(ale);
while (ret && --max_delay)
ret = HFC_BUSY & bytein(ale);
if (!max_delay) {
printk(KERN_WARNING "TeleInt Busy not inactive\n");
return;
}
data[i] = bytein(adr);
}
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
register u_char ret;
int max_delay = 2000;
byteout(ale, off);
ret = HFC_BUSY & bytein(ale);
while (ret && --max_delay)
ret = HFC_BUSY & bytein(ale);
if (!max_delay) {
printk(KERN_WARNING "TeleInt Busy not inactive\n");
return;
}
byteout(adr, data);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
{
register u_char ret;
register int max_delay = 20000;
register int i;
byteout(ale, off);
for (i = 0; i < size; i++) {
ret = HFC_BUSY & bytein(ale);
while (ret && --max_delay)
ret = HFC_BUSY & bytein(ale);
if (!max_delay) {
printk(KERN_WARNING "TeleInt Busy not inactive\n");
return;
}
byteout(adr, data[i]);
}
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
cs->hw.hfc.cip = offset;
return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
cs->hw.hfc.cip = offset;
writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
cs->hw.hfc.cip = 0;
readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
cs->hw.hfc.cip = 0;
writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
}
static u_char
ReadHFC(struct IsdnCardState *cs, int data, u_char reg)
{
register u_char ret;
if (data) {
cs->hw.hfc.cip = reg;
byteout(cs->hw.hfc.addr | 1, reg);
ret = bytein(cs->hw.hfc.addr);
if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
debugl1(cs, "hfc RD %02x %02x", reg, ret);
} else
ret = bytein(cs->hw.hfc.addr | 1);
return (ret);
}
static void
WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
{
byteout(cs->hw.hfc.addr | 1, reg);
cs->hw.hfc.cip = reg;
if (data)
byteout(cs->hw.hfc.addr, value);
if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value);
}
static irqreturn_t
TeleInt_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF);
writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
TeleInt_Timer(struct timer_list *t)
{
struct IsdnCardState *cs = from_timer(cs, t, hw.hfc.timer);
int stat = 0;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
if (cs->bcs[0].mode) {
stat |= 1;
main_irq_hfc(&cs->bcs[0]);
}
if (cs->bcs[1].mode) {
stat |= 2;
main_irq_hfc(&cs->bcs[1]);
}
spin_unlock_irqrestore(&cs->lock, flags);
stat = HZ / 100;
if (!stat)
stat = 1;
cs->hw.hfc.timer.expires = jiffies + stat;
add_timer(&cs->hw.hfc.timer);
}
static void
release_io_TeleInt(struct IsdnCardState *cs)
{
del_timer(&cs->hw.hfc.timer);
releasehfc(cs);
if (cs->hw.hfc.addr)
release_region(cs->hw.hfc.addr, 2);
}
static void
reset_TeleInt(struct IsdnCardState *cs)
{
printk(KERN_INFO "TeleInt: resetting card\n");
cs->hw.hfc.cirm |= HFC_RESET;
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */
mdelay(10);
cs->hw.hfc.cirm &= ~HFC_RESET;
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */
mdelay(10);
}
static int
TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
int delay;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_TeleInt(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_TeleInt(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
reset_TeleInt(cs);
inithfc(cs);
clear_pending_isac_ints(cs);
initisac(cs);
/* Reenable all IRQ */
cs->writeisac(cs, ISAC_MASK, 0);
cs->writeisac(cs, ISAC_CMDR, 0x41);
spin_unlock_irqrestore(&cs->lock, flags);
delay = HZ / 100;
if (!delay)
delay = 1;
cs->hw.hfc.timer.expires = jiffies + delay;
add_timer(&cs->hw.hfc.timer);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
int setup_TeleInt(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, TeleInt_revision);
printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_TELEINT)
return (0);
cs->hw.hfc.addr = card->para[1] & 0x3fe;
cs->irq = card->para[0];
cs->hw.hfc.cirm = HFC_CIRM;
cs->hw.hfc.isac_spcr = 0x00;
cs->hw.hfc.cip = 0;
cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER;
cs->bcs[0].hw.hfc.send = NULL;
cs->bcs[1].hw.hfc.send = NULL;
cs->hw.hfc.fifosize = 7 * 1024 + 512;
timer_setup(&cs->hw.hfc.timer, TeleInt_Timer, 0);
if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) {
printk(KERN_WARNING
"HiSax: TeleInt config port %x-%x already in use\n",
cs->hw.hfc.addr,
cs->hw.hfc.addr + 2);
return (0);
}
/* HW IO = IO */
byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff);
byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54);
switch (cs->irq) {
case 3:
cs->hw.hfc.cirm |= HFC_INTA;
break;
case 4:
cs->hw.hfc.cirm |= HFC_INTB;
break;
case 5:
cs->hw.hfc.cirm |= HFC_INTC;
break;
case 7:
cs->hw.hfc.cirm |= HFC_INTD;
break;
case 10:
cs->hw.hfc.cirm |= HFC_INTE;
break;
case 11:
cs->hw.hfc.cirm |= HFC_INTF;
break;
default:
printk(KERN_WARNING "TeleInt: wrong IRQ\n");
release_io_TeleInt(cs);
return (0);
}
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt);
printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n",
cs->hw.hfc.addr, cs->irq);
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHFC;
cs->BC_Write_Reg = &WriteHFC;
cs->cardmsg = &TeleInt_card_msg;
cs->irq_func = &TeleInt_interrupt;
ISACVersion(cs, "TeleInt:");
return (1);
}

View File

@ -1,364 +0,0 @@
/* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for Teles Memory IO isdn cards
*
* Author Karsten Keil
* based on the teles driver from Jan den Ouden
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
*/
#include <linux/init.h>
#include "hisax.h"
#include "isdnl1.h"
#include "isac.h"
#include "hscx.h"
static const char *teles0_revision = "$Revision: 2.15.2.4 $";
#define TELES_IOMEM_SIZE 0x400
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(addr)
static inline u_char
readisac(void __iomem *adr, u_char off)
{
return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off);
}
static inline void
writeisac(void __iomem *adr, u_char off, u_char data)
{
writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb();
}
static inline u_char
readhscx(void __iomem *adr, int hscx, u_char off)
{
return readb(adr + (hscx ? 0x1c0 : 0x180) +
((off & 1) ? 0x1ff : 0) + off);
}
static inline void
writehscx(void __iomem *adr, int hscx, u_char off, u_char data)
{
writeb(data, adr + (hscx ? 0x1c0 : 0x180) +
((off & 1) ? 0x1ff : 0) + off); mb();
}
static inline void
read_fifo_isac(void __iomem *adr, u_char *data, int size)
{
register int i;
register u_char __iomem *ad = adr + 0x100;
for (i = 0; i < size; i++)
data[i] = readb(ad);
}
static inline void
write_fifo_isac(void __iomem *adr, u_char *data, int size)
{
register int i;
register u_char __iomem *ad = adr + 0x100;
for (i = 0; i < size; i++) {
writeb(data[i], ad); mb();
}
}
static inline void
read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
{
register int i;
register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
for (i = 0; i < size; i++)
data[i] = readb(ad);
}
static inline void
write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size)
{
int i;
register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180);
for (i = 0; i < size; i++) {
writeb(data[i], ad); mb();
}
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readisac(cs->hw.teles0.membase, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writeisac(cs->hw.teles0.membase, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
read_fifo_isac(cs->hw.teles0.membase, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
write_fifo_isac(cs->hw.teles0.membase, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readhscx(cs->hw.teles0.membase, hscx, offset));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writehscx(cs->hw.teles0.membase, hscx, offset, value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg)
#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
teles0_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
int count = 0;
spin_lock_irqsave(&cs->lock, flags);
val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
count++;
val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA);
if (val && count < 5) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readisac(cs->hw.teles0.membase, ISAC_ISTA);
if (val && count < 5) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF);
writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF);
writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF);
writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0);
writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0);
writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static void
release_io_teles0(struct IsdnCardState *cs)
{
if (cs->hw.teles0.cfg_reg)
release_region(cs->hw.teles0.cfg_reg, 8);
iounmap(cs->hw.teles0.membase);
release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
}
static int
reset_teles0(struct IsdnCardState *cs)
{
u_char cfval;
if (cs->hw.teles0.cfg_reg) {
switch (cs->irq) {
case 2:
case 9:
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:
return (1);
}
cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0);
byteout(cs->hw.teles0.cfg_reg + 4, cfval);
HZDELAY(HZ / 10 + 1);
byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1);
HZDELAY(HZ / 10 + 1);
}
writeb(0, cs->hw.teles0.membase + 0x80); mb();
HZDELAY(HZ / 5 + 1);
writeb(1, cs->hw.teles0.membase + 0x80); mb();
HZDELAY(HZ / 5 + 1);
return (0);
}
static int
Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_teles0(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_teles0(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscxisac(cs, 3);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
int setup_teles0(struct IsdnCard *card)
{
u_char val;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, teles0_revision);
printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp));
if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0))
return (0);
if (cs->typ == ISDN_CTYPE_16_0)
cs->hw.teles0.cfg_reg = card->para[2];
else /* 8.0 */
cs->hw.teles0.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]);
}
cs->irq = card->para[0];
if (cs->hw.teles0.cfg_reg) {
if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
cs->hw.teles0.cfg_reg,
cs->hw.teles0.cfg_reg + 8);
return (0);
}
}
if (cs->hw.teles0.cfg_reg) {
if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) {
printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
cs->hw.teles0.cfg_reg + 0, val);
release_region(cs->hw.teles0.cfg_reg, 8);
return (0);
}
if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) {
printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
cs->hw.teles0.cfg_reg + 1, val);
release_region(cs->hw.teles0.cfg_reg, 8);
return (0);
}
val = bytein(cs->hw.teles0.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",
cs->hw.teles0.cfg_reg + 2, val);
release_region(cs->hw.teles0.cfg_reg, 8);
return (0);
}
}
/* 16.0 and 8.0 designed for IOM1 */
test_and_set_bit(HW_IOM1, &cs->HW_Flags);
cs->hw.teles0.phymem = card->para[1];
if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) {
printk(KERN_WARNING
"HiSax: %s memory region %lx-%lx already in use\n",
CardType[card->typ],
cs->hw.teles0.phymem,
cs->hw.teles0.phymem + TELES_IOMEM_SIZE);
if (cs->hw.teles0.cfg_reg)
release_region(cs->hw.teles0.cfg_reg, 8);
return (0);
}
cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
printk(KERN_INFO
"HiSax: %s config irq:%d mem:%p cfg:0x%X\n",
CardType[cs->typ], cs->irq,
cs->hw.teles0.membase, cs->hw.teles0.cfg_reg);
if (reset_teles0(cs)) {
printk(KERN_WARNING "Teles0: wrong IRQ\n");
release_io_teles0(cs);
return (0);
}
setup_isac(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Teles_card_msg;
cs->irq_func = &teles0_interrupt;
ISACVersion(cs, "Teles0:");
if (HscxVersion(cs, "Teles0:")) {
printk(KERN_WARNING
"Teles0: wrong HSCX versions check IO/MEM addresses\n");
release_io_teles0(cs);
return (0);
}
return (1);
}

View File

@ -1,498 +0,0 @@
/* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $
*
* low level stuff for Teles 16.3 & PNP isdn cards
*
* Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
*/
#include <linux/init.h>
#include <linux/isapnp.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
static const char *teles3_revision = "$Revision: 2.19.2.4 $";
#define byteout(addr, val) outb(val, addr)
#define bytein(addr) inb(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, data, size);
}
static void
write_fifo(unsigned int adr, u_char *data, int size)
{
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.teles3.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.teles3.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
read_fifo(cs->hw.teles3.isacfifo, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
{
write_fifo(cs->hw.teles3.isacfifo, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.teles3.hscx[hscx], offset));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.teles3.hscx[hscx], offset, value);
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg)
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data)
#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt)
#include "hscx_irq.c"
static irqreturn_t
teles3_interrupt(int intno, void *dev_id)
{
#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
u_char val;
u_long flags;
int count = 0;
spin_lock_irqsave(&cs->lock, flags);
val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
count++;
val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA);
if (val && count < MAXCOUNT) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.teles3.isac, ISAC_ISTA);
if (val && count < MAXCOUNT) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (count >= MAXCOUNT)
printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count);
writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0);
writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
static inline void
release_ioregs(struct IsdnCardState *cs, int mask)
{
if (mask & 1)
release_region(cs->hw.teles3.isac + 32, 32);
if (mask & 2)
release_region(cs->hw.teles3.hscx[0] + 32, 32);
if (mask & 4)
release_region(cs->hw.teles3.hscx[1] + 32, 32);
}
static void
release_io_teles3(struct IsdnCardState *cs)
{
if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
release_region(cs->hw.teles3.hscx[1], 96);
} else {
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
release_region(cs->hw.teles3.cfg_reg, 1);
} else {
release_region(cs->hw.teles3.cfg_reg, 8);
}
}
release_ioregs(cs, 0x7);
}
}
static int
reset_teles3(struct IsdnCardState *cs)
{
u_char irqcfg;
if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
switch (cs->irq) {
case 2:
case 9:
irqcfg = 0x00;
break;
case 3:
irqcfg = 0x02;
break;
case 4:
irqcfg = 0x04;
break;
case 5:
irqcfg = 0x06;
break;
case 10:
irqcfg = 0x08;
break;
case 11:
irqcfg = 0x0A;
break;
case 12:
irqcfg = 0x0C;
break;
case 15:
irqcfg = 0x0E;
break;
default:
return (1);
}
byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
HZDELAY(HZ / 10 + 1);
byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
HZDELAY(HZ / 10 + 1);
} else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
byteout(cs->hw.teles3.cfg_reg, 0xff);
HZDELAY(2);
byteout(cs->hw.teles3.cfg_reg, 0x00);
HZDELAY(2);
} else {
/* Reset off for 16.3 PnP , thanks to Georg Acher */
byteout(cs->hw.teles3.isac + 0x3c, 0);
HZDELAY(2);
byteout(cs->hw.teles3.isac + 0x3c, 1);
HZDELAY(2);
}
}
return (0);
}
static int
Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
case CARD_RESET:
spin_lock_irqsave(&cs->lock, flags);
reset_teles3(cs);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_RELEASE:
release_io_teles3(cs);
return (0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
inithscxisac(cs, 3);
spin_unlock_irqrestore(&cs->lock, flags);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
#ifdef __ISAPNP__
static struct isapnp_device_id teles_ids[] = {
{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
(unsigned long) "Teles 16.3 PnP" },
{ ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
(unsigned long) "Creatix 16.3 PnP" },
{ ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
(unsigned long) "Compaq ISDN S0" },
{ 0, }
};
static struct isapnp_device_id *ipid = &teles_ids[0];
static struct pnp_card *pnp_c = NULL;
#endif
int setup_teles3(struct IsdnCard *card)
{
u_char val;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, teles3_revision);
printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp));
if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP)
&& (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
return (0);
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d;
while (ipid->card_vendor) {
if ((pnp_c = pnp_find_card(ipid->card_vendor,
ipid->card_device, pnp_c))) {
pnp_d = NULL;
if ((pnp_d = pnp_find_dev(pnp_c,
ipid->vendor, ipid->function, pnp_d))) {
int err;
printk(KERN_INFO "HiSax: %s detected\n",
(char *)ipid->driver_data);
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
if (err < 0) {
printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
__func__, err);
return (0);
}
card->para[3] = pnp_port_start(pnp_d, 2);
card->para[2] = pnp_port_start(pnp_d, 1);
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[0] = pnp_irq(pnp_d, 0);
if (card->para[0] == -1 || !card->para[1] || !card->para[2]) {
printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
card->para[0], card->para[1], card->para[2]);
pnp_disable_dev(pnp_d);
return (0);
}
break;
} else {
printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
}
}
ipid++;
pnp_c = NULL;
}
if (!ipid->card_vendor) {
printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
return (0);
}
}
#endif
if (cs->typ == ISDN_CTYPE_16_3) {
cs->hw.teles3.cfg_reg = card->para[1];
switch (cs->hw.teles3.cfg_reg) {
case 0x180:
case 0x280:
case 0x380:
cs->hw.teles3.cfg_reg |= 0xc00;
break;
}
cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420;
cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20;
cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820;
} else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
cs->hw.teles3.cfg_reg = 0;
cs->hw.teles3.hscx[0] = card->para[1] - 0x20;
cs->hw.teles3.hscx[1] = card->para[1];
cs->hw.teles3.isac = card->para[1] + 0x20;
} else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
cs->hw.teles3.cfg_reg = card->para[3];
cs->hw.teles3.isac = card->para[2] - 32;
cs->hw.teles3.hscx[0] = card->para[1] - 32;
cs->hw.teles3.hscx[1] = card->para[1];
} else { /* PNP */
cs->hw.teles3.cfg_reg = 0;
cs->hw.teles3.isac = card->para[1] - 32;
cs->hw.teles3.hscx[0] = card->para[2] - 32;
cs->hw.teles3.hscx[1] = card->para[2];
}
cs->irq = card->para[0];
cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) {
printk(KERN_WARNING
"HiSax: %s ports %x-%x already in use\n",
CardType[cs->typ],
cs->hw.teles3.hscx[1],
cs->hw.teles3.hscx[1] + 96);
return (0);
}
cs->irq_flags |= IRQF_SHARED; /* cardbus can share */
} else {
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) {
printk(KERN_WARNING
"HiSax: %s config port %x already in use\n",
CardType[card->typ],
cs->hw.teles3.cfg_reg);
return (0);
}
} else {
if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
cs->hw.teles3.cfg_reg,
cs->hw.teles3.cfg_reg + 8);
return (0);
}
}
}
if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) {
printk(KERN_WARNING
"HiSax: %s isac ports %x-%x already in use\n",
CardType[cs->typ],
cs->hw.teles3.isac + 32,
cs->hw.teles3.isac + 64);
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
release_region(cs->hw.teles3.cfg_reg, 1);
} else {
release_region(cs->hw.teles3.cfg_reg, 8);
}
}
return (0);
}
if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) {
printk(KERN_WARNING
"HiSax: %s hscx A ports %x-%x already in use\n",
CardType[cs->typ],
cs->hw.teles3.hscx[0] + 32,
cs->hw.teles3.hscx[0] + 64);
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
release_region(cs->hw.teles3.cfg_reg, 1);
} else {
release_region(cs->hw.teles3.cfg_reg, 8);
}
}
release_ioregs(cs, 1);
return (0);
}
if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) {
printk(KERN_WARNING
"HiSax: %s hscx B ports %x-%x already in use\n",
CardType[cs->typ],
cs->hw.teles3.hscx[1] + 32,
cs->hw.teles3.hscx[1] + 64);
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
release_region(cs->hw.teles3.cfg_reg, 1);
} else {
release_region(cs->hw.teles3.cfg_reg, 8);
}
}
release_ioregs(cs, 3);
return (0);
}
}
if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) {
if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
cs->hw.teles3.cfg_reg + 0, val);
release_io_teles3(cs);
return (0);
}
if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
cs->hw.teles3.cfg_reg + 1, val);
release_io_teles3(cs);
return (0);
}
val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB
* 0x1f=with AB
* 0x1c 16.3 ???
* 0x39 16.3 1.1
* 0x38 16.3 1.3
* 0x46 16.3 with AB + Video (Teles-Vision)
*/
if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
cs->hw.teles3.cfg_reg + 2, val);
release_io_teles3(cs);
return (0);
}
}
printk(KERN_INFO
"HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n",
CardType[cs->typ], cs->irq,
cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg);
printk(KERN_INFO
"HiSax: hscx A:0x%X hscx B:0x%X\n",
cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32);
setup_isac(cs);
if (reset_teles3(cs)) {
printk(KERN_WARNING "Teles3: wrong IRQ\n");
release_io_teles3(cs);
return (0);
}
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &Teles_card_msg;
cs->irq_func = &teles3_interrupt;
ISACVersion(cs, "Teles3:");
if (HscxVersion(cs, "Teles3:")) {
printk(KERN_WARNING
"Teles3: wrong HSCX versions check IO address\n");
release_io_teles3(cs);
return (0);
}
return (1);
}

View File

@ -1,201 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
/*======================================================================
A teles S0 PCMCIA client driver
Based on skeleton by David Hinds, dhinds@allegro.stanford.edu
Written by Christof Petig, christof.petig@wtal.de
Also inspired by ELSA PCMCIA driver
by Klaus Lichtenwalder <Lichtenwalder@ACM.org>
Extensions to new hisax_pcmcia by Karsten Keil
minor changes to be compatible with kernel 2.4.x
by Jan.Schubert@GMX.li
======================================================================*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#include "hisax_cfg.h"
MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
MODULE_LICENSE("GPL");
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int protocol = 2; /* EURO-ISDN Default */
module_param(protocol, int, 0);
static int teles_cs_config(struct pcmcia_device *link);
static void teles_cs_release(struct pcmcia_device *link);
static void teles_detach(struct pcmcia_device *p_dev);
typedef struct local_info_t {
struct pcmcia_device *p_dev;
int busy;
int cardnr;
} local_info_t;
static int teles_probe(struct pcmcia_device *link)
{
local_info_t *local;
dev_dbg(&link->dev, "teles_attach()\n");
/* Allocate space for private device-specific data */
local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) return -ENOMEM;
local->cardnr = -1;
local->p_dev = link;
link->priv = local;
link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
return teles_cs_config(link);
} /* teles_attach */
static void teles_detach(struct pcmcia_device *link)
{
local_info_t *info = link->priv;
dev_dbg(&link->dev, "teles_detach(0x%p)\n", link);
info->busy = 1;
teles_cs_release(link);
kfree(info);
} /* teles_detach */
static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
{
int j;
p_dev->io_lines = 5;
p_dev->resource[0]->end = 96;
p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
if (!pcmcia_request_io(p_dev))
return 0;
} else {
printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
for (j = 0x2f0; j > 0x100; j -= 0x10) {
p_dev->resource[0]->start = j;
if (!pcmcia_request_io(p_dev))
return 0;
}
}
return -ENODEV;
}
static int teles_cs_config(struct pcmcia_device *link)
{
int i;
IsdnCard_t icard;
dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
if (i != 0)
goto cs_failed;
if (!link->irq)
goto cs_failed;
i = pcmcia_enable_device(link);
if (i != 0)
goto cs_failed;
icard.para[0] = link->irq;
icard.para[1] = link->resource[0]->start;
icard.protocol = protocol;
icard.typ = ISDN_CTYPE_TELESPCMCIA;
i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard);
if (i < 0) {
printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
i, (unsigned int) link->resource[0]->start);
teles_cs_release(link);
return -ENODEV;
}
((local_info_t *)link->priv)->cardnr = i;
return 0;
cs_failed:
teles_cs_release(link);
return -ENODEV;
} /* teles_cs_config */
static void teles_cs_release(struct pcmcia_device *link)
{
local_info_t *local = link->priv;
dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
if (local) {
if (local->cardnr >= 0) {
/* no unregister function with hisax */
HiSax_closecard(local->cardnr);
}
}
pcmcia_disable_device(link);
} /* teles_cs_release */
static int teles_suspend(struct pcmcia_device *link)
{
local_info_t *dev = link->priv;
dev->busy = 1;
return 0;
}
static int teles_resume(struct pcmcia_device *link)
{
local_info_t *dev = link->priv;
dev->busy = 0;
return 0;
}
static const struct pcmcia_device_id teles_ids[] = {
PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, teles_ids);
static struct pcmcia_driver teles_cs_driver = {
.owner = THIS_MODULE,
.name = "teles_cs",
.probe = teles_probe,
.remove = teles_detach,
.id_table = teles_ids,
.suspend = teles_suspend,
.resume = teles_resume,
};
module_pcmcia_driver(teles_cs_driver);

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