提交 85993b8c 编写于 作者: A Arnd Bergmann

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: NArnd Bergmann <arnd@arndb.de>
上级 8e6c8aa3
-----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-----
此差异已折叠。
......@@ -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/
# 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
# 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
此差异已折叠。
/* 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 *);
/* $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);
}
/* $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);
/* $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);
}
/* $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);
}
/* $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);
}
此差异已折叠。
/*
* 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);
/* $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);
}
此差异已折叠。
/* $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__ */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*======================================================================
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);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册