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:
66
drivers/isdn/hardware/avm/Kconfig
Normal file
66
drivers/isdn/hardware/avm/Kconfig
Normal 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
|
||||
|
11
drivers/isdn/hardware/avm/Makefile
Normal file
11
drivers/isdn/hardware/avm/Makefile
Normal 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
|
510
drivers/isdn/hardware/avm/avm_cs.c
Normal file
510
drivers/isdn/hardware/avm/avm_cs.c
Normal 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);
|
585
drivers/isdn/hardware/avm/avmcard.h
Normal file
585
drivers/isdn/hardware/avm/avmcard.h
Normal 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_ */
|
814
drivers/isdn/hardware/avm/b1.c
Normal file
814
drivers/isdn/hardware/avm/b1.c
Normal 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);
|
980
drivers/isdn/hardware/avm/b1dma.c
Normal file
980
drivers/isdn/hardware/avm/b1dma.c
Normal 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, ®, 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, ®, 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);
|
245
drivers/isdn/hardware/avm/b1isa.c
Normal file
245
drivers/isdn/hardware/avm/b1isa.c
Normal 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);
|
417
drivers/isdn/hardware/avm/b1pci.c
Normal file
417
drivers/isdn/hardware/avm/b1pci.c
Normal 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(¶m, pdev);
|
||||
#else
|
||||
retval = b1pci_probe(¶m, 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(¶m, 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);
|
224
drivers/isdn/hardware/avm/b1pcmcia.c
Normal file
224
drivers/isdn/hardware/avm/b1pcmcia.c
Normal 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);
|
1310
drivers/isdn/hardware/avm/c4.c
Normal file
1310
drivers/isdn/hardware/avm/c4.c
Normal file
File diff suppressed because it is too large
Load Diff
596
drivers/isdn/hardware/avm/t1isa.c
Normal file
596
drivers/isdn/hardware/avm/t1isa.c
Normal 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);
|
260
drivers/isdn/hardware/avm/t1pci.c
Normal file
260
drivers/isdn/hardware/avm/t1pci.c
Normal 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(¶m, 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);
|
Reference in New Issue
Block a user