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!
diff --git a/drivers/isdn/hardware/avm/Kconfig b/drivers/isdn/hardware/avm/Kconfig
new file mode 100644
index 0000000..29a32a8
--- /dev/null
+++ b/drivers/isdn/hardware/avm/Kconfig
@@ -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
+
diff --git a/drivers/isdn/hardware/avm/Makefile b/drivers/isdn/hardware/avm/Makefile
new file mode 100644
index 0000000..b540e8f
--- /dev/null
+++ b/drivers/isdn/hardware/avm/Makefile
@@ -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
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
new file mode 100644
index 0000000..dc00c85
--- /dev/null
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -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);
diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
new file mode 100644
index 0000000..296d6a6
--- /dev/null
+++ b/drivers/isdn/hardware/avm/avmcard.h
@@ -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_ */
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
new file mode 100644
index 0000000..0c7061d
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1.c
@@ -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);
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
new file mode 100644
index 0000000..55bed00
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -0,0 +1,980 @@
+/* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $
+ * 
+ * Common module for AVM B1 cards that support dma with AMCC
+ * 
+ * Copyright 2000 by Carsten Paeth <calle@calle.de>
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+#include <asm/io.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/netdevice.h>
+#include <linux/isdn/capilli.h>
+#include "avmcard.h"
+#include <linux/isdn/capicmd.h>
+#include <linux/isdn/capiutil.h>
+
+static char *revision = "$Revision: 1.1.2.3 $";
+
+#undef CONFIG_B1DMA_DEBUG
+
+/* ------------------------------------------------------------- */
+
+MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards");
+MODULE_AUTHOR("Carsten Paeth");
+MODULE_LICENSE("GPL");
+
+static int suppress_pollack = 0;
+MODULE_PARM(suppress_pollack, "0-1i");
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+/* S5933 */
+
+#define	AMCC_RXPTR	0x24
+#define	AMCC_RXLEN	0x28
+#define	AMCC_TXPTR	0x2c
+#define	AMCC_TXLEN	0x30
+
+#define	AMCC_INTCSR	0x38
+#	define EN_READ_TC_INT		0x00008000L
+#	define EN_WRITE_TC_INT		0x00004000L
+#	define EN_TX_TC_INT		EN_READ_TC_INT
+#	define EN_RX_TC_INT		EN_WRITE_TC_INT
+#	define AVM_FLAG			0x30000000L
+
+#	define ANY_S5933_INT		0x00800000L
+#	define READ_TC_INT		0x00080000L
+#	define WRITE_TC_INT		0x00040000L
+#	define	TX_TC_INT		READ_TC_INT
+#	define	RX_TC_INT		WRITE_TC_INT
+#	define MASTER_ABORT_INT		0x00100000L
+#	define TARGET_ABORT_INT		0x00200000L
+#	define BUS_MASTER_INT		0x00200000L
+#	define ALL_INT			0x000C0000L
+
+#define	AMCC_MCSR	0x3c
+#	define A2P_HI_PRIORITY		0x00000100L
+#	define EN_A2P_TRANSFERS		0x00000400L
+#	define P2A_HI_PRIORITY		0x00001000L
+#	define EN_P2A_TRANSFERS		0x00004000L
+#	define RESET_A2P_FLAGS		0x04000000L
+#	define RESET_P2A_FLAGS		0x02000000L
+
+/* ------------------------------------------------------------- */
+
+static inline void b1dma_writel(avmcard *card, u32 value, int off)
+{
+	writel(value, card->mbase + off);
+}
+
+static inline u32 b1dma_readl(avmcard *card, int off)
+{
+	return readl(card->mbase + off);
+}
+
+/* ------------------------------------------------------------- */
+
+static inline int b1dma_tx_empty(unsigned int port)
+{
+	return inb(port + 0x03) & 0x1;
+}
+
+static inline int b1dma_rx_full(unsigned int port)
+{
+	return inb(port + 0x02) & 0x1;
+}
+
+static int b1dma_tolink(avmcard *card, void *buf, unsigned int len)
+{
+	unsigned long stop = jiffies + 1 * HZ;	/* maximum wait time 1 sec */
+	unsigned char *s = (unsigned char *)buf;
+	while (len--) {
+		while (   !b1dma_tx_empty(card->port)
+		       && time_before(jiffies, stop));
+		if (!b1dma_tx_empty(card->port)) 
+			return -1;
+	        t1outp(card->port, 0x01, *s++);
+	}
+	return 0;
+}
+
+static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len)
+{
+	unsigned long stop = jiffies + 1 * HZ;	/* maximum wait time 1 sec */
+	unsigned char *s = (unsigned char *)buf;
+	while (len--) {
+		while (   !b1dma_rx_full(card->port)
+		       && time_before(jiffies, stop));
+		if (!b1dma_rx_full(card->port)) 
+			return -1;
+	        *s++ = t1inp(card->port, 0x00);
+	}
+	return 0;
+}
+
+static int WriteReg(avmcard *card, u32 reg, u8 val)
+{
+	u8 cmd = 0x00;
+	if (   b1dma_tolink(card, &cmd, 1) == 0
+	    && b1dma_tolink(card, &reg, 4) == 0) {
+		u32 tmp = val;
+		return b1dma_tolink(card, &tmp, 4);
+	}
+	return -1;
+}
+
+static u8 ReadReg(avmcard *card, u32 reg)
+{
+	u8 cmd = 0x01;
+	if (   b1dma_tolink(card, &cmd, 1) == 0
+	    && b1dma_tolink(card, &reg, 4) == 0) {
+		u32 tmp;
+		if (b1dma_fromlink(card, &tmp, 4) == 0)
+			return (u8)tmp;
+	}
+	return 0xff;
+}
+
+/* ------------------------------------------------------------- */
+
+static inline void _put_byte(void **pp, u8 val)
+{
+	u8 *s = *pp;
+	*s++ = val;
+	*pp = s;
+}
+
+static inline void _put_word(void **pp, u32 val)
+{
+	u8 *s = *pp;
+	*s++ = val & 0xff;
+	*s++ = (val >> 8) & 0xff;
+	*s++ = (val >> 16) & 0xff;
+	*s++ = (val >> 24) & 0xff;
+	*pp = s;
+}
+
+static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len)
+{
+	unsigned i = len;
+	_put_word(pp, i);
+	while (i-- > 0)
+		_put_byte(pp, *dp++);
+}
+
+static inline u8 _get_byte(void **pp)
+{
+	u8 *s = *pp;
+	u8 val;
+	val = *s++;
+	*pp = s;
+	return val;
+}
+
+static inline u32 _get_word(void **pp)
+{
+	u8 *s = *pp;
+	u32 val;
+	val = *s++;
+	val |= (*s++ << 8);
+	val |= (*s++ << 16);
+	val |= (*s++ << 24);
+	*pp = s;
+	return val;
+}
+
+static inline u32 _get_slice(void **pp, unsigned char *dp)
+{
+	unsigned int len, i;
+
+	len = i = _get_word(pp);
+	while (i-- > 0) *dp++ = _get_byte(pp);
+	return len;
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_reset(avmcard *card)
+{
+	card->csr = 0x0;
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
+	b1dma_writel(card, 0, AMCC_MCSR);
+	b1dma_writel(card, 0, AMCC_RXLEN);
+	b1dma_writel(card, 0, AMCC_TXLEN);
+
+	t1outp(card->port, 0x10, 0x00);
+	t1outp(card->port, 0x07, 0x00);
+
+	b1dma_writel(card, 0, AMCC_MCSR);
+	mdelay(10);
+	b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
+	mdelay(10);
+	b1dma_writel(card, 0, AMCC_MCSR);
+	if (card->cardtype == avm_t1pci)
+		mdelay(42);
+	else
+		mdelay(10);
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1dma_detect(avmcard *card)
+{
+	b1dma_writel(card, 0, AMCC_MCSR);
+	mdelay(10);
+	b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */
+	mdelay(10);
+	b1dma_writel(card, 0, AMCC_MCSR);
+	mdelay(42);
+
+	b1dma_writel(card, 0, AMCC_RXLEN);
+	b1dma_writel(card, 0, AMCC_TXLEN);
+	card->csr = 0x0;
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
+
+	if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6)
+		return 1;
+
+	b1dma_writel(card, 0xffffffff, AMCC_RXPTR);
+	b1dma_writel(card, 0xffffffff, AMCC_TXPTR);
+	if (   b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc
+	    || b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc)
+		return 2;
+
+	b1dma_writel(card, 0x0, AMCC_RXPTR);
+	b1dma_writel(card, 0x0, AMCC_TXPTR);
+	if (   b1dma_readl(card, AMCC_RXPTR) != 0x0
+	    || b1dma_readl(card, AMCC_TXPTR) != 0x0)
+		return 3;
+
+	t1outp(card->port, 0x10, 0x00);
+	t1outp(card->port, 0x07, 0x00);
+	
+	t1outp(card->port, 0x02, 0x02);
+	t1outp(card->port, 0x03, 0x02);
+
+	if (   (t1inp(card->port, 0x02) & 0xFE) != 0x02
+	    || t1inp(card->port, 0x3) != 0x03)
+		return 4;
+
+	t1outp(card->port, 0x02, 0x00);
+	t1outp(card->port, 0x03, 0x00);
+
+	if (   (t1inp(card->port, 0x02) & 0xFE) != 0x00
+	    || t1inp(card->port, 0x3) != 0x01)
+		return 5;
+
+	return 0;
+}
+
+int t1pci_detect(avmcard *card)
+{
+	int ret;
+
+	if ((ret = b1dma_detect(card)) != 0)
+		return ret;
+	
+	/* Transputer test */
+	
+	if (   WriteReg(card, 0x80001000, 0x11) != 0
+	    || WriteReg(card, 0x80101000, 0x22) != 0
+	    || WriteReg(card, 0x80201000, 0x33) != 0
+	    || WriteReg(card, 0x80301000, 0x44) != 0)
+		return 6;
+
+	if (   ReadReg(card, 0x80001000) != 0x11
+	    || ReadReg(card, 0x80101000) != 0x22
+	    || ReadReg(card, 0x80201000) != 0x33
+	    || ReadReg(card, 0x80301000) != 0x44)
+		return 7;
+
+	if (   WriteReg(card, 0x80001000, 0x55) != 0
+	    || WriteReg(card, 0x80101000, 0x66) != 0
+	    || WriteReg(card, 0x80201000, 0x77) != 0
+	    || WriteReg(card, 0x80301000, 0x88) != 0)
+		return 8;
+
+	if (   ReadReg(card, 0x80001000) != 0x55
+	    || ReadReg(card, 0x80101000) != 0x66
+	    || ReadReg(card, 0x80201000) != 0x77
+	    || ReadReg(card, 0x80301000) != 0x88)
+		return 9;
+
+	return 0;
+}
+
+int b1pciv4_detect(avmcard *card)
+{
+	int ret, i;
+
+	if ((ret = b1dma_detect(card)) != 0)
+		return ret;
+	
+	for (i=0; i < 5 ; i++) {
+		if (WriteReg(card, 0x80A00000, 0x21) != 0)
+			return 6;
+		if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01)
+			return 7;
+	}
+	for (i=0; i < 5 ; i++) {
+		if (WriteReg(card, 0x80A00000, 0x20) != 0)
+			return 8;
+		if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00)
+			return 9;
+	}
+	
+	return 0;
+}
+
+static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+
+	if (!(card->csr & EN_TX_TC_INT)) {
+		b1dma_dispatch_tx(card);
+		b1dma_writel(card, card->csr, AMCC_INTCSR);
+	}
+
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_dispatch_tx(avmcard *card)
+{
+	avmcard_dmainfo *dma = card->dma;
+	struct sk_buff *skb;
+	u8 cmd, subcmd;
+	u16 len;
+	u32 txlen;
+	void *p;
+	
+	skb = skb_dequeue(&dma->send_queue);
+
+	len = CAPIMSG_LEN(skb->data);
+
+	if (len) {
+		cmd = CAPIMSG_COMMAND(skb->data);
+		subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+
+		p = dma->sendbuf.dmabuf;
+
+		if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+			u16 dlen = CAPIMSG_DATALEN(skb->data);
+			_put_byte(&p, SEND_DATA_B3_REQ);
+			_put_slice(&p, skb->data, len);
+			_put_slice(&p, skb->data + len, dlen);
+		} else {
+			_put_byte(&p, SEND_MESSAGE);
+			_put_slice(&p, skb->data, len);
+		}
+		txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
+#ifdef CONFIG_B1DMA_DEBUG
+		printk(KERN_DEBUG "tx: put msg len=%d\n", txlen);
+#endif
+	} else {
+		txlen = skb->len-2;
+#ifdef CONFIG_B1DMA_POLLDEBUG
+		if (skb->data[2] == SEND_POLLACK)
+			printk(KERN_INFO "%s: send ack\n", card->name);
+#endif
+#ifdef CONFIG_B1DMA_DEBUG
+		printk(KERN_DEBUG "tx: put 0x%x len=%d\n", 
+		       skb->data[2], txlen);
+#endif
+		memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
+	}
+	txlen = (txlen + 3) & ~3;
+
+	b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR);
+	b1dma_writel(card, txlen, AMCC_TXLEN);
+
+	card->csr |= EN_TX_TC_INT;
+
+	dev_kfree_skb_any(skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void queue_pollack(avmcard *card)
+{
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(3, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost poll ack\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_POLLACK);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
+
+	b1dma_queue_tx(card, skb);
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_handle_rx(avmcard *card)
+{
+	avmctrl_info *cinfo = &card->ctrlinfo[0];
+	avmcard_dmainfo *dma = card->dma;
+	struct capi_ctr *ctrl = &cinfo->capi_ctrl;
+	struct sk_buff *skb;
+	void *p = dma->recvbuf.dmabuf+4;
+	u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+	u8 b1cmd =  _get_byte(&p);
+
+#ifdef CONFIG_B1DMA_DEBUG
+	printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
+#endif
+	
+	switch (b1cmd) {
+	case RECEIVE_DATA_B3_IND:
+
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		DataB3Len = _get_slice(&p, card->databuf);
+
+		if (MsgLen < 30) { /* not CAPI 64Bit */
+			memset(card->msgbuf+MsgLen, 0, 30-MsgLen);
+			MsgLen = 30;
+			CAPIMSG_SETLEN(card->msgbuf, 30);
+		}
+		if (!(skb = alloc_skb(DataB3Len+MsgLen, GFP_ATOMIC))) {
+			printk(KERN_ERR "%s: incoming packet dropped\n",
+					card->name);
+		} else {
+			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+			memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+			capi_ctr_handle_message(ctrl, ApplId, skb);
+		}
+		break;
+
+	case RECEIVE_MESSAGE:
+
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+			printk(KERN_ERR "%s: incoming packet dropped\n",
+					card->name);
+		} else {
+			memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+			if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
+				capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
+						     CAPIMSG_NCCI(skb->data),
+						     CAPIMSG_MSGID(skb->data));
+
+			capi_ctr_handle_message(ctrl, ApplId, skb);
+		}
+		break;
+
+	case RECEIVE_NEW_NCCI:
+
+		ApplId = _get_word(&p);
+		NCCI = _get_word(&p);
+		WindowSize = _get_word(&p);
+
+		capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
+
+		break;
+
+	case RECEIVE_FREE_NCCI:
+
+		ApplId = _get_word(&p);
+		NCCI = _get_word(&p);
+
+		if (NCCI != 0xffffffff)
+			capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
+
+		break;
+
+	case RECEIVE_START:
+#ifdef CONFIG_B1DMA_POLLDEBUG
+		printk(KERN_INFO "%s: receive poll\n", card->name);
+#endif
+		if (!suppress_pollack)
+			queue_pollack(card);
+		capi_ctr_resume_output(ctrl);
+		break;
+
+	case RECEIVE_STOP:
+		capi_ctr_suspend_output(ctrl);
+		break;
+
+	case RECEIVE_INIT:
+
+		cinfo->versionlen = _get_slice(&p, cinfo->versionbuf);
+		b1_parse_version(cinfo);
+		printk(KERN_INFO "%s: %s-card (%s) now active\n",
+		       card->name,
+		       cinfo->version[VER_CARDTYPE],
+		       cinfo->version[VER_DRIVER]);
+		capi_ctr_ready(ctrl);
+		break;
+
+	case RECEIVE_TASK_READY:
+		ApplId = (unsigned) _get_word(&p);
+		MsgLen = _get_slice(&p, card->msgbuf);
+		card->msgbuf[MsgLen] = 0;
+		while (    MsgLen > 0
+		       && (   card->msgbuf[MsgLen-1] == '\n'
+			   || card->msgbuf[MsgLen-1] == '\r')) {
+			card->msgbuf[MsgLen-1] = 0;
+			MsgLen--;
+		}
+		printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
+				card->name, ApplId, card->msgbuf);
+		break;
+
+	case RECEIVE_DEBUGMSG:
+		MsgLen = _get_slice(&p, card->msgbuf);
+		card->msgbuf[MsgLen] = 0;
+		while (    MsgLen > 0
+		       && (   card->msgbuf[MsgLen-1] == '\n'
+			   || card->msgbuf[MsgLen-1] == '\r')) {
+			card->msgbuf[MsgLen-1] = 0;
+			MsgLen--;
+		}
+		printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
+		break;
+
+	default:
+		printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n",
+				card->name, b1cmd);
+		return;
+	}
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_handle_interrupt(avmcard *card)
+{
+	u32 status;
+	u32 newcsr;
+
+	spin_lock(&card->lock);
+
+	status = b1dma_readl(card, AMCC_INTCSR);
+	if ((status & ANY_S5933_INT) == 0) {
+		spin_unlock(&card->lock);
+		return;
+	}
+
+        newcsr = card->csr | (status & ALL_INT);
+	if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
+	if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
+	b1dma_writel(card, newcsr, AMCC_INTCSR);
+
+	if ((status & RX_TC_INT) != 0) {
+		struct avmcard_dmainfo *dma = card->dma;
+		u32 rxlen;
+	   	if (card->dma->recvlen == 0) {
+	        	rxlen = b1dma_readl(card, AMCC_RXLEN);
+			if (rxlen == 0) {
+				dma->recvlen = *((u32 *)dma->recvbuf.dmabuf);
+				rxlen = (dma->recvlen + 3) & ~3;
+				b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR);
+				b1dma_writel(card, rxlen, AMCC_RXLEN);
+#ifdef CONFIG_B1DMA_DEBUG
+			} else {
+				printk(KERN_ERR "%s: rx not complete (%d).\n",
+					card->name, rxlen);
+#endif
+			}
+		} else {
+			spin_unlock(&card->lock);
+			b1dma_handle_rx(card);
+	   		dma->recvlen = 0;
+			spin_lock(&card->lock);
+			b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR);
+			b1dma_writel(card, 4, AMCC_RXLEN);
+		}
+	}
+
+	if ((status & TX_TC_INT) != 0) {
+		if (skb_queue_empty(&card->dma->send_queue))
+			card->csr &= ~EN_TX_TC_INT;
+		else
+			b1dma_dispatch_tx(card);
+	}
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
+
+	spin_unlock(&card->lock);
+}
+
+irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+	avmcard *card = devptr;
+
+	b1dma_handle_interrupt(card);
+	return IRQ_HANDLED;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1dma_loaded(avmcard *card)
+{
+	unsigned long stop;
+	unsigned char ans;
+	unsigned long tout = 2;
+	unsigned int base = card->port;
+
+	for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+		if (b1_tx_empty(base))
+			break;
+	}
+	if (!b1_tx_empty(base)) {
+		printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n",
+				card->name);
+		return 0;
+	}
+	b1_put_byte(base, SEND_POLLACK);
+	for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) {
+		if (b1_rx_full(base)) {
+			if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) {
+				return 1;
+			}
+			printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans);
+			return 0;
+		}
+	}
+	printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name);
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void b1dma_send_init(avmcard *card)
+{
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(15, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_INIT);
+	_put_word(&p, CAPI_MAXAPPL);
+	_put_word(&p, AVM_NCCI_PER_CHANNEL*30);
+	_put_word(&p, card->cardnr - 1);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
+
+	b1dma_queue_tx(card, skb);
+}
+
+int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	int retval;
+
+	b1dma_reset(card);
+
+	if ((retval = b1_load_t4file(card, &data->firmware))) {
+		b1dma_reset(card);
+		printk(KERN_ERR "%s: failed to load t4file!!\n",
+					card->name);
+		return retval;
+	}
+
+	if (data->configuration.len > 0 && data->configuration.data) {
+		if ((retval = b1_load_config(card, &data->configuration))) {
+			b1dma_reset(card);
+			printk(KERN_ERR "%s: failed to load config!!\n",
+					card->name);
+			return retval;
+		}
+	}
+
+	if (!b1dma_loaded(card)) {
+		b1dma_reset(card);
+		printk(KERN_ERR "%s: failed to load t4file.\n", card->name);
+		return -EIO;
+	}
+
+	card->csr = AVM_FLAG;
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
+	b1dma_writel(card, EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|A2P_HI_PRIORITY|
+		     P2A_HI_PRIORITY|RESET_A2P_FLAGS|RESET_P2A_FLAGS, 
+		     AMCC_MCSR);
+	t1outp(card->port, 0x07, 0x30);
+	t1outp(card->port, 0x10, 0xF0);
+
+	card->dma->recvlen = 0;
+	b1dma_writel(card, card->dma->recvbuf.dmaaddr, AMCC_RXPTR);
+	b1dma_writel(card, 4, AMCC_RXLEN);
+	card->csr |= EN_RX_TC_INT;
+	b1dma_writel(card, card->csr, AMCC_INTCSR);
+
+        b1dma_send_init(card);
+
+	return 0;
+}
+
+void b1dma_reset_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+ 	b1dma_reset(card);
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	memset(cinfo->version, 0, sizeof(cinfo->version));
+	capilib_release(&cinfo->ncci_head);
+	capi_ctr_reseted(ctrl);
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_register_appl(struct capi_ctr *ctrl,
+				u16 appl,
+				capi_register_params *rp)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	struct sk_buff *skb;
+	int want = rp->level3cnt;
+	int nconn;
+	void *p;
+
+	if (want > 0) nconn = want;
+	else nconn = ctrl->profile.nbchannel * -want;
+	if (nconn == 0) nconn = ctrl->profile.nbchannel;
+
+	skb = alloc_skb(23, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost register appl.\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_REGISTER);
+	_put_word(&p, appl);
+	_put_word(&p, 1024 * (nconn+1));
+	_put_word(&p, nconn);
+	_put_word(&p, rp->datablkcnt);
+	_put_word(&p, rp->datablklen);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
+
+	b1dma_queue_tx(card, skb);
+}
+
+/* ------------------------------------------------------------- */
+
+void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	struct sk_buff *skb;
+	void *p;
+
+	capilib_release_appl(&cinfo->ncci_head, appl);
+
+	skb = alloc_skb(7, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, lost release appl.\n",
+					card->name);
+		return;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_RELEASE);
+	_put_word(&p, appl);
+
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
+
+	b1dma_queue_tx(card, skb);
+}
+
+/* ------------------------------------------------------------- */
+
+u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	u16 retval = CAPI_NOERROR;
+
+ 	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
+		retval = capilib_data_b3_req(&cinfo->ncci_head,
+					     CAPIMSG_APPID(skb->data),
+					     CAPIMSG_NCCI(skb->data),
+					     CAPIMSG_MSGID(skb->data));
+	}
+	if (retval == CAPI_NOERROR) 
+		b1dma_queue_tx(card, skb);
+
+	return retval;
+}
+
+/* ------------------------------------------------------------- */
+
+int b1dmactl_read_proc(char *page, char **start, off_t off,
+        		int count, int *eof, struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	u8 flag;
+	int len = 0;
+	char *s;
+	u32 txoff, txlen, rxoff, rxlen, csr;
+	unsigned long flags;
+
+	len += sprintf(page+len, "%-16s %s\n", "name", card->name);
+	len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
+	len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+	len += sprintf(page+len, "%-16s 0x%lx\n", "membase", card->membase);
+	switch (card->cardtype) {
+	case avm_b1isa: s = "B1 ISA"; break;
+	case avm_b1pci: s = "B1 PCI"; break;
+	case avm_b1pcmcia: s = "B1 PCMCIA"; break;
+	case avm_m1: s = "M1"; break;
+	case avm_m2: s = "M2"; break;
+	case avm_t1isa: s = "T1 ISA (HEMA)"; break;
+	case avm_t1pci: s = "T1 PCI"; break;
+	case avm_c4: s = "C4"; break;
+	case avm_c2: s = "C2"; break;
+	default: s = "???"; break;
+	}
+	len += sprintf(page+len, "%-16s %s\n", "type", s);
+	if ((s = cinfo->version[VER_DRIVER]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+	if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+	if ((s = cinfo->version[VER_SERIAL]) != 0)
+	   len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+
+	if (card->cardtype != avm_m1) {
+        	flag = ((u8 *)(ctrl->profile.manu))[3];
+        	if (flag)
+			len += sprintf(page+len, "%-16s%s%s%s%s%s%s%s\n",
+			"protocol",
+			(flag & 0x01) ? " DSS1" : "",
+			(flag & 0x02) ? " CT1" : "",
+			(flag & 0x04) ? " VN3" : "",
+			(flag & 0x08) ? " NI1" : "",
+			(flag & 0x10) ? " AUSTEL" : "",
+			(flag & 0x20) ? " ESS" : "",
+			(flag & 0x40) ? " 1TR6" : ""
+			);
+	}
+	if (card->cardtype != avm_m1) {
+        	flag = ((u8 *)(ctrl->profile.manu))[5];
+		if (flag)
+			len += sprintf(page+len, "%-16s%s%s%s%s\n",
+			"linetype",
+			(flag & 0x01) ? " point to point" : "",
+			(flag & 0x02) ? " point to multipoint" : "",
+			(flag & 0x08) ? " leased line without D-channel" : "",
+			(flag & 0x04) ? " leased line with D-channel" : ""
+			);
+	}
+	len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr;
+	txlen = b1dma_readl(card, AMCC_TXLEN);
+
+	rxoff = (dma_addr_t)b1dma_readl(card, AMCC_RXPTR)-card->dma->recvbuf.dmaaddr;
+	rxlen = b1dma_readl(card, AMCC_RXLEN);
+
+	csr  = b1dma_readl(card, AMCC_INTCSR);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+        len += sprintf(page+len, "%-16s 0x%lx\n",
+				"csr (cached)", (unsigned long)card->csr);
+        len += sprintf(page+len, "%-16s 0x%lx\n",
+				"csr", (unsigned long)csr);
+        len += sprintf(page+len, "%-16s %lu\n",
+				"txoff", (unsigned long)txoff);
+        len += sprintf(page+len, "%-16s %lu\n",
+				"txlen", (unsigned long)txlen);
+        len += sprintf(page+len, "%-16s %lu\n",
+				"rxoff", (unsigned long)rxoff);
+        len += sprintf(page+len, "%-16s %lu\n",
+				"rxlen", (unsigned long)rxlen);
+
+	if (off+count >= len)
+	   *eof = 1;
+	if (len < off)
+           return 0;
+	*start = page + off;
+	return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+EXPORT_SYMBOL(b1dma_reset);
+EXPORT_SYMBOL(t1pci_detect);
+EXPORT_SYMBOL(b1pciv4_detect);
+EXPORT_SYMBOL(b1dma_interrupt);
+
+EXPORT_SYMBOL(b1dma_load_firmware);
+EXPORT_SYMBOL(b1dma_reset_ctr);
+EXPORT_SYMBOL(b1dma_register_appl);
+EXPORT_SYMBOL(b1dma_release_appl);
+EXPORT_SYMBOL(b1dma_send_message);
+EXPORT_SYMBOL(b1dmactl_read_proc);
+
+int b1dma_init(void)
+{
+	char *p;
+	char rev[32];
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, sizeof(rev));
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
+
+	printk(KERN_INFO "b1dma: revision %s\n", rev);
+
+	return 0;
+}
+
+void b1dma_exit(void)
+{
+}
+
+module_init(b1dma_init);
+module_exit(b1dma_exit);
diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c
new file mode 100644
index 0000000..38bd4df
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1isa.c
@@ -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);
diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
new file mode 100644
index 0000000..5435a6c
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1pci.c
@@ -0,0 +1,417 @@
+/* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
+ * 
+ * Module for AVM B1 PCI-card.
+ * 
+ * Copyright 1999 by Carsten Paeth <calle@calle.de>
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/capi.h>
+#include <asm/io.h>
+#include <linux/init.h>
+#include <linux/isdn/capicmd.h>
+#include <linux/isdn/capiutil.h>
+#include <linux/isdn/capilli.h>
+#include "avmcard.h"
+
+/* ------------------------------------------------------------- */
+
+static char *revision = "$Revision: 1.1.2.2 $";
+
+/* ------------------------------------------------------------- */
+
+static struct pci_device_id b1pci_pci_tbl[] = {
+	{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID },
+	{ }				/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(pci, b1pci_pci_tbl);
+MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 PCI card");
+MODULE_AUTHOR("Carsten Paeth");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------- */
+
+static char *b1pci_procinfo(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
+		return "";
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0,
+		cinfo->card ? cinfo->card->revision : 0
+		);
+	return cinfo->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
+{
+	avmcard *card;
+	avmctrl_info *cinfo;
+	int retval;
+
+	card = b1_alloc_card(1);
+	if (!card) {
+		printk(KERN_WARNING "b1pci: no memory.\n");
+		retval = -ENOMEM;
+		goto err;
+	}
+
+	cinfo = card->ctrlinfo;
+	sprintf(card->name, "b1pci-%x", p->port);
+	card->port = p->port;
+	card->irq = p->irq;
+	card->cardtype = avm_b1pci;
+	
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
+		printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
+		retval = -EBUSY;
+		goto err_free;
+	}
+	b1_reset(card->port);
+	retval = b1_detect(card->port, card->cardtype);
+	if (retval) {
+		printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
+		       card->port, retval);
+		retval = -ENODEV;
+		goto err_release_region;
+	}
+	b1_reset(card->port);
+	b1_getrevision(card);
+	
+	retval = request_irq(card->irq, b1_interrupt, SA_SHIRQ, card->name, card);
+	if (retval) {
+		printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
+		retval = -EBUSY;
+		goto err_release_region;
+	}
+	
+	cinfo->capi_ctrl.driver_name   = "b1pci";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1_release_appl;
+	cinfo->capi_ctrl.send_message  = b1_send_message;
+	cinfo->capi_ctrl.load_firmware = b1_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = b1_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = b1pci_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+	cinfo->capi_ctrl.owner         = THIS_MODULE;
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
+		printk(KERN_ERR "b1pci: attach controller failed.\n");
+		goto err_free_irq;
+	}
+
+	if (card->revision >= 4) {
+		printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n",
+		       card->port, card->irq, card->revision);
+	} else {
+		printk(KERN_INFO "b1pci: AVM B1 PCI at i/o %#x, irq %d, revision %d\n",
+		       card->port, card->irq, card->revision);
+	}
+
+	pci_set_drvdata(pdev, card);
+	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_free:
+	b1_free_card(card);
+ err:
+	return retval;
+}
+
+static void b1pci_remove(struct pci_dev *pdev)
+{
+	avmcard *card = pci_get_drvdata(pdev);
+	avmctrl_info *cinfo = card->ctrlinfo;
+	unsigned int port = card->port;
+
+	b1_reset(port);
+	b1_reset(port);
+
+	detach_capi_ctr(&cinfo->capi_ctrl);
+	free_irq(card->irq, card);
+	release_region(card->port, AVMB1_PORTLEN);
+	b1_free_card(card);
+}
+
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+/* ------------------------------------------------------------- */
+
+static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
+		return "";
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0,
+		cinfo->card ? cinfo->card->membase : 0,
+		cinfo->card ? cinfo->card->revision : 0
+		);
+	return cinfo->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
+static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
+{
+	avmcard *card;
+	avmctrl_info *cinfo;
+	int retval;
+
+	card = b1_alloc_card(1);
+	if (!card) {
+		printk(KERN_WARNING "b1pci: no memory.\n");
+		retval = -ENOMEM;
+		goto err;
+	}
+
+        card->dma = avmcard_dma_alloc("b1pci", pdev, 2048+128, 2048+128);
+	if (!card->dma) {
+		printk(KERN_WARNING "b1pci: dma alloc.\n");
+		retval = -ENOMEM;
+		goto err_free;
+	}
+
+	cinfo = card->ctrlinfo;
+	sprintf(card->name, "b1pciv4-%x", p->port);
+	card->port = p->port;
+	card->irq = p->irq;
+	card->membase = p->membase;
+	card->cardtype = avm_b1pci;
+
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
+		printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
+		retval = -EBUSY;
+		goto err_free_dma;
+	}
+
+	card->mbase = ioremap(card->membase, 64);
+	if (!card->mbase) {
+		printk(KERN_NOTICE "b1pci: can't remap memory at 0x%lx\n",
+		       card->membase);
+		retval = -ENOMEM;
+		goto err_release_region;
+	}
+
+	b1dma_reset(card);
+
+	retval = b1pciv4_detect(card);
+	if (retval) {
+		printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n",
+		       card->port, retval);
+		retval = -ENODEV;
+		goto err_unmap;
+	}
+	b1dma_reset(card);
+	b1_getrevision(card);
+
+	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
+	if (retval) {
+		printk(KERN_ERR "b1pci: unable to get IRQ %d.\n",
+		       card->irq);
+		retval = -EBUSY;
+		goto err_unmap;
+	}
+
+	cinfo->capi_ctrl.owner         = THIS_MODULE;
+	cinfo->capi_ctrl.driver_name   = "b1pciv4";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1dma_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1dma_release_appl;
+	cinfo->capi_ctrl.send_message  = b1dma_send_message;
+	cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = b1dma_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = b1pciv4_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
+		printk(KERN_ERR "b1pci: attach controller failed.\n");
+		goto err_free_irq;
+	}
+	card->cardnr = cinfo->capi_ctrl.cnr;
+
+	printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n",
+	       card->port, card->irq, card->membase, card->revision);
+
+	pci_set_drvdata(pdev, card);
+	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_free_dma:
+	avmcard_dma_free(card->dma);
+ err_free:
+	b1_free_card(card);
+ err:
+	return retval;
+
+}
+
+static void b1pciv4_remove(struct pci_dev *pdev)
+{
+	avmcard *card = pci_get_drvdata(pdev);
+	avmctrl_info *cinfo = card->ctrlinfo;
+
+ 	b1dma_reset(card);
+
+	detach_capi_ctr(&cinfo->capi_ctrl);
+	free_irq(card->irq, card);
+	iounmap(card->mbase);
+	release_region(card->port, AVMB1_PORTLEN);
+        avmcard_dma_free(card->dma);
+	b1_free_card(card);
+}
+
+#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
+
+static int __devinit b1pci_pci_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	struct capicardparams param;
+	int retval;
+
+	if (pci_enable_device(pdev) < 0) {
+		printk(KERN_ERR "b1pci: failed to enable AVM-B1\n");
+		return -ENODEV;
+	}
+	param.irq = pdev->irq;
+
+	if (pci_resource_start(pdev, 2)) { /* B1 PCI V4 */
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+		pci_set_master(pdev);
+#endif
+		param.membase = pci_resource_start(pdev, 0);
+		param.port = pci_resource_start(pdev, 2);
+
+		printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
+		       param.port, param.irq, param.membase);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+		retval = b1pciv4_probe(&param, pdev);
+#else
+		retval = b1pci_probe(&param, pdev);
+#endif
+		if (retval != 0) {
+		        printk(KERN_ERR "b1pci: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n",
+			       param.port, param.irq, param.membase);
+		}
+	} else {
+		param.membase = 0;
+		param.port = pci_resource_start(pdev, 1);
+
+		printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
+		       param.port, param.irq);
+		retval = b1pci_probe(&param, pdev);
+		if (retval != 0) {
+		        printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n",
+			       param.port, param.irq);
+		}
+	}
+	return retval;
+}
+
+static void __devexit b1pci_pci_remove(struct pci_dev *pdev)
+{
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+	avmcard *card = pci_get_drvdata(pdev);
+
+	if (card->dma)
+		b1pciv4_remove(pdev);
+	else
+		b1pci_remove(pdev);
+#else
+	b1pci_remove(pdev);
+#endif
+}
+
+static struct pci_driver b1pci_pci_driver = {
+	.name		= "b1pci",
+	.id_table	= b1pci_pci_tbl,
+	.probe		= b1pci_pci_probe,
+	.remove		= __devexit_p(b1pci_pci_remove),
+};
+
+static struct capi_driver capi_driver_b1pci = {
+	.name		= "b1pci",
+	.revision	= "1.0",
+};
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+static struct capi_driver capi_driver_b1pciv4 = {
+	.name		= "b1pciv4",
+	.revision	= "1.0",
+};
+#endif
+
+static int __init b1pci_init(void)
+{
+	char *p;
+	char rev[32];
+	int err;
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, 32);
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
+
+
+	err = pci_register_driver(&b1pci_pci_driver);
+	if (!err) {
+		strlcpy(capi_driver_b1pci.revision, rev, 32);
+		register_capi_driver(&capi_driver_b1pci);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+		strlcpy(capi_driver_b1pciv4.revision, rev, 32);
+		register_capi_driver(&capi_driver_b1pciv4);
+#endif
+		printk(KERN_INFO "b1pci: revision %s\n", rev);
+	}
+	return err;
+}
+
+static void __exit b1pci_exit(void)
+{
+	unregister_capi_driver(&capi_driver_b1pci);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+	unregister_capi_driver(&capi_driver_b1pciv4);
+#endif
+	pci_unregister_driver(&b1pci_pci_driver);
+}
+
+module_init(b1pci_init);
+module_exit(b1pci_exit);
diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c
new file mode 100644
index 0000000..9746cc5
--- /dev/null
+++ b/drivers/isdn/hardware/avm/b1pcmcia.c
@@ -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);
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
new file mode 100644
index 0000000..fa6b93b
--- /dev/null
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -0,0 +1,1310 @@
+/* $Id: c4.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
+ * 
+ * Module for AVM C4 & C2 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/kernelcapi.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/netdevice.h>
+#include <linux/isdn/capicmd.h>
+#include <linux/isdn/capiutil.h>
+#include <linux/isdn/capilli.h>
+#include "avmcard.h"
+
+#undef CONFIG_C4_DEBUG
+#undef CONFIG_C4_POLLDEBUG
+
+/* ------------------------------------------------------------- */
+
+static char *revision = "$Revision: 1.1.2.2 $";
+
+/* ------------------------------------------------------------- */
+
+static int suppress_pollack;
+
+static struct pci_device_id c4_pci_tbl[] = {
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 },
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2, 0, 0, (unsigned long)2 },
+	{ }			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(pci, c4_pci_tbl);
+MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM C2/C4 cards");
+MODULE_AUTHOR("Carsten Paeth");
+MODULE_LICENSE("GPL");
+MODULE_PARM(suppress_pollack, "0-1i");
+
+/* ------------------------------------------------------------- */
+
+static void c4_dispatch_tx(avmcard *card);
+
+/* ------------------------------------------------------------- */
+
+#define DC21285_DRAM_A0MR	0x40000000
+#define DC21285_DRAM_A1MR	0x40004000
+#define DC21285_DRAM_A2MR	0x40008000
+#define DC21285_DRAM_A3MR	0x4000C000
+
+#define	CAS_OFFSET	0x88
+
+#define DC21285_ARMCSR_BASE	0x42000000
+
+#define	PCI_OUT_INT_STATUS	0x30
+#define	PCI_OUT_INT_MASK	0x34
+#define	MAILBOX_0		0x50
+#define	MAILBOX_1		0x54
+#define	MAILBOX_2		0x58
+#define	MAILBOX_3		0x5C
+#define	DOORBELL		0x60
+#define	DOORBELL_SETUP		0x64
+
+#define CHAN_1_CONTROL		0x90
+#define CHAN_2_CONTROL		0xB0
+#define DRAM_TIMING		0x10C
+#define DRAM_ADDR_SIZE_0	0x110
+#define DRAM_ADDR_SIZE_1	0x114
+#define DRAM_ADDR_SIZE_2	0x118
+#define DRAM_ADDR_SIZE_3	0x11C
+#define	SA_CONTROL		0x13C
+#define	XBUS_CYCLE		0x148
+#define	XBUS_STROBE		0x14C
+#define	DBELL_PCI_MASK		0x150
+#define DBELL_SA_MASK		0x154
+
+#define SDRAM_SIZE		0x1000000
+
+/* ------------------------------------------------------------- */
+
+#define	MBOX_PEEK_POKE		MAILBOX_0
+
+#define DBELL_ADDR		0x01
+#define DBELL_DATA		0x02
+#define DBELL_RNWR		0x40
+#define DBELL_INIT		0x80
+
+/* ------------------------------------------------------------- */
+
+#define	MBOX_UP_ADDR		MAILBOX_0
+#define	MBOX_UP_LEN		MAILBOX_1
+#define	MBOX_DOWN_ADDR		MAILBOX_2
+#define	MBOX_DOWN_LEN		MAILBOX_3
+
+#define	DBELL_UP_HOST		0x00000100
+#define	DBELL_UP_ARM		0x00000200
+#define	DBELL_DOWN_HOST		0x00000400
+#define	DBELL_DOWN_ARM		0x00000800
+#define	DBELL_RESET_HOST	0x40000000
+#define	DBELL_RESET_ARM		0x80000000
+
+/* ------------------------------------------------------------- */
+
+#define	DRAM_TIMING_DEF		0x001A01A5
+#define DRAM_AD_SZ_DEF0		0x00000045
+#define DRAM_AD_SZ_NULL		0x00000000
+
+#define SA_CTL_ALLRIGHT		0x64AA0271
+
+#define	INIT_XBUS_CYCLE		0x100016DB
+#define	INIT_XBUS_STROBE	0xF1F1F1F1
+
+/* ------------------------------------------------------------- */
+
+#define	RESET_TIMEOUT		(15*HZ)	/* 15 sec */
+#define	PEEK_POKE_TIMEOUT	(HZ/10)	/* 0.1 sec */
+
+/* ------------------------------------------------------------- */
+
+#define c4outmeml(addr, value)	writel(value, addr)
+#define c4inmeml(addr)	readl(addr)
+#define c4outmemw(addr, value)	writew(value, addr)
+#define c4inmemw(addr)	readw(addr)
+#define c4outmemb(addr, value)	writeb(value, addr)
+#define c4inmemb(addr)	readb(addr)
+
+/* ------------------------------------------------------------- */
+
+static inline int wait_for_doorbell(avmcard *card, unsigned long t)
+{
+	unsigned long stop;
+
+	stop = jiffies + t;
+	while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+		if (!time_before(jiffies, stop))
+			return -1;
+		mb();
+	}
+	return 0;
+}
+
+static int c4_poke(avmcard *card,  unsigned long off, unsigned long value)
+{
+
+	if (wait_for_doorbell(card, HZ/10) < 0)
+		return -1;
+	
+	c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
+	c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+
+	if (wait_for_doorbell(card, HZ/10) < 0)
+		return -1;
+
+	c4outmeml(card->mbase+MBOX_PEEK_POKE, value);
+	c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR);
+
+	return 0;
+}
+
+static int c4_peek(avmcard *card,  unsigned long off, unsigned long *valuep)
+{
+	if (wait_for_doorbell(card, HZ/10) < 0)
+		return -1;
+
+	c4outmeml(card->mbase+MBOX_PEEK_POKE, off);
+	c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR);
+
+	if (wait_for_doorbell(card, HZ/10) < 0)
+		return -1;
+
+	*valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_load_t4file(avmcard *card, capiloaddatapart * t4file)
+{
+	u32 val;
+	unsigned char *dp;
+	u_int left;
+	u32 loadoff = 0;
+
+	dp = t4file->data;
+	left = t4file->len;
+	while (left >= sizeof(u32)) {
+	        if (t4file->user) {
+			if (copy_from_user(&val, dp, sizeof(val)))
+				return -EFAULT;
+		} else {
+			memcpy(&val, dp, sizeof(val));
+		}
+		if (c4_poke(card, loadoff, val)) {
+			printk(KERN_ERR "%s: corrupted firmware file ?\n",
+					card->name);
+			return -EIO;
+		}
+		left -= sizeof(u32);
+		dp += sizeof(u32);
+		loadoff += sizeof(u32);
+	}
+	if (left) {
+		val = 0;
+		if (t4file->user) {
+			if (copy_from_user(&val, dp, left))
+				return -EFAULT;
+		} else {
+			memcpy(&val, dp, left);
+		}
+		if (c4_poke(card, loadoff, val)) {
+			printk(KERN_ERR "%s: corrupted firmware file ?\n",
+					card->name);
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+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;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_reset(avmcard *card)
+{
+	unsigned long stop;
+
+	c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
+
+	stop = jiffies + HZ*10;
+	while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+		if (!time_before(jiffies, stop))
+			return;
+		c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+		mb();
+	}
+
+	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
+	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_detect(avmcard *card)
+{
+	unsigned long stop, dummy;
+
+	c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+	if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c)
+		return	1;
+
+	c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM);
+
+	stop = jiffies + HZ*10;
+	while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) {
+		if (!time_before(jiffies, stop))
+			return 2;
+		c4outmeml(card->mbase+DOORBELL, DBELL_ADDR);
+		mb();
+	}
+
+	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0);
+	c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0);
+
+	c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa);
+	if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3;
+
+	c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55);
+	if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4;
+
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT))
+		return 7;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE))
+		return 8;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE))
+		return 8;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9;
+
+        mdelay(1);
+
+	if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10;
+	if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11;
+	if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12;
+	if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13;
+
+	if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14;
+	if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15;
+	if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16;
+	if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17;
+
+        mdelay(1);
+
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF))
+		return 18;
+
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0))
+		return 19;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL))
+		return 20;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL))
+		return 21;
+	if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL))
+		return 22;
+
+	/* Transputer test */
+	
+	if (   c4_poke(card, 0x000000, 0x11111111)
+	    || c4_poke(card, 0x400000, 0x22222222)
+	    || c4_poke(card, 0x800000, 0x33333333)
+	    || c4_poke(card, 0xC00000, 0x44444444))
+		return 23;
+
+	if (   c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111
+	    || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222
+	    || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333
+	    || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444)
+		return 24;
+
+	if (   c4_poke(card, 0x000000, 0x55555555)
+	    || c4_poke(card, 0x400000, 0x66666666)
+	    || c4_poke(card, 0x800000, 0x77777777)
+	    || c4_poke(card, 0xC00000, 0x88888888))
+		return 25;
+
+	if (   c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555
+	    || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666
+	    || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777
+	    || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888)
+		return 26;
+
+	return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_dispatch_tx(avmcard *card)
+{
+	avmcard_dmainfo *dma = card->dma;
+	struct sk_buff *skb;
+	u8 cmd, subcmd;
+	u16 len;
+	u32 txlen;
+	void *p;
+
+
+	if (card->csr & DBELL_DOWN_ARM) { /* tx busy */
+		return;
+	}
+
+	skb = skb_dequeue(&dma->send_queue);
+	if (!skb) {
+#ifdef CONFIG_C4_DEBUG
+		printk(KERN_DEBUG "%s: tx underrun\n", card->name);
+#endif
+		return;
+	}
+
+	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_C4_DEBUG
+		printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
+#endif
+	} else {
+		txlen = skb->len-2;
+#ifdef CONFIG_C4_POLLDEBUG
+		if (skb->data[2] == SEND_POLLACK)
+			printk(KERN_INFO "%s: ack to c4\n", card->name);
+#endif
+#ifdef CONFIG_C4_DEBUG
+		printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
+				card->name, skb->data[2], txlen);
+#endif
+		memcpy(dma->sendbuf.dmabuf, skb->data+2, skb->len-2);
+	}
+	txlen = (txlen + 3) & ~3;
+
+	c4outmeml(card->mbase+MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr);
+	c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen);
+
+	card->csr |= DBELL_DOWN_ARM;
+
+	c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM);
+
+	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);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_handle_rx(avmcard *card)
+{
+	avmcard_dmainfo *dma = card->dma;
+	struct capi_ctr *ctrl;
+	avmctrl_info *cinfo;
+	struct sk_buff *skb;
+	void *p = dma->recvbuf.dmabuf;
+	u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
+	u8 b1cmd =  _get_byte(&p);
+	u32 cidx;
+
+
+#ifdef CONFIG_C4_DEBUG
+	printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name,
+				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);
+		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
+		if (cidx >= card->nlogcontr) cidx = 0;
+		ctrl = &card->ctrlinfo[cidx].capi_ctrl;
+
+		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);
+		cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr;
+		if (cidx >= card->nlogcontr) cidx = 0;
+		cinfo = &card->ctrlinfo[cidx];
+		ctrl = &card->ctrlinfo[cidx].capi_ctrl;
+
+		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);
+		cidx = (NCCI&0x7f) - card->cardnr;
+		if (cidx >= card->nlogcontr) cidx = 0;
+
+		capilib_new_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI, WindowSize);
+
+		break;
+
+	case RECEIVE_FREE_NCCI:
+
+		ApplId = _get_word(&p);
+		NCCI = _get_word(&p);
+
+		if (NCCI != 0xffffffff) {
+			cidx = (NCCI&0x7f) - card->cardnr;
+			if (cidx >= card->nlogcontr) cidx = 0;
+			capilib_free_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI);
+		}
+		break;
+
+	case RECEIVE_START:
+#ifdef CONFIG_C4_POLLDEBUG
+		printk(KERN_INFO "%s: poll from c4\n", card->name);
+#endif
+		if (!suppress_pollack)
+			queue_pollack(card);
+		for (cidx=0; cidx < card->nr_controllers; cidx++) {
+			ctrl = &card->ctrlinfo[cidx].capi_ctrl;
+			capi_ctr_resume_output(ctrl);
+		}
+		break;
+
+	case RECEIVE_STOP:
+		for (cidx=0; cidx < card->nr_controllers; cidx++) {
+			ctrl = &card->ctrlinfo[cidx].capi_ctrl;
+			capi_ctr_suspend_output(ctrl);
+		}
+		break;
+
+	case RECEIVE_INIT:
+
+	        cidx = card->nlogcontr;
+		if (cidx >= card->nr_controllers) {
+			printk(KERN_ERR "%s: card with %d controllers ??\n",
+					card->name, cidx+1);
+			break;
+		}
+	        card->nlogcontr++;
+	        cinfo = &card->ctrlinfo[cidx];
+		ctrl = &cinfo->capi_ctrl;
+		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(&cinfo->capi_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: c4_interrupt: 0x%x ???\n",
+				card->name, b1cmd);
+		return;
+	}
+}
+
+/* ------------------------------------------------------------- */
+
+static irqreturn_t c4_handle_interrupt(avmcard *card)
+{
+	unsigned long flags;
+	u32 status;
+
+	spin_lock_irqsave(&card->lock, flags);
+	status = c4inmeml(card->mbase+DOORBELL);
+
+	if (status & DBELL_RESET_HOST) {
+		u_int i;
+		c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c);
+		spin_unlock_irqrestore(&card->lock, flags);
+		if (card->nlogcontr == 0)
+			return IRQ_HANDLED;
+		printk(KERN_ERR "%s: unexpected reset\n", card->name);
+                for (i=0; i < card->nr_controllers; i++) {
+			avmctrl_info *cinfo = &card->ctrlinfo[i];
+			memset(cinfo->version, 0, sizeof(cinfo->version));
+			capilib_release(&cinfo->ncci_head);
+			capi_ctr_reseted(&cinfo->capi_ctrl);
+		}
+		card->nlogcontr = 0;
+		return IRQ_HANDLED;
+	}
+
+	status &= (DBELL_UP_HOST | DBELL_DOWN_HOST);
+	if (!status) {
+		spin_unlock_irqrestore(&card->lock, flags);
+		return IRQ_HANDLED;
+	}
+	c4outmeml(card->mbase+DOORBELL, status);
+
+	if ((status & DBELL_UP_HOST) != 0) {
+		card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN);
+		c4outmeml(card->mbase+MBOX_UP_LEN, 0);
+		c4_handle_rx(card);
+		card->dma->recvlen = 0;
+		c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
+		c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
+	}
+
+	if ((status & DBELL_DOWN_HOST) != 0) {
+		card->csr &= ~DBELL_DOWN_ARM;
+	        c4_dispatch_tx(card);
+	} else if (card->csr & DBELL_DOWN_HOST) {
+		if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) {
+		        card->csr &= ~DBELL_DOWN_ARM;
+			c4_dispatch_tx(card);
+		}
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+{
+	avmcard *card = devptr;
+
+	return c4_handle_interrupt(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static void c4_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);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+}
+
+static int queue_sendconfigword(avmcard *card, u32 val)
+{
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(3+4, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, send config\n",
+					card->name);
+		return -ENOMEM;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_CONFIG);
+	_put_word(&p, val);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+	return 0;
+}
+
+static int queue_sendconfig(avmcard *card, char cval[4])
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+	void *p;
+
+	skb = alloc_skb(3+4, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, send config\n",
+					card->name);
+		return -ENOMEM;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
+	_put_byte(&p, SEND_CONFIG);
+	_put_byte(&p, cval[0]);
+	_put_byte(&p, cval[1]);
+	_put_byte(&p, cval[2]);
+	_put_byte(&p, cval[3]);
+	skb_put(skb, (u8 *)p - (u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	
+	spin_lock_irqsave(&card->lock, flags);
+	c4_dispatch_tx(card);
+	spin_unlock_irqrestore(&card->lock, flags);
+	return 0;
+}
+
+static int c4_send_config(avmcard *card, capiloaddatapart * config)
+{
+	u8 val[4];
+	unsigned char *dp;
+	u_int left;
+	int retval;
+	
+	if ((retval = queue_sendconfigword(card, 1)) != 0)
+		return retval;
+	if ((retval = queue_sendconfigword(card, config->len)) != 0)
+		return retval;
+
+	dp = config->data;
+	left = config->len;
+	while (left >= sizeof(u32)) {
+	        if (config->user) {
+			if (copy_from_user(val, dp, sizeof(val)))
+				return -EFAULT;
+		} else {
+			memcpy(val, dp, sizeof(val));
+		}
+		if ((retval = queue_sendconfig(card, val)) != 0)
+			return retval;
+		left -= sizeof(val);
+		dp += sizeof(val);
+	}
+	if (left) {
+		memset(val, 0, sizeof(val));
+		if (config->user) {
+			if (copy_from_user(&val, dp, left))
+				return -EFAULT;
+		} else {
+			memcpy(&val, dp, left);
+		}
+		if ((retval = queue_sendconfig(card, val)) != 0)
+			return retval;
+	}
+
+	return 0;
+}
+
+static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	int retval;
+
+	if ((retval = c4_load_t4file(card, &data->firmware))) {
+		printk(KERN_ERR "%s: failed to load t4file!!\n",
+					card->name);
+		c4_reset(card);
+		return retval;
+	}
+
+	card->csr = 0;
+	c4outmeml(card->mbase+MBOX_UP_LEN, 0);
+	c4outmeml(card->mbase+MBOX_DOWN_LEN, 0);
+	c4outmeml(card->mbase+DOORBELL, DBELL_INIT);
+	mdelay(1);
+	c4outmeml(card->mbase+DOORBELL,
+			DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST);
+
+	c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08);
+
+	card->dma->recvlen = 0;
+	c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr);
+	c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size);
+	c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
+
+	if (data->configuration.len > 0 && data->configuration.data) {
+		retval = c4_send_config(card, &data->configuration);
+		if (retval) {
+			printk(KERN_ERR "%s: failed to set config!!\n",
+					card->name);
+			c4_reset(card);
+			return retval;
+		}
+	}
+
+        c4_send_init(card);
+
+	return 0;
+}
+
+
+void c4_reset_ctr(struct capi_ctr *ctrl)
+{
+	avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
+	avmctrl_info *cinfo;
+	u_int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+ 	c4_reset(card);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+        for (i=0; i < card->nr_controllers; i++) {
+		cinfo = &card->ctrlinfo[i];
+		memset(cinfo->version, 0, sizeof(cinfo->version));
+		capi_ctr_reseted(&cinfo->capi_ctrl);
+	}
+	card->nlogcontr = 0;
+}
+
+static void c4_remove(struct pci_dev *pdev)
+{
+	avmcard *card = pci_get_drvdata(pdev);
+	avmctrl_info *cinfo;
+	u_int i;
+
+	if (!card)
+		return;
+
+ 	c4_reset(card);
+
+        for (i=0; i < card->nr_controllers; i++) {
+		cinfo = &card->ctrlinfo[i];
+		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);
+        pci_set_drvdata(pdev, NULL);
+	b1_free_card(card);
+}
+
+/* ------------------------------------------------------------- */
+
+
+void c4_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;
+	unsigned long flags;
+	int nconn;
+	void *p;
+
+	if (ctrl->cnr == card->cardnr) {
+
+		if (want > 0) nconn = want;
+		else nconn = ctrl->profile.nbchannel * 4 * -want;
+		if (nconn == 0) nconn = ctrl->profile.nbchannel * 4;
+
+		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);
+
+		skb_queue_tail(&card->dma->send_queue, skb);
+	
+		spin_lock_irqsave(&card->lock, flags);
+		c4_dispatch_tx(card);
+		spin_unlock_irqrestore(&card->lock, flags);
+	}
+}
+
+/* ------------------------------------------------------------- */
+
+void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	unsigned long flags;
+	struct sk_buff *skb;
+	void *p;
+
+	capilib_release_appl(&cinfo->ncci_head, appl);
+
+	if (ctrl->cnr == card->cardnr) {
+		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);
+		skb_queue_tail(&card->dma->send_queue, skb);
+		spin_lock_irqsave(&card->lock, flags);
+		c4_dispatch_tx(card);
+		spin_unlock_irqrestore(&card->lock, flags);
+	}
+}
+
+/* ------------------------------------------------------------- */
+
+
+static u16 c4_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;
+	unsigned long flags;
+
+ 	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) {
+		skb_queue_tail(&card->dma->send_queue, skb);
+		spin_lock_irqsave(&card->lock, flags);
+		c4_dispatch_tx(card);
+		spin_unlock_irqrestore(&card->lock, flags);
+	}
+	return retval;
+}
+
+/* ------------------------------------------------------------- */
+
+static char *c4_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 c4_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);
+	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);
+
+	if (off+count >= len)
+	   *eof = 1;
+	if (len < off)
+           return 0;
+	*start = page + off;
+	return ((count < len-off) ? count : len-off);
+}
+
+/* ------------------------------------------------------------- */
+
+static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
+		       int nr_controllers)
+{
+	avmcard *card;
+	avmctrl_info *cinfo;
+	int retval;
+	int i;
+
+	card = b1_alloc_card(nr_controllers);
+	if (!card) {
+		printk(KERN_WARNING "c4: no memory.\n");
+		retval = -ENOMEM;
+		goto err;
+	}
+        card->dma = avmcard_dma_alloc("c4", dev, 2048+128, 2048+128);
+	if (!card->dma) {
+		printk(KERN_WARNING "c4: no memory.\n");
+		retval = -ENOMEM;
+		goto err_free;
+	}
+
+	sprintf(card->name, "c%d-%x", nr_controllers, p->port);
+	card->port = p->port;
+	card->irq = p->irq;
+	card->membase = p->membase;
+	card->cardtype = (nr_controllers == 4) ? avm_c4 : avm_c2;
+
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
+		printk(KERN_WARNING "c4: 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, 128);
+	if (card->mbase == 0) {
+		printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n",
+		       card->membase);
+		retval = -EIO;
+		goto err_release_region;
+	}
+
+	retval = c4_detect(card);
+	if (retval != 0) {
+		printk(KERN_NOTICE "c4: NO card at 0x%x error(%d)\n",
+		       card->port, retval);
+		retval = -EIO;
+		goto err_unmap;
+	}
+	c4_reset(card);
+
+	retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
+	if (retval) {
+		printk(KERN_ERR "c4: unable to get IRQ %d.\n",card->irq);
+		retval = -EBUSY;
+		goto err_unmap;
+	}
+
+	for (i=0; i < nr_controllers ; i++) {
+		cinfo = &card->ctrlinfo[i];
+		cinfo->capi_ctrl.owner = THIS_MODULE;
+		cinfo->capi_ctrl.driver_name   = "c4";
+		cinfo->capi_ctrl.driverdata    = cinfo;
+		cinfo->capi_ctrl.register_appl = c4_register_appl;
+		cinfo->capi_ctrl.release_appl  = c4_release_appl;
+		cinfo->capi_ctrl.send_message  = c4_send_message;
+		cinfo->capi_ctrl.load_firmware = c4_load_firmware;
+		cinfo->capi_ctrl.reset_ctr     = c4_reset_ctr;
+		cinfo->capi_ctrl.procinfo      = c4_procinfo;
+		cinfo->capi_ctrl.ctr_read_proc = c4_read_proc;
+		strcpy(cinfo->capi_ctrl.name, card->name);
+
+		retval = attach_capi_ctr(&cinfo->capi_ctrl);
+		if (retval) {
+			printk(KERN_ERR "c4: attach controller failed (%d).\n", i);
+			for (i--; i >= 0; i--) {
+				cinfo = &card->ctrlinfo[i];
+				detach_capi_ctr(&cinfo->capi_ctrl);
+			}
+			goto err_free_irq;
+		}
+		if (i == 0)
+			card->cardnr = cinfo->capi_ctrl.cnr;
+	}
+
+	printk(KERN_INFO "c4: AVM C%d at i/o %#x, irq %d, mem %#lx\n",
+	       nr_controllers, card->port, card->irq,
+	       card->membase);
+	pci_set_drvdata(dev, 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 int __devinit c4_probe(struct pci_dev *dev,
+			      const struct pci_device_id *ent)
+{
+	int nr = ent->driver_data;
+	int retval = 0;
+	struct capicardparams param;
+
+	if (pci_enable_device(dev) < 0) {
+		printk(KERN_ERR "c4: failed to enable AVM-C%d\n", nr);
+		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 "c4: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
+	       nr, param.port, param.irq, param.membase);
+	
+	retval = c4_add_card(&param, dev, nr);
+	if (retval != 0) {
+		printk(KERN_ERR "c4: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n",
+		       nr, param.port, param.irq, param.membase);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static struct pci_driver c4_pci_driver = {
+       .name           = "c4",
+       .id_table       = c4_pci_tbl,
+       .probe          = c4_probe,
+       .remove         = c4_remove,
+};
+
+static struct capi_driver capi_driver_c2 = {
+	.name		= "c2",
+	.revision	= "1.0",
+};
+
+static struct capi_driver capi_driver_c4 = {
+	.name		= "c4",
+	.revision	= "1.0",
+};
+
+static int __init c4_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(&c4_pci_driver);
+	if (!err) {
+		strlcpy(capi_driver_c2.revision, rev, 32);
+		register_capi_driver(&capi_driver_c2);
+		strlcpy(capi_driver_c4.revision, rev, 32);
+		register_capi_driver(&capi_driver_c4);
+		printk(KERN_INFO "c4: revision %s\n", rev);
+	}
+	return err;
+}
+
+static void __exit c4_exit(void)
+{
+	unregister_capi_driver(&capi_driver_c2);
+	unregister_capi_driver(&capi_driver_c4);
+	pci_unregister_driver(&c4_pci_driver);
+}
+
+module_init(c4_init);
+module_exit(c4_exit);
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
new file mode 100644
index 0000000..cb9d9ce
--- /dev/null
+++ b/drivers/isdn/hardware/avm/t1isa.c
@@ -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);
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
new file mode 100644
index 0000000..2ceec8e
--- /dev/null
+++ b/drivers/isdn/hardware/avm/t1pci.c
@@ -0,0 +1,260 @@
+/* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $
+ * 
+ * Module for AVM T1 PCI-card.
+ * 
+ * Copyright 1999 by Carsten Paeth <calle@calle.de>
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/capi.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/isdn/capicmd.h>
+#include <linux/isdn/capiutil.h>
+#include <linux/isdn/capilli.h>
+#include "avmcard.h"
+
+#undef CONFIG_T1PCI_DEBUG
+#undef CONFIG_T1PCI_POLLDEBUG
+
+/* ------------------------------------------------------------- */
+static char *revision = "$Revision: 1.1.2.2 $";
+/* ------------------------------------------------------------- */
+
+static struct pci_device_id t1pci_pci_tbl[] = {
+	{ PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID },
+	{ }				/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(pci, t1pci_pci_tbl);
+MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 PCI card");
+MODULE_AUTHOR("Carsten Paeth");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------- */
+
+static char *t1pci_procinfo(struct capi_ctr *ctrl);
+
+static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
+{
+	avmcard *card;
+	avmctrl_info *cinfo;
+	int retval;
+
+	card = b1_alloc_card(1);
+	if (!card) {
+		printk(KERN_WARNING "t1pci: no memory.\n");
+		retval = -ENOMEM;
+		goto err;
+	}
+
+        card->dma = avmcard_dma_alloc("t1pci", pdev, 2048+128, 2048+128);
+	if (!card->dma) {
+		printk(KERN_WARNING "t1pci: no memory.\n");
+		retval = -ENOMEM;
+		goto err_free;
+	}
+
+	cinfo = card->ctrlinfo;
+	sprintf(card->name, "t1pci-%x", p->port);
+	card->port = p->port;
+	card->irq = p->irq;
+	card->membase = p->membase;
+	card->cardtype = avm_t1pci;
+
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
+		printk(KERN_WARNING "t1pci: ports 0x%03x-0x%03x in use.\n",
+		       card->port, card->port + AVMB1_PORTLEN);
+		retval = -EBUSY;
+		goto err_free_dma;
+	}
+
+	card->mbase = ioremap(card->membase, 64);
+	if (!card->mbase) {
+		printk(KERN_NOTICE "t1pci: can't remap memory at 0x%lx\n",
+		       card->membase);
+		retval = -EIO;
+		goto err_release_region;
+	}
+
+	b1dma_reset(card);
+
+	retval = t1pci_detect(card);
+	if (retval != 0) {
+		if (retval < 6)
+			printk(KERN_NOTICE "t1pci: NO card at 0x%x (%d)\n",
+			       card->port, retval);
+		else
+			printk(KERN_NOTICE "t1pci: card at 0x%x, but cable not connected or T1 has no power (%d)\n",
+			       card->port, retval);
+		retval = -EIO;
+		goto err_unmap;
+	}
+	b1dma_reset(card);
+
+	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
+	if (retval) {
+		printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq);
+		retval = -EBUSY;
+		goto err_unmap;
+	}
+
+	cinfo->capi_ctrl.owner         = THIS_MODULE;
+	cinfo->capi_ctrl.driver_name   = "t1pci";
+	cinfo->capi_ctrl.driverdata    = cinfo;
+	cinfo->capi_ctrl.register_appl = b1dma_register_appl;
+	cinfo->capi_ctrl.release_appl  = b1dma_release_appl;
+	cinfo->capi_ctrl.send_message  = b1dma_send_message;
+	cinfo->capi_ctrl.load_firmware = b1dma_load_firmware;
+	cinfo->capi_ctrl.reset_ctr     = b1dma_reset_ctr;
+	cinfo->capi_ctrl.procinfo      = t1pci_procinfo;
+	cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
+	strcpy(cinfo->capi_ctrl.name, card->name);
+
+	retval = attach_capi_ctr(&cinfo->capi_ctrl);
+	if (retval) {
+		printk(KERN_ERR "t1pci: attach controller failed.\n");
+		retval = -EBUSY;
+		goto err_free_irq;
+	}
+	card->cardnr = cinfo->capi_ctrl.cnr;
+
+	printk(KERN_INFO "t1pci: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n",
+	       card->port, card->irq, card->membase);
+
+	pci_set_drvdata(pdev, card);
+	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_free_dma:
+	avmcard_dma_free(card->dma);
+ err_free:
+	b1_free_card(card);
+ err:
+	return retval;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_remove(struct pci_dev *pdev)
+{
+	avmcard *card = pci_get_drvdata(pdev);
+	avmctrl_info *cinfo = card->ctrlinfo;
+
+ 	b1dma_reset(card);
+
+	detach_capi_ctr(&cinfo->capi_ctrl);
+	free_irq(card->irq, card);
+	iounmap(card->mbase);
+	release_region(card->port, AVMB1_PORTLEN);
+	avmcard_dma_free(card->dma);
+	b1_free_card(card);
+}
+
+/* ------------------------------------------------------------- */
+
+static char *t1pci_procinfo(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+
+	if (!cinfo)
+		return "";
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->port : 0x0,
+		cinfo->card ? cinfo->card->irq : 0,
+		cinfo->card ? cinfo->card->membase : 0
+		);
+	return cinfo->infobuf;
+}
+
+/* ------------------------------------------------------------- */
+
+static int __devinit t1pci_probe(struct pci_dev *dev,
+				 const struct pci_device_id *ent)
+{
+	struct capicardparams param;
+	int retval;
+
+	if (pci_enable_device(dev) < 0) {
+		printk(KERN_ERR	"t1pci: failed to enable AVM-T1-PCI\n");
+		return -ENODEV;
+	}
+	pci_set_master(dev);
+
+	param.port = pci_resource_start(dev, 1);
+	param.irq = dev->irq;
+	param.membase = pci_resource_start(dev, 0);
+
+	printk(KERN_INFO "t1pci: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
+	       param.port, param.irq, param.membase);
+
+	retval = t1pci_add_card(&param, dev);
+	if (retval != 0) {
+		printk(KERN_ERR "t1pci: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
+		       param.port, param.irq, param.membase);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static struct pci_driver t1pci_pci_driver = {
+       .name           = "t1pci",
+       .id_table       = t1pci_pci_tbl,
+       .probe          = t1pci_probe,
+       .remove         = t1pci_remove,
+};
+
+static struct capi_driver capi_driver_t1pci = {
+	.name		= "t1pci",
+	.revision	= "1.0",
+};
+
+static int __init t1pci_init(void)
+{
+	char *p;
+	char rev[32];
+	int err;
+
+	if ((p = strchr(revision, ':')) != 0 && p[1]) {
+		strlcpy(rev, p + 2, 32);
+		if ((p = strchr(rev, '$')) != 0 && p > rev)
+		   *(p-1) = 0;
+	} else
+		strcpy(rev, "1.0");
+
+	err = pci_register_driver(&t1pci_pci_driver);
+	if (!err) {
+		strlcpy(capi_driver_t1pci.revision, rev, 32);
+		register_capi_driver(&capi_driver_t1pci);
+		printk(KERN_INFO "t1pci: revision %s\n", rev);
+	}
+	return err;
+}
+
+static void __exit t1pci_exit(void)
+{
+	unregister_capi_driver(&capi_driver_t1pci);
+	pci_unregister_driver(&t1pci_pci_driver);
+}
+
+module_init(t1pci_init);
+module_exit(t1pci_exit);