Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,64 @@
#
# ISDN AVM drivers
#
menuconfig CAPI_AVM
bool "Active AVM cards"
help
Enable support for AVM active ISDN cards.
if CAPI_AVM
config ISDN_DRV_AVMB1_B1ISA
tristate "AVM B1 ISA support"
depends on ISA
help
Enable support for the ISA version of the AVM B1 card.
config ISDN_DRV_AVMB1_B1PCI
tristate "AVM B1 PCI support"
depends on PCI
help
Enable support for the PCI version of the AVM B1 card.
config ISDN_DRV_AVMB1_B1PCIV4
bool "AVM B1 PCI V4 support"
depends on ISDN_DRV_AVMB1_B1PCI
help
Enable support for the V4 version of AVM B1 PCI card.
config ISDN_DRV_AVMB1_T1ISA
tristate "AVM T1/T1-B ISA support"
depends on ISA
help
Enable support for the AVM T1 T1B card.
Note: This is a PRI card and handle 30 B-channels.
config ISDN_DRV_AVMB1_B1PCMCIA
tristate "AVM B1/M1/M2 PCMCIA support"
depends on PCMCIA
help
Enable support for the PCMCIA version of the AVM B1 card.
config ISDN_DRV_AVMB1_AVM_CS
tristate "AVM B1/M1/M2 PCMCIA cs module"
depends on ISDN_DRV_AVMB1_B1PCMCIA
help
Enable the PCMCIA client driver for the AVM B1/M1/M2
PCMCIA cards.
config ISDN_DRV_AVMB1_T1PCI
tristate "AVM T1/T1-B PCI support"
depends on PCI
help
Enable support for the AVM T1 T1B card.
Note: This is a PRI card and handle 30 B-channels.
config ISDN_DRV_AVMB1_C4
tristate "AVM C4/C2 support"
depends on PCI
help
Enable support for the AVM C4/C2 PCI cards.
These cards handle 4/2 BRI ISDN lines (8/4 channels).
endif # CAPI_AVM

View file

@ -0,0 +1,11 @@
# Makefile for the AVM ISDN device drivers
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN_DRV_AVMB1_B1ISA) += b1isa.o b1.o
obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCI) += b1pci.o b1.o b1dma.o
obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCMCIA) += b1pcmcia.o b1.o
obj-$(CONFIG_ISDN_DRV_AVMB1_AVM_CS) += avm_cs.o
obj-$(CONFIG_ISDN_DRV_AVMB1_T1ISA) += t1isa.o b1.o
obj-$(CONFIG_ISDN_DRV_AVMB1_T1PCI) += t1pci.o b1.o b1dma.o
obj-$(CONFIG_ISDN_DRV_AVMB1_C4) += c4.o b1.o

View file

