Commit 85993b8c authored by Arnd Bergmann's avatar 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: default avatarArnd Bergmann <arnd@arndb.de>
parent 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-----
This diff is collapsed.
......@@ -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/
This diff is collapsed.
# 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
This diff is collapsed.
/* 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);
This diff is collapsed.
/* $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);
}
This diff is collapsed.
/*
* 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);
}
This diff is collapsed.
/* $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__ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*======================================================================
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);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment