Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
This commit is contained in:
Linus Torvalds
2005-04-16 15:20:36 -07:00
commit 1da177e4c3
17291 changed files with 6718755 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
#
# ISDN AVM drivers
#
menu "Active AVM cards"
depends on NET && ISDN && ISDN_CAPI!=n
config CAPI_AVM
bool "Support AVM cards"
help
Enable support for AVM active ISDN cards.
config ISDN_DRV_AVMB1_B1ISA
tristate "AVM B1 ISA support"
depends on CAPI_AVM && ISDN_CAPI && 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 CAPI_AVM && ISDN_CAPI && 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 CAPI_AVM && ISDN_CAPI && 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 CAPI_AVM && ISDN_CAPI
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 && PCMCIA
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 CAPI_AVM && ISDN_CAPI && 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 CAPI_AVM && ISDN_CAPI && PCI
help
Enable support for the AVM C4/C2 PCI cards.
These cards handle 4/2 BRI ISDN lines (8/4 channels).
endmenu

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,510 @@
/* $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/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/major.h>
#include <asm/io.h>
#include <asm/system.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.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");
/*====================================================================*/
/*
The event() function is this driver's Card Services event handler.
It will be called by Card Services when an appropriate card status
event is received. The config() and release() entry points are
used to configure or release a socket, in response to card insertion
and ejection events. They are invoked from the skeleton event
handler.
*/
static void avmcs_config(dev_link_t *link);
static void avmcs_release(dev_link_t *link);
static int avmcs_event(event_t event, int priority,
event_callback_args_t *args);
/*
The attach() and detach() entry points are used to create and destroy
"instances" of the driver, where each instance represents everything
needed to manage one actual PCMCIA card.
*/
static dev_link_t *avmcs_attach(void);
static void avmcs_detach(dev_link_t *);
/*
The dev_info variable is the "key" that is used to match up this
device driver with appropriate cards, through the card configuration
database.
*/
static dev_info_t dev_info = "avm_cs";
/*
A linked list of "instances" of the skeleton device. Each actual
PCMCIA card corresponds to one device instance, and is described
by one dev_link_t structure (defined in ds.h).
You may not want to use a linked list for this -- for example, the
memory card driver uses an array of dev_link_t pointers, where minor
device numbers are used to derive the corresponding array index.
*/
static dev_link_t *dev_list = NULL;
/*
A dev_link_t structure has fields for most things that are needed
to keep track of a socket, but there will usually be some device
specific information that also needs to be kept track of. The
'priv' pointer in a dev_link_t structure can be used to point to
a device-specific private data structure, like this.
A driver needs to provide a dev_node_t structure for each device
on a card. In some cases, there is only one device per card (for
example, ethernet cards, modems). In other cases, there may be
many actual or logical devices (SCSI adapters, memory cards with
multiple partitions). The dev_node_t structures need to be kept
in a linked list starting at the 'dev' field of a dev_link_t
structure. We allocate them in the card's private data structure,
because they generally can't be allocated dynamically.
*/
typedef struct local_info_t {
dev_node_t node;
} local_info_t;
/*======================================================================
avmcs_attach() creates an "instance" of the driver, allocating
local data structures for one device. The device is registered
with Card Services.
The dev_link structure is initialized, but we don't actually
configure the card at this point -- we wait until we receive a
card insertion event.
======================================================================*/
static dev_link_t *avmcs_attach(void)
{
client_reg_t client_reg;
dev_link_t *link;
local_info_t *local;
int ret;
/* Initialize the dev_link_t structure */
link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
if (!link)
goto err;
memset(link, 0, sizeof(struct dev_link_t));
/* The io structure describes IO port mapping */
link->io.NumPorts1 = 16;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts2 = 0;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.Vcc = 50;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
/* Allocate space for private device-specific data */
local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local)
goto err_kfree;
memset(local, 0, sizeof(local_info_t));
link->priv = local;
/* Register with Card Services */
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
client_reg.EventMask =
CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.event_handler = &avmcs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
if (ret != 0) {
cs_error(link->handle, RegisterClient, ret);
avmcs_detach(link);
goto err;
}
return link;
err_kfree:
kfree(link);
err:
return NULL;
} /* avmcs_attach */
/*======================================================================
This deletes a driver "instance". The device is de-registered
with Card Services. If it has been released, all local data
structures are freed. Otherwise, the structures will be freed
when the device is released.
======================================================================*/
static void avmcs_detach(dev_link_t *link)
{
dev_link_t **linkp;
/* Locate device structure */
for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
if (*linkp == link) break;
if (*linkp == NULL)
return;
/*
If the device is currently configured and active, we won't
actually delete it yet. Instead, it is marked so that when
the release() function is called, that will trigger a proper
detach().
*/
if (link->state & DEV_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
/* Break the link with Card Services */
if (link->handle)
pcmcia_deregister_client(link->handle);
/* Unlink device structure, free pieces */
*linkp = link->next;
if (link->priv) {
kfree(link->priv);
}
kfree(link);
} /* avmcs_detach */
/*======================================================================
avmcs_config() is scheduled to run after a CARD_INSERTION event
is received, to configure the PCMCIA socket, and to make the
ethernet device available to the system.
======================================================================*/
static int get_tuple(client_handle_t handle, tuple_t *tuple,
cisparse_t *parse)
{
int i = pcmcia_get_tuple_data(handle, tuple);
if (i != CS_SUCCESS) return i;
return pcmcia_parse_tuple(handle, tuple, parse);
}
static int first_tuple(client_handle_t handle, tuple_t *tuple,
cisparse_t *parse)
{
int i = pcmcia_get_first_tuple(handle, tuple);
if (i != CS_SUCCESS) return i;
return get_tuple(handle, tuple, parse);
}
static int next_tuple(client_handle_t handle, tuple_t *tuple,
cisparse_t *parse)
{
int i = pcmcia_get_next_tuple(handle, tuple);
if (i != CS_SUCCESS) return i;
return get_tuple(handle, tuple, parse);
}
static void avmcs_config(dev_link_t *link)
{
client_handle_t handle;
tuple_t tuple;
cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
local_info_t *dev;
int i;
u_char buf[64];
char devname[128];
int cardtype;
int (*addcard)(unsigned int port, unsigned irq);
handle = link->handle;
dev = link->priv;
/*
This reads the card's CONFIG tuple to find its configuration
registers.
*/
do {
tuple.DesiredTuple = CISTPL_CONFIG;
i = pcmcia_get_first_tuple(handle, &tuple);
if (i != CS_SUCCESS) break;
tuple.TupleData = buf;
tuple.TupleDataMax = 64;
tuple.TupleOffset = 0;
i = pcmcia_get_tuple_data(handle, &tuple);
if (i != CS_SUCCESS) break;
i = pcmcia_parse_tuple(handle, &tuple, &parse);
if (i != CS_SUCCESS) break;
link->conf.ConfigBase = parse.config.base;
} while (0);
if (i != CS_SUCCESS) {
cs_error(link->handle, ParseTuple, i);
link->state &= ~DEV_CONFIG_PENDING;
return;
}
/* Configure card */
link->state |= DEV_CONFIG;
do {
tuple.Attributes = 0;
tuple.TupleData = buf;
tuple.TupleDataMax = 254;
tuple.TupleOffset = 0;
tuple.DesiredTuple = CISTPL_VERS_1;
devname[0] = 0;
if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) {
strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1],
sizeof(devname));
}
/*
* find IO port
*/
tuple.TupleData = (cisdata_t *)buf;
tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
tuple.Attributes = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
i = first_tuple(handle, &tuple, &parse);
while (i == CS_SUCCESS) {
if (cf->io.nwin > 0) {
link->conf.ConfigIndex = cf->index;
link->io.BasePort1 = cf->io.win[0].base;
link->io.NumPorts1 = cf->io.win[0].len;
link->io.NumPorts2 = 0;
printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n",
link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
i = pcmcia_request_io(link->handle, &link->io);
if (i == CS_SUCCESS) goto found_port;
}
i = next_tuple(handle, &tuple, &parse);
}
found_port:
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestIO, i);
break;
}
/*
* allocate an interrupt line
*/
i = pcmcia_request_irq(link->handle, &link->irq);
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestIRQ, i);
pcmcia_release_io(link->handle, &link->io);
break;
}
/*
* configure the PCMCIA socket
*/
i = pcmcia_request_configuration(link->handle, &link->conf);
if (i != CS_SUCCESS) {
cs_error(link->handle, RequestConfiguration, i);
pcmcia_release_io(link->handle, &link->io);
pcmcia_release_irq(link->handle, &link->irq);
break;
}
} while (0);
/* At this point, the dev_node_t structure(s) should be
initialized and arranged in a linked list at link->dev. */
if (devname[0]) {
char *s = strrchr(devname, ' ');
if (!s)
s = devname;
else s++;
strcpy(dev->node.dev_name, 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 {
strcpy(dev->node.dev_name, "b1");
cardtype = AVM_CARDTYPE_B1;
}
dev->node.major = 64;
dev->node.minor = 0;
link->dev = &dev->node;
link->state &= ~DEV_CONFIG_PENDING;
/* If any step failed, release any partially configured state */
if (i != 0) {
avmcs_release(link);
return;
}
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->io.BasePort1, link->irq.AssignedIRQ)) < 0) {
printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n",
dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ);
avmcs_release(link);
return;
}
dev->node.minor = i;
} /* avmcs_config */
/*======================================================================
After a card is removed, avmcs_release() will unregister the net
device, and release the PCMCIA configuration. If the device is
still open, this will be postponed until it is closed.
======================================================================*/
static void avmcs_release(dev_link_t *link)
{
b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ);
/* Unlink the device chain */
link->dev = NULL;
/* Don't bother checking to see if these succeed or not */
pcmcia_release_configuration(link->handle);
pcmcia_release_io(link->handle, &link->io);
pcmcia_release_irq(link->handle, &link->irq);
link->state &= ~DEV_CONFIG;
if (link->state & DEV_STALE_LINK)
avmcs_detach(link);
} /* avmcs_release */
/*======================================================================
The card status event handler. Mostly, this schedules other
stuff to run after an event is received. A CARD_REMOVAL event
also sets some flags to discourage the net drivers from trying
to talk to the card any more.
When a CARD_REMOVAL event is received, we immediately set a flag
to block future accesses to this device. All the functions that
actually access the device should check this flag to make sure
the card is still present.
======================================================================*/
static int avmcs_event(event_t event, int priority,
event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
switch (event) {
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG)
avmcs_release(link);
break;
case CS_EVENT_CARD_INSERTION:
link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
avmcs_config(link);
break;
case CS_EVENT_PM_SUSPEND:
link->state |= DEV_SUSPEND;
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG)
pcmcia_release_configuration(link->handle);
break;
case CS_EVENT_PM_RESUME:
link->state &= ~DEV_SUSPEND;
/* Fall through... */
case CS_EVENT_CARD_RESET:
if (link->state & DEV_CONFIG)
pcmcia_request_configuration(link->handle, &link->conf);
break;
}
return 0;
} /* avmcs_event */
static struct pcmcia_driver avmcs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "avm_cs",
},
.attach = avmcs_attach,
.detach = avmcs_detach,
};
static int __init avmcs_init(void)
{
return pcmcia_register_driver(&avmcs_driver);
}
static void __exit avmcs_exit(void)
{
pcmcia_unregister_driver(&avmcs_driver);
BUG_ON(dev_list != NULL);
}
module_init(avmcs_init);
module_exit(avmcs_exit);