@ -0,0 +1,166 @@
/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $
*
* A PCMCIA client driver for AVM B1/M1/M2
*
* Copyright 1999 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/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/major.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
#include <linux/skbuff.h>
#include <linux/capi.h>
#include <linux/b1lli.h>
#include <linux/b1pcmcia.h>
/*====================================================================*/
MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/*====================================================================*/
static int avmcs_config(struct pcmcia_device *link);
static void avmcs_release(struct pcmcia_device *link);
static void avmcs_detach(struct pcmcia_device *p_dev);
static int avmcs_probe(struct pcmcia_device *p_dev)
{
/* 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 avmcs_config(p_dev);
} /* avmcs_attach */
static void avmcs_detach(struct pcmcia_device *link)
{
avmcs_release(link);
} /* avmcs_detach */
static int avmcs_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;
return pcmcia_request_io(p_dev);
}
static int avmcs_config(struct pcmcia_device *link)
{
int i = -1;
char devname[128];
int cardtype;
int (*addcard)(unsigned int port, unsigned irq);
devname[0] = 0;
if (link->prod_id[1])
strlcpy(devname, link->prod_id[1], sizeof(devname));
/*
* find IO port
*/
if (pcmcia_loop_config(link, avmcs_configcheck, NULL))
return -ENODEV;
do {
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 (devname[0]) {
char *s = strrchr(devname, ' ');
if (!s)
s = devname;
else s++;
if (strcmp("M1", s) == 0) {
cardtype = AVM_CARDTYPE_M1;
} else if (strcmp("M2", s) == 0) {
cardtype = AVM_CARDTYPE_M2;
} else {
cardtype = AVM_CARDTYPE_B1;
}
} else
cardtype = AVM_CARDTYPE_B1;
/* If any step failed, release any partially configured state */
if (i != 0) {
avmcs_release(link);
return -ENODEV;
}
switch (cardtype) {
case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break;
case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break;
default:
case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break;
}
if ((i = (*addcard)(link->resource[0]->start, link->irq)) < 0) {
dev_err(&link->dev,
"avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n",
(unsigned int) link->resource[0]->start, link->irq);
avmcs_release(link);
return -ENODEV;
}
return 0;
} /* avmcs_config */
static void avmcs_release(struct pcmcia_device *link)
{
b1pcmcia_delcard(link->resource[0]->start, link->irq);
pcmcia_disable_device(link);
} /* avmcs_release */
static const struct pcmcia_device_id avmcs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
static struct pcmcia_driver avmcs_driver = {
.owner = THIS_MODULE,
.name = "avm_cs",
.probe = avmcs_probe,
.remove = avmcs_detach,
.id_table = avmcs_ids,
};
module_pcmcia_driver(avmcs_driver);

View file

@ -0,0 +1,581 @@
/* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $
*
* Copyright 1999 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.
*
*/
#ifndef _AVMCARD_H_
#define _AVMCARD_H_
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#define AVMB1_PORTLEN 0x1f
#define AVM_MAXVERSION 8
#define AVM_NCCI_PER_CHANNEL 4
/*
* Versions
*/
#define VER_DRIVER 0
#define VER_CARDTYPE 1
#define VER_HWID 2
#define VER_SERIAL 3
#define VER_OPTION 4
#define VER_PROTO 5
#define VER_PROFILE 6
#define VER_CAPI 7
enum avmcardtype {
avm_b1isa,
avm_b1pci,
avm_b1pcmcia,
avm_m1,
avm_m2,
avm_t1isa,
avm_t1pci,
avm_c4,
avm_c2
};
typedef struct avmcard_dmabuf {
long size;
u8 *dmabuf;
dma_addr_t dmaaddr;
} avmcard_dmabuf;
typedef struct avmcard_dmainfo {
u32 recvlen;
avmcard_dmabuf recvbuf;
avmcard_dmabuf sendbuf;
struct sk_buff_head send_queue;
struct pci_dev *pcidev;
} avmcard_dmainfo;
typedef struct avmctrl_info {
char cardname[32];
int versionlen;
char versionbuf[1024];
char *version[AVM_MAXVERSION];
char infobuf[128]; /* for function procinfo */
struct avmcard *card;
struct capi_ctr capi_ctrl;
struct list_head ncci_head;
} avmctrl_info;
typedef struct avmcard {
char name[32];
spinlock_t lock;
unsigned int port;
unsigned irq;
unsigned long membase;
enum avmcardtype cardtype;
unsigned char revision;
unsigned char class;
int cardnr; /* for t1isa */
char msgbuf[128]; /* capimsg msg part */
char databuf[2048]; /* capimsg data part */
void __iomem *mbase;
volatile u32 csr;
avmcard_dmainfo *dma;
struct avmctrl_info *ctrlinfo;
u_int nr_controllers;
u_int nlogcontr;
struct list_head list;
} avmcard;
extern int b1_irq_table[16];
/*
* LLI Messages to the ISDN-ControllerISDN Controller
*/
#define SEND_POLL 0x72 /*
* after load <- RECEIVE_POLL
*/
#define SEND_INIT 0x11 /*
* first message <- RECEIVE_INIT
* int32 NumApplications int32
* NumNCCIs int32 BoardNumber
*/
#define SEND_REGISTER 0x12 /*
* register an application int32
* ApplIDId int32 NumMessages
* int32 NumB3Connections int32
* NumB3Blocks int32 B3Size
*
* AnzB3Connection != 0 &&
* AnzB3Blocks >= 1 && B3Size >= 1
*/
#define SEND_RELEASE 0x14 /*
* deregister an application int32
* ApplID
*/
#define SEND_MESSAGE 0x15 /*
* send capi-message int32 length
* capi-data ...
*/
#define SEND_DATA_B3_REQ 0x13 /*
* send capi-data-message int32
* MsgLength capi-data ... int32
* B3Length data ....
*/
#define SEND_CONFIG 0x21 /*
*/
#define SEND_POLLACK 0x73 /* T1 Watchdog */
/*
* LLI Messages from the ISDN-ControllerISDN Controller
*/
#define RECEIVE_POLL 0x32 /*
* <- after SEND_POLL
*/
#define RECEIVE_INIT 0x27 /*
* <- after SEND_INIT int32 length
* byte total length b1struct board
* driver revision b1struct card
* type b1struct reserved b1struct
* serial number b1struct driver
* capability b1struct d-channel
* protocol b1struct CAPI-2.0
* profile b1struct capi version
*/
#define RECEIVE_MESSAGE 0x21 /*
* <- after SEND_MESSAGE int32
* AppllID int32 Length capi-data
* ....
*/
#define RECEIVE_DATA_B3_IND 0x22 /*
* received data int32 AppllID
* int32 Length capi-data ...
* int32 B3Length data ...
*/
#define RECEIVE_START 0x23 /*
* Handshake
*/
#define RECEIVE_STOP 0x24 /*
* Handshake
*/
#define RECEIVE_NEW_NCCI 0x25 /*
* int32 AppllID int32 NCCI int32
* WindowSize
*/
#define RECEIVE_FREE_NCCI 0x26 /*
* int32 AppllID int32 NCCI
*/
#define RECEIVE_RELEASE 0x26 /*
* int32 AppllID int32 0xffffffff
*/
#define RECEIVE_TASK_READY 0x31 /*
* int32 tasknr
* int32 Length Taskname ...
*/
#define RECEIVE_DEBUGMSG 0x71 /*
* int32 Length message
*
*/
#define RECEIVE_POLLDWORD 0x75 /* t1pci in dword mode */
#define WRITE_REGISTER 0x00
#define READ_REGISTER 0x01
/*
* port offsets
*/
#define B1_READ 0x00
#define B1_WRITE 0x01
#define B1_INSTAT 0x02
#define B1_OUTSTAT 0x03
#define B1_ANALYSE 0x04
#define B1_REVISION 0x05
#define B1_RESET 0x10
#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l)
#define B1_STAT1(cardtype) (0x80E00000l)
/* ---------------------------------------------------------------- */
static inline unsigned char b1outp(unsigned int base,
unsigned short offset,
unsigned char value)
{
outb(value, base + offset);
return inb(base + B1_ANALYSE);
}
static inline int b1_rx_full(unsigned int base)
{
return inb(base + B1_INSTAT) & 0x1;
}
static inline unsigned char b1_get_byte(unsigned int base)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
while (!b1_rx_full(base) && time_before(jiffies, stop));
if (b1_rx_full(base))
return inb(base + B1_READ);
printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base);
return 0;
}
static inline unsigned int b1_get_word(unsigned int base)
{
unsigned int val = 0;
val |= b1_get_byte(base);
val |= (b1_get_byte(base) << 8);
val |= (b1_get_byte(base) << 16);
val |= (b1_get_byte(base) << 24);
return val;
}
static inline int b1_tx_empty(unsigned int base)
{
return inb(base + B1_OUTSTAT) & 0x1;
}
static inline void b1_put_byte(unsigned int base, unsigned char val)
{
while (!b1_tx_empty(base));
b1outp(base, B1_WRITE, val);
}
static inline int b1_save_put_byte(unsigned int base, unsigned char val)
{
unsigned long stop = jiffies + 2 * HZ;
while (!b1_tx_empty(base) && time_before(jiffies, stop));
if (!b1_tx_empty(base)) return -1;
b1outp(base, B1_WRITE, val);
return 0;
}
static inline void b1_put_word(unsigned int base, unsigned int val)
{
b1_put_byte(base, val & 0xff);
b1_put_byte(base, (val >> 8) & 0xff);
b1_put_byte(base, (val >> 16) & 0xff);
b1_put_byte(base, (val >> 24) & 0xff);
}
static inline unsigned int b1_get_slice(unsigned int base,
unsigned char *dp)
{
unsigned int len, i;
len = i = b1_get_word(base);
while (i-- > 0) *dp++ = b1_get_byte(base);
return len;
}
static inline void b1_put_slice(unsigned int base,
unsigned char *dp, unsigned int len)
{
unsigned i = len;
b1_put_word(base, i);
while (i-- > 0)
b1_put_byte(base, *dp++);
}
static void b1_wr_reg(unsigned int base,
unsigned int reg,
unsigned int value)
{
b1_put_byte(base, WRITE_REGISTER);
b1_put_word(base, reg);
b1_put_word(base, value);
}
static inline unsigned int b1_rd_reg(unsigned int base,
unsigned int reg)
{
b1_put_byte(base, READ_REGISTER);
b1_put_word(base, reg);
return b1_get_word(base);
}
static inline void b1_reset(unsigned int base)
{
b1outp(base, B1_RESET, 0);
mdelay(55 * 2); /* 2 TIC's */
b1outp(base, B1_RESET, 1);
mdelay(55 * 2); /* 2 TIC's */
b1outp(base, B1_RESET, 0);
mdelay(55 * 2); /* 2 TIC's */
}
static inline unsigned char b1_disable_irq(unsigned int base)
{
return b1outp(base, B1_INSTAT, 0x00);
}
/* ---------------------------------------------------------------- */
static inline void b1_set_test_bit(unsigned int base,
enum avmcardtype cardtype,
int onoff)
{
b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20);
}
static inline int b1_get_test_bit(unsigned int base,
enum avmcardtype cardtype)
{
return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0;
}
/* ---------------------------------------------------------------- */
#define T1_FASTLINK 0x00
#define T1_SLOWLINK 0x08
#define T1_READ B1_READ
#define T1_WRITE B1_WRITE
#define T1_INSTAT B1_INSTAT
#define T1_OUTSTAT B1_OUTSTAT
#define T1_IRQENABLE 0x05
#define T1_FIFOSTAT 0x06
#define T1_RESETLINK 0x10
#define T1_ANALYSE 0x11
#define T1_IRQMASTER 0x12
#define T1_IDENT 0x17
#define T1_RESETBOARD 0x1f
#define T1F_IREADY 0x01
#define T1F_IHALF 0x02
#define T1F_IFULL 0x04
#define T1F_IEMPTY 0x08
#define T1F_IFLAGS 0xF0
#define T1F_OREADY 0x10
#define T1F_OHALF 0x20
#define T1F_OEMPTY 0x40
#define T1F_OFULL 0x80
#define T1F_OFLAGS 0xF0
/* there are HEMA cards with 1k and 4k FIFO out */
#define FIFO_OUTBSIZE 256
#define FIFO_INPBSIZE 512
#define HEMA_VERSION_ID 0
#define HEMA_PAL_ID 0
static inline void t1outp(unsigned int base,
unsigned short offset,
unsigned char value)
{
outb(value, base + offset);
}
static inline unsigned char t1inp(unsigned int base,
unsigned short offset)
{
return inb(base + offset);
}
static inline int t1_isfastlink(unsigned int base)
{
return (inb(base + T1_IDENT) & ~0x82) == 1;
}
static inline unsigned char t1_fifostatus(unsigned int base)
{
return inb(base + T1_FIFOSTAT);
}
static inline unsigned int t1_get_slice(unsigned int base,
unsigned char *dp)
{
unsigned int len, i;
#ifdef FASTLINK_DEBUG
unsigned wcnt = 0, bcnt = 0;
#endif
len = i = b1_get_word(base);
if (t1_isfastlink(base)) {
int status;
while (i > 0) {
status = t1_fifostatus(base) & (T1F_IREADY | T1F_IHALF);
if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
switch (status) {
case T1F_IREADY | T1F_IHALF | T1F_IFULL:
insb(base + B1_READ, dp, FIFO_INPBSIZE);
dp += FIFO_INPBSIZE;
i -= FIFO_INPBSIZE;
#ifdef FASTLINK_DEBUG
wcnt += FIFO_INPBSIZE;
#endif
break;
case T1F_IREADY | T1F_IHALF:
insb(base + B1_READ, dp, i);
#ifdef FASTLINK_DEBUG
wcnt += i;
#endif
dp += i;
i = 0;
break;
default:
*dp++ = b1_get_byte(base);
i--;
#ifdef FASTLINK_DEBUG
bcnt++;
#endif
break;
}
}
#ifdef FASTLINK_DEBUG
if (wcnt)
printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n",
base, len, wcnt, bcnt);
#endif
} else {
while (i-- > 0)
*dp++ = b1_get_byte(base);
}
return len;
}
static inline void t1_put_slice(unsigned int base,
unsigned char *dp, unsigned int len)
{
unsigned i = len;
b1_put_word(base, i);
if (t1_isfastlink(base)) {
int status;
while (i > 0) {
status = t1_fifostatus(base) & (T1F_OREADY | T1F_OHALF);
if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY;
switch (status) {
case T1F_OREADY | T1F_OHALF | T1F_OEMPTY:
outsb(base + B1_WRITE, dp, FIFO_OUTBSIZE);
dp += FIFO_OUTBSIZE;
i -= FIFO_OUTBSIZE;
break;
case T1F_OREADY | T1F_OHALF:
outsb(base + B1_WRITE, dp, i);
dp += i;
i = 0;
break;
default:
b1_put_byte(base, *dp++);
i--;
break;
}
}
} else {
while (i-- > 0)
b1_put_byte(base, *dp++);
}
}
static inline void t1_disable_irq(unsigned int base)
{
t1outp(base, T1_IRQMASTER, 0x00);
}
static inline void t1_reset(unsigned int base)
{
/* reset T1 Controller */
b1_reset(base);
/* disable irq on HEMA */
t1outp(base, B1_INSTAT, 0x00);
t1outp(base, B1_OUTSTAT, 0x00);
t1outp(base, T1_IRQMASTER, 0x00);
/* reset HEMA board configuration */
t1outp(base, T1_RESETBOARD, 0xf);
}
static inline void b1_setinterrupt(unsigned int base, unsigned irq,
enum avmcardtype cardtype)
{
switch (cardtype) {
case avm_t1isa:
t1outp(base, B1_INSTAT, 0x00);
t1outp(base, B1_INSTAT, 0x02);
t1outp(base, T1_IRQMASTER, 0x08);
break;
case avm_b1isa:
b1outp(base, B1_INSTAT, 0x00);
b1outp(base, B1_RESET, b1_irq_table[irq]);
b1outp(base, B1_INSTAT, 0x02);
break;
default:
case avm_m1:
case avm_m2:
case avm_b1pci:
b1outp(base, B1_INSTAT, 0x00);
b1outp(base, B1_RESET, 0xf0);
b1outp(base, B1_INSTAT, 0x02);
break;
case avm_c4:
case avm_t1pci:
b1outp(base, B1_RESET, 0xf0);
break;
}
}
/* b1.c */
avmcard *b1_alloc_card(int nr_controllers);
void b1_free_card(avmcard *card);
int b1_detect(unsigned int base, enum avmcardtype cardtype);
void b1_getrevision(avmcard *card);
int b1_load_t4file(avmcard *card, capiloaddatapart *t4file);
int b1_load_config(avmcard *card, capiloaddatapart *config);
int b1_loaded(avmcard *card);
int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
void b1_reset_ctr(struct capi_ctr *ctrl);
void b1_register_appl(struct capi_ctr *ctrl, u16 appl,
capi_register_params *rp);
void b1_release_appl(struct capi_ctr *ctrl, u16 appl);
u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
void b1_parse_version(avmctrl_info *card);
irqreturn_t b1_interrupt(int interrupt, void *devptr);
extern const struct file_operations b1ctl_proc_fops;
avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *,
long rsize, long ssize);
void avmcard_dma_free(avmcard_dmainfo *);
/* b1dma.c */
int b1pciv4_detect(avmcard *card);
int t1pci_detect(avmcard *card);
void b1dma_reset(avmcard *card);
irqreturn_t b1dma_interrupt(int interrupt, void *devptr);
int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
void b1dma_reset_ctr(struct capi_ctr *ctrl);
void b1dma_remove_ctr(struct capi_ctr *ctrl);
void b1dma_register_appl(struct capi_ctr *ctrl,
u16 appl,
capi_register_params *rp);
void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl);
u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
extern const struct file_operations b1dmactl_proc_fops;
#endif /* _AVMCARD_H_ */

View file

@ -0,0 +1,817 @@
/* $Id: b1.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
*
* Common module for AVM B1 cards.
*
* Copyright 1999 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/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
static char *revision = "$Revision: 1.1.2.2 $";
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: Common support for active AVM cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
int b1_irq_table[16] =
{0,
0,
0,
192, /* irq 3 */
32, /* irq 4 */
160, /* irq 5 */
96, /* irq 6 */
224, /* irq 7 */
0,
64, /* irq 9 */
80, /* irq 10 */
208, /* irq 11 */
48, /* irq 12 */
0,
0,
112, /* irq 15 */
};
/* ------------------------------------------------------------- */
avmcard *b1_alloc_card(int nr_controllers)
{
avmcard *card;
avmctrl_info *cinfo;
int i;
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card)
return NULL;
cinfo = kzalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL);
if (!cinfo) {
kfree(card);
return NULL;
}
card->ctrlinfo = cinfo;
for (i = 0; i < nr_controllers; i++) {
INIT_LIST_HEAD(&cinfo[i].ncci_head);
cinfo[i].card = card;
}
spin_lock_init(&card->lock);
card->nr_controllers = nr_controllers;
return card;
}
/* ------------------------------------------------------------- */
void b1_free_card(avmcard *card)
{
kfree(card->ctrlinfo);
kfree(card);
}
/* ------------------------------------------------------------- */
int b1_detect(unsigned int base, enum avmcardtype cardtype)
{
int onoff, i;
/*
* Statusregister 0000 00xx
*/
if ((inb(base + B1_INSTAT) & 0xfc)
|| (inb(base + B1_OUTSTAT) & 0xfc))
return 1;
/*
* Statusregister 0000 001x
*/
b1outp(base, B1_INSTAT, 0x2); /* enable irq */
/* b1outp(base, B1_OUTSTAT, 0x2); */
if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
/* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */)
return 2;
/*
* Statusregister 0000 000x
*/
b1outp(base, B1_INSTAT, 0x0); /* disable irq */
b1outp(base, B1_OUTSTAT, 0x0);
if ((inb(base + B1_INSTAT) & 0xfe)
|| (inb(base + B1_OUTSTAT) & 0xfe))
return 3;
for (onoff = !0, i = 0; i < 10; i++) {
b1_set_test_bit(base, cardtype, onoff);
if (b1_get_test_bit(base, cardtype) != onoff)
return 4;
onoff = !onoff;
}
if (cardtype == avm_m1)
return 0;
if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01)
return 5;
return 0;
}
void b1_getrevision(avmcard *card)
{
card->class = inb(card->port + B1_ANALYSE);
card->revision = inb(card->port + B1_REVISION);
}
#define FWBUF_SIZE 256
int b1_load_t4file(avmcard *card, capiloaddatapart *t4file)
{
unsigned char buf[FWBUF_SIZE];
unsigned char *dp;
int i, left;
unsigned int base = card->port;
dp = t4file->data;
left = t4file->len;
while (left > FWBUF_SIZE) {
if (t4file->user) {
if (copy_from_user(buf, dp, FWBUF_SIZE))
return -EFAULT;
} else {
memcpy(buf, dp, FWBUF_SIZE);
}
for (i = 0; i < FWBUF_SIZE; i++)
if (b1_save_put_byte(base, buf[i]) < 0) {
printk(KERN_ERR "%s: corrupted firmware file ?\n",
card->name);
return -EIO;
}
left -= FWBUF_SIZE;
dp += FWBUF_SIZE;
}
if (left) {
if (t4file->user) {
if (copy_from_user(buf, dp, left))
return -EFAULT;
} else {
memcpy(buf, dp, left);
}
for (i = 0; i < left; i++)
if (b1_save_put_byte(base, buf[i]) < 0) {
printk(KERN_ERR "%s: corrupted firmware file ?\n",
card->name);
return -EIO;
}
}
return 0;
}
int b1_load_config(avmcard *card, capiloaddatapart *config)
{
unsigned char buf[FWBUF_SIZE];
unsigned char *dp;
unsigned int base = card->port;
int i, j, left;
dp = config->data;
left = config->len;
if (left) {
b1_put_byte(base, SEND_CONFIG);
b1_put_word(base, 1);
b1_put_byte(base, SEND_CONFIG);
b1_put_word(base, left);
}
while (left > FWBUF_SIZE) {
if (config->user) {
if (copy_from_user(buf, dp, FWBUF_SIZE))
return -EFAULT;
} else {
memcpy(buf, dp, FWBUF_SIZE);
}
for (i = 0; i < FWBUF_SIZE; ) {
b1_put_byte(base, SEND_CONFIG);
for (j = 0; j < 4; j++) {
b1_put_byte(base, buf[i++]);
}
}
left -= FWBUF_SIZE;
dp += FWBUF_SIZE;
}
if (left) {
if (config->user) {
if (copy_from_user(buf, dp, left))
return -EFAULT;
} else {
memcpy(buf, dp, left);
}
for (i = 0; i < left; ) {
b1_put_byte(base, SEND_CONFIG);
for (j = 0; j < 4; j++) {
if (i < left)
b1_put_byte(base, buf[i++]);
else
b1_put_byte(base, 0);
}
}
}
return 0;
}
int b1_loaded(avmcard *card)
{
unsigned int base = card->port;
unsigned long stop;
unsigned char ans;
unsigned long tout = 2;
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_tx_empty(base))
break;
}
if (!b1_tx_empty(base)) {
printk(KERN_ERR "%s: b1_loaded: tx err, corrupted t4 file ?\n",
card->name);
return 0;
}
b1_put_byte(base, SEND_POLL);
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_rx_full(base)) {
if ((ans = b1_get_byte(base)) == RECEIVE_POLL) {
return 1;
}
printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n",
card->name, ans);
return 0;
}
}
printk(KERN_ERR "%s: b1_loaded: firmware not running\n", card->name);
return 0;
}
/* ------------------------------------------------------------- */
int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int retval;
b1_reset(port);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
b1_disable_irq(port);
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1_loaded(card)) {
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
spin_lock_irqsave(&card->lock, flags);
b1_setinterrupt(port, card->irq, card->cardtype);
b1_put_byte(port, SEND_INIT);
b1_put_word(port, CAPI_MAXAPPL);
b1_put_word(port, AVM_NCCI_PER_CHANNEL * 2);
b1_put_word(port, ctrl->cnr - 1);
spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
void b1_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
spin_lock_irqsave(&card->lock, flags);
capilib_release(&cinfo->ncci_head);
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_down(ctrl);
}
void b1_register_appl(struct capi_ctr *ctrl,
u16 appl,
capi_register_params *rp)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int nconn, want = rp->level3cnt;
if (want > 0) nconn = want;
else nconn = ctrl->profile.nbchannel * -want;
if (nconn == 0) nconn = ctrl->profile.nbchannel;
spin_lock_irqsave(&card->lock, flags);
b1_put_byte(port, SEND_REGISTER);
b1_put_word(port, appl);
b1_put_word(port, 1024 * (nconn + 1));
b1_put_word(port, nconn);
b1_put_word(port, rp->datablkcnt);
b1_put_word(port, rp->datablklen);
spin_unlock_irqrestore(&card->lock, flags);
}
void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
capilib_release_appl(&cinfo->ncci_head, appl);
b1_put_byte(port, SEND_RELEASE);
b1_put_word(port, appl);
spin_unlock_irqrestore(&card->lock, flags);
}
u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
u16 len = CAPIMSG_LEN(skb->data);
u8 cmd = CAPIMSG_COMMAND(skb->data);
u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
u16 dlen, retval;
spin_lock_irqsave(&card->lock, flags);
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
if (retval != CAPI_NOERROR) {
spin_unlock_irqrestore(&card->lock, flags);
return retval;
}
dlen = CAPIMSG_DATALEN(skb->data);
b1_put_byte(port, SEND_DATA_B3_REQ);
b1_put_slice(port, skb->data, len);
b1_put_slice(port, skb->data + len, dlen);
} else {
b1_put_byte(port, SEND_MESSAGE);
b1_put_slice(port, skb->data, len);
}
spin_unlock_irqrestore(&card->lock, flags);
dev_kfree_skb_any(skb);
return CAPI_NOERROR;
}
/* ------------------------------------------------------------- */
void b1_parse_version(avmctrl_info *cinfo)
{
struct capi_ctr *ctrl = &cinfo->capi_ctrl;
avmcard *card = cinfo->card;
capi_profile *profp;
u8 *dversion;
u8 flag;
int i, j;
for (j = 0; j < AVM_MAXVERSION; j++)
cinfo->version[j] = "\0\0" + 1;
for (i = 0, j = 0;
j < AVM_MAXVERSION && i < cinfo->versionlen;
j++, i += cinfo->versionbuf[i] + 1)
cinfo->version[j] = &cinfo->versionbuf[i + 1];
strlcpy(ctrl->serial, cinfo->version[VER_SERIAL], sizeof(ctrl->serial));
memcpy(&ctrl->profile, cinfo->version[VER_PROFILE], sizeof(capi_profile));
strlcpy(ctrl->manu, "AVM GmbH", sizeof(ctrl->manu));
dversion = cinfo->version[VER_DRIVER];
ctrl->version.majorversion = 2;
ctrl->version.minorversion = 0;
ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4);
ctrl->version.majormanuversion |= ((dversion[2] - '0') & 0xf);
ctrl->version.minormanuversion = (dversion[3] - '0') << 4;
ctrl->version.minormanuversion |=
(dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf);
profp = &ctrl->profile;
flag = ((u8 *)(profp->manu))[1];
switch (flag) {
case 0: if (cinfo->version[VER_CARDTYPE])
strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]);
else strcpy(cinfo->cardname, "B1");
break;
case 3: strcpy(cinfo->cardname, "PCMCIA B"); break;
case 4: strcpy(cinfo->cardname, "PCMCIA M1"); break;
case 5: strcpy(cinfo->cardname, "PCMCIA M2"); break;
case 6: strcpy(cinfo->cardname, "B1 V3.0"); break;
case 7: strcpy(cinfo->cardname, "B1 PCI"); break;
default: sprintf(cinfo->cardname, "AVM?%u", (unsigned int)flag); break;
}
printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n",
card->name, ctrl->cnr, cinfo->cardname);
flag = ((u8 *)(profp->manu))[3];
if (flag)
printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n",
card->name,
ctrl->cnr,
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
flag = ((u8 *)(profp->manu))[5];
if (flag)
printk(KERN_NOTICE "%s: card %d Linetype:%s%s%s%s\n",
card->name,
ctrl->cnr,
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
/* ------------------------------------------------------------- */
irqreturn_t b1_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
avmctrl_info *cinfo = &card->ctrlinfo[0];
struct capi_ctr *ctrl = &cinfo->capi_ctrl;
unsigned char b1cmd;
struct sk_buff *skb;
unsigned ApplId;
unsigned MsgLen;
unsigned DataB3Len;
unsigned NCCI;
unsigned WindowSize;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
if (!b1_rx_full(card->port)) {
spin_unlock_irqrestore(&card->lock, flags);
return IRQ_NONE;
}
b1cmd = b1_get_byte(card->port);
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
DataB3Len = b1_get_slice(card->port, card->databuf);
spin_unlock_irqrestore(&card->lock, flags);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf + MsgLen, 0, 30-MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
spin_unlock_irqrestore(&card->lock, flags);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_START:
/* b1_put_byte(card->port, SEND_POLLACK); */
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_resume_output(ctrl);
break;
case RECEIVE_STOP:
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf);
spin_unlock_irqrestore(&card->lock, flags);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
capi_ctr_ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
spin_unlock_irqrestore(&card->lock, flags);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = b1_get_slice(card->port, card->msgbuf);
spin_unlock_irqrestore(&card->lock, flags);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
case 0xff:
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: card removed ?\n", card->name);
return IRQ_NONE;
default:
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
card->name, b1cmd);
return IRQ_HANDLED;
}
return IRQ_HANDLED;
}
/* ------------------------------------------------------------- */
static int b1ctl_proc_show(struct seq_file *m, void *v)
{
struct capi_ctr *ctrl = m->private;
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
char *s;
seq_printf(m, "%-16s %s\n", "name", card->name);
seq_printf(m, "%-16s 0x%x\n", "io", card->port);
seq_printf(m, "%-16s %d\n", "irq", card->irq);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
case avm_b1pcmcia: s = "B1 PCMCIA"; break;
case avm_m1: s = "M1"; break;
case avm_m2: s = "M2"; break;
case avm_t1isa: s = "T1 ISA (HEMA)"; break;
case avm_t1pci: s = "T1 PCI"; break;
case avm_c4: s = "C4"; break;
case avm_c2: s = "C2"; break;
default: s = "???"; break;
}
seq_printf(m, "%-16s %s\n", "type", s);
if (card->cardtype == avm_t1isa)
seq_printf(m, "%-16s %d\n", "cardnr", card->cardnr);
if ((s = cinfo->version[VER_DRIVER]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
}
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[5];
if (flag)
seq_printf(m, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
return 0;
}
static int b1ctl_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, b1ctl_proc_show, PDE_DATA(inode));
}
const struct file_operations b1ctl_proc_fops = {
.owner = THIS_MODULE,
.open = b1ctl_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
EXPORT_SYMBOL(b1ctl_proc_fops);
/* ------------------------------------------------------------- */
#ifdef CONFIG_PCI
avmcard_dmainfo *
avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize)
{
avmcard_dmainfo *p;
void *buf;
p = kzalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
if (!p) {
printk(KERN_WARNING "%s: no memory.\n", name);
goto err;
}
p->recvbuf.size = rsize;
buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr);
if (!buf) {
printk(KERN_WARNING "%s: allocation of receive dma buffer failed.\n", name);
goto err_kfree;
}
p->recvbuf.dmabuf = buf;
p->sendbuf.size = ssize;
buf = pci_alloc_consistent(pdev, ssize, &p->sendbuf.dmaaddr);
if (!buf) {
printk(KERN_WARNING "%s: allocation of send dma buffer failed.\n", name);
goto err_free_consistent;
}
p->sendbuf.dmabuf = buf;
skb_queue_head_init(&p->send_queue);
return p;
err_free_consistent:
pci_free_consistent(p->pcidev, p->recvbuf.size,
p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
err_kfree:
kfree(p);
err:
return NULL;
}
void avmcard_dma_free(avmcard_dmainfo *p)
{
pci_free_consistent(p->pcidev, p->recvbuf.size,
p->recvbuf.dmabuf, p->recvbuf.dmaaddr);
pci_free_consistent(p->pcidev, p->sendbuf.size,
p->sendbuf.dmabuf, p->sendbuf.dmaaddr);
skb_queue_purge(&p->send_queue);
kfree(p);
}
EXPORT_SYMBOL(avmcard_dma_alloc);
EXPORT_SYMBOL(avmcard_dma_free);
#endif
EXPORT_SYMBOL(b1_irq_table);
EXPORT_SYMBOL(b1_alloc_card);
EXPORT_SYMBOL(b1_free_card);
EXPORT_SYMBOL(b1_detect);
EXPORT_SYMBOL(b1_getrevision);
EXPORT_SYMBOL(b1_load_t4file);
EXPORT_SYMBOL(b1_load_config);
EXPORT_SYMBOL(b1_loaded);
EXPORT_SYMBOL(b1_load_firmware);
EXPORT_SYMBOL(b1_reset_ctr);
EXPORT_SYMBOL(b1_register_appl);
EXPORT_SYMBOL(b1_release_appl);
EXPORT_SYMBOL(b1_send_message);
EXPORT_SYMBOL(b1_parse_version);
EXPORT_SYMBOL(b1_interrupt);
static int __init b1_init(void)
{
char *p;
char rev[32];
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
printk(KERN_INFO "b1: revision %s\n", rev);
return 0;
}
static void __exit b1_exit(void)
{
}
module_init(b1_init);
module_exit(b1_exit);