View File

@@ -0,0 +1,585 @@
/* $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;
if (i == 0)
break;
/* fall through */
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, struct pt_regs *regs);
int b1ctl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl);
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, struct pt_regs *regs);
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);
int b1dmactl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl);
#endif /* _AVMCARD_H_ */

View File

@@ -0,0 +1,814 @@
/* $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/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 <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 = kmalloc(sizeof(*card), GFP_KERNEL);
if (!card)
return NULL;
memset(card, 0, sizeof(*card));
cinfo = kmalloc(sizeof(*cinfo) * nr_controllers, GFP_KERNEL);
if (!cinfo) {
kfree(card);
return NULL;
}
memset(cinfo, 0, sizeof(*cinfo) * nr_controllers);
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;
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
capi_ctr_reseted(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;
capilib_release_appl(&cinfo->ncci_head, appl);
spin_lock_irqsave(&card->lock, flags);
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;
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)
return retval;
dlen = CAPIMSG_DATALEN(skb->data);
spin_lock_irqsave(&card->lock, flags);
b1_put_byte(port, SEND_DATA_B3_REQ);
b1_put_slice(port, skb->data, len);
b1_put_slice(port, skb->data + len, dlen);
spin_unlock_irqrestore(&card->lock, flags);
} else {
spin_lock_irqsave(&card->lock, flags);
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, struct pt_regs *regs)
{
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);
spin_unlock_irqrestore(&card->lock, flags);
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)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
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);
spin_unlock_irqrestore(&card->lock, flags);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
spin_unlock_irqrestore(&card->lock, flags);
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
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;
}
/* ------------------------------------------------------------- */
int b1ctl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
int len = 0;
char *s;
len += sprintf(page+len, "%-16s %s\n", "name", card->name);
len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
len += sprintf(page+len, "%-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;
}
len += sprintf(page+len, "%-16s %s\n", "type", s);
if (card->cardtype == avm_t1isa)
len += sprintf(page+len, "%-16s %d\n", "cardnr", card->cardnr);
if ((s = cinfo->version[VER_DRIVER]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
len += sprintf(page+len, "%-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)
len += sprintf(page+len, "%-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" : ""
);
}
len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
if (off+count >= len)
*eof = 1;
if (len < off)
return 0;
*start = page + off;
return ((count < len-off) ? count : len-off);
}
/* ------------------------------------------------------------- */
#ifdef CONFIG_PCI
avmcard_dmainfo *
avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize)
{
avmcard_dmainfo *p;
void *buf;
p = kmalloc(sizeof(avmcard_dmainfo), GFP_KERNEL);
if (!p) {
printk(KERN_WARNING "%s: no memory.\n", name);
goto err;
}
memset(p, 0, sizeof(avmcard_dmainfo));
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);
EXPORT_SYMBOL(b1ctl_read_proc);
static int __init b1_init(void)
{
char *p;
char rev[32];
if ((p = strchr(revision, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != 0 && 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,980 @@
/* $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/config.h>
#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/kernelcapi.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 CONFIG_B1DMA_DEBUG
/* ------------------------------------------------------------- */
MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
static int suppress_pollack = 0;
MODULE_PARM(suppress_pollack, "0-1i");
/* ------------------------------------------------------------- */
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 CONFIG_B1DMA_DEBUG
printk(KERN_DEBUG "tx: put msg len=%d\n", txlen);
#endif
} else {
txlen = skb->len-2;
#ifdef CONFIG_B1DMA_POLLDEBUG
if (skb->data[2] == SEND_POLLACK)
printk(KERN_INFO "%s: send ack\n", card->name);
#endif
#ifdef CONFIG_B1DMA_DEBUG
printk(KERN_DEBUG "tx: put 0x%x len=%d\n",
skb->data[2], txlen);
#endif
memcpy(dma->sendbuf.dmabuf, skb->data+2, 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 CONFIG_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)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
case RECEIVE_NEW_NCCI:
ApplId = _get_word(&p);
NCCI = _get_word(&p);
WindowSize = _get_word(&p);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
break;
case RECEIVE_FREE_NCCI:
ApplId = _get_word(&p);
NCCI = _get_word(&p);
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
break;
case RECEIVE_START:
#ifdef CONFIG_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 CONFIG_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, struct pt_regs *regs)
{
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);
spin_unlock_irqrestore(&card->lock, flags);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
capi_ctr_reseted(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;
capilib_release_appl(&cinfo->ncci_head, appl);
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) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
}
if (retval == CAPI_NOERROR)
b1dma_queue_tx(card, skb);
return retval;
}
/* ------------------------------------------------------------- */
int b1dmactl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
u8 flag;
int len = 0;
char *s;
u32 txoff, txlen, rxoff, rxlen, csr;
unsigned long flags;
len += sprintf(page+len, "%-16s %s\n", "name", card->name);
len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
len += sprintf(page+len, "%-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;
}
len += sprintf(page+len, "%-16s %s\n", "type", s);
if ((s = cinfo->version[VER_DRIVER]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
if ((s = cinfo->version[VER_CARDTYPE]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
if ((s = cinfo->version[VER_SERIAL]) != 0)
len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
if (card->cardtype != avm_m1) {
flag = ((u8 *)(ctrl->profile.manu))[3];
if (flag)
len += sprintf(page+len, "%-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)
len += sprintf(page+len, "%-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" : ""
);
}
len += sprintf(page+len, "%-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);
len += sprintf(page+len, "%-16s 0x%lx\n",
"csr (cached)", (unsigned long)card->csr);
len += sprintf(page+len, "%-16s 0x%lx\n",
"csr", (unsigned long)csr);
len += sprintf(page+len, "%-16s %lu\n",
"txoff", (unsigned long)txoff);
len += sprintf(page+len, "%-16s %lu\n",
"txlen", (unsigned long)txlen);
len += sprintf(page+len, "%-16s %lu\n",
"rxoff", (unsigned long)rxoff);
len += sprintf(page+len, "%-16s %lu\n",
"rxlen", (unsigned long)rxlen);
if (off+count >= len)
*eof = 1;
if (len < off)
return 0;
*start = page + off;
return ((count < len-off) ? count : len-off);
}
/* ------------------------------------------------------------- */
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);
EXPORT_SYMBOL(b1dmactl_read_proc);
int b1dma_init(void)
{
char *p;
char rev[32];
if ((p = strchr(revision, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, sizeof(rev));
if ((p = strchr(rev, '$')) != 0 && p > rev)
*(p-1) = 0;
} else
strcpy(rev, "1.0");
printk(KERN_INFO "b1dma: revision %s\n", rev);
return 0;
}
void b1dma_exit(void)
{
}
module_init(b1dma_init);
module_exit(b1dma_exit);

View File

@@ -0,0 +1,245 @@
/* $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.ctr_read_proc = b1ctl_read_proc;
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_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
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, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != 0 && 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 (!io[i])
break;
b1isa_remove(&isa_dev[i]);
}
unregister_capi_driver(&capi_driver_b1isa);
}
module_init(b1isa_init);
module_exit(b1isa_exit);

View File

@@ -0,0 +1,417 @@
/* $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/config.h>
#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, SA_SHIRQ, 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.ctr_read_proc = b1ctl_read_proc;
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, SA_SHIRQ, 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.ctr_read_proc = b1dmactl_read_proc;
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 __devinit 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 __devexit 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 = __devexit_p(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, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != 0 && 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, 0, 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.ctr_read_proc = b1ctl_read_proc;
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, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != 0 && 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,596 @@
/* $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 <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, struct pt_regs *regs)
{
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);
spin_unlock_irqrestore(&card->lock, flags);
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)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
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);
spin_unlock_irqrestore(&card->lock, flags);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
spin_unlock_irqrestore(&card->lock, flags);
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
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;
}
void t1isa_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
t1_disable_irq(port);
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
capi_ctr_reseted(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.ctr_read_proc = b1ctl_read_proc;
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;
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)
return retval;
dlen = CAPIMSG_DATALEN(skb->data);
spin_lock_irqsave(&card->lock, flags);
b1_put_byte(port, SEND_DATA_B3_REQ);
t1_put_slice(port, skb->data, len);
t1_put_slice(port, skb->data + len, dlen);
spin_unlock_irqrestore(&card->lock, flags);
} else {
spin_lock_irqsave(&card->lock, flags);
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_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
MODULE_PARM(cardnr, "1-" __MODULE_STRING(MAX_CARDS) "i");
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, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != 0 && 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;
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,260 @@
/* $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/config.h>
#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, SA_SHIRQ, 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.ctr_read_proc = b1dmactl_read_proc;
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 __devinit 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);
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, ':')) != 0 && p[1]) {
strlcpy(rev, p + 2, 32);
if ((p = strchr(rev, '$')) != 0 && 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);