View file

@ -0,0 +1,994 @@
/* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
*
* Common module for AVM B1 cards that support dma with AMCC
*
* Copyright 2000 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/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/gfp.h>
#include <asm/io.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
static char *revision = "$Revision: 1.1.2.3 $";
#undef AVM_B1DMA_DEBUG
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
static bool suppress_pollack = 0;
module_param(suppress_pollack, bool, 0);
/* ------------------------------------------------------------- */
static void b1dma_dispatch_tx(avmcard *card);
/* ------------------------------------------------------------- */
/* S5933 */
#define AMCC_RXPTR 0x24
#define AMCC_RXLEN 0x28
#define AMCC_TXPTR 0x2c
#define AMCC_TXLEN 0x30
#define AMCC_INTCSR 0x38
# define EN_READ_TC_INT 0x00008000L
# define EN_WRITE_TC_INT 0x00004000L
# define EN_TX_TC_INT EN_READ_TC_INT
# define EN_RX_TC_INT EN_WRITE_TC_INT
# define AVM_FLAG 0x30000000L
# define ANY_S5933_INT 0x00800000L
# define READ_TC_INT 0x00080000L
# define WRITE_TC_INT 0x00040000L
# define TX_TC_INT READ_TC_INT
# define RX_TC_INT WRITE_TC_INT
# define MASTER_ABORT_INT 0x00100000L
# define TARGET_ABORT_INT 0x00200000L
# define BUS_MASTER_INT 0x00200000L
# define ALL_INT 0x000C0000L
#define AMCC_MCSR 0x3c
# define A2P_HI_PRIORITY 0x00000100L
# define EN_A2P_TRANSFERS 0x00000400L
# define P2A_HI_PRIORITY 0x00001000L
# define EN_P2A_TRANSFERS 0x00004000L
# define RESET_A2P_FLAGS 0x04000000L
# define RESET_P2A_FLAGS 0x02000000L
/* ------------------------------------------------------------- */
static inline void b1dma_writel(avmcard *card, u32 value, int off)
{
writel(value, card->mbase + off);
}
static inline u32 b1dma_readl(avmcard *card, int off)
{
return readl(card->mbase + off);
}
/* ------------------------------------------------------------- */
static inline int b1dma_tx_empty(unsigned int port)
{
return inb(port + 0x03) & 0x1;
}
static inline int b1dma_rx_full(unsigned int port)
{
return inb(port + 0x02) & 0x1;
}
static int b1dma_tolink(avmcard *card, void *buf, unsigned int len)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
unsigned char *s = (unsigned char *)buf;
while (len--) {
while (!b1dma_tx_empty(card->port)
&& time_before(jiffies, stop));
if (!b1dma_tx_empty(card->port))
return -1;
t1outp(card->port, 0x01, *s++);
}
return 0;
}
static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len)
{
unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */
unsigned char *s = (unsigned char *)buf;
while (len--) {
while (!b1dma_rx_full(card->port)
&& time_before(jiffies, stop));
if (!b1dma_rx_full(card->port))
return -1;
*s++ = t1inp(card->port, 0x00);
}
return 0;
}
static int WriteReg(avmcard *card, u32 reg, u8 val)
{
u8 cmd = 0x00;
if (b1dma_tolink(card, &cmd, 1) == 0
&& b1dma_tolink(card, &reg, 4) == 0) {
u32 tmp = val;
return b1dma_tolink(card, &tmp, 4);
}
return -1;
}
static u8 ReadReg(avmcard *card, u32 reg)
{
u8 cmd = 0x01;
if (b1dma_tolink(card, &cmd, 1) == 0
&& b1dma_tolink(card, &reg, 4) == 0) {
u32 tmp;
if (b1dma_fromlink(card, &tmp, 4) == 0)
return (u8)tmp;
}
return 0xff;
}
/* ------------------------------------------------------------- */
static inline void _put_byte(void **pp, u8 val)
{
u8 *s = *pp;
*s++ = val;
*pp = s;
}
static inline void _put_word(void **pp, u32 val)
{
u8 *s = *pp;
*s++ = val & 0xff;
*s++ = (val >> 8) & 0xff;
*s++ = (val >> 16) & 0xff;
*s++ = (val >> 24) & 0xff;
*pp = s;
}
static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
{
unsigned i = len;
_put_word(pp, i);
while (i-- > 0)
_put_byte(pp, *dp++);
}
static inline u8 _get_byte(void **pp)
{
u8 *s = *pp;
u8 val;
val = *s++;
*pp = s;
return val;
}
static inline u32 _get_word(void **pp)
{
u8 *s = *pp;
u32 val;
val = *s++;
val |= (*s++ << 8);
val |= (*s++ << 16);
val |= (*s++ << 24);
*pp = s;
return val;
}
static inline u32 _get_slice(void **pp, unsigned char *dp)
{
unsigned int len, i;
len = i = _get_word(pp);
while (i-- > 0) *dp++ = _get_byte(pp);
return len;
}
/* ------------------------------------------------------------- */
void b1dma_reset(avmcard *card)
{
card->csr = 0x0;
b1dma_writel(card, card->csr, AMCC_INTCSR);
b1dma_writel(card, 0, AMCC_MCSR);
b1dma_writel(card, 0, AMCC_RXLEN);
b1dma_writel(card, 0, AMCC_TXLEN);
t1outp(card->port, 0x10, 0x00);
t1outp(card->port, 0x07, 0x00);
b1dma_writel(card, 0, AMCC_MCSR);
mdelay(10);
b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
mdelay(10);
b1dma_writel(card, 0, AMCC_MCSR);
if (card->cardtype == avm_t1pci)
mdelay(42);
else
mdelay(10);
}
/* ------------------------------------------------------------- */
static int b1dma_detect(avmcard *card)
{
b1dma_writel(card, 0, AMCC_MCSR);
mdelay(10);
b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
mdelay(10);
b1dma_writel(card, 0, AMCC_MCSR);
mdelay(42);
b1dma_writel(card, 0, AMCC_RXLEN);
b1dma_writel(card, 0, AMCC_TXLEN);
card->csr = 0x0;
b1dma_writel(card, card->csr, AMCC_INTCSR);
if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6)
return 1;
b1dma_writel(card, 0xffffffff, AMCC_RXPTR);
b1dma_writel(card, 0xffffffff, AMCC_TXPTR);
if (b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc
|| b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc)
return 2;
b1dma_writel(card, 0x0, AMCC_RXPTR);
b1dma_writel(card, 0x0, AMCC_TXPTR);
if (b1dma_readl(card, AMCC_RXPTR) != 0x0
|| b1dma_readl(card, AMCC_TXPTR) != 0x0)
return 3;
t1outp(card->port, 0x10, 0x00);
t1outp(card->port, 0x07, 0x00);
t1outp(card->port, 0x02, 0x02);
t1outp(card->port, 0x03, 0x02);
if ((t1inp(card->port, 0x02) & 0xFE) != 0x02
|| t1inp(card->port, 0x3) != 0x03)
return 4;
t1outp(card->port, 0x02, 0x00);
t1outp(card->port, 0x03, 0x00);
if ((t1inp(card->port, 0x02) & 0xFE) != 0x00
|| t1inp(card->port, 0x3) != 0x01)
return 5;
return 0;
}
int t1pci_detect(avmcard *card)
{
int ret;
if ((ret = b1dma_detect(card)) != 0)
return ret;
/* Transputer test */
if (WriteReg(card, 0x80001000, 0x11) != 0
|| WriteReg(card, 0x80101000, 0x22) != 0
|| WriteReg(card, 0x80201000, 0x33) != 0
|| WriteReg(card, 0x80301000, 0x44) != 0)
return 6;
if (ReadReg(card, 0x80001000) != 0x11
|| ReadReg(card, 0x80101000) != 0x22
|| ReadReg(card, 0x80201000) != 0x33
|| ReadReg(card, 0x80301000) != 0x44)
return 7;
if (WriteReg(card, 0x80001000, 0x55) != 0
|| WriteReg(card, 0x80101000, 0x66) != 0
|| WriteReg(card, 0x80201000, 0x77) != 0
|| WriteReg(card, 0x80301000, 0x88) != 0)
return 8;
if (ReadReg(card, 0x80001000) != 0x55
|| ReadReg(card, 0x80101000) != 0x66
|| ReadReg(card, 0x80201000) != 0x77
|| ReadReg(card, 0x80301000) != 0x88)
return 9;
return 0;
}
int b1pciv4_detect(avmcard *card)
{
int ret, i;
if ((ret = b1dma_detect(card)) != 0)
return ret;
for (i = 0; i < 5; i++) {
if (WriteReg(card, 0x80A00000, 0x21) != 0)
return 6;
if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01)
return 7;
}
for (i = 0; i < 5; i++) {
if (WriteReg(card, 0x80A00000, 0x20) != 0)
return 8;
if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00)
return 9;
}
return 0;
}
static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb)
{
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
skb_queue_tail(&card->dma->send_queue, skb);
if (!(card->csr & EN_TX_TC_INT)) {
b1dma_dispatch_tx(card);
b1dma_writel(card, card->csr, AMCC_INTCSR);
}
spin_unlock_irqrestore(&card->lock, flags);
}
/* ------------------------------------------------------------- */
static void b1dma_dispatch_tx(avmcard *card)
{
avmcard_dmainfo *dma = card->dma;
struct sk_buff *skb;
u8 cmd, subcmd;
u16 len;
u32 txlen;
void *p;
skb = skb_dequeue(&dma->send_queue);
len = CAPIMSG_LEN(skb->data);
if (len) {
cmd = CAPIMSG_COMMAND(skb->data);
subcmd = CAPIMSG_SUBCOMMAND(skb->data);
p = dma->sendbuf.dmabuf;
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
u16 dlen = CAPIMSG_DATALEN(skb->data);
_put_byte(&p, SEND_DATA_B3_REQ);
_put_slice(&p, skb->data, len);
_put_slice(&p, skb->data + len, dlen);
} else {
_put_byte(&p, SEND_MESSAGE);
_put_slice(&p, skb->data, len);
}
txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "tx: put msg len=%d\n", txlen);
#endif
} else {
txlen = skb->len - 2;
#ifdef AVM_B1DMA_POLLDEBUG
if (skb->data[2] == SEND_POLLACK)
printk(KERN_INFO "%s: send ack\n", card->name);
#endif
#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "tx: put 0x%x len=%d\n",
skb->data[2], txlen);
#endif
skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf,
skb->len - 2);
}
txlen = (txlen + 3) & ~3;
b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR);
b1dma_writel(card, txlen, AMCC_TXLEN);
card->csr |= EN_TX_TC_INT;
dev_kfree_skb_any(skb);
}
/* ------------------------------------------------------------- */
static void queue_pollack(avmcard *card)
{
struct sk_buff *skb;
void *p;
skb = alloc_skb(3, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost poll ack\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_POLLACK);
skb_put(skb, (u8 *)p - (u8 *)skb->data);
b1dma_queue_tx(card, skb);
}
/* ------------------------------------------------------------- */
static void b1dma_handle_rx(avmcard *card)
{
avmctrl_info *cinfo = &card->ctrlinfo[0];
avmcard_dmainfo *dma = card->dma;
struct capi_ctr *ctrl = &cinfo->capi_ctrl;
struct sk_buff *skb;
void *p = dma->recvbuf.dmabuf + 4;
u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
u8 b1cmd = _get_byte(&p);
#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
#endif
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
DataB3Len = _get_slice(&p, card->databuf);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf + MsgLen, 0, 30 - MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) {
spin_lock(&card->lock);
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
spin_unlock(&card->lock);
}
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = _get_word(&p);
NCCI = _get_word(&p);
WindowSize = _get_word(&p);
spin_lock(&card->lock);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
spin_unlock(&card->lock);
break;
case RECEIVE_FREE_NCCI:
ApplId = _get_word(&p);
NCCI = _get_word(&p);
if (NCCI != 0xffffffff) {
spin_lock(&card->lock);
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
spin_unlock(&card->lock);
}
break;
case RECEIVE_START:
#ifdef AVM_B1DMA_POLLDEBUG
printk(KERN_INFO "%s: receive poll\n", card->name);
#endif
if (!suppress_pollack)
queue_pollack(card);
capi_ctr_resume_output(ctrl);
break;
case RECEIVE_STOP:
capi_ctr_suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
capi_ctr_ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) _get_word(&p);
MsgLen = _get_slice(&p, card->msgbuf);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = _get_slice(&p, card->msgbuf);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
default:
printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n",
card->name, b1cmd);
return;
}
}
/* ------------------------------------------------------------- */
static void b1dma_handle_interrupt(avmcard *card)
{
u32 status;
u32 newcsr;
spin_lock(&card->lock);
status = b1dma_readl(card, AMCC_INTCSR);
if ((status & ANY_S5933_INT) == 0) {
spin_unlock(&card->lock);
return;
}
newcsr = card->csr | (status & ALL_INT);
if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
b1dma_writel(card, newcsr, AMCC_INTCSR);
if ((status & RX_TC_INT) != 0) {
struct avmcard_dmainfo *dma = card->dma;
u32 rxlen;
if (card->dma->recvlen == 0) {
rxlen = b1dma_readl(card, AMCC_RXLEN);
if (rxlen == 0) {
dma->recvlen = *((u32 *)dma->recvbuf.dmabuf);
rxlen = (dma->recvlen + 3) & ~3;
b1dma_writel(card, dma->recvbuf.dmaaddr + 4, AMCC_RXPTR);
b1dma_writel(card, rxlen, AMCC_RXLEN);
#ifdef AVM_B1DMA_DEBUG
} else {
printk(KERN_ERR "%s: rx not complete (%d).\n",
card->name, rxlen);
#endif
}
} else {
spin_unlock(&card->lock);
b1dma_handle_rx(card);
dma->recvlen = 0;
spin_lock(&card->lock);
b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR);
b1dma_writel(card, 4, AMCC_RXLEN);
}
}
if ((status & TX_TC_INT) != 0) {
if (skb_queue_empty(&card->dma->send_queue))
card->csr &= ~EN_TX_TC_INT;
else
b1dma_dispatch_tx(card);
}
b1dma_writel(card, card->csr, AMCC_INTCSR);
spin_unlock(&card->lock);
}
irqreturn_t b1dma_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
b1dma_handle_interrupt(card);
return IRQ_HANDLED;
}
/* ------------------------------------------------------------- */
static int b1dma_loaded(avmcard *card)
{
unsigned long stop;
unsigned char ans;
unsigned long tout = 2;
unsigned int base = card->port;
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_tx_empty(base))
break;
}
if (!b1_tx_empty(base)) {
printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n",
card->name);
return 0;
}
b1_put_byte(base, SEND_POLLACK);
for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
if (b1_rx_full(base)) {
if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
return 1;
}
printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
return 0;
}
}
printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name);
return 0;
}
/* ------------------------------------------------------------- */
static void b1dma_send_init(avmcard *card)
{
struct sk_buff *skb;
void *p;
skb = alloc_skb(15, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost register appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_INIT);
_put_word(&p, CAPI_MAXAPPL);
_put_word(&p, AVM_NCCI_PER_CHANNEL * 30);
_put_word(&p, card->cardnr - 1);
skb_put(skb, (u8 *)p - (u8 *)skb->data);
b1dma_queue_tx(card, skb);
}
int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
int retval;
b1dma_reset(card);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1dma_loaded(card)) {
b1dma_reset(card);
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
card->csr = AVM_FLAG;
b1dma_writel(card, card->csr, AMCC_INTCSR);
b1dma_writel(card, EN_A2P_TRANSFERS | EN_P2A_TRANSFERS | A2P_HI_PRIORITY |
P2A_HI_PRIORITY | RESET_A2P_FLAGS | RESET_P2A_FLAGS,
AMCC_MCSR);
t1outp(card->port, 0x07, 0x30);
t1outp(card->port, 0x10, 0xF0);
card->dma->recvlen = 0;
b1dma_writel(card, card->dma->recvbuf.dmaaddr, AMCC_RXPTR);
b1dma_writel(card, 4, AMCC_RXLEN);
card->csr |= EN_RX_TC_INT;
b1dma_writel(card, card->csr, AMCC_INTCSR);
b1dma_send_init(card);
return 0;
}
void b1dma_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
b1dma_reset(card);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_down(ctrl);
}
/* ------------------------------------------------------------- */
void b1dma_register_appl(struct capi_ctr *ctrl,
u16 appl,
capi_register_params *rp)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
struct sk_buff *skb;
int want = rp->level3cnt;
int nconn;
void *p;
if (want > 0) nconn = want;
else nconn = ctrl->profile.nbchannel * -want;
if (nconn == 0) nconn = ctrl->profile.nbchannel;
skb = alloc_skb(23, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost register appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_REGISTER);
_put_word(&p, appl);
_put_word(&p, 1024 * (nconn + 1));
_put_word(&p, nconn);
_put_word(&p, rp->datablkcnt);
_put_word(&p, rp->datablklen);
skb_put(skb, (u8 *)p - (u8 *)skb->data);
b1dma_queue_tx(card, skb);
}
/* ------------------------------------------------------------- */
void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
struct sk_buff *skb;
void *p;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
capilib_release_appl(&cinfo->ncci_head, appl);
spin_unlock_irqrestore(&card->lock, flags);
skb = alloc_skb(7, GFP_ATOMIC);
if (!skb) {
printk(KERN_CRIT "%s: no memory, lost release appl.\n",
card->name);
return;
}
p = skb->data;
_put_byte(&p, 0);
_put_byte(&p, 0);
_put_byte(&p, SEND_RELEASE);
_put_word(&p, appl);
skb_put(skb, (u8 *)p - (u8 *)skb->data);
b1dma_queue_tx(card, skb);
}
/* ------------------------------------------------------------- */
u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u16 retval = CAPI_NOERROR;
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
spin_unlock_irqrestore(&card->lock, flags);
}
if (retval == CAPI_NOERROR)
b1dma_queue_tx(card, skb);
return retval;
}
/* ------------------------------------------------------------- */
static int b1dmactl_proc_show(struct seq_file *m, void *v)
{
struct capi_ctr *ctrl = m->private;
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
char *s;
u32 txoff, txlen, rxoff, rxlen, csr;
unsigned long flags;
seq_printf(m, "%-16s %s\n", "name", card->name);
seq_printf(m, "%-16s 0x%x\n", "io", card->port);
seq_printf(m, "%-16s %d\n", "irq", card->irq);
seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase);
switch (card->cardtype) {
case avm_b1isa: s = "B1 ISA"; break;
case avm_b1pci: s = "B1 PCI"; break;
case avm_b1pcmcia: s = "B1 PCMCIA"; break;
case avm_m1: s = "M1"; break;
case avm_m2: s = "M2"; break;
case avm_t1isa: s = "T1 ISA (HEMA)"; break;
case avm_t1pci: s = "T1 PCI"; break;
case avm_c4: s = "C4"; break;
case avm_c2: s = "C2"; break;
default: s = "???"; break;
}
seq_printf(m, "%-16s %s\n", "type", s);
if ((s = cinfo->version[VER_DRIVER]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != NULL)
seq_printf(m, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
seq_printf(m, "%-16s%s%s%s%s%s%s%s\n",
"protocol",
(flag & 0x01) ? " DSS1" : "",
(flag & 0x02) ? " CT1" : "",
(flag & 0x04) ? " VN3" : "",
(flag & 0x08) ? " NI1" : "",
(flag & 0x10) ? " AUSTEL" : "",
(flag & 0x20) ? " ESS" : "",
(flag & 0x40) ? " 1TR6" : ""
);
}
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[5];
if (flag)
seq_printf(m, "%-16s%s%s%s%s\n",
"linetype",
(flag & 0x01) ? " point to point" : "",
(flag & 0x02) ? " point to multipoint" : "",
(flag & 0x08) ? " leased line without D-channel" : "",
(flag & 0x04) ? " leased line with D-channel" : ""
);
}
seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname);
spin_lock_irqsave(&card->lock, flags);
txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr;
txlen = b1dma_readl(card, AMCC_TXLEN);
rxoff = (dma_addr_t)b1dma_readl(card, AMCC_RXPTR)-card->dma->recvbuf.dmaaddr;
rxlen = b1dma_readl(card, AMCC_RXLEN);
csr = b1dma_readl(card, AMCC_INTCSR);
spin_unlock_irqrestore(&card->lock, flags);
seq_printf(m, "%-16s 0x%lx\n", "csr (cached)", (unsigned long)card->csr);
seq_printf(m, "%-16s 0x%lx\n", "csr", (unsigned long)csr);
seq_printf(m, "%-16s %lu\n", "txoff", (unsigned long)txoff);
seq_printf(m, "%-16s %lu\n", "txlen", (unsigned long)txlen);
seq_printf(m, "%-16s %lu\n", "rxoff", (unsigned long)rxoff);
seq_printf(m, "%-16s %lu\n", "rxlen", (unsigned long)rxlen);
return 0;
}
static int b1dmactl_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, b1dmactl_proc_show, PDE_DATA(inode));
}
const struct file_operations b1dmactl_proc_fops = {
.owner = THIS_MODULE,
.open = b1dmactl_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
EXPORT_SYMBOL(b1dmactl_proc_fops);
/* ------------------------------------------------------------- */
EXPORT_SYMBOL(b1dma_reset);
EXPORT_SYMBOL(t1pci_detect);
EXPORT_SYMBOL(b1pciv4_detect);
EXPORT_SYMBOL(b1dma_interrupt);
EXPORT_SYMBOL(b1dma_load_firmware);
EXPORT_SYMBOL(b1dma_reset_ctr);
EXPORT_SYMBOL(b1dma_register_appl);
EXPORT_SYMBOL(b1dma_release_appl);
EXPORT_SYMBOL(b1dma_send_message);
static int __init b1dma_init(void)
{
char *p;
char rev[32];
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
printk(KERN_INFO "b1dma: revision %s\n", rev);
return 0;
}
static void __exit b1dma_exit(void)
{
}
module_init(b1dma_init);
module_exit(b1dma_exit);

View file

@ -0,0 +1,243 @@
/* $Id: b1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
*
* Module for AVM B1 ISA-card.
*
* Copyright 1999 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/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.3 $";
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static void b1isa_remove(struct pci_dev *pdev)
{
avmctrl_info *cinfo = pci_get_drvdata(pdev);
avmcard *card;
if (!cinfo)
return;
card = cinfo->card;
b1_reset(card->port);
b1_reset(card->port);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
b1_free_card(card);
}
/* ------------------------------------------------------------- */
static char *b1isa_procinfo(struct capi_ctr *ctrl);
static int b1isa_probe(struct pci_dev *pdev)
{
avmctrl_info *cinfo;
avmcard *card;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "b1isa: no memory.\n");
retval = -ENOMEM;
goto err;
}
cinfo = card->ctrlinfo;
card->port = pci_resource_start(pdev, 0);
card->irq = pdev->irq;
card->cardtype = avm_b1isa;
sprintf(card->name, "b1isa-%x", card->port);
if (card->port != 0x150 && card->port != 0x250
&& card->port != 0x300 && card->port != 0x340) {
printk(KERN_WARNING "b1isa: invalid port 0x%x.\n", card->port);
retval = -EINVAL;
goto err_free;
}
if (b1_irq_table[card->irq & 0xf] == 0) {
printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq);
retval = -EINVAL;
goto err_free;
}
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING "b1isa: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free;
}
retval = request_irq(card->irq, b1_interrupt, 0, card->name, card);
if (retval) {
printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq);
goto err_release_region;
}
b1_reset(card->port);
if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_free_irq;
}
b1_reset(card->port);
b1_getrevision(card);
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "b1isa";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
cinfo->capi_ctrl.release_appl = b1_release_appl;
cinfo->capi_ctrl.send_message = b1_send_message;
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1isa_procinfo;
cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "b1isa: attach controller failed.\n");
goto err_free_irq;
}
printk(KERN_INFO "b1isa: AVM B1 ISA at i/o %#x, irq %d, revision %d\n",
card->port, card->irq, card->revision);
pci_set_drvdata(pdev, cinfo);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free:
b1_free_card(card);
err:
return retval;
}
static char *b1isa_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
#define MAX_CARDS 4
static struct pci_dev isa_dev[MAX_CARDS];
static int io[MAX_CARDS];
static int irq[MAX_CARDS];
module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
MODULE_PARM_DESC(io, "I/O base address(es)");
MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
static int b1isa_add_card(struct capi_driver *driver, capicardparams *data)
{
int i;
for (i = 0; i < MAX_CARDS; i++) {
if (isa_dev[i].resource[0].start)
continue;
isa_dev[i].resource[0].start = data->port;
isa_dev[i].irq = data->irq;
if (b1isa_probe(&isa_dev[i]) == 0)
return 0;
}
return -ENODEV;
}
static struct capi_driver capi_driver_b1isa = {
.name = "b1isa",
.revision = "1.0",
.add_card = b1isa_add_card,
};
static int __init b1isa_init(void)
{
char *p;
char rev[32];
int i;
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
for (i = 0; i < MAX_CARDS; i++) {
if (!io[i])
break;
isa_dev[i].resource[0].start = io[i];
isa_dev[i].irq = irq[i];
if (b1isa_probe(&isa_dev[i]) != 0)
return -ENODEV;
}
strlcpy(capi_driver_b1isa.revision, rev, 32);
register_capi_driver(&capi_driver_b1isa);
printk(KERN_INFO "b1isa: revision %s\n", rev);
return 0;
}
static void __exit b1isa_exit(void)
{
int i;
for (i = 0; i < MAX_CARDS; i++) {
if (isa_dev[i].resource[0].start)
b1isa_remove(&isa_dev[i]);
}
unregister_capi_driver(&capi_driver_b1isa);
}
module_init(b1isa_init);
module_exit(b1isa_exit);

View file

@ -0,0 +1,416 @@
/* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
*
* Module for AVM B1 PCI-card.
*
* Copyright 1999 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/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/capi.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.2 $";
/* ------------------------------------------------------------- */
static struct pci_device_id b1pci_pci_tbl[] = {
{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, b1pci_pci_tbl);
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 PCI card");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static char *b1pci_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
{
avmcard *card;
avmctrl_info *cinfo;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "b1pci: no memory.\n");
retval = -ENOMEM;
goto err;
}
cinfo = card->ctrlinfo;
sprintf(card->name, "b1pci-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->cardtype = avm_b1pci;
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free;
}
b1_reset(card->port);
retval = b1_detect(card->port, card->cardtype);
if (retval) {
printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_release_region;
}
b1_reset(card->port);
b1_getrevision(card);
retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
retval = -EBUSY;
goto err_release_region;
}
cinfo->capi_ctrl.driver_name = "b1pci";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
cinfo->capi_ctrl.release_appl = b1_release_appl;
cinfo->capi_ctrl.send_message = b1_send_message;
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pci_procinfo;
cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
cinfo->capi_ctrl.owner = THIS_MODULE;
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "b1pci: attach controller failed.\n");
goto err_free_irq;
}
if (card->revision >= 4) {
printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
card->port, card->irq, card->revision);
} else {
printk(KERN_INFO "b1pci: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
card->port, card->irq, card->revision);
}
pci_set_drvdata(pdev, card);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free:
b1_free_card(card);
err:
return retval;
}
static void b1pci_remove(struct pci_dev *pdev)
{
avmcard *card = pci_get_drvdata(pdev);
avmctrl_info *cinfo = card->ctrlinfo;
unsigned int port = card->port;
b1_reset(port);
b1_reset(port);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
b1_free_card(card);
}
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
/* ------------------------------------------------------------- */
static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->membase : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
{
avmcard *card;
avmctrl_info *cinfo;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "b1pci: no memory.\n");
retval = -ENOMEM;
goto err;
}
card->dma = avmcard_dma_alloc("b1pci", pdev, 2048 + 128, 2048 + 128);
if (!card->dma) {
printk(KERN_WARNING "b1pci: dma alloc.\n");
retval = -ENOMEM;
goto err_free;
}
cinfo = card->ctrlinfo;
sprintf(card->name, "b1pciv4-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->membase = p->membase;
card->cardtype = avm_b1pci;
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free_dma;
}
card->mbase = ioremap(card->membase, 64);
if (!card->mbase) {
printk(KERN_NOTICE "b1pci: can't remap memory at 0x%lx\n",
card->membase);
retval = -ENOMEM;
goto err_release_region;
}
b1dma_reset(card);
retval = b1pciv4_detect(card);
if (retval) {
printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_unmap;
}
b1dma_reset(card);
b1_getrevision(card);
retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pci: unable to get IRQ %d.\n",
card->irq);
retval = -EBUSY;
goto err_unmap;
}
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "b1pciv4";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1dma_register_appl;
cinfo->capi_ctrl.release_appl = b1dma_release_appl;
cinfo->capi_ctrl.send_message = b1dma_send_message;
cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pciv4_procinfo;
cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "b1pci: attach controller failed.\n");
goto err_free_irq;
}
card->cardnr = cinfo->capi_ctrl.cnr;
printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
card->port, card->irq, card->membase, card->revision);
pci_set_drvdata(pdev, card);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_unmap:
iounmap(card->mbase);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free_dma:
avmcard_dma_free(card->dma);
err_free:
b1_free_card(card);
err:
return retval;
}
static void b1pciv4_remove(struct pci_dev *pdev)
{
avmcard *card = pci_get_drvdata(pdev);
avmctrl_info *cinfo = card->ctrlinfo;
b1dma_reset(card);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
iounmap(card->mbase);
release_region(card->port, AVMB1_PORTLEN);
avmcard_dma_free(card->dma);
b1_free_card(card);
}
#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
static int b1pci_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct capicardparams param;
int retval;
if (pci_enable_device(pdev) < 0) {
printk(KERN_ERR "b1pci: failed to enable AVM-B1\n");
return -ENODEV;
}
param.irq = pdev->irq;
if (pci_resource_start(pdev, 2)) { /* B1 PCI V4 */
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
pci_set_master(pdev);
#endif
param.membase = pci_resource_start(pdev, 0);
param.port = pci_resource_start(pdev, 2);
printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
param.port, param.irq, param.membase);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
retval = b1pciv4_probe(&param, pdev);
#else
retval = b1pci_probe(&param, pdev);
#endif
if (retval != 0) {
printk(KERN_ERR "b1pci: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
param.port, param.irq, param.membase);
}
} else {
param.membase = 0;
param.port = pci_resource_start(pdev, 1);
printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
param.port, param.irq);
retval = b1pci_probe(&param, pdev);
if (retval != 0) {
printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
param.port, param.irq);
}
}
return retval;
}
static void b1pci_pci_remove(struct pci_dev *pdev)
{
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
avmcard *card = pci_get_drvdata(pdev);
if (card->dma)
b1pciv4_remove(pdev);
else
b1pci_remove(pdev);
#else
b1pci_remove(pdev);
#endif
}
static struct pci_driver b1pci_pci_driver = {
.name = "b1pci",
.id_table = b1pci_pci_tbl,
.probe = b1pci_pci_probe,
.remove = b1pci_pci_remove,
};
static struct capi_driver capi_driver_b1pci = {
.name = "b1pci",
.revision = "1.0",
};
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
static struct capi_driver capi_driver_b1pciv4 = {
.name = "b1pciv4",
.revision = "1.0",
};
#endif
static int __init b1pci_init(void)
{
char *p;
char rev[32];
int err;
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
err = pci_register_driver(&b1pci_pci_driver);
if (!err) {
strlcpy(capi_driver_b1pci.revision, rev, 32);
register_capi_driver(&capi_driver_b1pci);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
strlcpy(capi_driver_b1pciv4.revision, rev, 32);
register_capi_driver(&capi_driver_b1pciv4);
#endif
printk(KERN_INFO "b1pci: revision %s\n", rev);
}
return err;
}
static void __exit b1pci_exit(void)
{
unregister_capi_driver(&capi_driver_b1pci);
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
unregister_capi_driver(&capi_driver_b1pciv4);
#endif
pci_unregister_driver(&b1pci_pci_driver);
}
module_init(b1pci_init);
module_exit(b1pci_exit);

View file

@ -0,0 +1,224 @@
/* $Id: b1pcmcia.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
*
* Module for AVM B1/M1/M2 PCMCIA-card.
*
* Copyright 1999 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/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/capi.h>
#include <linux/b1pcmcia.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.2 $";
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
b1_reset(port);
b1_reset(port);
detach_capi_ctr(ctrl);
free_irq(card->irq, card);
b1_free_card(card);
}
/* ------------------------------------------------------------- */
static LIST_HEAD(cards);
static char *b1pcmcia_procinfo(struct capi_ctr *ctrl);
static int b1pcmcia_add_card(unsigned int port, unsigned irq,
enum avmcardtype cardtype)
{
avmctrl_info *cinfo;
avmcard *card;
char *cardname;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "b1pcmcia: no memory.\n");
retval = -ENOMEM;
goto err;
}
cinfo = card->ctrlinfo;
switch (cardtype) {
case avm_m1: sprintf(card->name, "m1-%x", port); break;
case avm_m2: sprintf(card->name, "m2-%x", port); break;
default: sprintf(card->name, "b1pcmcia-%x", port); break;
}
card->port = port;
card->irq = irq;
card->cardtype = cardtype;
retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n",
card->irq);
retval = -EBUSY;
goto err_free;
}
b1_reset(card->port);
if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_free_irq;
}
b1_reset(card->port);
b1_getrevision(card);
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "b1pcmcia";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
cinfo->capi_ctrl.release_appl = b1_release_appl;
cinfo->capi_ctrl.send_message = b1_send_message;
cinfo->capi_ctrl.load_firmware = b1_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1_reset_ctr;
cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo;
cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "b1pcmcia: attach controller failed.\n");
goto err_free_irq;
}
switch (cardtype) {
case avm_m1: cardname = "M1"; break;
case avm_m2: cardname = "M2"; break;
default: cardname = "B1 PCMCIA"; break;
}
printk(KERN_INFO "b1pcmcia: AVM %s at i/o %#x, irq %d, revision %d\n",
cardname, card->port, card->irq, card->revision);
list_add(&card->list, &cards);
return cinfo->capi_ctrl.cnr;
err_free_irq:
free_irq(card->irq, card);
err_free:
b1_free_card(card);
err:
return retval;
}
/* ------------------------------------------------------------- */
static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->revision : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
int b1pcmcia_addcard_b1(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(port, irq, avm_b1pcmcia);
}
int b1pcmcia_addcard_m1(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(port, irq, avm_m1);
}
int b1pcmcia_addcard_m2(unsigned int port, unsigned irq)
{
return b1pcmcia_add_card(port, irq, avm_m2);
}
int b1pcmcia_delcard(unsigned int port, unsigned irq)
{
struct list_head *l;
avmcard *card;
list_for_each(l, &cards) {
card = list_entry(l, avmcard, list);
if (card->port == port && card->irq == irq) {
b1pcmcia_remove_ctr(&card->ctrlinfo[0].capi_ctrl);
return 0;
}
}
return -ESRCH;
}
EXPORT_SYMBOL(b1pcmcia_addcard_b1);
EXPORT_SYMBOL(b1pcmcia_addcard_m1);
EXPORT_SYMBOL(b1pcmcia_addcard_m2);
EXPORT_SYMBOL(b1pcmcia_delcard);
static struct capi_driver capi_driver_b1pcmcia = {
.name = "b1pcmcia",
.revision = "1.0",
};
static int __init b1pcmcia_init(void)
{
char *p;
char rev[32];
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
strlcpy(capi_driver_b1pcmcia.revision, rev, 32);
register_capi_driver(&capi_driver_b1pcmcia);
printk(KERN_INFO "b1pci: revision %s\n", rev);
return 0;
}
static void __exit b1pcmcia_exit(void)
{
unregister_capi_driver(&capi_driver_b1pcmcia);
}
module_init(b1pcmcia_init);
module_exit(b1pcmcia_exit);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,594 @@
/* $Id: t1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
*
* Module for AVM T1 HEMA-card.
*
* Copyright 1999 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/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
#include <linux/netdevice.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/gfp.h>
#include <asm/io.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.3 $";
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static int hema_irq_table[16] =
{0,
0,
0,
0x80, /* irq 3 */
0,
0x90, /* irq 5 */
0,
0xA0, /* irq 7 */
0,
0xB0, /* irq 9 */
0xC0, /* irq 10 */
0xD0, /* irq 11 */
0xE0, /* irq 12 */
0,
0,
0xF0, /* irq 15 */
};
static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
{
unsigned char cregs[8];
unsigned char reverse_cardnr;
unsigned char dummy;
int i;
reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1)
| ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3);
cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf);
cregs[1] = 0x00; /* fast & slow link connected to CON1 */
cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */
cregs[3] = 0;
cregs[4] = 0x11; /* zero wait state */
cregs[5] = hema_irq_table[irq & 0xf];
cregs[6] = 0;
cregs[7] = 0;
/*
* no one else should use the ISA bus in this moment,
* but no function there to prevent this :-(
* save_flags(flags); cli();
*/
/* board reset */
t1outp(base, T1_RESETBOARD, 0xf);
mdelay(100);
dummy = t1inp(base, T1_FASTLINK + T1_OUTSTAT); /* first read */
/* write config */
dummy = (base >> 4) & 0xff;
for (i = 1; i <= 0xf; i++) t1outp(base, i, dummy);
t1outp(base, HEMA_PAL_ID & 0xf, dummy);
t1outp(base, HEMA_PAL_ID >> 4, cregs[0]);
for (i = 1; i < 7; i++) t1outp(base, 0, cregs[i]);
t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
/* restore_flags(flags); */
mdelay(100);
t1outp(base, T1_FASTLINK + T1_RESETLINK, 0);
t1outp(base, T1_SLOWLINK + T1_RESETLINK, 0);
mdelay(10);
t1outp(base, T1_FASTLINK + T1_RESETLINK, 1);
t1outp(base, T1_SLOWLINK + T1_RESETLINK, 1);
mdelay(100);
t1outp(base, T1_FASTLINK + T1_RESETLINK, 0);
t1outp(base, T1_SLOWLINK + T1_RESETLINK, 0);
mdelay(10);
t1outp(base, T1_FASTLINK + T1_ANALYSE, 0);
mdelay(5);
t1outp(base, T1_SLOWLINK + T1_ANALYSE, 0);
if (t1inp(base, T1_FASTLINK + T1_OUTSTAT) != 0x1) /* tx empty */
return 1;
if (t1inp(base, T1_FASTLINK + T1_INSTAT) != 0x0) /* rx empty */
return 2;
if (t1inp(base, T1_FASTLINK + T1_IRQENABLE) != 0x0)
return 3;
if ((t1inp(base, T1_FASTLINK + T1_FIFOSTAT) & 0xf0) != 0x70)
return 4;
if ((t1inp(base, T1_FASTLINK + T1_IRQMASTER) & 0x0e) != 0)
return 5;
if ((t1inp(base, T1_FASTLINK + T1_IDENT) & 0x7d) != 1)
return 6;
if (t1inp(base, T1_SLOWLINK + T1_OUTSTAT) != 0x1) /* tx empty */
return 7;
if ((t1inp(base, T1_SLOWLINK + T1_IRQMASTER) & 0x0e) != 0)
return 8;
if ((t1inp(base, T1_SLOWLINK + T1_IDENT) & 0x7d) != 0)
return 9;
return 0;
}
static irqreturn_t t1isa_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
avmctrl_info *cinfo = &card->ctrlinfo[0];
struct capi_ctr *ctrl = &cinfo->capi_ctrl;
unsigned char b1cmd;
struct sk_buff *skb;
unsigned ApplId;
unsigned MsgLen;
unsigned DataB3Len;
unsigned NCCI;
unsigned WindowSize;
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
while (b1_rx_full(card->port)) {
b1cmd = b1_get_byte(card->port);
switch (b1cmd) {
case RECEIVE_DATA_B3_IND:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
DataB3Len = t1_get_slice(card->port, card->databuf);
spin_unlock_irqrestore(&card->lock, flags);
if (MsgLen < 30) { /* not CAPI 64Bit */
memset(card->msgbuf + MsgLen, 0, 30 - MsgLen);
MsgLen = 30;
CAPIMSG_SETLEN(card->msgbuf, 30);
}
if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_MESSAGE:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_START:
b1_put_byte(card->port, SEND_POLLACK);
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_resume_output(ctrl);
break;
case RECEIVE_STOP:
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_suspend_output(ctrl);
break;
case RECEIVE_INIT:
cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf);
spin_unlock_irqrestore(&card->lock, flags);
b1_parse_version(cinfo);
printk(KERN_INFO "%s: %s-card (%s) now active\n",
card->name,
cinfo->version[VER_CARDTYPE],
cinfo->version[VER_DRIVER]);
capi_ctr_ready(ctrl);
break;
case RECEIVE_TASK_READY:
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
spin_unlock_irqrestore(&card->lock, flags);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
card->name, ApplId, card->msgbuf);
break;
case RECEIVE_DEBUGMSG:
MsgLen = t1_get_slice(card->port, card->msgbuf);
spin_unlock_irqrestore(&card->lock, flags);
card->msgbuf[MsgLen] = 0;
while (MsgLen > 0
&& (card->msgbuf[MsgLen - 1] == '\n'
|| card->msgbuf[MsgLen - 1] == '\r')) {
card->msgbuf[MsgLen - 1] = 0;
MsgLen--;
}
printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
break;
case 0xff:
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: card reseted ?\n", card->name);
return IRQ_HANDLED;
default:
spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n",
card->name, b1cmd);
return IRQ_NONE;
}
}
return IRQ_HANDLED;
}
/* ------------------------------------------------------------- */
static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
int retval;
t1_disable_irq(port);
b1_reset(port);
if ((retval = b1_load_t4file(card, &data->firmware))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load t4file!!\n",
card->name);
return retval;
}
if (data->configuration.len > 0 && data->configuration.data) {
if ((retval = b1_load_config(card, &data->configuration))) {
b1_reset(port);
printk(KERN_ERR "%s: failed to load config!!\n",
card->name);
return retval;
}
}
if (!b1_loaded(card)) {
printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
return -EIO;
}
spin_lock_irqsave(&card->lock, flags);
b1_setinterrupt(port, card->irq, card->cardtype);
b1_put_byte(port, SEND_INIT);
b1_put_word(port, CAPI_MAXAPPL);
b1_put_word(port, AVM_NCCI_PER_CHANNEL * 30);
b1_put_word(port, ctrl->cnr - 1);
spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
static void t1isa_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
t1_disable_irq(port);
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
spin_lock_irqsave(&card->lock, flags);
capilib_release(&cinfo->ncci_head);
spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_down(ctrl);
}
static void t1isa_remove(struct pci_dev *pdev)
{
avmctrl_info *cinfo = pci_get_drvdata(pdev);
avmcard *card;
if (!cinfo)
return;
card = cinfo->card;
t1_disable_irq(card->port);
b1_reset(card->port);
b1_reset(card->port);
t1_reset(card->port);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
release_region(card->port, AVMB1_PORTLEN);
b1_free_card(card);
}
/* ------------------------------------------------------------- */
static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
static char *t1isa_procinfo(struct capi_ctr *ctrl);
static int t1isa_probe(struct pci_dev *pdev, int cardnr)
{
avmctrl_info *cinfo;
avmcard *card;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "t1isa: no memory.\n");
retval = -ENOMEM;
goto err;
}
cinfo = card->ctrlinfo;
card->port = pci_resource_start(pdev, 0);
card->irq = pdev->irq;
card->cardtype = avm_t1isa;
card->cardnr = cardnr;
sprintf(card->name, "t1isa-%x", card->port);
if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) {
printk(KERN_WARNING "t1isa: invalid port 0x%x.\n", card->port);
retval = -EINVAL;
goto err_free;
}
if (hema_irq_table[card->irq & 0xf] == 0) {
printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq);
retval = -EINVAL;
goto err_free;
}
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_INFO "t1isa: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free;
}
retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card);
if (retval) {
printk(KERN_INFO "t1isa: unable to get IRQ %d.\n", card->irq);
retval = -EBUSY;
goto err_release_region;
}
if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) {
printk(KERN_INFO "t1isa: NO card at 0x%x (%d)\n",
card->port, retval);
retval = -ENODEV;
goto err_free_irq;
}
t1_disable_irq(card->port);
b1_reset(card->port);
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "t1isa";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
cinfo->capi_ctrl.release_appl = b1_release_appl;
cinfo->capi_ctrl.send_message = t1isa_send_message;
cinfo->capi_ctrl.load_firmware = t1isa_load_firmware;
cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr;
cinfo->capi_ctrl.procinfo = t1isa_procinfo;
cinfo->capi_ctrl.proc_fops = &b1ctl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_INFO "t1isa: attach controller failed.\n");
goto err_free_irq;
}
printk(KERN_INFO "t1isa: AVM T1 ISA at i/o %#x, irq %d, card %d\n",
card->port, card->irq, card->cardnr);
pci_set_drvdata(pdev, cinfo);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free:
b1_free_card(card);
err:
return retval;
}
static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
unsigned long flags;
u16 len = CAPIMSG_LEN(skb->data);
u8 cmd = CAPIMSG_COMMAND(skb->data);
u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
u16 dlen, retval;
spin_lock_irqsave(&card->lock, flags);
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
if (retval != CAPI_NOERROR) {
spin_unlock_irqrestore(&card->lock, flags);
return retval;
}
dlen = CAPIMSG_DATALEN(skb->data);
b1_put_byte(port, SEND_DATA_B3_REQ);
t1_put_slice(port, skb->data, len);
t1_put_slice(port, skb->data + len, dlen);
} else {
b1_put_byte(port, SEND_MESSAGE);
t1_put_slice(port, skb->data, len);
}
spin_unlock_irqrestore(&card->lock, flags);
dev_kfree_skb_any(skb);
return CAPI_NOERROR;
}
/* ------------------------------------------------------------- */
static char *t1isa_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d %d",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->cardnr : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
#define MAX_CARDS 4
static struct pci_dev isa_dev[MAX_CARDS];
static int io[MAX_CARDS];
static int irq[MAX_CARDS];
static int cardnr[MAX_CARDS];
module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param_array(cardnr, int, NULL, 0);
MODULE_PARM_DESC(io, "I/O base address(es)");
MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)");
static int t1isa_add_card(struct capi_driver *driver, capicardparams *data)
{
int i;
for (i = 0; i < MAX_CARDS; i++) {
if (isa_dev[i].resource[0].start)
continue;
isa_dev[i].resource[0].start = data->port;
isa_dev[i].irq = data->irq;
if (t1isa_probe(&isa_dev[i], data->cardnr) == 0)
return 0;
}
return -ENODEV;
}
static struct capi_driver capi_driver_t1isa = {
.name = "t1isa",
.revision = "1.0",
.add_card = t1isa_add_card,
};
static int __init t1isa_init(void)
{
char rev[32];
char *p;
int i;
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
for (i = 0; i < MAX_CARDS; i++) {
if (!io[i])
break;
isa_dev[i].resource[0].start = io[i];
isa_dev[i].irq = irq[i];
if (t1isa_probe(&isa_dev[i], cardnr[i]) != 0)
return -ENODEV;
}
strlcpy(capi_driver_t1isa.revision, rev, 32);
register_capi_driver(&capi_driver_t1isa);
printk(KERN_INFO "t1isa: revision %s\n", rev);
return 0;
}
static void __exit t1isa_exit(void)
{
int i;
unregister_capi_driver(&capi_driver_t1isa);
for (i = 0; i < MAX_CARDS; i++) {
if (!io[i])
break;
t1isa_remove(&isa_dev[i]);
}
}
module_init(t1isa_init);
module_exit(t1isa_exit);

View file

@ -0,0 +1,259 @@
/* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
*
* Module for AVM T1 PCI-card.
*
* Copyright 1999 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/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/capi.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/isdn/capicmd.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capilli.h>
#include "avmcard.h"
#undef CONFIG_T1PCI_DEBUG
#undef CONFIG_T1PCI_POLLDEBUG
/* ------------------------------------------------------------- */
static char *revision = "$Revision: 1.1.2.2 $";
/* ------------------------------------------------------------- */
static struct pci_device_id t1pci_pci_tbl[] = {
{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, t1pci_pci_tbl);
MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 PCI card");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------- */
static char *t1pci_procinfo(struct capi_ctr *ctrl);
static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
{
avmcard *card;
avmctrl_info *cinfo;
int retval;
card = b1_alloc_card(1);
if (!card) {
printk(KERN_WARNING "t1pci: no memory.\n");
retval = -ENOMEM;
goto err;
}
card->dma = avmcard_dma_alloc("t1pci", pdev, 2048 + 128, 2048 + 128);
if (!card->dma) {
printk(KERN_WARNING "t1pci: no memory.\n");
retval = -ENOMEM;
goto err_free;
}
cinfo = card->ctrlinfo;
sprintf(card->name, "t1pci-%x", p->port);
card->port = p->port;
card->irq = p->irq;
card->membase = p->membase;
card->cardtype = avm_t1pci;
if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
printk(KERN_WARNING "t1pci: ports 0x%03x-0x%03x in use.\n",
card->port, card->port + AVMB1_PORTLEN);
retval = -EBUSY;
goto err_free_dma;
}
card->mbase = ioremap(card->membase, 64);
if (!card->mbase) {
printk(KERN_NOTICE "t1pci: can't remap memory at 0x%lx\n",
card->membase);
retval = -EIO;
goto err_release_region;
}
b1dma_reset(card);
retval = t1pci_detect(card);
if (retval != 0) {
if (retval < 6)
printk(KERN_NOTICE "t1pci: NO card at 0x%x (%d)\n",
card->port, retval);
else
printk(KERN_NOTICE "t1pci: card at 0x%x, but cable not connected or T1 has no power (%d)\n",
card->port, retval);
retval = -EIO;
goto err_unmap;
}
b1dma_reset(card);
retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq);
retval = -EBUSY;
goto err_unmap;
}
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "t1pci";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1dma_register_appl;
cinfo->capi_ctrl.release_appl = b1dma_release_appl;
cinfo->capi_ctrl.send_message = b1dma_send_message;
cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr;
cinfo->capi_ctrl.procinfo = t1pci_procinfo;
cinfo->capi_ctrl.proc_fops = &b1dmactl_proc_fops;
strcpy(cinfo->capi_ctrl.name, card->name);
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
printk(KERN_ERR "t1pci: attach controller failed.\n");
retval = -EBUSY;
goto err_free_irq;
}
card->cardnr = cinfo->capi_ctrl.cnr;
printk(KERN_INFO "t1pci: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
card->port, card->irq, card->membase);
pci_set_drvdata(pdev, card);
return 0;
err_free_irq:
free_irq(card->irq, card);
err_unmap:
iounmap(card->mbase);
err_release_region:
release_region(card->port, AVMB1_PORTLEN);
err_free_dma:
avmcard_dma_free(card->dma);
err_free:
b1_free_card(card);
err:
return retval;
}
/* ------------------------------------------------------------- */
static void t1pci_remove(struct pci_dev *pdev)
{
avmcard *card = pci_get_drvdata(pdev);
avmctrl_info *cinfo = card->ctrlinfo;
b1dma_reset(card);
detach_capi_ctr(&cinfo->capi_ctrl);
free_irq(card->irq, card);
iounmap(card->mbase);
release_region(card->port, AVMB1_PORTLEN);
avmcard_dma_free(card->dma);
b1_free_card(card);
}
/* ------------------------------------------------------------- */
static char *t1pci_procinfo(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
if (!cinfo)
return "";
sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
cinfo->cardname[0] ? cinfo->cardname : "-",
cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
cinfo->card ? cinfo->card->port : 0x0,
cinfo->card ? cinfo->card->irq : 0,
cinfo->card ? cinfo->card->membase : 0
);
return cinfo->infobuf;
}
/* ------------------------------------------------------------- */
static int t1pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
struct capicardparams param;
int retval;
if (pci_enable_device(dev) < 0) {
printk(KERN_ERR "t1pci: failed to enable AVM-T1-PCI\n");
return -ENODEV;
}
pci_set_master(dev);
param.port = pci_resource_start(dev, 1);
param.irq = dev->irq;
param.membase = pci_resource_start(dev, 0);
printk(KERN_INFO "t1pci: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
param.port, param.irq, param.membase);
retval = t1pci_add_card(&param, dev);
if (retval != 0) {
printk(KERN_ERR "t1pci: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
param.port, param.irq, param.membase);
pci_disable_device(dev);
return -ENODEV;
}
return 0;
}
static struct pci_driver t1pci_pci_driver = {
.name = "t1pci",
.id_table = t1pci_pci_tbl,
.probe = t1pci_probe,
.remove = t1pci_remove,
};
static struct capi_driver capi_driver_t1pci = {
.name = "t1pci",
.revision = "1.0",
};
static int __init t1pci_init(void)
{
char *p;
char rev[32];
int err;
if ((p = strchr(revision, ':')) != NULL && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != NULL && p > rev)
*(p - 1) = 0;
} else
strcpy(rev, "1.0");
err = pci_register_driver(&t1pci_pci_driver);
if (!err) {
strlcpy(capi_driver_t1pci.revision, rev, 32);
register_capi_driver(&capi_driver_t1pci);
printk(KERN_INFO "t1pci: revision %s\n", rev);
}
return err;
}
static void __exit t1pci_exit(void)
{
unregister_capi_driver(&capi_driver_t1pci);
pci_unregister_driver(&t1pci_pci_driver);
}
module_init(t1pci_init);
module_exit(t1pci_exit);