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/Kconfig b/drivers/isdn/hardware/Kconfig
new file mode 100644
index 0000000..139f197
--- /dev/null
+++ b/drivers/isdn/hardware/Kconfig
@@ -0,0 +1,10 @@
+#
+# ISDN hardware drivers
+#
+comment "CAPI hardware drivers"
+	depends on NET && ISDN && ISDN_CAPI
+
+source "drivers/isdn/hardware/avm/Kconfig"
+
+source "drivers/isdn/hardware/eicon/Kconfig"
+
diff --git a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile
new file mode 100644
index 0000000..11c8a18
--- /dev/null
+++ b/drivers/isdn/hardware/Makefile
@@ -0,0 +1,6 @@
+# Makefile for the CAPI hardware drivers
+
+# Object files in subdirectories
+
+obj-$(CONFIG_CAPI_AVM)		+= avm/
+obj-$(CONFIG_CAPI_EICON)	+= eicon/
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);
diff --git a/drivers/isdn/hardware/eicon/Kconfig b/drivers/isdn/hardware/eicon/Kconfig
new file mode 100644
index 0000000..51e66bc
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/Kconfig
@@ -0,0 +1,53 @@
+#
+# ISDN DIVAS Eicon driver
+#
+
+menu "Active Eicon DIVA Server cards"
+	depends on NET && ISDN && ISDN_CAPI!=n
+
+config CAPI_EICON
+	bool "Support Eicon cards"
+	help
+	  Enable support for Eicon Networks active ISDN cards.
+
+config ISDN_DIVAS
+	tristate "Support Eicon DIVA Server cards"
+	depends on CAPI_EICON && PROC_FS && PCI
+	help
+	  Say Y here if you have an Eicon Networks DIVA Server PCI ISDN card.
+	  In order to use this card, additional firmware is necessary, which
+	  has to be downloaded into the card using the divactrl utility.
+
+config ISDN_DIVAS_BRIPCI
+	bool "DIVA Server BRI/PCI support"
+	depends on ISDN_DIVAS
+	help
+	  Enable support for DIVA Server BRI-PCI.
+
+config ISDN_DIVAS_PRIPCI
+	bool "DIVA Server PRI/PCI support"
+	depends on ISDN_DIVAS
+	help
+	  Enable support for DIVA Server PRI-PCI.
+
+config ISDN_DIVAS_DIVACAPI
+	tristate "DIVA CAPI2.0 interface support"
+	depends on ISDN_DIVAS && ISDN_CAPI
+	help
+	  You need this to provide the CAPI interface
+	  for DIVA Server cards.
+
+config ISDN_DIVAS_USERIDI
+	tristate "DIVA User-IDI interface support"
+	depends on ISDN_DIVAS
+	help
+	  Enable support for user-mode IDI interface.
+
+config ISDN_DIVAS_MAINT
+	tristate "DIVA Maint driver support"
+	depends on ISDN_DIVAS && m
+	help
+	  Enable Divas Maintainance driver.
+
+endmenu
+
diff --git a/drivers/isdn/hardware/eicon/Makefile b/drivers/isdn/hardware/eicon/Makefile
new file mode 100644
index 0000000..4fa7fdb
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/Makefile
@@ -0,0 +1,23 @@
+# Makefile for the Eicon DIVA ISDN drivers.
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DIVAS)		+= divadidd.o divas.o
+obj-$(CONFIG_ISDN_DIVAS_MAINT)		+= diva_mnt.o
+obj-$(CONFIG_ISDN_DIVAS_USERIDI)	+= diva_idi.o
+obj-$(CONFIG_ISDN_DIVAS_DIVACAPI)	+= divacapi.o
+
+# Multipart objects. 
+
+divas-y					:= divasmain.o divasfunc.o di.o io.o istream.o \
+					   diva.o divasproc.o diva_dma.o
+divas-$(CONFIG_ISDN_DIVAS_BRIPCI)	+= os_bri.o  s_bri.o os_4bri.o s_4bri.o
+divas-$(CONFIG_ISDN_DIVAS_PRIPCI)	+= os_pri.o  s_pri.o
+
+divacapi-y				:= capimain.o capifunc.o message.o capidtmf.o
+
+divadidd-y				:= diva_didd.o diddfunc.o dadapter.o
+
+diva_mnt-y				:= divamnt.o mntfunc.o debug.o maintidi.o
+
+diva_idi-y				:= divasi.o idifunc.o um_idi.o dqueue.o
diff --git a/drivers/isdn/hardware/eicon/adapter.h b/drivers/isdn/hardware/eicon/adapter.h
new file mode 100644
index 0000000..71a7c2f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/adapter.h
@@ -0,0 +1,17 @@
+/* $Id: adapter.h,v 1.4 2004/03/21 17:26:01 armin Exp $ */
+
+#ifndef __DIVA_USER_MODE_IDI_ADAPTER_H__
+#define __DIVA_USER_MODE_IDI_ADAPTER_H__
+
+#define DIVA_UM_IDI_ADAPTER_REMOVED 0x00000001
+
+typedef struct _diva_um_idi_adapter {
+	struct list_head link;
+	DESCRIPTOR d;
+	int adapter_nr;
+	struct list_head entity_q;	/* entities linked to this adapter */
+	dword status;
+} diva_um_idi_adapter_t;
+
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/capi20.h b/drivers/isdn/hardware/eicon/capi20.h
new file mode 100644
index 0000000..7ebcccd
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capi20.h
@@ -0,0 +1,699 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef _INC_CAPI20  
+#define _INC_CAPI20
+        /* operations on message queues                             */
+        /* the common device type for CAPI20 drivers */
+#define FILE_DEVICE_CAPI20 0x8001
+        /* DEVICE_CONTROL codes for user and kernel mode applications */
+#define CAPI20_CTL_REGISTER             0x0801
+#define CAPI20_CTL_RELEASE              0x0802
+#define CAPI20_CTL_GET_MANUFACTURER     0x0805
+#define CAPI20_CTL_GET_VERSION          0x0806
+#define CAPI20_CTL_GET_SERIAL           0x0807
+#define CAPI20_CTL_GET_PROFILE          0x0808
+        /* INTERNAL_DEVICE_CONTROL codes for kernel mode applicatios only */
+#define CAPI20_CTL_PUT_MESSAGE          0x0803
+#define CAPI20_CTL_GET_MESSAGE          0x0804
+        /* the wrapped codes as required by the system */
+#define CAPI_CTL_CODE(f,m)              CTL_CODE(FILE_DEVICE_CAPI20,f,m,FILE_ANY_ACCESS)
+#define IOCTL_CAPI_REGISTER             CAPI_CTL_CODE(CAPI20_CTL_REGISTER,METHOD_BUFFERED)
+#define IOCTL_CAPI_RELEASE              CAPI_CTL_CODE(CAPI20_CTL_RELEASE,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_MANUFACTURER     CAPI_CTL_CODE(CAPI20_CTL_GET_MANUFACTURER,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_VERSION          CAPI_CTL_CODE(CAPI20_CTL_GET_VERSION,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_SERIAL           CAPI_CTL_CODE(CAPI20_CTL_GET_SERIAL,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_PROFILE          CAPI_CTL_CODE(CAPI20_CTL_GET_PROFILE,METHOD_BUFFERED)
+#define IOCTL_CAPI_PUT_MESSAGE          CAPI_CTL_CODE(CAPI20_CTL_PUT_MESSAGE,METHOD_BUFFERED)
+#define IOCTL_CAPI_GET_MESSAGE          CAPI_CTL_CODE(CAPI20_CTL_GET_MESSAGE,METHOD_BUFFERED)
+struct divas_capi_register_params  {
+  word MessageBufferSize;
+  word maxLogicalConnection;
+  word maxBDataBlocks;
+  word maxBDataLen;
+};
+struct divas_capi_version  {
+  word CapiMajor;
+  word CapiMinor;
+  word ManuMajor;
+  word ManuMinor;
+};
+typedef struct api_profile_s {
+  word          Number;
+  word          Channels;
+  dword         Global_Options;
+  dword         B1_Protocols;
+  dword         B2_Protocols;
+  dword         B3_Protocols;
+} API_PROFILE;
+        /* ISDN Common API message types                            */
+#define _ALERT_R                        0x8001
+#define _CONNECT_R                      0x8002
+#define _CONNECT_I                      0x8202
+#define _CONNECT_ACTIVE_I               0x8203
+#define _DISCONNECT_R                   0x8004
+#define _DISCONNECT_I                   0x8204
+#define _LISTEN_R                       0x8005
+#define _INFO_R                         0x8008
+#define _INFO_I                         0x8208
+#define _SELECT_B_REQ                   0x8041
+#define _FACILITY_R                     0x8080
+#define _FACILITY_I                     0x8280
+#define _CONNECT_B3_R                   0x8082
+#define _CONNECT_B3_I                   0x8282
+#define _CONNECT_B3_ACTIVE_I            0x8283
+#define _DISCONNECT_B3_R                0x8084
+#define _DISCONNECT_B3_I                0x8284
+#define _DATA_B3_R                      0x8086
+#define _DATA_B3_I                      0x8286
+#define _RESET_B3_R                     0x8087
+#define _RESET_B3_I                     0x8287
+#define _CONNECT_B3_T90_ACTIVE_I        0x8288
+#define _MANUFACTURER_R                 0x80ff
+#define _MANUFACTURER_I                 0x82ff
+        /* OR this to convert a REQUEST to a CONFIRM                */
+#define CONFIRM                 0x0100
+        /* OR this to convert a INDICATION to a RESPONSE            */
+#define RESPONSE                0x0100
+/*------------------------------------------------------------------*/
+/* diehl isdn private MANUFACTURER codes                            */
+/*------------------------------------------------------------------*/
+#define _DI_MANU_ID             0x44444944
+#define _DI_ASSIGN_PLCI         0x0001
+#define _DI_ADV_CODEC           0x0002
+#define _DI_DSP_CTRL            0x0003
+#define _DI_SIG_CTRL            0x0004
+#define _DI_RXT_CTRL            0x0005
+#define _DI_IDI_CTRL            0x0006
+#define _DI_CFG_CTRL            0x0007
+#define _DI_REMOVE_CODEC        0x0008
+#define _DI_OPTIONS_REQUEST     0x0009
+#define _DI_SSEXT_CTRL          0x000a
+#define _DI_NEGOTIATE_B3        0x000b
+/*------------------------------------------------------------------*/
+/* parameter structures                                             */
+/*------------------------------------------------------------------*/
+        /* ALERT-REQUEST                                            */
+typedef struct {
+  byte structs[1];      /* Additional Info */
+} _ALT_REQP;
+        /* ALERT-CONFIRM                                            */
+typedef struct {
+  word Info;
+} _ALT_CONP;
+        /* CONNECT-REQUEST                                          */
+typedef struct {
+  word CIP_Value;
+  byte structs[1];      /* Called party number,
+                           Called party subaddress,
+                           Calling party number,
+                           Calling party subaddress,
+                           B_protocol,
+                           BC,
+                           LLC,
+                           HLC,
+                           Additional Info */
+} _CON_REQP;
+        /* CONNECT-CONFIRM                                          */
+typedef struct {
+  word Info;
+} _CON_CONP;
+        /* CONNECT-INDICATION                                       */
+typedef struct {
+  word CIP_Value;
+  byte structs[1];      /* Called party number,
+                           Called party subaddress,
+                           Calling party number,
+                           Calling party subaddress,
+                           BC,
+                           LLC,
+                           HLC,
+                           Additional Info */
+} _CON_INDP;
+        /* CONNECT-RESPONSE                                         */
+typedef struct {
+  word Accept;
+  byte structs[1];      /* B_protocol,
+                           Connected party number,
+                           Connected party subaddress,
+                           LLC */
+} _CON_RESP;
+        /* CONNECT-ACTIVE-INDICATION                                */
+typedef struct {
+  byte structs[1];      /* Connected party number,
+                           Connected party subaddress,
+                           LLC */
+} _CON_A_INDP;
+        /* CONNECT-ACTIVE-RESPONSE                                  */
+typedef struct {
+  byte structs[1];      /* empty */
+} _CON_A_RESP;
+        /* DISCONNECT-REQUEST                                       */
+typedef struct {
+  byte structs[1];      /* Additional Info */
+} _DIS_REQP;
+        /* DISCONNECT-CONFIRM                                       */
+typedef struct {
+  word Info;
+} _DIS_CONP;
+        /* DISCONNECT-INDICATION                                    */
+typedef struct {
+  word Info;
+} _DIS_INDP;
+        /* DISCONNECT-RESPONSE                                      */
+typedef struct {
+  byte structs[1];      /* empty */
+} _DIS_RESP;
+        /* LISTEN-REQUEST                                           */
+typedef struct {
+  dword Info_Mask;
+  dword CIP_Mask;
+  byte structs[1];      /* Calling party number,
+                           Calling party subaddress */
+} _LIS_REQP;
+        /* LISTEN-CONFIRM                                           */
+typedef struct {
+  word Info;
+} _LIS_CONP;
+        /* INFO-REQUEST                                             */
+typedef struct {
+  byte structs[1];      /* Called party number,
+                           Additional Info */
+} _INF_REQP;
+        /* INFO-CONFIRM                                             */
+typedef struct {
+  word Info;
+} _INF_CONP;
+        /* INFO-INDICATION                                          */
+typedef struct {
+  word Number;
+  byte structs[1];      /* Info element */
+} _INF_INDP;
+        /* INFO-RESPONSE                                            */
+typedef struct {
+  byte structs[1];      /* empty */
+} _INF_RESP;
+        /* SELECT-B-REQUEST                                         */
+typedef struct {
+  byte structs[1];      /* B-protocol */
+} _SEL_B_REQP;
+        /* SELECT-B-CONFIRM                                         */
+typedef struct {
+  word Info;
+} _SEL_B_CONP;
+        /* FACILITY-REQUEST */
+typedef struct {
+  word Selector;
+  byte structs[1];      /* Facility parameters */
+} _FAC_REQP;
+        /* FACILITY-CONFIRM STRUCT FOR SUPPLEMENT. SERVICES */
+typedef struct {
+  byte  struct_length;
+  word  function;
+  byte  length;
+  word  SupplementaryServiceInfo;
+  dword SupportedServices;
+} _FAC_CON_STRUCTS;
+        /* FACILITY-CONFIRM */
+typedef struct {
+  word Info;
+  word Selector;
+  byte structs[1];      /* Facility parameters */
+} _FAC_CONP;
+        /* FACILITY-INDICATION */
+typedef struct {
+  word Selector;
+  byte structs[1];      /* Facility parameters */
+} _FAC_INDP;
+        /* FACILITY-RESPONSE */
+typedef struct {
+  word Selector;
+  byte structs[1];      /* Facility parameters */
+} _FAC_RESP;
+        /* CONNECT-B3-REQUEST                                       */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _CON_B3_REQP;
+        /* CONNECT-B3-CONFIRM                                       */
+typedef struct {
+  word Info;
+} _CON_B3_CONP;
+        /* CONNECT-B3-INDICATION                                    */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _CON_B3_INDP;
+        /* CONNECT-B3-RESPONSE                                      */
+typedef struct {
+  word Accept;
+  byte structs[1];      /* NCPI */
+} _CON_B3_RESP;
+        /* CONNECT-B3-ACTIVE-INDICATION                             */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _CON_B3_A_INDP;
+        /* CONNECT-B3-ACTIVE-RESPONSE                               */
+typedef struct {
+  byte structs[1];      /* empty */
+} _CON_B3_A_RESP;
+        /* DISCONNECT-B3-REQUEST                                    */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _DIS_B3_REQP;
+        /* DISCONNECT-B3-CONFIRM                                    */
+typedef struct {
+  word Info;
+} _DIS_B3_CONP;
+        /* DISCONNECT-B3-INDICATION                                 */
+typedef struct {
+  word Info;
+  byte structs[1];      /* NCPI */
+} _DIS_B3_INDP;
+        /* DISCONNECT-B3-RESPONSE                                   */
+typedef struct {
+  byte structs[1];      /* empty */
+} _DIS_B3_RESP;
+        /* DATA-B3-REQUEST                                          */
+typedef struct {
+  dword         Data;
+  word          Data_Length;
+  word          Number;
+  word          Flags;
+} _DAT_B3_REQP;
+        /* DATA-B3-REQUEST 64 BIT Systems                           */
+typedef struct {
+  dword         Data;
+  word          Data_Length;
+  word          Number;
+  word          Flags;
+  void          *pData;
+} _DAT_B3_REQ64P;
+        /* DATA-B3-CONFIRM                                          */
+typedef struct {
+  word          Number;
+  word          Info;
+} _DAT_B3_CONP;
+        /* DATA-B3-INDICATION                                       */
+typedef struct {
+  dword         Data;
+  word          Data_Length;
+  word          Number;
+  word          Flags;
+} _DAT_B3_INDP;
+        /* DATA-B3-INDICATION  64 BIT Systems                       */
+typedef struct {
+  dword         Data;
+  word          Data_Length;
+  word          Number;
+  word          Flags;
+  void          *pData;
+} _DAT_B3_IND64P;
+        /* DATA-B3-RESPONSE                                         */
+typedef struct {
+  word          Number;
+} _DAT_B3_RESP;
+        /* RESET-B3-REQUEST                                         */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _RES_B3_REQP;
+        /* RESET-B3-CONFIRM                                         */
+typedef struct {
+  word Info;
+} _RES_B3_CONP;
+        /* RESET-B3-INDICATION                                      */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _RES_B3_INDP;
+        /* RESET-B3-RESPONSE                                        */
+typedef struct {
+  byte structs[1];      /* empty */
+} _RES_B3_RESP;
+        /* CONNECT-B3-T90-ACTIVE-INDICATION                         */
+typedef struct {
+  byte structs[1];      /* NCPI */
+} _CON_B3_T90_A_INDP;
+        /* CONNECT-B3-T90-ACTIVE-RESPONSE                           */
+typedef struct {
+  word Reject;
+  byte structs[1];      /* NCPI */
+} _CON_B3_T90_A_RESP;
+/*------------------------------------------------------------------*/
+/* message structure                                                */
+/*------------------------------------------------------------------*/
+typedef struct _API_MSG CAPI_MSG;
+typedef struct _MSG_HEADER CAPI_MSG_HEADER;
+struct _API_MSG {
+  struct _MSG_HEADER {
+    word        length;
+    word        appl_id;
+    word        command;
+    word        number;
+    byte        controller;
+    byte        plci;
+    word        ncci;
+  } header;
+  union {
+    _ALT_REQP           alert_req;
+    _ALT_CONP           alert_con;
+    _CON_REQP           connect_req;
+    _CON_CONP           connect_con;
+    _CON_INDP           connect_ind;
+    _CON_RESP           connect_res;
+    _CON_A_INDP         connect_a_ind;
+    _CON_A_RESP         connect_a_res;
+    _DIS_REQP           disconnect_req;
+    _DIS_CONP           disconnect_con;
+    _DIS_INDP           disconnect_ind;
+    _DIS_RESP           disconnect_res;
+    _LIS_REQP           listen_req;
+    _LIS_CONP           listen_con;
+    _INF_REQP           info_req;
+    _INF_CONP           info_con;
+    _INF_INDP           info_ind;
+    _INF_RESP           info_res;
+    _SEL_B_REQP         select_b_req;
+    _SEL_B_CONP         select_b_con;
+    _FAC_REQP           facility_req;
+    _FAC_CONP           facility_con;
+    _FAC_INDP           facility_ind;
+    _FAC_RESP           facility_res;
+    _CON_B3_REQP        connect_b3_req;
+    _CON_B3_CONP        connect_b3_con;
+    _CON_B3_INDP        connect_b3_ind;
+    _CON_B3_RESP        connect_b3_res;
+    _CON_B3_A_INDP      connect_b3_a_ind;
+    _CON_B3_A_RESP      connect_b3_a_res;
+    _DIS_B3_REQP        disconnect_b3_req;
+    _DIS_B3_CONP        disconnect_b3_con;
+    _DIS_B3_INDP        disconnect_b3_ind;
+    _DIS_B3_RESP        disconnect_b3_res;
+    _DAT_B3_REQP        data_b3_req;
+    _DAT_B3_REQ64P      data_b3_req64;
+    _DAT_B3_CONP        data_b3_con;
+    _DAT_B3_INDP        data_b3_ind;
+    _DAT_B3_IND64P      data_b3_ind64;
+    _DAT_B3_RESP        data_b3_res;
+    _RES_B3_REQP        reset_b3_req;
+    _RES_B3_CONP        reset_b3_con;
+    _RES_B3_INDP        reset_b3_ind;
+    _RES_B3_RESP        reset_b3_res;
+    _CON_B3_T90_A_INDP  connect_b3_t90_a_ind;
+    _CON_B3_T90_A_RESP  connect_b3_t90_a_res;
+    byte                b[200];
+  } info;
+};
+/*------------------------------------------------------------------*/
+/* non-fatal errors                                                 */
+/*------------------------------------------------------------------*/
+#define _NCPI_IGNORED           0x0001
+#define _FLAGS_IGNORED          0x0002
+#define _ALERT_IGNORED          0x0003
+/*------------------------------------------------------------------*/
+/* API function error codes                                         */
+/*------------------------------------------------------------------*/
+#define GOOD                            0x0000
+#define _TOO_MANY_APPLICATIONS          0x1001
+#define _BLOCK_TOO_SMALL                0x1002
+#define _BUFFER_TOO_BIG                 0x1003
+#define _MSG_BUFFER_TOO_SMALL           0x1004
+#define _TOO_MANY_CONNECTIONS           0x1005
+#define _REG_CAPI_BUSY                  0x1007
+#define _REG_RESOURCE_ERROR             0x1008
+#define _REG_CAPI_NOT_INSTALLED         0x1009
+#define _WRONG_APPL_ID                  0x1101
+#define _BAD_MSG                        0x1102
+#define _QUEUE_FULL                     0x1103
+#define _GET_NO_MSG                     0x1104
+#define _MSG_LOST                       0x1105
+#define _WRONG_NOTIFY                   0x1106
+#define _CAPI_BUSY                      0x1107
+#define _RESOURCE_ERROR                 0x1108
+#define _CAPI_NOT_INSTALLED             0x1109
+#define _NO_EXTERNAL_EQUIPMENT          0x110a
+#define _ONLY_EXTERNAL_EQUIPMENT        0x110b
+/*------------------------------------------------------------------*/
+/* addressing/coding error codes                                    */
+/*------------------------------------------------------------------*/
+#define _WRONG_STATE                    0x2001
+#define _WRONG_IDENTIFIER               0x2002
+#define _OUT_OF_PLCI                    0x2003
+#define _OUT_OF_NCCI                    0x2004
+#define _OUT_OF_LISTEN                  0x2005
+#define _OUT_OF_FAX                     0x2006
+#define _WRONG_MESSAGE_FORMAT           0x2007
+#define _OUT_OF_INTERCONNECT_RESOURCES  0x2008
+/*------------------------------------------------------------------*/
+/* configuration error codes                                        */
+/*------------------------------------------------------------------*/
+#define _B1_NOT_SUPPORTED                    0x3001
+#define _B2_NOT_SUPPORTED                    0x3002
+#define _B3_NOT_SUPPORTED                    0x3003
+#define _B1_PARM_NOT_SUPPORTED               0x3004
+#define _B2_PARM_NOT_SUPPORTED               0x3005
+#define _B3_PARM_NOT_SUPPORTED               0x3006
+#define _B_STACK_NOT_SUPPORTED               0x3007
+#define _NCPI_NOT_SUPPORTED                  0x3008
+#define _CIP_NOT_SUPPORTED                   0x3009
+#define _FLAGS_NOT_SUPPORTED                 0x300a
+#define _FACILITY_NOT_SUPPORTED              0x300b
+#define _DATA_LEN_NOT_SUPPORTED              0x300c
+#define _RESET_NOT_SUPPORTED                 0x300d
+#define _SUPPLEMENTARY_SERVICE_NOT_SUPPORTED 0x300e
+#define _REQUEST_NOT_ALLOWED_IN_THIS_STATE   0x3010
+#define _FACILITY_SPECIFIC_FUNCTION_NOT_SUPP 0x3011
+/*------------------------------------------------------------------*/
+/* reason codes                                                     */
+/*------------------------------------------------------------------*/
+#define _L1_ERROR                       0x3301
+#define _L2_ERROR                       0x3302
+#define _L3_ERROR                       0x3303
+#define _OTHER_APPL_CONNECTED           0x3304
+#define _CAPI_GUARD_ERROR               0x3305
+#define _L3_CAUSE                       0x3400
+/*------------------------------------------------------------------*/
+/* b3 reason codes                                                  */
+/*------------------------------------------------------------------*/
+#define _B_CHANNEL_LOST                 0x3301
+#define _B2_ERROR                       0x3302
+#define _B3_ERROR                       0x3303
+/*------------------------------------------------------------------*/
+/* fax error codes                                                  */
+/*------------------------------------------------------------------*/
+#define _FAX_NO_CONNECTION              0x3311
+#define _FAX_TRAINING_ERROR             0x3312
+#define _FAX_REMOTE_REJECT              0x3313
+#define _FAX_REMOTE_ABORT               0x3314
+#define _FAX_PROTOCOL_ERROR             0x3315
+#define _FAX_TX_UNDERRUN                0x3316
+#define _FAX_RX_OVERFLOW                0x3317
+#define _FAX_LOCAL_ABORT                0x3318
+#define _FAX_PARAMETER_ERROR            0x3319
+/*------------------------------------------------------------------*/
+/* line interconnect error codes                                    */
+/*------------------------------------------------------------------*/
+#define _LI_USER_INITIATED               0x0000
+#define _LI_LINE_NO_LONGER_AVAILABLE     0x3805
+#define _LI_INTERCONNECT_NOT_ESTABLISHED 0x3806
+#define _LI_LINES_NOT_COMPATIBLE         0x3807
+#define _LI2_USER_INITIATED              0x0000
+#define _LI2_PLCI_HAS_NO_BCHANNEL        0x3800
+#define _LI2_LINES_NOT_COMPATIBLE        0x3801
+#define _LI2_NOT_IN_SAME_INTERCONNECTION 0x3802
+/*------------------------------------------------------------------*/
+/* global options                                                   */
+/*------------------------------------------------------------------*/
+#define GL_INTERNAL_CONTROLLER_SUPPORTED     0x00000001L
+#define GL_EXTERNAL_EQUIPMENT_SUPPORTED      0x00000002L
+#define GL_HANDSET_SUPPORTED                 0x00000004L
+#define GL_DTMF_SUPPORTED                    0x00000008L
+#define GL_SUPPLEMENTARY_SERVICES_SUPPORTED  0x00000010L
+#define GL_CHANNEL_ALLOCATION_SUPPORTED      0x00000020L
+#define GL_BCHANNEL_OPERATION_SUPPORTED      0x00000040L
+#define GL_LINE_INTERCONNECT_SUPPORTED       0x00000080L
+#define GL_ECHO_CANCELLER_SUPPORTED          0x00000100L
+/*------------------------------------------------------------------*/
+/* protocol selection                                               */
+/*------------------------------------------------------------------*/
+#define B1_HDLC                 0
+#define B1_TRANSPARENT          1
+#define B1_V110_ASYNC           2
+#define B1_V110_SYNC            3
+#define B1_T30                  4
+#define B1_HDLC_INVERTED        5
+#define B1_TRANSPARENT_R        6
+#define B1_MODEM_ALL_NEGOTIATE  7
+#define B1_MODEM_ASYNC          8
+#define B1_MODEM_SYNC_HDLC      9
+#define B2_X75                  0
+#define B2_TRANSPARENT          1
+#define B2_SDLC                 2
+#define B2_LAPD                 3
+#define B2_T30                  4
+#define B2_PPP                  5
+#define B2_TRANSPARENT_NO_CRC   6
+#define B2_MODEM_EC_COMPRESSION 7
+#define B2_X75_V42BIS           8
+#define B2_V120_ASYNC           9
+#define B2_V120_ASYNC_V42BIS    10
+#define B2_V120_BIT_TRANSPARENT 11
+#define B2_LAPD_FREE_SAPI_SEL   12
+#define B3_TRANSPARENT          0
+#define B3_T90NL                1
+#define B3_ISO8208              2
+#define B3_X25_DCE              3
+#define B3_T30                  4
+#define B3_T30_WITH_EXTENSIONS  5
+#define B3_RESERVED             6
+#define B3_MODEM                7
+/*------------------------------------------------------------------*/
+/*  facility definitions                                            */
+/*------------------------------------------------------------------*/
+#define SELECTOR_HANDSET            0
+#define SELECTOR_DTMF               1
+#define SELECTOR_V42BIS             2
+#define SELECTOR_SU_SERV            3
+#define SELECTOR_POWER_MANAGEMENT   4
+#define SELECTOR_LINE_INTERCONNECT  5
+#define SELECTOR_ECHO_CANCELLER     6
+/*------------------------------------------------------------------*/
+/*  supplementary services definitions                              */
+/*------------------------------------------------------------------*/
+#define S_GET_SUPPORTED_SERVICES  0x0000
+#define S_LISTEN                  0x0001
+#define S_HOLD                    0x0002
+#define S_RETRIEVE                0x0003
+#define S_SUSPEND                 0x0004
+#define S_RESUME                  0x0005
+#define S_ECT                     0x0006
+#define S_3PTY_BEGIN              0x0007
+#define S_3PTY_END                0x0008
+#define S_CALL_DEFLECTION         0x000d
+#define S_CALL_FORWARDING_START   0x0009
+#define S_CALL_FORWARDING_STOP    0x000a
+#define S_INTERROGATE_DIVERSION   0x000b /* or interrogate parameters */
+#define S_INTERROGATE_NUMBERS     0x000c
+#define S_CCBS_REQUEST            0x000f
+#define S_CCBS_DEACTIVATE         0x0010
+#define S_CCBS_INTERROGATE        0x0011
+#define S_CCBS_CALL               0x0012
+#define S_MWI_ACTIVATE            0x0013
+#define S_MWI_DEACTIVATE          0x0014
+#define S_CONF_BEGIN           0x0017
+#define S_CONF_ADD                0x0018
+#define S_CONF_SPLIT           0x0019
+#define S_CONF_DROP               0x001a
+#define S_CONF_ISOLATE           0x001b
+#define S_CONF_REATTACH           0x001c
+#define S_CCBS_ERASECALLLINKAGEID 0x800d
+#define S_CCBS_STOP_ALERTING      0x8012
+#define S_CCBS_INFO_RETAIN        0x8013
+#define S_MWI_INDICATE            0x8014
+#define S_CONF_PARTYDISC          0x8016
+#define S_CONF_NOTIFICATION       0x8017
+/* Service Masks */
+#define MASK_HOLD_RETRIEVE        0x00000001
+#define MASK_TERMINAL_PORTABILITY 0x00000002
+#define MASK_ECT                  0x00000004
+#define MASK_3PTY                 0x00000008
+#define MASK_CALL_FORWARDING      0x00000010
+#define MASK_CALL_DEFLECTION      0x00000020
+#define MASK_MWI                  0x00000100
+#define MASK_CCNR                 0x00000200
+#define MASK_CONF                 0x00000400
+/*------------------------------------------------------------------*/
+/*  dtmf definitions                                                */
+/*------------------------------------------------------------------*/
+#define DTMF_LISTEN_START     1
+#define DTMF_LISTEN_STOP      2
+#define DTMF_DIGITS_SEND      3
+#define DTMF_SUCCESS          0
+#define DTMF_INCORRECT_DIGIT  1
+#define DTMF_UNKNOWN_REQUEST  2
+/*------------------------------------------------------------------*/
+/*  line interconnect definitions                                   */
+/*------------------------------------------------------------------*/
+#define LI_GET_SUPPORTED_SERVICES       0
+#define LI_REQ_CONNECT                  1
+#define LI_REQ_DISCONNECT               2
+#define LI_IND_CONNECT_ACTIVE           1
+#define LI_IND_DISCONNECT               2
+#define LI_FLAG_CONFERENCE_A_B          ((dword) 0x00000001L)
+#define LI_FLAG_CONFERENCE_B_A          ((dword) 0x00000002L)
+#define LI_FLAG_MONITOR_A               ((dword) 0x00000004L)
+#define LI_FLAG_MONITOR_B               ((dword) 0x00000008L)
+#define LI_FLAG_ANNOUNCEMENT_A          ((dword) 0x00000010L)
+#define LI_FLAG_ANNOUNCEMENT_B          ((dword) 0x00000020L)
+#define LI_FLAG_MIX_A                   ((dword) 0x00000040L)
+#define LI_FLAG_MIX_B                   ((dword) 0x00000080L)
+#define LI_CONFERENCING_SUPPORTED       ((dword) 0x00000001L)
+#define LI_MONITORING_SUPPORTED         ((dword) 0x00000002L)
+#define LI_ANNOUNCEMENTS_SUPPORTED      ((dword) 0x00000004L)
+#define LI_MIXING_SUPPORTED             ((dword) 0x00000008L)
+#define LI_CROSS_CONTROLLER_SUPPORTED   ((dword) 0x00000010L)
+#define LI2_GET_SUPPORTED_SERVICES      0
+#define LI2_REQ_CONNECT                 1
+#define LI2_REQ_DISCONNECT              2
+#define LI2_IND_CONNECT_ACTIVE          1
+#define LI2_IND_DISCONNECT              2
+#define LI2_FLAG_INTERCONNECT_A_B       ((dword) 0x00000001L)
+#define LI2_FLAG_INTERCONNECT_B_A       ((dword) 0x00000002L)
+#define LI2_FLAG_MONITOR_B              ((dword) 0x00000004L)
+#define LI2_FLAG_MIX_B                  ((dword) 0x00000008L)
+#define LI2_FLAG_MONITOR_X              ((dword) 0x00000010L)
+#define LI2_FLAG_MIX_X                  ((dword) 0x00000020L)
+#define LI2_FLAG_LOOP_B                 ((dword) 0x00000040L)
+#define LI2_FLAG_LOOP_PC                ((dword) 0x00000080L)
+#define LI2_FLAG_LOOP_X                 ((dword) 0x00000100L)
+#define LI2_CROSS_CONTROLLER_SUPPORTED  ((dword) 0x00000001L)
+#define LI2_ASYMMETRIC_SUPPORTED        ((dword) 0x00000002L)
+#define LI2_MONITORING_SUPPORTED        ((dword) 0x00000004L)
+#define LI2_MIXING_SUPPORTED            ((dword) 0x00000008L)
+#define LI2_REMOTE_MONITORING_SUPPORTED ((dword) 0x00000010L)
+#define LI2_REMOTE_MIXING_SUPPORTED     ((dword) 0x00000020L)
+#define LI2_B_LOOPING_SUPPORTED         ((dword) 0x00000040L)
+#define LI2_PC_LOOPING_SUPPORTED        ((dword) 0x00000080L)
+#define LI2_X_LOOPING_SUPPORTED         ((dword) 0x00000100L)
+/*------------------------------------------------------------------*/
+/* echo canceller definitions                                       */
+/*------------------------------------------------------------------*/
+#define EC_GET_SUPPORTED_SERVICES            0
+#define EC_ENABLE_OPERATION                  1
+#define EC_DISABLE_OPERATION                 2
+#define EC_ENABLE_NON_LINEAR_PROCESSING      0x0001
+#define EC_DO_NOT_REQUIRE_REVERSALS          0x0002
+#define EC_DETECT_DISABLE_TONE               0x0004
+#define EC_ENABLE_ADAPTIVE_PREDELAY          0x0008
+#define EC_NON_LINEAR_PROCESSING_SUPPORTED   0x0001
+#define EC_BYPASS_ON_ANY_2100HZ_SUPPORTED    0x0002
+#define EC_BYPASS_ON_REV_2100HZ_SUPPORTED    0x0004
+#define EC_ADAPTIVE_PREDELAY_SUPPORTED       0x0008
+#define EC_BYPASS_INDICATION                 1
+#define EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ   1
+#define EC_BYPASS_DUE_TO_REVERSED_2100HZ     2
+#define EC_BYPASS_RELEASED                   3
+/*------------------------------------------------------------------*/
+/* function prototypes                                              */
+/*------------------------------------------------------------------*/
+/*------------------------------------------------------------------*/
+#endif /* _INC_CAPI20 */  
diff --git a/drivers/isdn/hardware/eicon/capidtmf.c b/drivers/isdn/hardware/eicon/capidtmf.c
new file mode 100644
index 0000000..f130724
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capidtmf.c
@@ -0,0 +1,685 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "platform.h"
+
+
+  
+  
+
+
+
+
+
+#include "capidtmf.h"
+
+/* #define TRACE_ */
+
+#define FILE_ "CAPIDTMF.C"
+
+/*---------------------------------------------------------------------------*/
+
+
+#define trace(a)
+
+
+
+/*---------------------------------------------------------------------------*/
+
+static short capidtmf_expand_table_alaw[0x0100] =
+{
+   -5504,   5504,   -344,    344, -22016,  22016,  -1376,   1376,
+   -2752,   2752,    -88,     88, -11008,  11008,   -688,    688,
+   -7552,   7552,   -472,    472, -30208,  30208,  -1888,   1888,
+   -3776,   3776,   -216,    216, -15104,  15104,   -944,    944,
+   -4480,   4480,   -280,    280, -17920,  17920,  -1120,   1120,
+   -2240,   2240,    -24,     24,  -8960,   8960,   -560,    560,
+   -6528,   6528,   -408,    408, -26112,  26112,  -1632,   1632,
+   -3264,   3264,   -152,    152, -13056,  13056,   -816,    816,
+   -6016,   6016,   -376,    376, -24064,  24064,  -1504,   1504,
+   -3008,   3008,   -120,    120, -12032,  12032,   -752,    752,
+   -8064,   8064,   -504,    504, -32256,  32256,  -2016,   2016,
+   -4032,   4032,   -248,    248, -16128,  16128,  -1008,   1008,
+   -4992,   4992,   -312,    312, -19968,  19968,  -1248,   1248,
+   -2496,   2496,    -56,     56,  -9984,   9984,   -624,    624,
+   -7040,   7040,   -440,    440, -28160,  28160,  -1760,   1760,
+   -3520,   3520,   -184,    184, -14080,  14080,   -880,    880,
+   -5248,   5248,   -328,    328, -20992,  20992,  -1312,   1312,
+   -2624,   2624,    -72,     72, -10496,  10496,   -656,    656,
+   -7296,   7296,   -456,    456, -29184,  29184,  -1824,   1824,
+   -3648,   3648,   -200,    200, -14592,  14592,   -912,    912,
+   -4224,   4224,   -264,    264, -16896,  16896,  -1056,   1056,
+   -2112,   2112,     -8,      8,  -8448,   8448,   -528,    528,
+   -6272,   6272,   -392,    392, -25088,  25088,  -1568,   1568,
+   -3136,   3136,   -136,    136, -12544,  12544,   -784,    784,
+   -5760,   5760,   -360,    360, -23040,  23040,  -1440,   1440,
+   -2880,   2880,   -104,    104, -11520,  11520,   -720,    720,
+   -7808,   7808,   -488,    488, -31232,  31232,  -1952,   1952,
+   -3904,   3904,   -232,    232, -15616,  15616,   -976,    976,
+   -4736,   4736,   -296,    296, -18944,  18944,  -1184,   1184,
+   -2368,   2368,    -40,     40,  -9472,   9472,   -592,    592,
+   -6784,   6784,   -424,    424, -27136,  27136,  -1696,   1696,
+   -3392,   3392,   -168,    168, -13568,  13568,   -848,    848
+};
+
+static short capidtmf_expand_table_ulaw[0x0100] =
+{
+  -32124,  32124,  -1884,   1884,  -7932,   7932,   -372,    372,
+  -15996,  15996,   -876,    876,  -3900,   3900,   -120,    120,
+  -23932,  23932,  -1372,   1372,  -5884,   5884,   -244,    244,
+  -11900,  11900,   -620,    620,  -2876,   2876,    -56,     56,
+  -28028,  28028,  -1628,   1628,  -6908,   6908,   -308,    308,
+  -13948,  13948,   -748,    748,  -3388,   3388,    -88,     88,
+  -19836,  19836,  -1116,   1116,  -4860,   4860,   -180,    180,
+   -9852,   9852,   -492,    492,  -2364,   2364,    -24,     24,
+  -30076,  30076,  -1756,   1756,  -7420,   7420,   -340,    340,
+  -14972,  14972,   -812,    812,  -3644,   3644,   -104,    104,
+  -21884,  21884,  -1244,   1244,  -5372,   5372,   -212,    212,
+  -10876,  10876,   -556,    556,  -2620,   2620,    -40,     40,
+  -25980,  25980,  -1500,   1500,  -6396,   6396,   -276,    276,
+  -12924,  12924,   -684,    684,  -3132,   3132,    -72,     72,
+  -17788,  17788,   -988,    988,  -4348,   4348,   -148,    148,
+   -8828,   8828,   -428,    428,  -2108,   2108,     -8,      8,
+  -31100,  31100,  -1820,   1820,  -7676,   7676,   -356,    356,
+  -15484,  15484,   -844,    844,  -3772,   3772,   -112,    112,
+  -22908,  22908,  -1308,   1308,  -5628,   5628,   -228,    228,
+  -11388,  11388,   -588,    588,  -2748,   2748,    -48,     48,
+  -27004,  27004,  -1564,   1564,  -6652,   6652,   -292,    292,
+  -13436,  13436,   -716,    716,  -3260,   3260,    -80,     80,
+  -18812,  18812,  -1052,   1052,  -4604,   4604,   -164,    164,
+   -9340,   9340,   -460,    460,  -2236,   2236,    -16,     16,
+  -29052,  29052,  -1692,   1692,  -7164,   7164,   -324,    324,
+  -14460,  14460,   -780,    780,  -3516,   3516,    -96,     96,
+  -20860,  20860,  -1180,   1180,  -5116,   5116,   -196,    196,
+  -10364,  10364,   -524,    524,  -2492,   2492,    -32,     32,
+  -24956,  24956,  -1436,   1436,  -6140,   6140,   -260,    260,
+  -12412,  12412,   -652,    652,  -3004,   3004,    -64,     64,
+  -16764,  16764,   -924,    924,  -4092,   4092,   -132,    132,
+   -8316,   8316,   -396,    396,  -1980,   1980,      0,      0
+};
+
+
+/*---------------------------------------------------------------------------*/
+
+static short capidtmf_recv_window_function[CAPIDTMF_RECV_ACCUMULATE_CYCLES] =
+{
+    -500L,   -999L,  -1499L,  -1998L,  -2496L,  -2994L,  -3491L,  -3988L,
+   -4483L,  -4978L,  -5471L,  -5963L,  -6454L,  -6943L,  -7431L,  -7917L,
+   -8401L,  -8883L,  -9363L,  -9840L, -10316L, -10789L, -11259L, -11727L,
+  -12193L, -12655L, -13115L, -13571L, -14024L, -14474L, -14921L, -15364L,
+  -15804L, -16240L, -16672L, -17100L, -17524L, -17944L, -18360L, -18772L,
+  -19180L, -19583L, -19981L, -20375L, -20764L, -21148L, -21527L, -21901L,
+  -22270L, -22634L, -22993L, -23346L, -23694L, -24037L, -24374L, -24705L,
+  -25030L, -25350L, -25664L, -25971L, -26273L, -26568L, -26858L, -27141L,
+  -27418L, -27688L, -27952L, -28210L, -28461L, -28705L, -28943L, -29174L,
+  -29398L, -29615L, -29826L, -30029L, -30226L, -30415L, -30598L, -30773L,
+  -30941L, -31102L, -31256L, -31402L, -31541L, -31673L, -31797L, -31914L,
+  -32024L, -32126L, -32221L, -32308L, -32388L, -32460L, -32524L, -32581L,
+  -32631L, -32673L, -32707L, -32734L, -32753L, -32764L, -32768L, -32764L,
+  -32753L, -32734L, -32707L, -32673L, -32631L, -32581L, -32524L, -32460L,
+  -32388L, -32308L, -32221L, -32126L, -32024L, -31914L, -31797L, -31673L,
+  -31541L, -31402L, -31256L, -31102L, -30941L, -30773L, -30598L, -30415L,
+  -30226L, -30029L, -29826L, -29615L, -29398L, -29174L, -28943L, -28705L,
+  -28461L, -28210L, -27952L, -27688L, -27418L, -27141L, -26858L, -26568L,
+  -26273L, -25971L, -25664L, -25350L, -25030L, -24705L, -24374L, -24037L,
+  -23694L, -23346L, -22993L, -22634L, -22270L, -21901L, -21527L, -21148L,
+  -20764L, -20375L, -19981L, -19583L, -19180L, -18772L, -18360L, -17944L,
+  -17524L, -17100L, -16672L, -16240L, -15804L, -15364L, -14921L, -14474L,
+  -14024L, -13571L, -13115L, -12655L, -12193L, -11727L, -11259L, -10789L,
+  -10316L,  -9840L,  -9363L,  -8883L,  -8401L,  -7917L,  -7431L,  -6943L,
+   -6454L,  -5963L,  -5471L,  -4978L,  -4483L,  -3988L,  -3491L,  -2994L,
+   -2496L,  -1998L,  -1499L,   -999L,   -500L, 
+};
+
+static byte capidtmf_leading_zeroes_table[0x100] =
+{
+  8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+#define capidtmf_byte_leading_zeroes(b)  (capidtmf_leading_zeroes_table[(BYTE)(b)])
+#define capidtmf_word_leading_zeroes(w)  (((w) & 0xff00) ? capidtmf_leading_zeroes_table[(w) >> 8] : 8 + capidtmf_leading_zeroes_table[(w)])
+#define capidtmf_dword_leading_zeroes(d)  (((d) & 0xffff0000L) ?    (((d) & 0xff000000L) ? capidtmf_leading_zeroes_table[(d) >> 24] : 8 + capidtmf_leading_zeroes_table[(d) >> 16]) :    (((d) & 0xff00) ? 16 + capidtmf_leading_zeroes_table[(d) >> 8] : 24 + capidtmf_leading_zeroes_table[(d)]))
+
+
+/*---------------------------------------------------------------------------*/
+
+
+static void capidtmf_goertzel_loop (long *buffer, long *coeffs, short *sample, long count)
+{
+  int i, j;
+  long c, d, q0, q1, q2;
+
+  for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - 1; i++)
+  {
+    q1 = buffer[i];
+    q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+    d = coeffs[i] >> 1;
+    c = d << 1;
+    if (c >= 0)
+    {
+      for (j = 0; j < count; j++)
+      {
+        q0 = sample[j] - q2 + (c * (q1 >> 16)) + (((dword)(((dword) d) * ((dword)(q1 & 0xffff)))) >> 15);
+        q2 = q1;
+        q1 = q0;
+      }
+    }
+    else
+    {
+      c = -c;
+      d = -d;
+      for (j = 0; j < count; j++)
+      {
+        q0 = sample[j] - q2 - ((c * (q1 >> 16)) + (((dword)(((dword) d) * ((dword)(q1 & 0xffff)))) >> 15));
+        q2 = q1;
+        q1 = q0;
+      }
+    }
+    buffer[i] = q1;
+    buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = q2;
+  }
+  q1 = buffer[i];
+  q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+  c = (coeffs[i] >> 1) << 1;
+  if (c >= 0)
+  {
+    for (j = 0; j < count; j++)
+    {
+      q0 = sample[j] - q2 + (c * (q1 >> 16)) + (((dword)(((dword)(c >> 1)) * ((dword)(q1 & 0xffff)))) >> 15);
+      q2 = q1;
+      q1 = q0;
+      c -= CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT;
+    }
+  }
+  else
+  {
+    c = -c;
+    for (j = 0; j < count; j++)
+    {
+      q0 = sample[j] - q2 - ((c * (q1 >> 16)) + (((dword)(((dword)(c >> 1)) * ((dword)(q1 & 0xffff)))) >> 15));
+      q2 = q1;
+      q1 = q0;
+      c += CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT;
+    }
+  }
+  coeffs[i] = c;
+  buffer[i] = q1;
+  buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = q2;
+}
+
+
+static void capidtmf_goertzel_result (long *buffer, long *coeffs)
+{
+  int i;
+  long d, e, q1, q2, lo, mid, hi;
+  dword k;
+
+  for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
+  {
+    q1 = buffer[i];
+    q2 = buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+    d = coeffs[i] >> 1;
+    if (d >= 0)
+      d = ((d << 1) * (-q1 >> 16)) + (((dword)(((dword) d) * ((dword)(-q1 & 0xffff)))) >> 15);
+    else
+      d = ((-d << 1) * (-q1 >> 16)) + (((dword)(((dword) -d) * ((dword)(-q1 & 0xffff)))) >> 15);
+    e = (q2 >= 0) ? q2 : -q2;
+    if (d >= 0)
+    {
+      k = ((dword)(d & 0xffff)) * ((dword)(e & 0xffff));
+      lo = k & 0xffff;
+      mid = k >> 16;
+      k = ((dword)(d >> 16)) * ((dword)(e & 0xffff));
+      mid += k & 0xffff;
+      hi = k >> 16;
+      k = ((dword)(d & 0xffff)) * ((dword)(e >> 16));
+      mid += k & 0xffff;
+      hi += k >> 16;
+      hi += ((dword)(d >> 16)) * ((dword)(e >> 16));
+    }
+    else
+    {
+      d = -d;
+      k = ((dword)(d & 0xffff)) * ((dword)(e & 0xffff));
+      lo = -((long)(k & 0xffff));
+      mid = -((long)(k >> 16));
+      k = ((dword)(d >> 16)) * ((dword)(e & 0xffff));
+      mid -= k & 0xffff;
+      hi = -((long)(k >> 16));
+      k = ((dword)(d & 0xffff)) * ((dword)(e >> 16));
+      mid -= k & 0xffff;
+      hi -= k >> 16;
+      hi -= ((dword)(d >> 16)) * ((dword)(e >> 16));
+    }
+    if (q2 < 0)
+    {
+      lo = -lo;
+      mid = -mid;
+      hi = -hi;
+    }
+    d = (q1 >= 0) ? q1 : -q1;
+    k = ((dword)(d & 0xffff)) * ((dword)(d & 0xffff));
+    lo += k & 0xffff;
+    mid += k >> 16;
+    k = ((dword)(d >> 16)) * ((dword)(d & 0xffff));
+    mid += (k & 0xffff) << 1;
+    hi += (k >> 16) << 1;
+    hi += ((dword)(d >> 16)) * ((dword)(d >> 16));
+    d = (q2 >= 0) ? q2 : -q2;
+    k = ((dword)(d & 0xffff)) * ((dword)(d & 0xffff));
+    lo += k & 0xffff;
+    mid += k >> 16;
+    k = ((dword)(d >> 16)) * ((dword)(d & 0xffff));
+    mid += (k & 0xffff) << 1;
+    hi += (k >> 16) << 1;
+    hi += ((dword)(d >> 16)) * ((dword)(d >> 16));
+    mid += lo >> 16;
+    hi += mid >> 16;
+    buffer[i] = (lo & 0xffff) | (mid << 16);
+    buffer[i + CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] = hi;
+  }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_697     0
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_770     1
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_852     2
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_941     3
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1209    4
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1336    5
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1477    6
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1633    7
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_635     8
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1010    9
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1140    10
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1272    11
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1405    12
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1555    13
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1715    14
+#define CAPIDTMF_RECV_GUARD_SNR_INDEX_1875    15
+
+#define CAPIDTMF_RECV_GUARD_SNR_DONTCARE      0xc000
+#define CAPIDTMF_RECV_NO_DIGIT                0xff
+#define CAPIDTMF_RECV_TIME_GRANULARITY        (CAPIDTMF_RECV_ACCUMULATE_CYCLES + 1)
+
+#define CAPIDTMF_RECV_INDICATION_DIGIT        0x0001
+
+static long capidtmf_recv_goertzel_coef_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
+{
+  0xda97L * 2,  /* 697 Hz (Low group 697 Hz) */
+  0xd299L * 2,  /* 770 Hz (Low group 770 Hz) */
+  0xc8cbL * 2,  /* 852 Hz (Low group 852 Hz) */
+  0xbd36L * 2,  /* 941 Hz (Low group 941 Hz) */
+  0x9501L * 2,  /* 1209 Hz (High group 1209 Hz) */
+  0x7f89L * 2,  /* 1336 Hz (High group 1336 Hz) */
+  0x6639L * 2,  /* 1477 Hz (High group 1477 Hz) */
+  0x48c6L * 2,  /* 1633 Hz (High group 1633 Hz) */
+  0xe14cL * 2,  /* 630 Hz (Lower guard of low group 631 Hz) */
+  0xb2e0L * 2,  /* 1015 Hz (Upper guard of low group 1039 Hz) */
+  0xa1a0L * 2,  /* 1130 Hz (Lower guard of high group 1140 Hz) */
+  0x8a87L * 2,  /* 1272 Hz (Guard between 1209 Hz and 1336 Hz: 1271 Hz) */
+  0x7353L * 2,  /* 1405 Hz (2nd harmonics of 697 Hz and guard between 1336 Hz and 1477 Hz: 1405 Hz) */
+  0x583bL * 2,  /* 1552 Hz (2nd harmonics of 770 Hz and guard between 1477 Hz and 1633 Hz: 1553 Hz) */
+  0x37d8L * 2,  /* 1720 Hz (2nd harmonics of 852 Hz and upper guard of high group: 1715 Hz) */
+  0x0000L * 2   /* 100-630 Hz (fundamentals) */
+};
+
+
+static word capidtmf_recv_guard_snr_low_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
+{
+  14,                                    /* Low group peak versus 697 Hz */
+  14,                                    /* Low group peak versus 770 Hz */
+  16,                                    /* Low group peak versus 852 Hz */
+  16,                                    /* Low group peak versus 941 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1209 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1336 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1477 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1633 Hz */
+  14,                                    /* Low group peak versus 635 Hz */
+  16,                                    /* Low group peak versus 1010 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1140 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* Low group peak versus 1272 Hz */
+  DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 8,  /* Low group peak versus 1405 Hz */
+  DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 4,  /* Low group peak versus 1555 Hz */
+  DSPDTMF_RX_HARMONICS_SEL_DEFAULT - 4,  /* Low group peak versus 1715 Hz */
+  12                                     /* Low group peak versus 100-630 Hz */
+};
+
+
+static word capidtmf_recv_guard_snr_high_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT] =
+{
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 697 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 770 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 852 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 941 Hz */
+  20,                                    /* High group peak versus 1209 Hz */
+  20,                                    /* High group peak versus 1336 Hz */
+  20,                                    /* High group peak versus 1477 Hz */
+  20,                                    /* High group peak versus 1633 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 635 Hz */
+  CAPIDTMF_RECV_GUARD_SNR_DONTCARE,      /* High group peak versus 1010 Hz */
+  16,                                    /* High group peak versus 1140 Hz */
+  4,                                     /* High group peak versus 1272 Hz */
+  6,                                     /* High group peak versus 1405 Hz */
+  8,                                     /* High group peak versus 1555 Hz */
+  16,                                    /* High group peak versus 1715 Hz */
+  12                                     /* High group peak versus 100-630 Hz */
+};
+
+
+/*---------------------------------------------------------------------------*/
+
+static void capidtmf_recv_init (t_capidtmf_state   *p_state)
+{
+  p_state->recv.min_gap_duration = 1;
+  p_state->recv.min_digit_duration = 1;
+
+  p_state->recv.cycle_counter = 0;
+  p_state->recv.current_digit_on_time = 0;
+  p_state->recv.current_digit_off_time = 0;
+  p_state->recv.current_digit_value = CAPIDTMF_RECV_NO_DIGIT;
+
+  p_state->recv.digit_write_pos = 0;
+  p_state->recv.digit_read_pos = 0;
+  p_state->recv.indication_state = 0;
+  p_state->recv.indication_state_ack = 0;
+  p_state->recv.state = CAPIDTMF_RECV_STATE_IDLE;
+}
+
+
+void capidtmf_recv_enable (t_capidtmf_state   *p_state, word min_digit_duration, word min_gap_duration)
+{
+  p_state->recv.indication_state_ack &= CAPIDTMF_RECV_INDICATION_DIGIT;
+  p_state->recv.min_digit_duration = (word)(((((dword) min_digit_duration) * 8) +
+    ((dword)(CAPIDTMF_RECV_TIME_GRANULARITY / 2))) / ((dword) CAPIDTMF_RECV_TIME_GRANULARITY));
+  if (p_state->recv.min_digit_duration <= 1)
+    p_state->recv.min_digit_duration = 1;
+  else
+    (p_state->recv.min_digit_duration)--;
+  p_state->recv.min_gap_duration =
+    (word)((((dword) min_gap_duration) * 8) / ((dword) CAPIDTMF_RECV_TIME_GRANULARITY));
+  if (p_state->recv.min_gap_duration <= 1)
+    p_state->recv.min_gap_duration = 1;
+  else
+    (p_state->recv.min_gap_duration)--;
+  p_state->recv.state |= CAPIDTMF_RECV_STATE_DTMF_ACTIVE;
+}
+
+
+void capidtmf_recv_disable (t_capidtmf_state   *p_state)
+{
+  p_state->recv.state &= ~CAPIDTMF_RECV_STATE_DTMF_ACTIVE;
+  if (p_state->recv.state == CAPIDTMF_RECV_STATE_IDLE)
+    capidtmf_recv_init (p_state);
+  else
+  {
+    p_state->recv.cycle_counter = 0;
+    p_state->recv.current_digit_on_time = 0;
+    p_state->recv.current_digit_off_time = 0;
+    p_state->recv.current_digit_value = CAPIDTMF_RECV_NO_DIGIT;
+  }
+}
+
+
+word capidtmf_recv_indication (t_capidtmf_state   *p_state, byte *buffer)
+{
+  word i, j, k, flags;
+
+  flags = p_state->recv.indication_state ^ p_state->recv.indication_state_ack;
+  p_state->recv.indication_state_ack ^= flags & CAPIDTMF_RECV_INDICATION_DIGIT;
+  if (p_state->recv.digit_write_pos != p_state->recv.digit_read_pos)
+  {
+    i = 0;
+    k = p_state->recv.digit_write_pos;
+    j = p_state->recv.digit_read_pos;
+    do
+    {
+      buffer[i++] = p_state->recv.digit_buffer[j];
+      j = (j == CAPIDTMF_RECV_DIGIT_BUFFER_SIZE - 1) ? 0 : j + 1;
+    } while (j != k);
+    p_state->recv.digit_read_pos = k;
+    return (i);
+  }
+  p_state->recv.indication_state_ack ^= flags;
+  return (0);
+}
+
+
+#define CAPIDTMF_RECV_WINDOWED_SAMPLES  32
+
+void capidtmf_recv_block (t_capidtmf_state   *p_state, byte   *buffer, word length)
+{
+  byte result_digit;
+  word sample_number, cycle_counter, n, i;
+  word low_peak, high_peak;
+  dword lo, hi;
+  byte   *p;
+  short *q;
+  byte goertzel_result_buffer[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+    short windowed_sample_buffer[CAPIDTMF_RECV_WINDOWED_SAMPLES];
+
+
+  if (p_state->recv.state & CAPIDTMF_RECV_STATE_DTMF_ACTIVE)
+  {
+    cycle_counter = p_state->recv.cycle_counter;
+    sample_number = 0;
+    while (sample_number < length)
+    {
+      if (cycle_counter < CAPIDTMF_RECV_ACCUMULATE_CYCLES)
+      {
+        if (cycle_counter == 0)
+        {
+          for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
+          {
+            p_state->recv.goertzel_buffer[0][i] = 0;
+            p_state->recv.goertzel_buffer[1][i] = 0;
+          }
+        }
+        n = CAPIDTMF_RECV_ACCUMULATE_CYCLES - cycle_counter;
+        if (n > length - sample_number)
+          n = length - sample_number;
+        if (n > CAPIDTMF_RECV_WINDOWED_SAMPLES)
+          n = CAPIDTMF_RECV_WINDOWED_SAMPLES;
+        p = buffer + sample_number;
+        q = capidtmf_recv_window_function + cycle_counter;
+        if (p_state->ulaw)
+        {
+          for (i = 0; i < n; i++)
+          {
+            windowed_sample_buffer[i] =
+              (short)((capidtmf_expand_table_ulaw[p[i]] * ((long)(q[i]))) >> 15);
+	  }
+        }
+        else
+        {
+          for (i = 0; i < n; i++)
+          {
+            windowed_sample_buffer[i] =
+              (short)((capidtmf_expand_table_alaw[p[i]] * ((long)(q[i]))) >> 15);
+	  }
+        }
+        capidtmf_recv_goertzel_coef_table[CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - 1] = CAPIDTMF_RECV_FUNDAMENTAL_OFFSET;
+        capidtmf_goertzel_loop (p_state->recv.goertzel_buffer[0],
+          capidtmf_recv_goertzel_coef_table, windowed_sample_buffer, n);
+        cycle_counter += n;
+        sample_number += n;
+      }
+      else
+      {
+        capidtmf_goertzel_result (p_state->recv.goertzel_buffer[0],
+          capidtmf_recv_goertzel_coef_table);
+        for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
+        {
+          lo = (dword)(p_state->recv.goertzel_buffer[0][i]);
+          hi = (dword)(p_state->recv.goertzel_buffer[1][i]);
+          if (hi != 0)
+          {
+            n = capidtmf_dword_leading_zeroes (hi);
+            hi = (hi << n) | (lo >> (32 - n));
+          }
+          else
+          {
+            n = capidtmf_dword_leading_zeroes (lo);
+            hi = lo << n;
+	    n += 32;
+          }
+          n = 195 - 3 * n;
+          if (hi >= 0xcb300000L)
+            n += 2;
+          else if (hi >= 0xa1450000L)
+            n++;
+	  goertzel_result_buffer[i] = (byte) n;
+        }
+        low_peak = DSPDTMF_RX_SENSITIVITY_LOW_DEFAULT;
+        result_digit = CAPIDTMF_RECV_NO_DIGIT;
+        for (i = 0; i < CAPIDTMF_LOW_GROUP_FREQUENCIES; i++)
+        {
+          if (goertzel_result_buffer[i] > low_peak)
+	  {
+	    low_peak = goertzel_result_buffer[i];
+	    result_digit = (byte) i;
+	  }
+        }
+        high_peak = DSPDTMF_RX_SENSITIVITY_HIGH_DEFAULT;
+        n = CAPIDTMF_RECV_NO_DIGIT;
+        for (i = CAPIDTMF_LOW_GROUP_FREQUENCIES; i < CAPIDTMF_RECV_BASE_FREQUENCY_COUNT; i++)
+        {
+          if (goertzel_result_buffer[i] > high_peak)
+	  {
+	    high_peak = goertzel_result_buffer[i];
+	    n = (i - CAPIDTMF_LOW_GROUP_FREQUENCIES) << 2;
+	  }
+        }
+        result_digit |= (byte) n;
+        if (low_peak + DSPDTMF_RX_HIGH_EXCEEDING_LOW_DEFAULT < high_peak)
+          result_digit = CAPIDTMF_RECV_NO_DIGIT;
+        if (high_peak + DSPDTMF_RX_LOW_EXCEEDING_HIGH_DEFAULT < low_peak)
+          result_digit = CAPIDTMF_RECV_NO_DIGIT;
+        n = 0;
+        for (i = 0; i < CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT; i++)
+        {
+          if ((((short)(low_peak - goertzel_result_buffer[i] - capidtmf_recv_guard_snr_low_table[i])) < 0)
+           || (((short)(high_peak - goertzel_result_buffer[i] - capidtmf_recv_guard_snr_high_table[i])) < 0))
+	  {
+	    n++;
+	  }
+        }
+        if (n != 2)
+          result_digit = CAPIDTMF_RECV_NO_DIGIT;
+
+        if (result_digit == CAPIDTMF_RECV_NO_DIGIT)
+        {
+          if (p_state->recv.current_digit_on_time != 0)
+          {
+            if (++(p_state->recv.current_digit_off_time) >= p_state->recv.min_gap_duration)
+            {
+              p_state->recv.current_digit_on_time = 0;
+              p_state->recv.current_digit_off_time = 0;
+            }
+          }
+          else
+          {
+            if (p_state->recv.current_digit_off_time != 0)
+              (p_state->recv.current_digit_off_time)--;
+          }
+        }
+        else
+        {
+          if ((p_state->recv.current_digit_on_time == 0)
+           && (p_state->recv.current_digit_off_time != 0))
+          {
+            (p_state->recv.current_digit_off_time)--;
+          }
+          else
+          {
+            n = p_state->recv.current_digit_off_time;
+            if ((p_state->recv.current_digit_on_time != 0)
+             && (result_digit != p_state->recv.current_digit_value))
+            {
+              p_state->recv.current_digit_on_time = 0;
+              n = 0;
+            }
+            p_state->recv.current_digit_value = result_digit;
+            p_state->recv.current_digit_off_time = 0;
+            if (p_state->recv.current_digit_on_time != 0xffff)
+            {
+              p_state->recv.current_digit_on_time += n + 1;
+              if (p_state->recv.current_digit_on_time >= p_state->recv.min_digit_duration)
+              {
+                p_state->recv.current_digit_on_time = 0xffff;
+                i = (p_state->recv.digit_write_pos == CAPIDTMF_RECV_DIGIT_BUFFER_SIZE - 1) ?
+                  0 : p_state->recv.digit_write_pos + 1;
+                if (i == p_state->recv.digit_read_pos)
+                {
+                  trace (dprintf ("%s,%d: Receive digit overrun",
+                    (char   *)(FILE_), __LINE__));
+                }
+                else
+                {
+                  p_state->recv.digit_buffer[p_state->recv.digit_write_pos] = result_digit;
+                  p_state->recv.digit_write_pos = i;
+                  p_state->recv.indication_state =
+                    (p_state->recv.indication_state & ~CAPIDTMF_RECV_INDICATION_DIGIT) |
+                    (~p_state->recv.indication_state_ack & CAPIDTMF_RECV_INDICATION_DIGIT);
+                }
+              }
+            }
+          }
+        }
+        cycle_counter = 0;
+        sample_number++;
+      }
+    }
+    p_state->recv.cycle_counter = cycle_counter;
+  }
+}
+
+
+void capidtmf_init (t_capidtmf_state   *p_state, byte ulaw)
+{
+  p_state->ulaw = ulaw;
+  capidtmf_recv_init (p_state);
+}
+
+
+/*---------------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/capidtmf.h b/drivers/isdn/hardware/eicon/capidtmf.h
new file mode 100644
index 0000000..242048f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capidtmf.h
@@ -0,0 +1,79 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef CAPIDTMF_H_  
+#define CAPIDTMF_H_
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+#define CAPIDTMF_TONE_GROUP_COUNT            2
+#define CAPIDTMF_LOW_GROUP_FREQUENCIES       4
+#define CAPIDTMF_HIGH_GROUP_FREQUENCIES      4
+#define DSPDTMF_RX_SENSITIVITY_LOW_DEFAULT	50	/* -52 dBm */
+#define DSPDTMF_RX_SENSITIVITY_HIGH_DEFAULT	50	/* -52 dBm */
+#define DSPDTMF_RX_HIGH_EXCEEDING_LOW_DEFAULT	10	/* dB */
+#define DSPDTMF_RX_LOW_EXCEEDING_HIGH_DEFAULT	10	/* dB */
+#define DSPDTMF_RX_HARMONICS_SEL_DEFAULT	12	/* dB */
+#define CAPIDTMF_RECV_BASE_FREQUENCY_COUNT   (CAPIDTMF_LOW_GROUP_FREQUENCIES + CAPIDTMF_HIGH_GROUP_FREQUENCIES)
+#define CAPIDTMF_RECV_GUARD_FREQUENCY_COUNT  8
+#define CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT  (CAPIDTMF_RECV_BASE_FREQUENCY_COUNT + CAPIDTMF_RECV_GUARD_FREQUENCY_COUNT)
+#define CAPIDTMF_RECV_POSITIVE_COEFF_COUNT   16
+#define CAPIDTMF_RECV_NEGATIVE_COEFF_COUNT   (CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT - CAPIDTMF_RECV_POSITIVE_COEFF_COUNT)
+#define CAPIDTMF_RECV_ACCUMULATE_CYCLES      205
+#define CAPIDTMF_RECV_FUNDAMENTAL_OFFSET     (0xff35L * 2)
+#define CAPIDTMF_RECV_FUNDAMENTAL_DECREMENT  (0x0028L * 2)
+#define CAPIDTMF_RECV_DIGIT_BUFFER_SIZE      32
+#define CAPIDTMF_RECV_STATE_IDLE             0x00
+#define CAPIDTMF_RECV_STATE_DTMF_ACTIVE      0x01
+typedef struct tag_capidtmf_recv_state
+{
+  byte digit_buffer[CAPIDTMF_RECV_DIGIT_BUFFER_SIZE];
+  word digit_write_pos;
+  word digit_read_pos;
+  word indication_state;
+  word indication_state_ack;
+  long goertzel_buffer[2][CAPIDTMF_RECV_TOTAL_FREQUENCY_COUNT];
+  word min_gap_duration;
+  word min_digit_duration;
+  word cycle_counter;
+  word current_digit_on_time;
+  word current_digit_off_time;
+  byte current_digit_value;
+  byte state;
+} t_capidtmf_recv_state;
+typedef struct tag_capidtmf_state
+{
+  byte ulaw;
+  t_capidtmf_recv_state recv;
+} t_capidtmf_state;
+word capidtmf_recv_indication (t_capidtmf_state   *p_state, byte *buffer);
+void capidtmf_recv_block (t_capidtmf_state   *p_state, byte   *buffer, word length);
+void capidtmf_init (t_capidtmf_state   *p_state, byte ulaw);
+void capidtmf_recv_enable (t_capidtmf_state   *p_state, word min_digit_duration, word min_gap_duration);
+void capidtmf_recv_disable (t_capidtmf_state   *p_state);
+#define capidtmf_indication(p_state,buffer)  (((p_state)->recv.indication_state != (p_state)->recv.indication_state_ack) ?    capidtmf_recv_indication (p_state, buffer) : 0)
+#define capidtmf_recv_process_block(p_state,buffer,length)  { if ((p_state)->recv.state != CAPIDTMF_RECV_STATE_IDLE) capidtmf_recv_block (p_state, buffer, length); }
+/*---------------------------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+#endif  
diff --git a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c
new file mode 100644
index 0000000..0afd763
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capifunc.c
@@ -0,0 +1,1219 @@
+/* $Id: capifunc.c,v 1.61.4.7 2005/02/11 19:40:25 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards DIVA.
+ * CAPI Interface common functions
+ * 
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de) 
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "platform.h"
+#include "os_capi.h"
+#include "di_defs.h"
+#include "capi20.h"
+#include "divacapi.h"
+#include "divasync.h"
+#include "capifunc.h"
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+DIVA_CAPI_ADAPTER *adapter = (DIVA_CAPI_ADAPTER *) NULL;
+APPL *application = (APPL *) NULL;
+byte max_appl = MAX_APPL;
+byte max_adapter = 0;
+static CAPI_MSG *mapped_msg = (CAPI_MSG *) NULL;
+
+byte UnMapController(byte);
+char DRIVERRELEASE_CAPI[32];
+
+extern void AutomaticLaw(DIVA_CAPI_ADAPTER *);
+extern void callback(ENTITY *);
+extern word api_remove_start(void);
+extern word CapiRelease(word);
+extern word CapiRegister(word);
+extern word api_put(APPL *, CAPI_MSG *);
+
+static diva_os_spin_lock_t api_lock;
+
+static LIST_HEAD(cards);
+
+static dword notify_handle;
+static void DIRequest(ENTITY * e);
+static DESCRIPTOR MAdapter;
+static DESCRIPTOR DAdapter;
+static byte ControllerMap[MAX_DESCRIPTORS + 1];
+
+
+static void diva_register_appl(struct capi_ctr *, __u16,
+			       capi_register_params *);
+static void diva_release_appl(struct capi_ctr *, __u16);
+static char *diva_procinfo(struct capi_ctr *);
+static u16 diva_send_message(struct capi_ctr *,
+			     diva_os_message_buffer_s *);
+extern void diva_os_set_controller_struct(struct capi_ctr *);
+
+extern void DIVA_DIDD_Read(DESCRIPTOR *, int);
+
+/*
+ * debug
+ */
+static void no_printf(unsigned char *, ...);
+#include "debuglib.c"
+static void xlog(char *x, ...)
+{
+#ifndef DIVA_NO_DEBUGLIB
+	va_list ap;
+	if (myDriverDebugHandle.dbgMask & DL_XLOG) {
+		va_start(ap, x);
+		if (myDriverDebugHandle.dbg_irq) {
+			myDriverDebugHandle.dbg_irq(myDriverDebugHandle.id,
+						    DLI_XLOG, x, ap);
+		} else if (myDriverDebugHandle.dbg_old) {
+			myDriverDebugHandle.dbg_old(myDriverDebugHandle.id,
+						    x, ap);
+		}
+		va_end(ap);
+	}
+#endif
+}
+
+/*
+ * info for proc
+ */
+static char *diva_procinfo(struct capi_ctr *ctrl)
+{
+	return (ctrl->serial);
+}
+
+/*
+ * stop debugging
+ */
+static void stop_dbg(void)
+{
+	DbgDeregister();
+	memset(&MAdapter, 0, sizeof(MAdapter));
+	dprintf = no_printf;
+}
+
+/*
+ * dummy debug function
+ */
+static void no_printf(unsigned char *x, ...)
+{
+}
+
+/*
+ * Controller mapping
+ */
+byte MapController(byte Controller)
+{
+	byte i;
+	byte MappedController = 0;
+	byte ctrl = Controller & 0x7f;	/* mask external controller bit off */
+
+	for (i = 1; i < max_adapter + 1; i++) {
+		if (ctrl == ControllerMap[i]) {
+			MappedController = (byte) i;
+			break;
+		}
+	}
+	if (i > max_adapter) {
+		ControllerMap[0] = ctrl;
+		MappedController = 0;
+	}
+	return (MappedController | (Controller & 0x80));	/* put back external controller bit */
+}
+
+/*
+ * Controller unmapping
+ */
+byte UnMapController(byte MappedController)
+{
+	byte Controller;
+	byte ctrl = MappedController & 0x7f;	/* mask external controller bit off */
+
+	if (ctrl <= max_adapter) {
+		Controller = ControllerMap[ctrl];
+	} else {
+		Controller = 0;
+	}
+
+	return (Controller | (MappedController & 0x80));	/* put back external controller bit */
+}
+
+/*
+ * find a new free id
+ */
+static int find_free_id(void)
+{
+	int num = 0;
+	DIVA_CAPI_ADAPTER *a;
+
+	while (num < MAX_DESCRIPTORS) {
+		a = &adapter[num];
+		if (!a->Id)
+			break;
+		num++;
+	}
+	return(num + 1);
+}
+
+/*
+ * find a card structure by controller number
+ */
+static diva_card *find_card_by_ctrl(word controller)
+{
+	struct list_head *tmp;
+	diva_card *card;
+
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, diva_card, list);
+		if (ControllerMap[card->Id] == controller) {
+			if (card->remove_in_progress)
+				card = NULL;
+			return(card);
+		}
+	}
+	return (diva_card *) 0;
+}
+
+/*
+ * Buffer RX/TX 
+ */
+void *TransmitBufferSet(APPL * appl, dword ref)
+{
+	appl->xbuffer_used[ref] = TRUE;
+	DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1))
+	    return (void *) ref;
+}
+
+void *TransmitBufferGet(APPL * appl, void *p)
+{
+	if (appl->xbuffer_internal[(dword) p])
+		return appl->xbuffer_internal[(dword) p];
+
+	return appl->xbuffer_ptr[(dword) p];
+}
+
+void TransmitBufferFree(APPL * appl, void *p)
+{
+	appl->xbuffer_used[(dword) p] = FALSE;
+	DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword) p) + 1))
+}
+
+void *ReceiveBufferGet(APPL * appl, int Num)
+{
+	return &appl->ReceiveBuffer[Num * appl->MaxDataLength];
+}
+
+/*
+ * api_remove_start/complete for cleanup
+ */
+void api_remove_complete(void)
+{
+	DBG_PRV1(("api_remove_complete"))
+}
+
+/*
+ * main function called by message.c
+ */
+void sendf(APPL * appl, word command, dword Id, word Number, byte * format, ...)
+{
+	word i, j;
+	word length = 12, dlength = 0;
+	byte *write;
+	CAPI_MSG msg;
+	byte *string = NULL;
+	va_list ap;
+	diva_os_message_buffer_s *dmb;
+	diva_card *card = NULL;
+	dword tmp;
+
+	if (!appl)
+		return;
+
+	DBG_PRV1(("sendf(a=%d,cmd=%x,format=%s)",
+		  appl->Id, command, (byte *) format))
+
+	PUT_WORD(&msg.header.appl_id, appl->Id);
+	PUT_WORD(&msg.header.command, command);
+	if ((byte) (command >> 8) == 0x82)
+		Number = appl->Number++;
+	PUT_WORD(&msg.header.number, Number);
+
+	PUT_DWORD(&msg.header.controller, Id);
+	write = (byte *) & msg;
+	write += 12;
+
+	va_start(ap, format);
+	for (i = 0; format[i]; i++) {
+		switch (format[i]) {
+		case 'b':
+			tmp = va_arg(ap, dword);
+			*(byte *) write = (byte) (tmp & 0xff);
+			write += 1;
+			length += 1;
+			break;
+		case 'w':
+			tmp = va_arg(ap, dword);
+			PUT_WORD(write, (tmp & 0xffff));
+			write += 2;
+			length += 2;
+			break;
+		case 'd':
+			tmp = va_arg(ap, dword);
+			PUT_DWORD(write, tmp);
+			write += 4;
+			length += 4;
+			break;
+		case 's':
+		case 'S':
+			string = va_arg(ap, byte *);
+			length += string[0] + 1;
+			for (j = 0; j <= string[0]; j++)
+				*write++ = string[j];
+			break;
+		}
+	}
+	va_end(ap);
+
+	PUT_WORD(&msg.header.length, length);
+	msg.header.controller = UnMapController(msg.header.controller);
+
+	if (command == _DATA_B3_I)
+		dlength = GET_WORD(
+			      ((byte *) & msg.info.data_b3_ind.Data_Length));
+
+	if (!(dmb = diva_os_alloc_message_buffer(length + dlength,
+					  (void **) &write))) {
+		DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped."))
+		return;
+	}
+
+	/* copy msg header to sk_buff */
+	memcpy(write, (byte *) & msg, length);
+
+	/* if DATA_B3_IND, copy data too */
+	if (command == _DATA_B3_I) {
+		dword data = GET_DWORD(&msg.info.data_b3_ind.Data);
+		memcpy(write + length, (void *) data, dlength);
+	}
+
+#ifndef DIVA_NO_DEBUGLIB
+	if (myDriverDebugHandle.dbgMask & DL_XLOG) {
+		switch (command) {
+		default:
+			xlog("\x00\x02", &msg, 0x81, length);
+			break;
+		case _DATA_B3_R | CONFIRM:
+			if (myDriverDebugHandle.dbgMask & DL_BLK)
+				xlog("\x00\x02", &msg, 0x81, length);
+			break;
+		case _DATA_B3_I:
+			if (myDriverDebugHandle.dbgMask & DL_BLK) {
+				xlog("\x00\x02", &msg, 0x81, length);
+				for (i = 0; i < dlength; i += 256) {
+				  DBG_BLK((((char *) GET_DWORD(&msg.info.data_b3_ind.Data)) + i,
+				  	((dlength - i) < 256) ? (dlength - i) : 256))
+				  if (!(myDriverDebugHandle.dbgMask & DL_PRV0))
+					  break; /* not more if not explicitely requested */
+				}
+			}
+			break;
+		}
+	}
+#endif
+
+	/* find the card structure for this controller */
+	if (!(card = find_card_by_ctrl(write[8] & 0x7f))) {
+		DBG_ERR(("sendf - controller %d not found, incoming msg dropped",
+			 write[8] & 0x7f))
+		diva_os_free_message_buffer(dmb);
+		return;
+	}
+	/* send capi msg to capi layer */
+	capi_ctr_handle_message(&card->capi_ctrl, appl->Id, dmb);
+}
+
+/*
+ * cleanup adapter
+ */
+static void clean_adapter(int id, struct list_head *free_mem_q)
+{
+	DIVA_CAPI_ADAPTER *a;
+	int i, k;
+
+	a = &adapter[id];
+	k = li_total_channels - a->li_channels;
+	if (k == 0) {
+		if (li_config_table) {
+			list_add((struct list_head *)li_config_table, free_mem_q);
+			li_config_table = NULL;
+		}
+	} else {
+		if (a->li_base < k) {
+			memmove(&li_config_table[a->li_base],
+				&li_config_table[a->li_base + a->li_channels],
+				(k - a->li_base) * sizeof(LI_CONFIG));
+			for (i = 0; i < k; i++) {
+				memmove(&li_config_table[i].flag_table[a->li_base],
+					&li_config_table[i].flag_table[a->li_base + a->li_channels],
+					k - a->li_base);
+				memmove(&li_config_table[i].
+					coef_table[a->li_base],
+					&li_config_table[i].coef_table[a->li_base + a->li_channels],
+					k - a->li_base);
+			}
+		}
+	}
+	li_total_channels = k;
+	for (i = id; i < max_adapter; i++) {
+		if (adapter[i].request)
+			adapter[i].li_base -= a->li_channels;
+	}
+	if (a->plci)
+		list_add((struct list_head *)a->plci, free_mem_q);
+
+	memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER));
+	while ((max_adapter != 0) && !adapter[max_adapter - 1].request)
+		max_adapter--;
+}
+
+/*
+ * remove a card, but ensures consistent state of LI tables
+ * in the time adapter is removed
+ */
+static void divacapi_remove_card(DESCRIPTOR * d)
+{
+	diva_card *card = NULL;
+	diva_os_spin_lock_magic_t old_irql;
+	LIST_HEAD(free_mem_q);
+	struct list_head *link;
+	struct list_head *tmp;
+
+	/*
+	 * Set "remove in progress flag".
+	 * Ensures that there is no call from sendf to CAPI in
+	 * the time CAPI controller is about to be removed.
+	 */
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, diva_card, list);
+		if (card->d.request == d->request) {
+			card->remove_in_progress = 1;
+			list_del(tmp);
+			break;
+		}
+	}
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");
+
+	if (card) {
+		/*
+		 * Detach CAPI. Sendf cannot call to CAPI any more.
+		 * After detach no call to send_message() is done too.
+		 */
+		detach_capi_ctr(&card->capi_ctrl);
+
+		/*
+		 * Now get API lock (to ensure stable state of LI tables)
+		 * and update the adapter map/LI table.
+		 */
+		diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");
+
+		clean_adapter(card->Id - 1, &free_mem_q);
+		DBG_TRC(("DelAdapterMap (%d) -> (%d)",
+				ControllerMap[card->Id], card->Id))
+				ControllerMap[card->Id] = 0;
+		DBG_TRC(("adapter remove, max_adapter=%d",
+				max_adapter));
+		diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");
+		
+		/* After releasing the lock, we can free the memory */
+		diva_os_free (0, card);
+	}
+
+	/* free queued memory areas */
+	list_for_each_safe(link, tmp, &free_mem_q) {
+		list_del(link);
+		diva_os_free(0, link);
+	}
+}
+
+/*
+ * remove cards
+ */
+static void divacapi_remove_cards(void)
+{
+	DESCRIPTOR d;
+	struct list_head *tmp;
+	diva_card *card;
+	diva_os_spin_lock_magic_t old_irql;
+
+rescan:
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards");
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, diva_card, list);
+		diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");
+		d.request = card->d.request;
+		divacapi_remove_card(&d);
+		goto rescan;
+	}
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");
+}
+
+/*
+ * sync_callback
+ */
+static void sync_callback(ENTITY * e)
+{
+	diva_os_spin_lock_magic_t old_irql;
+
+	DBG_TRC(("cb:Id=%x,Rc=%x,Ind=%x", e->Id, e->Rc, e->Ind))
+
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "sync_callback");
+	callback(e);
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "sync_callback");
+}
+
+/*
+ * add a new card
+ */
+static int diva_add_card(DESCRIPTOR * d)
+{
+	int k = 0, i = 0;
+	diva_os_spin_lock_magic_t old_irql;
+	diva_card *card = NULL;
+	struct capi_ctr *ctrl = NULL;
+	DIVA_CAPI_ADAPTER *a = NULL;
+	IDI_SYNC_REQ sync_req;
+	char serial[16];
+	void* mem_to_free;
+	LI_CONFIG *new_li_config_table;
+	int j;
+
+	if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) {
+		DBG_ERR(("diva_add_card: failed to allocate card struct."))
+		    return (0);
+	}
+	memset((char *) card, 0x00, sizeof(diva_card));
+	memcpy(&card->d, d, sizeof(DESCRIPTOR));
+	sync_req.GetName.Req = 0;
+	sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;
+	card->d.request((ENTITY *) & sync_req);
+	strlcpy(card->name, sync_req.GetName.name, sizeof(card->name));
+	ctrl = &card->capi_ctrl;
+	strcpy(ctrl->name, card->name);
+	ctrl->register_appl = diva_register_appl;
+	ctrl->release_appl = diva_release_appl;
+	ctrl->send_message = diva_send_message;
+	ctrl->procinfo = diva_procinfo;
+	ctrl->driverdata = card;
+	diva_os_set_controller_struct(ctrl);
+
+	if (attach_capi_ctr(ctrl)) {
+		DBG_ERR(("diva_add_card: failed to attach controller."))
+		    diva_os_free(0, card);
+		return (0);
+	}
+	
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "find id");
+	card->Id = find_free_id();
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "find id");
+	
+	strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu));
+	ctrl->version.majorversion = 2;
+	ctrl->version.minorversion = 0;
+	ctrl->version.majormanuversion = DRRELMAJOR;
+	ctrl->version.minormanuversion = DRRELMINOR;
+	sync_req.GetSerial.Req = 0;
+	sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
+	sync_req.GetSerial.serial = 0;
+	card->d.request((ENTITY *) & sync_req);
+	if ((i = ((sync_req.GetSerial.serial & 0xff000000) >> 24))) {
+		sprintf(serial, "%ld-%d",
+			sync_req.GetSerial.serial & 0x00ffffff, i + 1);
+	} else {
+		sprintf(serial, "%ld", sync_req.GetSerial.serial);
+	}
+	serial[CAPI_SERIAL_LEN - 1] = 0;
+	strlcpy(ctrl->serial, serial, sizeof(ctrl->serial));
+
+	a = &adapter[card->Id - 1];
+	card->adapter = a;
+	a->os_card = card;
+	ControllerMap[card->Id] = (byte) (ctrl->cnr);
+
+	DBG_TRC(("AddAdapterMap (%d) -> (%d)", ctrl->cnr, card->Id))
+
+	    sync_req.xdi_capi_prms.Req = 0;
+	sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS;
+	sync_req.xdi_capi_prms.info.structure_length =
+	    sizeof(diva_xdi_get_capi_parameters_t);
+	card->d.request((ENTITY *) & sync_req);
+	a->flag_dynamic_l1_down =
+	    sync_req.xdi_capi_prms.info.flag_dynamic_l1_down;
+	a->group_optimization_enabled =
+	    sync_req.xdi_capi_prms.info.group_optimization_enabled;
+	a->request = DIRequest;	/* card->d.request; */
+	a->max_plci = card->d.channels + 30;
+	a->max_listen = (card->d.channels > 2) ? 8 : 2;
+	if (!
+	    (a->plci =
+	     (PLCI *) diva_os_malloc(0, sizeof(PLCI) * a->max_plci))) {
+		DBG_ERR(("diva_add_card: failed alloc plci struct."))
+		    memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
+		return (0);
+	}
+	memset(a->plci, 0, sizeof(PLCI) * a->max_plci);
+
+	for (k = 0; k < a->max_plci; k++) {
+		a->Id = (byte) card->Id;
+		a->plci[k].Sig.callback = sync_callback;
+		a->plci[k].Sig.XNum = 1;
+		a->plci[k].Sig.X = a->plci[k].XData;
+		a->plci[k].Sig.user[0] = (word) (card->Id - 1);
+		a->plci[k].Sig.user[1] = (word) k;
+		a->plci[k].NL.callback = sync_callback;
+		a->plci[k].NL.XNum = 1;
+		a->plci[k].NL.X = a->plci[k].XData;
+		a->plci[k].NL.user[0] = (word) ((card->Id - 1) | 0x8000);
+		a->plci[k].NL.user[1] = (word) k;
+		a->plci[k].adapter = a;
+	}
+
+	a->profile.Number = card->Id;
+	a->profile.Channels = card->d.channels;
+	if (card->d.features & DI_FAX3) {
+		a->profile.Global_Options = 0x71;
+		if (card->d.features & DI_CODEC)
+			a->profile.Global_Options |= 0x6;
+#if IMPLEMENT_DTMF
+		a->profile.Global_Options |= 0x8;
+#endif				/* IMPLEMENT_DTMF */
+		a->profile.Global_Options |= 0x80; /* Line Interconnect */
+#if IMPLEMENT_ECHO_CANCELLER
+		a->profile.Global_Options |= 0x100;
+#endif				/* IMPLEMENT_ECHO_CANCELLER */
+		a->profile.B1_Protocols = 0xdf;
+		a->profile.B2_Protocols = 0x1fdb;
+		a->profile.B3_Protocols = 0xb7;
+		a->manufacturer_features = MANUFACTURER_FEATURE_HARDDTMF;
+	} else {
+		a->profile.Global_Options = 0x71;
+		if (card->d.features & DI_CODEC)
+			a->profile.Global_Options |= 0x2;
+		a->profile.B1_Protocols = 0x43;
+		a->profile.B2_Protocols = 0x1f0f;
+		a->profile.B3_Protocols = 0x07;
+		a->manufacturer_features = 0;
+	}
+
+	a->li_pri = (a->profile.Channels > 2);
+	a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI;
+	a->li_base = 0;
+	for (i = 0; &adapter[i] != a; i++) {
+		if (adapter[i].request)
+			a->li_base = adapter[i].li_base + adapter[i].li_channels;
+	}
+	k = li_total_channels + a->li_channels;
+	new_li_config_table =
+		(LI_CONFIG *) diva_os_malloc(0, ((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * k) * ((k + 3) & ~3));
+	if (new_li_config_table == NULL) {
+		DBG_ERR(("diva_add_card: failed alloc li_config table."))
+		memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
+		return (0);
+	}
+
+	/* Prevent access to line interconnect table in process update */
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "add card");
+	
+	j = 0;
+	for (i = 0; i < k; i++) {
+		if ((i >= a->li_base) && (i < a->li_base + a->li_channels))
+			memset(&new_li_config_table[i], 0, sizeof(LI_CONFIG));
+		else
+			memcpy(&new_li_config_table[i], &li_config_table[j], sizeof(LI_CONFIG));
+		new_li_config_table[i].flag_table =
+			((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i) * ((k + 3) & ~3));
+		new_li_config_table[i].coef_table =
+			((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i + 1) * ((k + 3) & ~3));
+		if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) {
+			new_li_config_table[i].adapter = a;
+			memset(&new_li_config_table[i].flag_table[0], 0, k);
+			memset(&new_li_config_table[i].coef_table[0], 0, k);
+		} else {
+			if (a->li_base != 0) {
+				memcpy(&new_li_config_table[i].flag_table[0],
+				       &li_config_table[j].flag_table[0],
+				       a->li_base);
+				memcpy(&new_li_config_table[i].coef_table[0],
+				       &li_config_table[j].coef_table[0],
+				       a->li_base);
+			}
+			memset(&new_li_config_table[i].flag_table[a->li_base], 0, a->li_channels);
+			memset(&new_li_config_table[i].coef_table[a->li_base], 0, a->li_channels);
+			if (a->li_base + a->li_channels < k) {
+				memcpy(&new_li_config_table[i].flag_table[a->li_base +
+				       a->li_channels],
+				       &li_config_table[j].flag_table[a->li_base],
+				       k - (a->li_base + a->li_channels));
+				memcpy(&new_li_config_table[i].coef_table[a->li_base +
+				       a->li_channels],
+				       &li_config_table[j].coef_table[a->li_base],
+				       k - (a->li_base + a->li_channels));
+			}
+			j++;
+		}
+	}
+	li_total_channels = k;
+
+	mem_to_free = li_config_table;
+
+	li_config_table = new_li_config_table;
+	for (i = card->Id; i < max_adapter; i++) {
+		if (adapter[i].request)
+			adapter[i].li_base += a->li_channels;
+	}
+
+	if (a == &adapter[max_adapter])
+		max_adapter++;
+
+	list_add(&(card->list), &cards);
+	AutomaticLaw(a);
+
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "add card");
+
+	if (mem_to_free) {
+		diva_os_free (0, mem_to_free);
+	}
+
+	i = 0;
+	while (i++ < 30) {
+		if (a->automatic_law > 3)
+			break;
+		diva_os_sleep(10);
+	}
+
+	/* profile information */
+	PUT_WORD(&ctrl->profile.nbchannel, card->d.channels);
+	ctrl->profile.goptions = a->profile.Global_Options;
+	ctrl->profile.support1 = a->profile.B1_Protocols;
+	ctrl->profile.support2 = a->profile.B2_Protocols;
+	ctrl->profile.support3 = a->profile.B3_Protocols;
+	/* manufacturer profile information */
+	ctrl->profile.manu[0] = a->man_profile.private_options;
+	ctrl->profile.manu[1] = a->man_profile.rtp_primary_payloads;
+	ctrl->profile.manu[2] = a->man_profile.rtp_additional_payloads;
+	ctrl->profile.manu[3] = 0;
+	ctrl->profile.manu[4] = 0;
+
+	capi_ctr_ready(ctrl);
+
+	DBG_TRC(("adapter added, max_adapter=%d", max_adapter));
+	return (1);
+}
+
+/*
+ *  register appl
+ */
+static void diva_register_appl(struct capi_ctr *ctrl, __u16 appl,
+			       capi_register_params * rp)
+{
+	APPL *this;
+	word bnum, xnum;
+	int i = 0;
+	unsigned char *p;
+	void *DataNCCI, *DataFlags, *ReceiveBuffer, *xbuffer_used;
+	void **xbuffer_ptr, **xbuffer_internal;
+	diva_os_spin_lock_magic_t old_irql;
+	unsigned int mem_len;
+	int nconn = rp->level3cnt;
+
+
+	if (diva_os_in_irq()) {
+		DBG_ERR(("CAPI_REGISTER - in irq context !"))
+		return;
+	}
+
+	DBG_TRC(("application register Id=%d", appl))
+
+	if (appl > MAX_APPL) {
+		DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL"))
+		return;
+	}
+
+	if (nconn <= 0)
+		nconn = ctrl->profile.nbchannel * -nconn;
+
+        if (nconn == 0)
+		nconn = ctrl->profile.nbchannel;
+
+	DBG_LOG(("CAPI_REGISTER - Id = %d", appl))
+	DBG_LOG(("  MaxLogicalConnections = %d(%d)", nconn, rp->level3cnt))
+	DBG_LOG(("  MaxBDataBuffers       = %d", rp->datablkcnt))
+	DBG_LOG(("  MaxBDataLength        = %d", rp->datablklen))
+
+	if (nconn < 1 ||
+	    nconn > 255 ||
+	    rp->datablklen < 80 ||
+	    rp->datablklen > 2150 || rp->datablkcnt > 255) {
+		DBG_ERR(("CAPI_REGISTER - invalid parameters"))
+		return;
+	}
+
+	if (application[appl - 1].Id == appl) {
+		DBG_LOG(("CAPI_REGISTER - appl already registered"))
+		return;	/* appl already registered */
+	}
+
+	/* alloc memory */
+
+	bnum = nconn * rp->datablkcnt;
+	xnum = nconn * MAX_DATA_B3;
+
+	mem_len  = bnum * sizeof(word);		/* DataNCCI */
+	mem_len += bnum * sizeof(word);		/* DataFlags */
+	mem_len += bnum * rp->datablklen;	/* ReceiveBuffer */
+	mem_len += xnum;			/* xbuffer_used */
+	mem_len += xnum * sizeof(void *);	/* xbuffer_ptr */
+	mem_len += xnum * sizeof(void *);	/* xbuffer_internal */
+	mem_len += xnum * rp->datablklen;	/* xbuffer_ptr[xnum] */
+
+	DBG_LOG(("  Allocated Memory      = %d", mem_len))
+	if (!(p = diva_os_malloc(0, mem_len))) {
+		DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
+		return;
+	}
+	memset(p, 0, mem_len);
+
+	DataNCCI = (void *)p;
+	p += bnum * sizeof(word);
+	DataFlags = (void *)p;
+	p += bnum * sizeof(word);
+	ReceiveBuffer = (void *)p;
+	p += bnum * rp->datablklen;
+	xbuffer_used = (void *)p;
+	p += xnum;
+	xbuffer_ptr = (void **)p;
+	p += xnum * sizeof(void *);
+	xbuffer_internal = (void **)p;
+	p += xnum * sizeof(void *);
+	for (i = 0; i < xnum; i++) {
+		xbuffer_ptr[i] = (void *)p;
+		p += rp->datablklen;
+	}
+
+	/* initialize application data */
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "register_appl");
+
+	this = &application[appl - 1];
+	memset(this, 0, sizeof(APPL));
+
+	this->Id = appl;
+
+	for (i = 0; i < max_adapter; i++) {
+		adapter[i].CIP_Mask[appl - 1] = 0;
+	}
+
+	this->queue_size = 1000;
+
+	this->MaxNCCI = (byte) nconn;
+	this->MaxNCCIData = (byte) rp->datablkcnt;
+	this->MaxBuffer = bnum;
+	this->MaxDataLength = rp->datablklen;
+
+	this->DataNCCI = DataNCCI;
+	this->DataFlags = DataFlags;
+	this->ReceiveBuffer = ReceiveBuffer;
+	this->xbuffer_used = xbuffer_used;
+	this->xbuffer_ptr = xbuffer_ptr;
+	this->xbuffer_internal = xbuffer_internal;
+	for (i = 0; i < xnum; i++) {
+		this->xbuffer_ptr[i] = xbuffer_ptr[i];
+	}
+
+	CapiRegister(this->Id);
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "register_appl");
+
+}
+
+/*
+ *  release appl
+ */
+static void diva_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	APPL *this = &application[appl - 1];
+	void *mem_to_free = NULL;
+
+	DBG_TRC(("application %d(%d) cleanup", this->Id, appl))
+
+	if (diva_os_in_irq()) {
+		DBG_ERR(("CAPI_RELEASE - in irq context !"))
+		return;
+	}
+
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl");
+	if (this->Id) {
+		CapiRelease(this->Id);
+		mem_to_free = this->DataNCCI;
+		this->DataNCCI = NULL;
+		this->Id = 0;
+	}
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl");
+
+	if (mem_to_free)
+		diva_os_free(0, mem_to_free);
+
+}
+
+/*
+ *  send message
+ */
+static u16 diva_send_message(struct capi_ctr *ctrl,
+			     diva_os_message_buffer_s * dmb)
+{
+	int i = 0;
+	word ret = 0;
+	diva_os_spin_lock_magic_t old_irql;
+	CAPI_MSG *msg = (CAPI_MSG *) DIVA_MESSAGE_BUFFER_DATA(dmb);
+	APPL *this = &application[GET_WORD(&msg->header.appl_id) - 1];
+	diva_card *card = ctrl->driverdata;
+	__u32 length = DIVA_MESSAGE_BUFFER_LEN(dmb);
+	word clength = GET_WORD(&msg->header.length);
+	word command = GET_WORD(&msg->header.command);
+	u16 retval = CAPI_NOERROR;
+
+	if (diva_os_in_irq()) {
+		DBG_ERR(("CAPI_SEND_MSG - in irq context !"))
+		return CAPI_REGOSRESOURCEERR;
+	}
+	DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command))
+
+	if (card->remove_in_progress) {
+		DBG_ERR(("CAPI_SEND_MSG - remove in progress!"))
+		return CAPI_REGOSRESOURCEERR;
+	}
+
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "send message");
+
+	if (!this->Id) {
+		diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");
+		return CAPI_ILLAPPNR;
+	}
+
+	/* patch controller number */
+	msg->header.controller = ControllerMap[card->Id]
+	    | (msg->header.controller & 0x80);	/* preserve external controller bit */
+
+	switch (command) {
+	default:
+		xlog("\x00\x02", msg, 0x80, clength);
+		break;
+
+	case _DATA_B3_I | RESPONSE:
+#ifndef DIVA_NO_DEBUGLIB
+		if (myDriverDebugHandle.dbgMask & DL_BLK)
+			xlog("\x00\x02", msg, 0x80, clength);
+#endif
+		break;
+
+	case _DATA_B3_R:
+#ifndef DIVA_NO_DEBUGLIB
+		if (myDriverDebugHandle.dbgMask & DL_BLK)
+			xlog("\x00\x02", msg, 0x80, clength);
+#endif
+
+		if (clength == 24)
+			clength = 22;	/* workaround for PPcom bug */
+		/* header is always 22      */
+		if (GET_WORD(&msg->info.data_b3_req.Data_Length) >
+		    this->MaxDataLength
+		    || GET_WORD(&msg->info.data_b3_req.Data_Length) >
+		    (length - clength)) {
+			DBG_ERR(("Write - invalid message size"))
+			retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
+			goto write_end;
+		}
+
+		for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI)
+		     && this->xbuffer_used[i]; i++);
+		if (i == (MAX_DATA_B3 * this->MaxNCCI)) {
+			DBG_ERR(("Write - too many data pending"))
+			retval = CAPI_SENDQUEUEFULL;
+			goto write_end;
+		}
+		msg->info.data_b3_req.Data = i;
+
+		this->xbuffer_internal[i] = NULL;
+		memcpy(this->xbuffer_ptr[i], &((__u8 *) msg)[clength],
+		       GET_WORD(&msg->info.data_b3_req.Data_Length));
+
+#ifndef DIVA_NO_DEBUGLIB
+		if ((myDriverDebugHandle.dbgMask & DL_BLK)
+		    && (myDriverDebugHandle.dbgMask & DL_XLOG)) {
+			int j;
+			for (j = 0; j <
+			     GET_WORD(&msg->info.data_b3_req.Data_Length);
+			     j += 256) {
+				DBG_BLK((((char *) this->xbuffer_ptr[i]) + j,
+					((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) <
+					  256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256))
+				if (!(myDriverDebugHandle.dbgMask & DL_PRV0))
+					break;	/* not more if not explicitely requested */
+			}
+		}
+#endif
+		break;
+	}
+
+	memcpy(mapped_msg, msg, (__u32) clength);
+	mapped_msg->header.controller = MapController(mapped_msg->header.controller);
+	mapped_msg->header.length = clength;
+	mapped_msg->header.command = command;
+	mapped_msg->header.number = GET_WORD(&msg->header.number);
+
+	ret = api_put(this, mapped_msg);
+	switch (ret) {
+	case 0:
+		break;
+	case _BAD_MSG:
+		DBG_ERR(("Write - bad message"))
+		retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
+		break;
+	case _QUEUE_FULL:
+		DBG_ERR(("Write - queue full"))
+		retval = CAPI_SENDQUEUEFULL;
+		break;
+	default:
+		DBG_ERR(("Write - api_put returned unknown error"))
+		retval = CAPI_UNKNOWNNOTPAR;
+		break;
+	}
+
+      write_end:
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");
+	if (retval == CAPI_NOERROR)
+		diva_os_free_message_buffer(dmb);
+	return retval;
+}
+
+
+/*
+ * cards request function
+ */
+static void DIRequest(ENTITY * e)
+{
+	DIVA_CAPI_ADAPTER *a = &(adapter[(byte) e->user[0]]);
+	diva_card *os_card = (diva_card *) a->os_card;
+
+	if (e->Req && (a->FlowControlIdTable[e->ReqCh] == e->Id)) {
+		a->FlowControlSkipTable[e->ReqCh] = 1;
+	}
+
+	(*(os_card->d.request)) (e);
+}
+
+/*
+ * callback function from didd
+ */
+static void didd_callback(void *context, DESCRIPTOR * adapter, int removal)
+{
+	if (adapter->type == IDI_DADAPTER) {
+		DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
+		return;
+	} else if (adapter->type == IDI_DIMAINT) {
+		if (removal) {
+			stop_dbg();
+		} else {
+			memcpy(&MAdapter, adapter, sizeof(MAdapter));
+			dprintf = (DIVA_DI_PRINTF) MAdapter.request;
+			DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT);
+		}
+	} else if ((adapter->type > 0) && (adapter->type < 16)) {	/* IDI Adapter */
+		if (removal) {
+			divacapi_remove_card(adapter);
+		} else {
+			diva_add_card(adapter);
+		}
+	}
+	return;
+}
+
+/*
+ * connect to didd
+ */
+static int divacapi_connect_didd(void)
+{
+	int x = 0;
+	int dadapter = 0;
+	IDI_SYNC_REQ req;
+	DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+	DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+	for (x = 0; x < MAX_DESCRIPTORS; x++) {
+		if (DIDD_Table[x].type == IDI_DIMAINT) {	/* MAINT found */
+			memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
+			dprintf = (DIVA_DI_PRINTF) MAdapter.request;
+			DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT);
+			break;
+		}
+	}
+	for (x = 0; x < MAX_DESCRIPTORS; x++) {
+		if (DIDD_Table[x].type == IDI_DADAPTER) {	/* DADAPTER found */
+			dadapter = 1;
+			memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+			req.didd_notify.e.Req = 0;
+			req.didd_notify.e.Rc =
+			    IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+			req.didd_notify.info.callback = (void *)didd_callback;
+			req.didd_notify.info.context = NULL;
+			DAdapter.request((ENTITY *) & req);
+			if (req.didd_notify.e.Rc != 0xff) {
+				stop_dbg();
+				return (0);
+			}
+			notify_handle = req.didd_notify.info.handle;
+		}
+			else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) {	/* IDI Adapter found */
+			diva_add_card(&DIDD_Table[x]);
+		}
+	}
+
+	if (!dadapter) {
+		stop_dbg();
+	}
+
+	return (dadapter);
+}
+
+/*
+ * diconnect from didd
+ */
+static void divacapi_disconnect_didd(void)
+{
+	IDI_SYNC_REQ req;
+
+	stop_dbg();
+
+	req.didd_notify.e.Req = 0;
+	req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+	req.didd_notify.info.handle = notify_handle;
+	DAdapter.request((ENTITY *) & req);
+}
+
+/*
+ * we do not provide date/time here,
+ * the application should do this. 
+ */
+int fax_head_line_time(char *buffer)
+{
+	return (0);
+}
+
+/*
+ * init (alloc) main structures
+ */
+static int DIVA_INIT_FUNCTION init_main_structs(void)
+{
+	if (!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) {
+		DBG_ERR(("init: failed alloc mapped_msg."))
+		    return 0;
+	}
+
+	if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) {
+		DBG_ERR(("init: failed alloc adapter struct."))
+		diva_os_free(0, mapped_msg);
+		return 0;
+	}
+	memset(adapter, 0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS);
+
+	if (!(application = diva_os_malloc(0, sizeof(APPL) * MAX_APPL))) {
+		DBG_ERR(("init: failed alloc application struct."))
+		diva_os_free(0, mapped_msg);
+		diva_os_free(0, adapter);
+		return 0;
+	}
+	memset(application, 0, sizeof(APPL) * MAX_APPL);
+
+	return (1);
+}
+
+/*
+ * remove (free) main structures
+ */
+static void remove_main_structs(void)
+{
+	if (application)
+		diva_os_free(0, application);
+	if (adapter)
+		diva_os_free(0, adapter);
+	if (mapped_msg)
+		diva_os_free(0, mapped_msg);
+}
+
+/*
+ * api_remove_start
+ */
+static void do_api_remove_start(void)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	int ret = 1, count = 100;
+
+	do {
+		diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start");
+		ret = api_remove_start();
+		diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start");
+
+		diva_os_sleep(10);
+	} while (ret && count--);
+
+	if (ret)
+		DBG_ERR(("could not remove signaling ID's"))
+}
+
+/*
+ * init
+ */
+int DIVA_INIT_FUNCTION init_capifunc(void)
+{
+	diva_os_initialize_spin_lock(&api_lock, "capifunc");
+	memset(ControllerMap, 0, MAX_DESCRIPTORS + 1);
+	max_adapter = 0;
+
+
+	if (!init_main_structs()) {
+		DBG_ERR(("init: failed to init main structs."))
+		diva_os_destroy_spin_lock(&api_lock, "capifunc");
+		return (0);
+	}
+
+	if (!divacapi_connect_didd()) {
+		DBG_ERR(("init: failed to connect to DIDD."))
+		do_api_remove_start();
+		divacapi_remove_cards();
+		remove_main_structs();
+		diva_os_destroy_spin_lock(&api_lock, "capifunc");
+		return (0);
+	}
+
+	return (1);
+}
+
+/*
+ * finit
+ */
+void DIVA_EXIT_FUNCTION finit_capifunc(void)
+{
+	do_api_remove_start();
+	divacapi_disconnect_didd();
+	divacapi_remove_cards();
+	remove_main_structs();
+	diva_os_destroy_spin_lock(&api_lock, "capifunc");
+}
diff --git a/drivers/isdn/hardware/eicon/capifunc.h b/drivers/isdn/hardware/eicon/capifunc.h
new file mode 100644
index 0000000..bd256f2
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capifunc.h
@@ -0,0 +1,40 @@
+/* $Id: capifunc.h,v 1.11.4.1 2004/08/28 20:03:53 armin Exp $
+ *
+ * ISDN interface module for Eicon active cards DIVA.
+ * CAPI Interface common functions
+ * 
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de) 
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef __CAPIFUNC_H__
+#define __CAPIFUNC_H__
+
+#define DRRELMAJOR  2
+#define DRRELMINOR  0
+#define DRRELEXTRA  ""
+
+#define M_COMPANY "Eicon Networks"
+
+extern char DRIVERRELEASE_CAPI[];
+
+typedef struct _diva_card {
+	struct list_head list;
+	int remove_in_progress;
+	int Id;
+	struct capi_ctr capi_ctrl;
+	DIVA_CAPI_ADAPTER *adapter;
+	DESCRIPTOR d;
+	char name[32];
+} diva_card;
+
+/*
+ * prototypes
+ */
+int init_capifunc(void);
+void finit_capifunc(void);
+
+#endif /* __CAPIFUNC_H__ */
diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c
new file mode 100644
index 0000000..8fe4f3f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/capimain.c
@@ -0,0 +1,147 @@
+/* $Id: capimain.c,v 1.24 2003/09/09 06:51:05 schindler Exp $
+ *
+ * ISDN interface module for Eicon active cards DIVA.
+ * CAPI Interface
+ * 
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de) 
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.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/init.h>
+#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+
+#include "os_capi.h"
+
+#include "platform.h"
+#include "di_defs.h"
+#include "capi20.h"
+#include "divacapi.h"
+#include "cp_vers.h"
+#include "capifunc.h"
+
+static char *main_revision = "$Revision: 1.24 $";
+static char *DRIVERNAME =
+    "Eicon DIVA - CAPI Interface driver (http://www.melware.net)";
+static char *DRIVERLNAME = "divacapi";
+
+MODULE_DESCRIPTION("CAPI driver for Eicon DIVA cards");
+MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
+MODULE_SUPPORTED_DEVICE("CAPI and DIVA card drivers");
+MODULE_LICENSE("GPL");
+
+/*
+ * get revision number from revision string
+ */
+static char *getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "1.0";
+	return rev;
+
+}
+
+/*
+ * alloc a message buffer
+ */
+diva_os_message_buffer_s *diva_os_alloc_message_buffer(unsigned long size,
+						       void **data_buf)
+{
+	diva_os_message_buffer_s *dmb = alloc_skb(size, GFP_ATOMIC);
+	if (dmb) {
+		*data_buf = skb_put(dmb, size);
+	}
+	return (dmb);
+}
+
+/*
+ * free a message buffer
+ */
+void diva_os_free_message_buffer(diva_os_message_buffer_s * dmb)
+{
+	kfree_skb(dmb);
+}
+
+/*
+ * proc function for controller info
+ */
+static int diva_ctl_read_proc(char *page, char **start, off_t off,
+			      int count, int *eof, struct capi_ctr *ctrl)
+{
+	diva_card *card = (diva_card *) ctrl->driverdata;
+	int len = 0;
+
+	len += sprintf(page + len, "%s\n", ctrl->name);
+	len += sprintf(page + len, "Serial No. : %s\n", ctrl->serial);
+	len += sprintf(page + len, "Id         : %d\n", card->Id);
+	len += sprintf(page + len, "Channels   : %d\n", card->d.channels);
+
+	if (off + count >= len)
+		*eof = 1;
+	if (len < off)
+		return 0;
+	*start = page + off;
+	return ((count < len - off) ? count : len - off);
+}
+
+/*
+ * set additional os settings in capi_ctr struct
+ */
+void diva_os_set_controller_struct(struct capi_ctr *ctrl)
+{
+	ctrl->driver_name = DRIVERLNAME;
+	ctrl->load_firmware = NULL;
+	ctrl->reset_ctr = NULL;
+	ctrl->ctr_read_proc = diva_ctl_read_proc;
+	ctrl->owner = THIS_MODULE;
+}
+
+/*
+ * module init
+ */
+static int DIVA_INIT_FUNCTION divacapi_init(void)
+{
+	char tmprev[32];
+	int ret = 0;
+
+	sprintf(DRIVERRELEASE_CAPI, "%d.%d%s", DRRELMAJOR, DRRELMINOR,
+		DRRELEXTRA);
+
+	printk(KERN_INFO "%s\n", DRIVERNAME);
+	printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE_CAPI);
+	strcpy(tmprev, main_revision);
+	printk("%s  Build: %s(%s)\n", getrev(tmprev),
+	       diva_capi_common_code_build, DIVA_BUILD);
+
+	if (!(init_capifunc())) {
+		printk(KERN_ERR "%s: failed init capi_driver.\n",
+		       DRIVERLNAME);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+/*
+ * module exit
+ */
+static void DIVA_EXIT_FUNCTION divacapi_exit(void)
+{
+	finit_capifunc();
+	printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(divacapi_init);
+module_exit(divacapi_exit);
diff --git a/drivers/isdn/hardware/eicon/cardtype.h b/drivers/isdn/hardware/eicon/cardtype.h
new file mode 100644
index 0000000..18a5c42
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/cardtype.h
@@ -0,0 +1,1098 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef _CARDTYPE_H_
+#define _CARDTYPE_H_
+#ifndef CARDTYPE_H_WANT_DATA
+#define CARDTYPE_H_WANT_DATA   0
+#endif
+#ifndef CARDTYPE_H_WANT_IDI_DATA
+#define CARDTYPE_H_WANT_IDI_DATA  0
+#endif
+#ifndef CARDTYPE_H_WANT_RESOURCE_DATA
+#define CARDTYPE_H_WANT_RESOURCE_DATA 1
+#endif
+#ifndef CARDTYPE_H_WANT_FILE_DATA
+#define CARDTYPE_H_WANT_FILE_DATA  1
+#endif
+/*
+ * D-channel protocol identifiers
+ *
+ * Attention: Unfortunately the identifiers defined here differ from
+ *      the identifiers used in Protocol/1/Common/prot/q931.h .
+ *     The only reason for this is that q931.h has not a global
+ *     scope and we did not know about the definitions there.
+ *     But the definitions here cannot be changed easily because
+ *     they are used in setup scripts and programs.
+ *     Thus the definitions here have to be mapped if they are
+ *     used in the protocol code context !
+ *
+ * Now the identifiers are defined in the q931lib/constant.h file.
+ * Unfortunately this file has also not a global scope.
+ * But beginning with PROTTYPE_US any new identifier will get the same
+ * value as the corresponding PROT_* definition in q931lib/constant.h !
+ */
+#define PROTTYPE_MINVAL     0
+#define PROTTYPE_ETSI       0
+#define PROTTYPE_1TR6       1
+#define PROTTYPE_BELG       2
+#define PROTTYPE_FRANC      3
+#define PROTTYPE_ATEL       4
+#define PROTTYPE_NI         5  /* DMS 100, Nortel, National ISDN */
+#define PROTTYPE_5ESS       6  /* 5ESS   , AT&T,   5ESS Custom   */
+#define PROTTYPE_JAPAN      7
+#define PROTTYPE_SWED       8
+#define PROTTYPE_US         9  /* US autodetect */
+#define PROTTYPE_ITALY      10
+#define PROTTYPE_TWAN       11
+#define PROTTYPE_AUSTRAL    12
+#define PROTTYPE_4ESDN      13
+#define PROTTYPE_4ESDS      14
+#define PROTTYPE_4ELDS      15
+#define PROTTYPE_4EMGC      16
+#define PROTTYPE_4EMGI      17
+#define PROTTYPE_HONGKONG   18
+#define PROTTYPE_RBSCAS     19
+#define PROTTYPE_CORNETN    20
+#define PROTTYPE_QSIG       21
+#define PROTTYPE_NI_EWSD    22 /* EWSD, Siemens, National ISDN   */
+#define PROTTYPE_5ESS_NI    23 /* 5ESS, Lucent, National ISDN    */
+#define PROTTYPE_T1CORNETN  24
+#define PROTTYPE_CORNETNQ   25
+#define PROTTYPE_T1CORNETNQ 26
+#define PROTTYPE_T1QSIG     27
+#define PROTTYPE_E1UNCH     28
+#define PROTTYPE_T1UNCH     29
+#define PROTTYPE_E1CHAN     30
+#define PROTTYPE_T1CHAN     31
+#define PROTTYPE_R2CAS      32
+#define PROTTYPE_MAXVAL     32
+/*
+ * Card type identifiers
+ */
+#define CARD_UNKNOWN                      0
+#define CARD_NONE                         0
+  /* DIVA cards */
+#define CARDTYPE_DIVA_MCA                 0
+#define CARDTYPE_DIVA_ISA                 1
+#define CARDTYPE_DIVA_PCM                 2
+#define CARDTYPE_DIVAPRO_ISA              3
+#define CARDTYPE_DIVAPRO_PCM              4
+#define CARDTYPE_DIVAPICO_ISA             5
+#define CARDTYPE_DIVAPICO_PCM             6
+  /* DIVA 2.0 cards */
+#define CARDTYPE_DIVAPRO20_PCI            7
+#define CARDTYPE_DIVA20_PCI               8
+  /* S cards */
+#define CARDTYPE_QUADRO_ISA               9
+#define CARDTYPE_S_ISA                    10
+#define CARDTYPE_S_MCA                    11
+#define CARDTYPE_SX_ISA                   12
+#define CARDTYPE_SX_MCA                   13
+#define CARDTYPE_SXN_ISA                  14
+#define CARDTYPE_SXN_MCA                  15
+#define CARDTYPE_SCOM_ISA                 16
+#define CARDTYPE_SCOM_MCA                 17
+#define CARDTYPE_PR_ISA                   18
+#define CARDTYPE_PR_MCA                   19
+  /* Diva Server cards (formerly called Maestra, later Amadeo) */
+#define CARDTYPE_MAESTRA_ISA              20
+#define CARDTYPE_MAESTRA_PCI              21
+  /* Diva Server cards to be developed (Quadro, Primary rate) */
+#define CARDTYPE_DIVASRV_Q_8M_PCI         22
+#define CARDTYPE_DIVASRV_P_30M_PCI        23
+#define CARDTYPE_DIVASRV_P_2M_PCI         24
+#define CARDTYPE_DIVASRV_P_9M_PCI         25
+  /* DIVA 2.0 cards */
+#define CARDTYPE_DIVA20_ISA               26
+#define CARDTYPE_DIVA20U_ISA              27
+#define CARDTYPE_DIVA20U_PCI              28
+#define CARDTYPE_DIVAPRO20_ISA            29
+#define CARDTYPE_DIVAPRO20U_ISA           30
+#define CARDTYPE_DIVAPRO20U_PCI           31
+  /* DIVA combi cards (piccola ISDN + rockwell V.34 modem) */
+#define CARDTYPE_DIVAMOBILE_PCM           32
+#define CARDTYPE_TDKGLOBALPRO_PCM         33
+  /* DIVA Pro PC OEM card for 'New Media Corporation' */
+#define CARDTYPE_NMC_DIVAPRO_PCM          34
+  /* DIVA Pro 2.0 OEM cards for 'British Telecom' */
+#define CARDTYPE_BT_EXLANE_PCI            35
+#define CARDTYPE_BT_EXLANE_ISA            36
+  /* DIVA low cost cards, 1st name DIVA 3.0, 2nd DIVA 2.01, 3rd ??? */
+#define CARDTYPE_DIVALOW_ISA              37
+#define CARDTYPE_DIVALOWU_ISA             38
+#define CARDTYPE_DIVALOW_PCI              39
+#define CARDTYPE_DIVALOWU_PCI             40
+  /* DIVA combi cards (piccola ISDN + rockwell V.90 modem) */
+#define CARDTYPE_DIVAMOBILE_V90_PCM       41
+#define CARDTYPE_TDKGLOBPRO_V90_PCM       42
+#define CARDTYPE_DIVASRV_P_23M_PCI        43
+#define CARDTYPE_DIVALOW_USB              44
+  /* DIVA Audio (CT) family */
+#define CARDTYPE_DIVA_CT_ST               45
+#define CARDTYPE_DIVA_CT_U                46
+#define CARDTYPE_DIVA_CTLITE_ST           47
+#define CARDTYPE_DIVA_CTLITE_U            48
+  /* DIVA ISDN plus V.90 series */
+#define CARDTYPE_DIVAISDN_V90_PCM         49
+#define CARDTYPE_DIVAISDN_V90_PCI         50
+#define CARDTYPE_DIVAISDN_TA              51
+  /* DIVA Server Voice cards */
+#define CARDTYPE_DIVASRV_VOICE_Q_8M_PCI   52
+  /* DIVA Server V2 cards */
+#define CARDTYPE_DIVASRV_Q_8M_V2_PCI      53
+#define CARDTYPE_DIVASRV_P_30M_V2_PCI     54
+  /* DIVA Server Voice V2 cards */
+#define CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI 55
+#define CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI 56
+    /* Diva LAN */
+#define CARDTYPE_DIVAISDN_LAN             57
+#define CARDTYPE_DIVA_202_PCI_ST          58
+#define CARDTYPE_DIVA_202_PCI_U           59
+#define CARDTYPE_DIVASRV_B_2M_V2_PCI      60
+#define CARDTYPE_DIVASRV_B_2F_PCI         61
+#define CARDTYPE_DIVALOW_USBV2            62
+#define CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI 63
+#define CARDTYPE_DIVA_PRO_30_PCI_ST       64
+#define CARDTYPE_DIVA_CT_ST_V20           65
+/* Diva Mobile V.90 PC Card and Diva ISDN PC Card */
+#define CARDTYPE_DIVAMOBILE_V2_PCM        66
+#define CARDTYPE_DIVA_V2_PCM              67
+/* Re-badged Diva Pro PC Card */
+#define CARDTYPE_DIVA_PC_CARD             68
+  /* next free card type identifier */
+#define CARDTYPE_MAX                      69
+/*
+ * The card families
+ */
+#define FAMILY_DIVA   1
+#define FAMILY_S   2
+#define FAMILY_MAESTRA  3
+#define FAMILY_MAX   4
+/*
+ * The basic card types
+ */
+#define CARD_DIVA           1  /* DSP based, old DSP */
+#define CARD_PRO            2  /* DSP based, new DSP */
+#define CARD_PICO           3  /* HSCX based   */
+#define CARD_S    4  /* IDI on board based */
+#define CARD_SX    5  /* IDI on board based */
+#define CARD_SXN   6  /* IDI on board based */
+#define CARD_SCOM   7  /* IDI on board based */
+#define CARD_QUAD   8  /* IDI on board based */
+#define CARD_PR    9  /* IDI on board based */
+#define CARD_MAE         10  /* IDI on board based */
+#define CARD_MAEQ        11  /* IDI on board based */
+#define CARD_MAEP        12  /* IDI on board based */
+#define CARD_DIVALOW  13  /* IPAC based   */
+#define CARD_CT    14  /* SCOUT based          */
+#define CARD_DIVATA   15  /* DIVA TA */
+#define CARD_DIVALAN  16  /* DIVA LAN */
+#define CARD_MAE2         17  /* IDI on board based */
+#define CARD_MAX   18
+/*
+ * The internal card types of the S family
+ */
+#define CARD_I_NONE   0
+#define CARD_I_S   0
+#define CARD_I_SX   1
+#define CARD_I_SCOM   2
+#define CARD_I_QUAD   3
+#define CARD_I_PR   4
+/*
+ * The bus types we support
+ */
+#define BUS_ISA             1
+#define BUS_PCM             2
+#define BUS_PCI             3
+#define BUS_MCA             4
+#define BUS_USB             5
+#define BUS_COM    6
+#define BUS_LAN    7
+/*
+ * The chips we use for B-channel traffic
+ */
+#define CHIP_NONE           0
+#define CHIP_DSP            1
+#define CHIP_HSCX           2
+#define CHIP_IPAC           3
+#define CHIP_SCOUT          4
+#define CHIP_EXTERN         5
+#define CHIP_IPACX          6
+/*
+ * The structures where the card properties are aggregated by id
+ */
+typedef struct CARD_PROPERTIES
+{   char     *Name;  /* official marketing name     */
+ unsigned short PnPId;  /* plug and play ID (for non PCMIA cards) */
+ unsigned short Version; /* major and minor version no of the card */
+ unsigned char DescType; /* card type to set in the IDI descriptor */
+ unsigned char  Family;  /* basic family of the card     */
+ unsigned short  Features; /* features bits to set in the IDI desc. */
+ unsigned char Card;  /* basic card type       */
+ unsigned char IType;  /* internal type of S cards (read from ram) */
+ unsigned char  Bus;  /* bus type this card is designed for  */
+ unsigned char  Chip;  /* chipset used on card      */
+ unsigned char Adapters; /* number of adapters on card    */
+ unsigned char Channels; /* # of channels per adapter    */
+ unsigned short E_info;  /* # of ram entity info structs per adapter */
+ unsigned short SizeIo;  /* size of IO window per adapter   */
+ unsigned short SizeMem; /* size of memory window per adapter  */
+} CARD_PROPERTIES;
+typedef struct CARD_RESOURCE
+{ unsigned char Int [10];
+ unsigned short IoFirst;
+ unsigned short IoStep;
+ unsigned short IoCnt;
+ unsigned long MemFirst;
+ unsigned long MemStep;
+ unsigned short MemCnt;
+} CARD_RESOURCE;
+/* test if the card of type 't' is a plug & play card */
+#define IS_PNP(t) \
+( \
+ ( \
+  CardProperties[t].Bus != BUS_ISA \
+  && \
+  CardProperties[t].Bus != BUS_MCA \
+ ) \
+ || \
+ ( \
+  CardProperties[t].Family != FAMILY_S \
+  && \
+  CardProperties[t].Card != CARD_DIVA \
+ ) \
+)
+/* extract IDI Descriptor info for card type 't' (p == DescType/Features) */
+#define IDI_PROP(t,p) (CardProperties[t].p)
+#if CARDTYPE_H_WANT_DATA
+#if CARDTYPE_H_WANT_IDI_DATA
+/* include "di_defs.h" for IDI adapter type and feature flag definitions */
+#include "di_defs.h"
+#else /*!CARDTYPE_H_WANT_IDI_DATA*/
+/* define IDI adapter types and feature flags here to prevent inclusion  */
+#ifndef IDI_ADAPTER_S
+#define IDI_ADAPTER_S           1
+#define IDI_ADAPTER_PR          2
+#define IDI_ADAPTER_DIVA        3
+#define IDI_ADAPTER_MAESTRA     4
+#endif
+#ifndef DI_VOICE
+#define DI_VOICE          0x0 /* obsolete define */
+#define DI_FAX3           0x1
+#define DI_MODEM          0x2
+#define DI_POST           0x4
+#define DI_V110           0x8
+#define DI_V120           0x10
+#define DI_POTS           0x20
+#define DI_CODEC          0x40
+#define DI_MANAGE         0x80
+#define DI_V_42           0x0100
+#define DI_EXTD_FAX       0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
+#define DI_AT_PARSER      0x0400 /* Build-in AT Parser in the L2 */
+#define DI_VOICE_OVER_IP  0x0800 /* Voice over IP support */
+#endif
+#endif /*CARDTYPE_H_WANT_IDI_DATA*/
+#define DI_V1x0         (DI_V110 | DI_V120)
+#define DI_NULL         0x0000
+#if defined(SOFT_DSP_SUPPORT)
+#define SOFT_DSP_ADD_FEATURES  (DI_MODEM | DI_FAX3 | DI_AT_PARSER)
+#else
+#define SOFT_DSP_ADD_FEATURES  0
+#endif
+#if defined(SOFT_V110_SUPPORT)
+#define DI_SOFT_V110  DI_V110
+#else
+#define DI_SOFT_V110  0
+#endif
+/*--- CardProperties [Index=CARDTYPE_....] ---------------------------------*/
+CARD_PROPERTIES CardProperties [ ] =
+{
+{ /*  0  */
+ "Diva MCA",       0x6336,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
+ CARD_DIVA,   CARD_I_NONE, BUS_MCA, CHIP_DSP,
+ 1, 2,  0,   8,      0
+},
+{ /*  1  */
+ "Diva ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
+ CARD_DIVA,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,  0,   8,      0
+},
+{ /*  2  */
+ "Diva/PCM",       0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3,
+ CARD_DIVA,   CARD_I_NONE, BUS_PCM, CHIP_DSP,
+ 1, 2,  0,   8,      0
+},
+{ /*  3  */
+ "Diva PRO ISA",      0x0031,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_PRO,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,  0,   8,      0
+},
+{ /*  4  */
+ "Diva PRO PC-Card",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_PRO,   CARD_I_NONE, BUS_PCM, CHIP_DSP,
+ 1, 2,   0,   8,      0
+},
+{ /*  5  */
+ "Diva PICCOLA ISA",     0x0051,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_ISA, CHIP_HSCX,
+ 1, 2,   0,   8,      0
+},
+{ /*  6  */
+ "Diva PICCOLA PCM",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,   0,   8,      0
+},
+{ /*  7  */
+ "Diva PRO 2.0 S/T PCI",    0xe001,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   0,   8,      0
+},
+{ /*  8  */
+ "Diva 2.0 S/T PCI",     0xe002,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCI, CHIP_HSCX,
+ 1, 2,   0,   8,      0
+},
+{ /*  9  */
+ "QUADRO ISA",      0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_QUAD,   CARD_I_QUAD, BUS_ISA, CHIP_NONE,
+ 4, 2,   16,  0,  0x800
+},
+{ /* 10  */
+ "S ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_CODEC,
+ CARD_S,    CARD_I_S,  BUS_ISA, CHIP_NONE,
+ 1, 1,   16,  0,  0x800
+},
+{ /* 11  */
+ "S MCA",       0x6a93,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_CODEC,
+ CARD_S,    CARD_I_S,  BUS_MCA, CHIP_NONE,
+ 1, 1,   16,  16,  0x400
+},
+{ /* 12 */
+ "SX ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_SX,   CARD_I_SX,  BUS_ISA, CHIP_NONE,
+ 1, 2,  16,  0,  0x800
+},
+{ /* 13 */
+ "SX MCA",       0x6a93,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_SX,   CARD_I_SX,  BUS_MCA, CHIP_NONE,
+ 1, 2,  16,  16,  0x400
+},
+{ /* 14 */
+ "SXN ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_SXN,   CARD_I_SCOM, BUS_ISA, CHIP_NONE,
+ 1, 2,   16,  0,   0x800
+},
+{ /* 15 */
+ "SXN MCA",       0x6a93,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_NULL,
+ CARD_SXN,   CARD_I_SCOM, BUS_MCA, CHIP_NONE,
+ 1, 2,  16,  16,  0x400
+},
+{ /* 16 */
+ "SCOM ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_CODEC,
+ CARD_SCOM,   CARD_I_SCOM, BUS_ISA, CHIP_NONE,
+ 1, 2,   16,  0,   0x800
+},
+{ /* 17 */
+ "SCOM MCA",       0x6a93,  0x0100,
+ IDI_ADAPTER_S,  FAMILY_S,  DI_CODEC,
+ CARD_SCOM,   CARD_I_SCOM, BUS_MCA, CHIP_NONE,
+ 1, 2,  16,  16,  0x400
+},
+{ /* 18 */
+ "S2M ISA",       0x0000,  0x0100,
+ IDI_ADAPTER_PR,  FAMILY_S,  DI_NULL,
+ CARD_PR,   CARD_I_PR,  BUS_ISA, CHIP_NONE,
+ 1, 30,  256, 0,   0x4000
+},
+{ /* 19 */
+ "S2M MCA",       0x6abb,  0x0100,
+ IDI_ADAPTER_PR,  FAMILY_S,  DI_NULL,
+ CARD_PR,   CARD_I_PR,  BUS_MCA, CHIP_NONE,
+ 1, 30,  256, 16,  0x4000
+},
+{ /* 20 */
+ "Diva Server BRI-2M ISA",   0x0041,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAE,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,   16,  8,  0
+},
+{ /* 21 */
+ "Diva Server BRI-2M PCI",   0xE010,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAE,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   16,  8,   0
+},
+{ /* 22 */
+ "Diva Server 4BRI-8M PCI",   0xE012,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEQ,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 4, 2,   16,  8,   0
+},
+{ /* 23 */
+ "Diva Server PRI-30M PCI",   0xE014,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{ /* 24 */
+ "Diva Server PRI-2M PCI",   0xe014,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{ /* 25 */
+ "Diva Server PRI-9M PCI",   0x0000,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,     256,  8,   0
+},
+{ /* 26 */
+ "Diva 2.0 S/T ISA",     0x0071,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_ISA, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 27 */
+ "Diva 2.0 U ISA",     0x0091,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_ISA, CHIP_HSCX,
+ 1, 2,   0,   8,   0
+},
+{ /* 28 */
+ "Diva 2.0 U PCI",     0xe004,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | DI_POTS | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCI, CHIP_HSCX,
+ 1, 2,   0,   8,   0
+},
+{ /* 29 */
+ "Diva PRO 2.0 S/T ISA",    0x0061,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,  0,   8,   0
+},
+{ /* 30 */
+ "Diva PRO 2.0 U ISA",    0x0081,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,  0,   8,   0
+},
+{ /* 31 */
+ "Diva PRO 2.0 U PCI",    0xe003,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   0,   8,   0
+},
+{ /* 32 */
+ "Diva MOBILE",      0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 33 */
+ "TDK DFI3600",      0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 34 (OEM version of 4 - "Diva PRO PC-Card") */
+ "New Media ISDN",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_PRO,   CARD_I_NONE, BUS_PCM, CHIP_DSP,
+ 1, 2,   0,   8,   0
+},
+{ /* 35 (OEM version of 7 - "Diva PRO 2.0 S/T PCI") */
+ "BT ExLane PCI",     0xe101,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   0,   8,   0
+},
+{ /* 36 (OEM version of 29 - "Diva PRO 2.0 S/T ISA") */
+ "BT ExLane ISA",     0x1061,  0x0200,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_POTS,
+ CARD_PRO,   CARD_I_NONE, BUS_ISA, CHIP_DSP,
+ 1, 2,   0,   8,   0
+},
+{ /* 37 */
+ "Diva 2.01 S/T ISA",    0x00A1,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_ISA, CHIP_IPAC,
+ 1, 2,   0,   8,      0
+},
+{ /* 38 */
+ "Diva 2.01 U ISA",     0x00B1,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_ISA, CHIP_IPAC,
+ 1, 2,   0,   8,      0
+},
+{ /* 39 */
+ "Diva 2.01 S/T PCI",    0xe005,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPAC,
+ 1, 2,   0,   8,   0
+},
+{ /* 40        no ID yet */
+ "Diva 2.01 U PCI",     0x0000,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPAC,
+ 1, 2,   0,   8,   0
+},
+{ /* 41 */
+ "Diva MOBILE V.90",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 42 */
+ "TDK DFI3600 V.90",     0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_HSCX,
+ 1, 2,  0,   8,   0
+},
+{ /* 43 */
+ "Diva Server PRI-23M PCI",   0xe014,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{ /* 44 */
+ "Diva 2.01 S/T USB",    0x1000,     0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_USB, CHIP_IPAC,
+ 1,  2,  0,  8,   0
+},
+{ /* 45 */
+ "Diva CT S/T PCI",    0xe006,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 46 */
+ "Diva CT U PCI",     0xe007,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 47 */
+ "Diva CT Lite S/T PCI",   0xe008,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 48 */
+ "Diva CT Lite U PCI",   0xe009,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 49 */
+ "Diva ISDN+V.90 PC Card", 0x8D8C, 0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_DIVALOW, CARD_I_NONE, BUS_PCM, CHIP_IPAC,
+ 1, 2,  0,   8,   0
+},
+{ /* 50 */
+ "Diva ISDN+V.90 PCI",    0xe00A,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120  | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPAC,
+ 1, 2,   0,   8,   0
+},
+{ /* 51 (DivaTA)      no ID */
+ "Diva TA",       0x0000,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V110 | DI_FAX3 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVATA,  CARD_I_NONE, BUS_COM, CHIP_EXTERN,
+ 1, 1,   0,   8,   0
+},
+{ /* 52 (Diva Server 4BRI-8M PCI adapter enabled for Voice) */
+ "Diva Server Voice 4BRI-8M PCI", 0xE016,  0x0100,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
+ CARD_MAEQ,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 4, 2,   16,  8,   0
+},
+{ /* 53 (Diva Server 4BRI 2.0 adapter) */
+ "Diva Server 4BRI-8M 2.0 PCI",  0xE013,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEQ,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 4, 2,   16,  8,   0
+},
+{ /* 54 (Diva Server PRI 2.0 adapter) */
+ "Diva Server PRI 2.0 PCI",   0xE015,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{ /* 55 (Diva Server 4BRI-8M 2.0 PCI adapter enabled for Voice) */
+ "Diva Server Voice 4BRI-8M 2.0 PCI", 0xE017,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
+ CARD_MAEQ,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 4, 2,   16,  8,   0
+},
+{ /* 56 (Diva Server PRI 2.0 PCI adapter enabled for Voice) */
+ "Diva Server Voice PRI 2.0 PCI",  0xE019,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
+ CARD_MAEP,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 30,  256,  8,   0
+},
+{
+ /* 57 (DivaLan )      no ID */
+ "Diva LAN",       0x0000,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V110 | DI_FAX3 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALAN,  CARD_I_NONE, BUS_LAN, CHIP_EXTERN,
+ 1, 1,   0,   8,   0
+},
+{ /* 58 */
+ "Diva 2.02 PCI S/T",    0xE00B,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES | DI_SOFT_V110,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPACX,
+ 1, 2,   0,   8,   0
+},
+{ /* 59 */
+ "Diva 2.02 PCI U",     0xE00C,  0x0300,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_PCI, CHIP_IPACX,
+ 1, 2,   0,   8,   0
+},
+{ /* 60 */
+ "Diva Server BRI-2M 2.0 PCI",     0xE018,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_MAE2,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   16,  8,   0
+},
+{ /* 61  (the previous name was Diva Server BRI-2F 2.0 PCI) */
+ "Diva Server 2FX",                      0xE01A,     0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_SOFT_V110,
+ CARD_MAE2,          CARD_I_NONE,    BUS_PCI,    CHIP_IPACX,
+ 1,  2,      16,     8,   0
+},
+{ /* 62 */
+ " Diva ISDN USB 2.0",    0x1003,     0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_DIVALOW,  CARD_I_NONE, BUS_USB, CHIP_IPACX,
+ 1, 2,  0,  8,   0
+},
+{ /* 63 (Diva Server BRI-2M 2.0 PCI adapter enabled for Voice) */
+ "Diva Server Voice BRI-2M 2.0 PCI", 0xE01B,  0x0200,
+ IDI_ADAPTER_MAESTRA,FAMILY_MAESTRA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_VOICE_OVER_IP,
+ CARD_MAE2,   CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1, 2,   16,  8,   0
+},
+{ /* 64 */
+ "Diva Pro 3.0 PCI",    0xe00d,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM,
+ CARD_PRO,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 65 */
+ "Diva ISDN + CT 2.0",    0xE00E,  0x0300,
+ IDI_ADAPTER_DIVA   ,FAMILY_DIVA, DI_V1x0 | DI_FAX3 | DI_MODEM | DI_CODEC,
+ CARD_CT,       CARD_I_NONE, BUS_PCI, CHIP_DSP,
+ 1,  2,  0,  0,   0
+},
+{ /* 66 */
+ "Diva Mobile V.90 PC Card",  0x8331,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_IPACX,
+ 1, 2,  0,   8,   0
+},
+{ /* 67 */
+ "Diva ISDN PC Card",  0x8311,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PICO,   CARD_I_NONE, BUS_PCM, CHIP_IPACX,
+ 1, 2,  0,   8,   0
+},
+{ /* 68 */
+ "Diva ISDN PC Card",  0x0000,  0x0100,
+ IDI_ADAPTER_DIVA, FAMILY_DIVA, DI_V120 | SOFT_DSP_ADD_FEATURES,
+ CARD_PRO,   CARD_I_NONE, BUS_PCM, CHIP_DSP,
+ 1, 2,   0,   8,      0
+},
+} ;
+#if CARDTYPE_H_WANT_RESOURCE_DATA
+/*--- CardResource [Index=CARDTYPE_....]   ---------------------------(GEI)-*/
+CARD_RESOURCE CardResource [ ] =  {
+/*   Interrupts     IO-Address   Mem-Address */
+/* 0*/ {  3,4,9,0,0,0,0,0,0,0,   0x200,0x20,16,   0x0,0x0,0   }, // DIVA MCA
+/* 1*/ {  3,4,9,10,11,12,0,0,0,0,  0x200,0x20,16,   0x0,0x0,0   }, // DIVA ISA
+/* 2*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA PCMCIA
+/* 3*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,   0x0,0x0,0   }, // DIVA PRO ISA
+/* 4*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA PRO PCMCIA
+/* 5*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA PICCOLA ISA
+/* 6*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA PICCOLA PCMCIA
+/* 7*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA PRO 2.0 PCI
+/* 8*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.0 PCI
+/* 9*/ {  3,4,5,7,9,10,11,12,0,0,  0x0,0x0,0,   0x80000,0x2000,64 }, // QUADRO ISA
+/*10*/ {  3,4,9,10,11,12,0,0,0,0,  0x0,0x0,0,   0xc0000,0x2000,16 }, // S ISA
+/*11*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x2000,16 }, // S MCA
+/*12*/ {  3,4,9,10,11,12,0,0,0,0,  0x0,0x0,0,   0xc0000,0x2000,16 }, // SX ISA
+/*13*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x2000,16 }, // SX MCA
+/*14*/ {  3,4,5,7,9,10,11,12,0,0,  0x0,0x0,0,   0x80000,0x0800,256 }, // SXN ISA
+/*15*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x2000,16 }, // SXN MCA
+/*16*/ {  3,4,5,7,9,10,11,12,0,0,  0x0,0x0,0,   0x80000,0x0800,256 }, // SCOM ISA
+/*17*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x2000,16 }, // SCOM MCA
+/*18*/ {  3,4,5,7,9,10,11,12,0,0,  0x0,0x0,0,   0xc0000,0x4000,16 }, // S2M ISA
+/*19*/ {  3,4,9,0,0,0,0,0,0,0,  0xc00,0x10,16,  0xc0000,0x4000,16 }, // S2M MCA
+/*20*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // MAESTRA ISA
+/*21*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // MAESTRA PCI
+/*22*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // MAESTRA QUADRO ISA
+/*23*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // MAESTRA QUADRO PCI
+/*24*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // MAESTRA PRIMARY ISA
+/*25*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // MAESTRA PRIMARY PCI
+/*26*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA 2.0 ISA
+/*27*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA 2.0 /U ISA
+/*28*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.0 /U PCI
+/*29*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,   0x0,0x0,0   }, // DIVA PRO 2.0 ISA
+/*30*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,   0x0,0x0,0   }, // DIVA PRO 2.0 /U ISA
+/*31*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA PRO 2.0 /U PCI
+/*32*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA MOBILE
+/*33*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // TDK DFI3600 (same as DIVA MOBILE [32])
+/*34*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // New Media ISDN (same as DIVA PRO PCMCIA [4])
+/*35*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // BT ExLane PCI (same as DIVA PRO 2.0 PCI [7])
+/*36*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,   0x0,0x0,0   }, // BT ExLane ISA (same as DIVA PRO 2.0 ISA [29])
+/*37*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA 2.01 S/T ISA
+/*38*/ {  3,5,7,9,10,11,12,14,15,0, 0x200,0x20,16,  0x0,0x0,0   }, // DIVA 2.01 U ISA
+/*39*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.01 S/T PCI
+/*40*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.01 U PCI
+/*41*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA MOBILE V.90
+/*42*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // TDK DFI3600 V.90 (same as DIVA MOBILE V.90 [39])
+/*43*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // DIVA Server PRI-23M PCI
+/*44*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA 2.01 S/T USB
+/*45*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT S/T PCI
+/*46*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT U PCI
+/*47*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT Lite S/T PCI
+/*48*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT Lite U PCI
+/*49*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA ISDN+V.90 PC Card
+/*50*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA ISDN+V.90 PCI
+/*51*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA TA
+/*52*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // MAESTRA VOICE QUADRO PCI
+/*53*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // MAESTRA VOICE QUADRO PCI
+/*54*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // MAESTRA VOICE PRIMARY PCI
+/*55*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x20,2048,  0x0,0x0,0   }, // MAESTRA VOICE QUADRO PCI
+/*56*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // MAESTRA VOICE PRIMARY PCI
+/*57*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA LAN
+/*58*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.02 S/T PCI
+/*59*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 2.02 U PCI
+/*60*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // Diva Server BRI-2M 2.0 PCI
+/*61*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // Diva Server BRI-2F PCI
+/*62*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA 2.01 S/T USB
+/*63*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // Diva Server Voice BRI-2M 2.0 PCI
+/*64*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA 3.0 PCI
+/*65*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA CT S/T PCI V2.0
+/*66*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA Mobile V.90 PC Card
+/*67*/ {  0,0,0,0,0,0,0,0,0,0,  0x0,0x0,0,   0x0,0x0,0   }, // DIVA ISDN PC Card
+/*68*/ {  3,4,5,7,9,10,11,12,14,15, 0x0,0x8,8192,  0x0,0x0,0   }, // DIVA ISDN PC Card
+};
+#endif /*CARDTYPE_H_WANT_RESOURCE_DATA*/
+#else /*!CARDTYPE_H_WANT_DATA*/
+extern CARD_PROPERTIES  CardProperties [] ;
+extern CARD_RESOURCE  CardResource [] ;
+#endif /*CARDTYPE_H_WANT_DATA*/
+/*
+ * all existing download files
+ */
+#define CARD_DSP_CNT  5
+#define CARD_PROT_CNT  9
+#define CARD_FT_UNKNOWN     0
+#define CARD_FT_B   1
+#define CARD_FT_D   2
+#define CARD_FT_S   3
+#define CARD_FT_M   4
+#define CARD_FT_NEW_DSP_COMBIFILE 5  /* File format of new DSP code (the DSP code powered by Telindus) */
+#define CARD_FILE_NONE      0
+#define CARD_B_S   1
+#define CARD_B_P   2
+#define CARD_D_K1   3
+#define CARD_D_K2   4
+#define CARD_D_H   5
+#define CARD_D_V   6
+#define CARD_D_M   7
+#define CARD_D_F   8
+#define CARD_P_S_E   9
+#define CARD_P_S_1   10
+#define CARD_P_S_B   11
+#define CARD_P_S_F   12
+#define CARD_P_S_A   13
+#define CARD_P_S_N   14
+#define CARD_P_S_5   15
+#define CARD_P_S_J   16
+#define CARD_P_SX_E   17
+#define CARD_P_SX_1   18
+#define CARD_P_SX_B   19
+#define CARD_P_SX_F   20
+#define CARD_P_SX_A   21
+#define CARD_P_SX_N   22
+#define CARD_P_SX_5   23
+#define CARD_P_SX_J   24
+#define CARD_P_SY_E   25
+#define CARD_P_SY_1   26
+#define CARD_P_SY_B   27
+#define CARD_P_SY_F   28
+#define CARD_P_SY_A   29
+#define CARD_P_SY_N   30
+#define CARD_P_SY_5   31
+#define CARD_P_SY_J   32
+#define CARD_P_SQ_E   33
+#define CARD_P_SQ_1   34
+#define CARD_P_SQ_B   35
+#define CARD_P_SQ_F   36
+#define CARD_P_SQ_A   37
+#define CARD_P_SQ_N   38
+#define CARD_P_SQ_5   39
+#define CARD_P_SQ_J   40
+#define CARD_P_P_E   41
+#define CARD_P_P_1   42
+#define CARD_P_P_B   43
+#define CARD_P_P_F   44
+#define CARD_P_P_A   45
+#define CARD_P_P_N   46
+#define CARD_P_P_5   47
+#define CARD_P_P_J   48
+#define CARD_P_M_E   49
+#define CARD_P_M_1   50
+#define CARD_P_M_B   51
+#define CARD_P_M_F   52
+#define CARD_P_M_A   53
+#define CARD_P_M_N   54
+#define CARD_P_M_5   55
+#define CARD_P_M_J   56
+#define CARD_P_S_S   57
+#define CARD_P_SX_S   58
+#define CARD_P_SY_S   59
+#define CARD_P_SQ_S   60
+#define CARD_P_P_S   61
+#define CARD_P_M_S   62
+#define CARD_D_NEW_DSP_COMBIFILE 63
+typedef struct CARD_FILES_DATA
+{
+ char *    Name;
+ unsigned char  Type;
+}
+CARD_FILES_DATA;
+typedef struct CARD_FILES
+{
+ unsigned char  Boot;
+ unsigned char  Dsp  [CARD_DSP_CNT];
+ unsigned char  DspTelindus;
+ unsigned char  Prot [CARD_PROT_CNT];
+}
+CARD_FILES;
+#if CARDTYPE_H_WANT_DATA
+#if CARDTYPE_H_WANT_FILE_DATA
+CARD_FILES_DATA CardFData [] =  {
+// Filename   Filetype
+ 0,     CARD_FT_UNKNOWN,
+ "didnload.bin",  CARD_FT_B,
+ "diprload.bin",  CARD_FT_B,
+ "didiva.bin",  CARD_FT_D,
+ "didivapp.bin",  CARD_FT_D,
+ "dihscx.bin",  CARD_FT_D,
+ "div110.bin",  CARD_FT_D,
+ "dimodem.bin",  CARD_FT_D,
+ "difax.bin",  CARD_FT_D,
+ "di_etsi.bin",  CARD_FT_S,
+ "di_1tr6.bin",  CARD_FT_S,
+ "di_belg.bin",  CARD_FT_S,
+ "di_franc.bin",  CARD_FT_S,
+ "di_atel.bin",  CARD_FT_S,
+ "di_ni.bin",  CARD_FT_S,
+ "di_5ess.bin",  CARD_FT_S,
+ "di_japan.bin",  CARD_FT_S,
+ "di_etsi.sx",  CARD_FT_S,
+ "di_1tr6.sx",  CARD_FT_S,
+ "di_belg.sx",  CARD_FT_S,
+ "di_franc.sx",  CARD_FT_S,
+ "di_atel.sx",  CARD_FT_S,
+ "di_ni.sx",   CARD_FT_S,
+ "di_5ess.sx",  CARD_FT_S,
+ "di_japan.sx",  CARD_FT_S,
+ "di_etsi.sy",  CARD_FT_S,
+ "di_1tr6.sy",  CARD_FT_S,
+ "di_belg.sy",  CARD_FT_S,
+ "di_franc.sy",  CARD_FT_S,
+ "di_atel.sy",  CARD_FT_S,
+ "di_ni.sy",   CARD_FT_S,
+ "di_5ess.sy",  CARD_FT_S,
+ "di_japan.sy",  CARD_FT_S,
+ "di_etsi.sq",  CARD_FT_S,
+ "di_1tr6.sq",  CARD_FT_S,
+ "di_belg.sq",  CARD_FT_S,
+ "di_franc.sq",  CARD_FT_S,
+ "di_atel.sq",  CARD_FT_S,
+ "di_ni.sq",   CARD_FT_S,
+ "di_5ess.sq",  CARD_FT_S,
+ "di_japan.sq",  CARD_FT_S,
+ "di_etsi.p",  CARD_FT_S,
+ "di_1tr6.p",  CARD_FT_S,
+ "di_belg.p",  CARD_FT_S,
+ "di_franc.p",  CARD_FT_S,
+ "di_atel.p",  CARD_FT_S,
+ "di_ni.p",   CARD_FT_S,
+ "di_5ess.p",  CARD_FT_S,
+ "di_japan.p",  CARD_FT_S,
+ "di_etsi.sm",  CARD_FT_M,
+ "di_1tr6.sm",  CARD_FT_M,
+ "di_belg.sm",  CARD_FT_M,
+ "di_franc.sm",  CARD_FT_M,
+ "di_atel.sm",  CARD_FT_M,
+ "di_ni.sm",   CARD_FT_M,
+ "di_5ess.sm",  CARD_FT_M,
+ "di_japan.sm",  CARD_FT_M,
+ "di_swed.bin",  CARD_FT_S,
+ "di_swed.sx",  CARD_FT_S,
+ "di_swed.sy",  CARD_FT_S,
+ "di_swed.sq",  CARD_FT_S,
+ "di_swed.p",  CARD_FT_S,
+ "di_swed.sm",  CARD_FT_M,
+    "didspdld.bin",     CARD_FT_NEW_DSP_COMBIFILE
+};
+CARD_FILES CardFiles [] =
+{
+ { /* CARD_UNKNOWN */
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_DIVA */
+  CARD_FILE_NONE,
+  CARD_D_K1, CARD_D_H, CARD_D_V, CARD_FILE_NONE, CARD_D_F,
+  CARD_D_NEW_DSP_COMBIFILE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_PRO  */
+  CARD_FILE_NONE,
+  CARD_D_K2, CARD_D_H, CARD_D_V, CARD_D_M, CARD_D_F,
+  CARD_D_NEW_DSP_COMBIFILE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_PICO */
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_S    */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_S_E, CARD_P_S_1, CARD_P_S_B, CARD_P_S_F,
+  CARD_P_S_A, CARD_P_S_N, CARD_P_S_5, CARD_P_S_J,
+  CARD_P_S_S
+ },
+ { /* CARD_SX   */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_SX_E, CARD_P_SX_1, CARD_P_SX_B, CARD_P_SX_F,
+  CARD_P_SX_A, CARD_P_SX_N, CARD_P_SX_5, CARD_P_SX_J,
+  CARD_P_SX_S
+ },
+ { /* CARD_SXN  */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_SY_E, CARD_P_SY_1, CARD_P_SY_B, CARD_P_SY_F,
+  CARD_P_SY_A, CARD_P_SY_N, CARD_P_SY_5, CARD_P_SY_J,
+  CARD_P_SY_S
+ },
+ { /* CARD_SCOM */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_SY_E, CARD_P_SY_1, CARD_P_SY_B, CARD_P_SY_F,
+  CARD_P_SY_A, CARD_P_SY_N, CARD_P_SY_5, CARD_P_SY_J,
+  CARD_P_SY_S
+ },
+ { /* CARD_QUAD */
+  CARD_B_S,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_SQ_E, CARD_P_SQ_1, CARD_P_SQ_B, CARD_P_SQ_F,
+  CARD_P_SQ_A, CARD_P_SQ_N, CARD_P_SQ_5, CARD_P_SQ_J,
+  CARD_P_SQ_S
+ },
+ { /* CARD_PR   */
+  CARD_B_P,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_P_P_E, CARD_P_P_1, CARD_P_P_B, CARD_P_P_F,
+  CARD_P_P_A, CARD_P_P_N, CARD_P_P_5, CARD_P_P_J,
+  CARD_P_P_S
+ },
+ { /* CARD_MAE  */
+  CARD_FILE_NONE,
+  CARD_D_K2, CARD_D_H, CARD_D_V, CARD_D_M, CARD_D_F,
+  CARD_D_NEW_DSP_COMBIFILE,
+  CARD_P_M_E, CARD_P_M_1, CARD_P_M_B, CARD_P_M_F,
+  CARD_P_M_A, CARD_P_M_N, CARD_P_M_5, CARD_P_M_J,
+  CARD_P_M_S
+ },
+ { /* CARD_MAEQ */  /* currently not supported */
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ },
+ { /* CARD_MAEP */  /* currently not supported */
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE, CARD_FILE_NONE,
+  CARD_FILE_NONE
+ }
+};
+#endif /*CARDTYPE_H_WANT_FILE_DATA*/
+#else /*!CARDTYPE_H_WANT_DATA*/
+extern CARD_FILES_DATA  CardFData [] ;
+extern CARD_FILES   CardFiles [] ;
+#endif /*CARDTYPE_H_WANT_DATA*/
+#endif /* _CARDTYPE_H_ */
diff --git a/drivers/isdn/hardware/eicon/cp_vers.h b/drivers/isdn/hardware/eicon/cp_vers.h
new file mode 100644
index 0000000..cb5ada3
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/cp_vers.h
@@ -0,0 +1,26 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+static char diva_capi_common_code_build[] = "102-28";  
diff --git a/drivers/isdn/hardware/eicon/dadapter.c b/drivers/isdn/hardware/eicon/dadapter.c
new file mode 100644
index 0000000..6e548a2
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dadapter.c
@@ -0,0 +1,366 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "pc.h"
+#include "debuglib.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "dadapter.h"
+/* --------------------------------------------------------------------------
+  Adapter array change notification framework
+   -------------------------------------------------------------------------- */
+typedef struct _didd_adapter_change_notification {
+ didd_adapter_change_callback_t callback;
+ void IDI_CALL_ENTITY_T *    context;
+} didd_adapter_change_notification_t, \
+ * IDI_CALL_ENTITY_T pdidd_adapter_change_notification_t;
+#define DIVA_DIDD_MAX_NOTIFICATIONS 256
+static didd_adapter_change_notification_t\
+              NotificationTable[DIVA_DIDD_MAX_NOTIFICATIONS];
+/* --------------------------------------------------------------------------
+  Array to held adapter information
+   -------------------------------------------------------------------------- */
+static DESCRIPTOR  HandleTable[NEW_MAX_DESCRIPTORS];
+dword Adapters = 0; /* Number of adapters */
+/* --------------------------------------------------------------------------
+  Shadow IDI_DIMAINT
+  and 'shadow' debug stuff
+   -------------------------------------------------------------------------- */
+static void no_printf (unsigned char * format, ...)
+{
+#ifdef EBUG
+	va_list ap;
+	va_start (ap, format);
+	debug((format, ap));
+	va_end (ap);
+#endif
+}
+
+/* -------------------------------------------------------------------------
+  Portable debug Library
+  ------------------------------------------------------------------------- */
+#include "debuglib.c"
+  
+static DESCRIPTOR  MAdapter =  {IDI_DIMAINT, /* Adapter Type */
+                0x00,     /* Channels */
+                0x0000,    /* Features */
+                (IDI_CALL)no_printf};
+/* --------------------------------------------------------------------------
+  DAdapter. Only IDI clients with buffer, that is huge enough to
+  get all descriptors will receive information about DAdapter
+  { byte type, byte channels, word features, IDI_CALL request }
+   -------------------------------------------------------------------------- */
+static void IDI_CALL_LINK_T diva_dadapter_request (ENTITY IDI_CALL_ENTITY_T *);
+static DESCRIPTOR  DAdapter =  {IDI_DADAPTER, /* Adapter Type */
+                0x00,     /* Channels */
+                0x0000,    /* Features */
+                diva_dadapter_request };
+/* --------------------------------------------------------------------------
+  LOCALS
+   -------------------------------------------------------------------------- */
+static dword diva_register_adapter_callback (\
+                   didd_adapter_change_callback_t callback,
+                   void IDI_CALL_ENTITY_T* context);
+static void diva_remove_adapter_callback (dword handle);
+static void diva_notify_adapter_change (DESCRIPTOR* d, int removal);
+static diva_os_spin_lock_t didd_spin;
+/* --------------------------------------------------------------------------
+  Should be called as first step, after driver init
+  -------------------------------------------------------------------------- */
+void diva_didd_load_time_init (void) {
+ memset (&HandleTable[0], 0x00, sizeof(HandleTable));
+ memset (&NotificationTable[0], 0x00, sizeof(NotificationTable));
+ diva_os_initialize_spin_lock (&didd_spin, "didd");
+}
+/* --------------------------------------------------------------------------
+  Should be called as last step, if driver does unload
+  -------------------------------------------------------------------------- */
+void diva_didd_load_time_finit (void) {
+ diva_os_destroy_spin_lock (&didd_spin, "didd");
+}
+/* --------------------------------------------------------------------------
+  Called in order to register new adapter in adapter array
+  return adapter handle (> 0) on success
+  return -1 adapter array overflow
+  -------------------------------------------------------------------------- */
+static int diva_didd_add_descriptor (DESCRIPTOR* d) {
+ diva_os_spin_lock_magic_t      irql;
+ int i;
+ if (d->type == IDI_DIMAINT) {
+  if (d->request) {
+   MAdapter.request = d->request;
+   dprintf = (DIVA_DI_PRINTF)d->request;
+   diva_notify_adapter_change (&MAdapter, 0); /* Inserted */
+   DBG_TRC (("DIMAINT registered, dprintf=%08x", d->request))
+  } else {
+   DBG_TRC (("DIMAINT removed"))
+   diva_notify_adapter_change (&MAdapter, 1); /* About to remove */
+   MAdapter.request = (IDI_CALL)no_printf;
+   dprintf = no_printf;
+  }
+  return (NEW_MAX_DESCRIPTORS);
+ }
+ for (i = 0; i < NEW_MAX_DESCRIPTORS; i++) {
+  diva_os_enter_spin_lock (&didd_spin, &irql, "didd_add");
+  if (HandleTable[i].type == 0) {
+   memcpy (&HandleTable[i], d, sizeof(*d));
+   Adapters++;
+   diva_os_leave_spin_lock (&didd_spin, &irql, "didd_add");
+   diva_notify_adapter_change (d, 0); /* we have new adapter */
+   DBG_TRC (("Add adapter[%d], request=%08x", (i+1), d->request))
+   return (i+1);
+  }
+  diva_os_leave_spin_lock (&didd_spin, &irql, "didd_add");
+ }
+ DBG_ERR (("Can't add adapter, out of resources"))
+ return (-1);
+}
+/* --------------------------------------------------------------------------
+  Called in order to remove one registered adapter from array
+  return adapter handle (> 0) on success
+  return 0 on success
+  -------------------------------------------------------------------------- */
+static int diva_didd_remove_descriptor (IDI_CALL request) {
+ diva_os_spin_lock_magic_t      irql;
+ int i;
+ if (request == MAdapter.request) {
+  DBG_TRC(("DIMAINT removed"))
+  dprintf = no_printf;
+  diva_notify_adapter_change (&MAdapter, 1); /* About to remove */
+  MAdapter.request = (IDI_CALL)no_printf;
+  return (0);
+ }
+ for (i = 0; (Adapters && (i < NEW_MAX_DESCRIPTORS)); i++) {
+  if (HandleTable[i].request == request) {
+   diva_notify_adapter_change (&HandleTable[i], 1); /* About to remove */
+   diva_os_enter_spin_lock (&didd_spin, &irql, "didd_rm");
+   memset (&HandleTable[i], 0x00, sizeof(HandleTable[0]));
+   Adapters--;
+   diva_os_leave_spin_lock (&didd_spin, &irql, "didd_rm");
+   DBG_TRC (("Remove adapter[%d], request=%08x", (i+1), request))
+   return (0);
+  }
+ }
+ DBG_ERR (("Invalid request=%08x, can't remove adapter", request))
+ return (-1);
+}
+/* --------------------------------------------------------------------------
+  Read adapter array
+  return 1 if not enough space to save all available adapters
+   -------------------------------------------------------------------------- */
+static int diva_didd_read_adapter_array (DESCRIPTOR* buffer, int length) {
+ diva_os_spin_lock_magic_t      irql;
+ int src, dst;
+ memset (buffer, 0x00, length);
+ length /= sizeof(DESCRIPTOR);
+ DBG_TRC (("DIDD_Read, space = %d, Adapters = %d", length, Adapters+2))
+ 
+ diva_os_enter_spin_lock (&didd_spin, &irql, "didd_read");
+ for (src = 0, dst = 0;
+    (Adapters && (src < NEW_MAX_DESCRIPTORS) && (dst < length));
+    src++) {
+  if (HandleTable[src].type) {
+   memcpy (&buffer[dst], &HandleTable[src], sizeof(DESCRIPTOR));
+   dst++;
+  }
+ }
+ diva_os_leave_spin_lock (&didd_spin, &irql, "didd_read");
+ if (dst < length) {
+  memcpy (&buffer[dst], &MAdapter, sizeof(DESCRIPTOR));
+  dst++;
+ } else {
+  DBG_ERR (("Can't write DIMAINT. Array too small"))
+ }
+ if (dst < length) {
+  memcpy (&buffer[dst], &DAdapter, sizeof(DESCRIPTOR));
+  dst++;
+ } else {
+  DBG_ERR (("Can't write DADAPTER. Array too small"))
+ }
+ DBG_TRC (("Read %d adapters", dst))
+ return (dst == length);
+}
+/* --------------------------------------------------------------------------
+  DAdapter request function.
+  This function does process only synchronous requests, and is used
+  for reception/registration of new interfaces
+   -------------------------------------------------------------------------- */
+static void IDI_CALL_LINK_T diva_dadapter_request (\
+                      ENTITY IDI_CALL_ENTITY_T *e) {
+ IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e ;
+ if (e->Req) { /* We do not process it, also return error */
+  e->Rc = OUT_OF_RESOURCES;
+  DBG_ERR (("Can't process async request, Req=%02x", e->Req))
+  return;
+ }
+ /*
+  So, we process sync request
+  */
+ switch (e->Rc) {
+  case IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY: {
+   diva_didd_adapter_notify_t* pinfo = &syncReq->didd_notify.info;
+   pinfo->handle = diva_register_adapter_callback (\
+             (didd_adapter_change_callback_t)pinfo->callback,
+             (void IDI_CALL_ENTITY_T *)pinfo->context);
+   e->Rc = 0xff;
+  } break;
+  case IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY: {
+   diva_didd_adapter_notify_t* pinfo = &syncReq->didd_notify.info;
+   diva_remove_adapter_callback (pinfo->handle);
+   e->Rc = 0xff;
+  } break;
+  case IDI_SYNC_REQ_DIDD_ADD_ADAPTER: {
+   diva_didd_add_adapter_t* pinfo = &syncReq->didd_add_adapter.info;
+   if (diva_didd_add_descriptor ((DESCRIPTOR*)pinfo->descriptor) < 0) {
+    e->Rc = OUT_OF_RESOURCES;
+   } else {
+    e->Rc = 0xff;
+   }
+  } break;
+  case IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER: {
+   diva_didd_remove_adapter_t* pinfo = &syncReq->didd_remove_adapter.info;
+   if (diva_didd_remove_descriptor ((IDI_CALL)pinfo->p_request) < 0) {
+    e->Rc = OUT_OF_RESOURCES;
+   } else {
+    e->Rc = 0xff;
+   }
+  } break;
+  case IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY: {
+   diva_didd_read_adapter_array_t* pinfo =\
+                &syncReq->didd_read_adapter_array.info;
+   if (diva_didd_read_adapter_array ((DESCRIPTOR*)pinfo->buffer,
+                  (int)pinfo->length)) {
+    e->Rc = OUT_OF_RESOURCES;
+   } else {
+    e->Rc = 0xff;
+   }
+  } break;
+  default:
+   DBG_ERR (("Can't process sync request, Req=%02x", e->Rc))
+   e->Rc = OUT_OF_RESOURCES;
+ }
+}
+/* --------------------------------------------------------------------------
+  IDI client does register his notification function
+  -------------------------------------------------------------------------- */
+static dword diva_register_adapter_callback (\
+                   didd_adapter_change_callback_t callback,
+                   void IDI_CALL_ENTITY_T* context) {
+ diva_os_spin_lock_magic_t irql;
+ dword i;
+ 
+ for (i = 0; i < DIVA_DIDD_MAX_NOTIFICATIONS; i++) {
+  diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy_add");
+  if (!NotificationTable[i].callback) {
+   NotificationTable[i].callback = callback;
+   NotificationTable[i].context = context;
+   diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_add");
+   DBG_TRC(("Register adapter notification[%d]=%08x", i+1, callback))
+   return (i+1);
+  }
+  diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_add");
+ }
+ DBG_ERR (("Can't register adapter notification, overflow"))
+ return (0);
+}
+/* --------------------------------------------------------------------------
+  IDI client does register his notification function
+  -------------------------------------------------------------------------- */
+static void diva_remove_adapter_callback (dword handle) {
+ diva_os_spin_lock_magic_t irql;
+ if (handle && ((--handle) < DIVA_DIDD_MAX_NOTIFICATIONS)) {
+  diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy_rm");
+  NotificationTable[handle].callback = NULL;
+  NotificationTable[handle].context  = NULL;
+  diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy_rm");
+  DBG_TRC(("Remove adapter notification[%d]", (int)(handle+1)))
+  return;
+ }
+ DBG_ERR(("Can't remove adapter notification, handle=%d", handle))
+}
+/* --------------------------------------------------------------------------
+  Notify all client about adapter array change
+  Does suppose following behavior in the client side:
+  Step 1: Redister Notification
+  Step 2: Read Adapter Array
+  -------------------------------------------------------------------------- */
+static void diva_notify_adapter_change (DESCRIPTOR* d, int removal) {
+ int i, do_notify;
+ didd_adapter_change_notification_t nfy;
+ diva_os_spin_lock_magic_t irql;
+ for (i = 0; i < DIVA_DIDD_MAX_NOTIFICATIONS; i++) {
+  do_notify = 0;
+  diva_os_enter_spin_lock (&didd_spin, &irql, "didd_nfy");
+  if (NotificationTable[i].callback) {
+   memcpy (&nfy, &NotificationTable[i], sizeof(nfy));
+   do_notify = 1;
+  }
+  diva_os_leave_spin_lock (&didd_spin, &irql, "didd_nfy");
+  if (do_notify) {
+   (*(nfy.callback))(nfy.context, d, removal);
+  }
+ }
+}
+/* --------------------------------------------------------------------------
+  For all systems, that are linked by Kernel Mode Linker this is ONLY one
+  function thet should be exported by this device driver
+  IDI clients should look for IDI_DADAPTER, and use request function
+  of this adapter (sync request) in order to receive appropriate services:
+  - add new adapter
+  - remove existing adapter
+  - add adapter array notification
+  - remove adapter array notification
+  (read adapter is redundant in this case)
+  INPUT:
+   buffer - pointer to buffer that will receive adapter array
+   length  - length (in bytes) of space in buffer
+  OUTPUT:
+   Adapter array will be written to memory described by 'buffer'
+   If the last adapter seen in the returned adapter array is
+   IDI_DADAPTER or if last adapter in array does have type '0', then
+   it was enougth space in buffer to accommodate all available
+   adapter descriptors
+  *NOTE 1 (debug interface):
+   The IDI adapter of type 'IDI_DIMAINT' does register as 'request'
+   famous 'dprintf' function (of type DI_PRINTF, please look
+   include/debuglib.c and include/debuglib.h) for details.
+   So dprintf is not exported from module debug module directly,
+   instead of this IDI_DIMAINT is registered.
+   Module load order will receive in this case:
+    1. DIDD (this file)
+    2. DIMAINT does load and register 'IDI_DIMAINT', at this step
+      DIDD should be able to get 'dprintf', save it, and
+      register with DIDD by means of 'dprintf' function.
+    3. any other driver is loaded and is able to access adapter array
+      and debug interface
+   This approach does allow to load/unload debug interface on demand,
+   and save memory, it it is necessary.
+  -------------------------------------------------------------------------- */
+void IDI_CALL_LINK_T DIVA_DIDD_Read (void IDI_CALL_ENTITY_T * buffer,
+                   int length) {
+ diva_didd_read_adapter_array (buffer, length);
+}
+
diff --git a/drivers/isdn/hardware/eicon/dadapter.h b/drivers/isdn/hardware/eicon/dadapter.h
new file mode 100644
index 0000000..3575ac9
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dadapter.h
@@ -0,0 +1,34 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_DIDD_DADAPTER_INC__
+#define __DIVA_DIDD_DADAPTER_INC__
+ 
+void diva_didd_load_time_init (void);
+void diva_didd_load_time_finit (void);
+
+#define NEW_MAX_DESCRIPTORS     64
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/dbgioctl.h b/drivers/isdn/hardware/eicon/dbgioctl.h
new file mode 100644
index 0000000..0fb6f5e
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dbgioctl.h
@@ -0,0 +1,198 @@
+
+/*
+ *
+  Copyright (c) Eicon Technology Corporation, 2000.
+ *
+  This source file is supplied for the use with Eicon
+  Technology Corporation's range of DIVA Server Adapters.
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*------------------------------------------------------------------*/
+/* file: dbgioctl.h                                                 */
+/*------------------------------------------------------------------*/
+
+#if !defined(__DBGIOCTL_H__)
+
+#define __DBGIOCTL_H__
+
+#ifdef NOT_YET_NEEDED
+/*
+ * The requested operation is passed in arg0 of DbgIoctlArgs,
+ * additional arguments (if any) in arg1, arg2 and arg3.
+ */
+
+typedef struct
+{	ULONG	arg0 ;
+	ULONG	arg1 ;
+	ULONG	arg2 ;
+	ULONG	arg3 ;
+} DbgIoctlArgs ;
+
+#define	DBG_COPY_LOGS	0	/* copy debugs to user until buffer full	*/
+							/* arg1: size threshold						*/
+							/* arg2: timeout in milliseconds			*/
+
+#define DBG_FLUSH_LOGS	1	/* flush pending debugs to user buffer		*/
+							/* arg1: internal driver id					*/
+
+#define DBG_LIST_DRVS	2	/* return the list of registered drivers	*/
+
+#define	DBG_GET_MASK	3	/* get current debug mask of driver			*/
+							/* arg1: internal driver id					*/
+
+#define	DBG_SET_MASK	4	/* set/change debug mask of driver			*/
+							/* arg1: internal driver id					*/
+							/* arg2: new debug mask						*/
+
+#define	DBG_GET_BUFSIZE	5	/* get current buffer size of driver		*/
+							/* arg1: internal driver id					*/
+							/* arg2: new debug mask						*/
+
+#define	DBG_SET_BUFSIZE	6	/* set new buffer size of driver			*/
+							/* arg1: new buffer size					*/
+
+/*
+ *	common internal debug message structure
+ */
+
+typedef struct
+{	unsigned short id ;		/* virtual driver id                  */
+	unsigned short type ;	/* special message type               */
+	unsigned long  seq ;	/* sequence number of message         */
+	unsigned long  size ;	/* size of message in bytes           */
+	unsigned long  next ;	/* offset to next buffered message    */
+	LARGE_INTEGER  NTtime ;	/* 100 ns  since 1.1.1601             */
+	unsigned char  data[4] ;/* message data                       */
+} OldDbgMessage ;
+
+typedef struct
+{	LARGE_INTEGER  NTtime ;	/* 100 ns  since 1.1.1601             */
+	unsigned short size ;	/* size of message in bytes           */
+	unsigned short ffff ;	/* always 0xffff to indicate new msg  */
+	unsigned short id ;		/* virtual driver id                  */
+	unsigned short type ;	/* special message type               */
+	unsigned long  seq ;	/* sequence number of message         */
+	unsigned char  data[4] ;/* message data                       */
+} DbgMessage ;
+
+#endif
+
+#define DRV_ID_UNKNOWN		0x0C	/* for messages via prtComp() */
+
+#define	MSG_PROC_FLAG		0x80
+#define	MSG_PROC_NO_GET(x)	(((x) & MSG_PROC_FLAG) ? (((x) >> 4) & 7) : -1)
+#define	MSG_PROC_NO_SET(x)	(MSG_PROC_FLAG | (((x) & 7) << 4))
+
+#define MSG_TYPE_DRV_ID		0x0001
+#define MSG_TYPE_FLAGS		0x0002
+#define MSG_TYPE_STRING		0x0003
+#define MSG_TYPE_BINARY		0x0004
+
+#define MSG_HEAD_SIZE	((unsigned long)&(((DbgMessage *)0)->data[0]))
+#define MSG_ALIGN(len)	(((unsigned long)(len) + MSG_HEAD_SIZE + 3) & ~3)
+#define MSG_SIZE(pMsg)	MSG_ALIGN((pMsg)->size)
+#define MSG_NEXT(pMsg)	((DbgMessage *)( ((char *)(pMsg)) + MSG_SIZE(pMsg) ))
+
+#define OLD_MSG_HEAD_SIZE	((unsigned long)&(((OldDbgMessage *)0)->data[0]))
+#define OLD_MSG_ALIGN(len)	(((unsigned long)(len)+OLD_MSG_HEAD_SIZE+3) & ~3)
+
+/*
+ * manifest constants
+ */
+
+#define MSG_FRAME_MAX_SIZE	2150		/* maximum size of B1 frame	 */
+#define MSG_TEXT_MAX_SIZE	1024		/* maximum size of msg text	 */
+#define MSG_MAX_SIZE		MSG_ALIGN(MSG_FRAME_MAX_SIZE)
+#define DBG_MIN_BUFFER_SIZE	0x00008000	/* minimal total buffer size  32 KB */
+#define DBG_DEF_BUFFER_SIZE	0x00020000	/* default total buffer size 128 KB */
+#define DBG_MAX_BUFFER_SIZE	0x00400000	/* maximal total buffer size   4 MB */
+
+#define DBGDRV_NAME		"Diehl_DIMAINT"
+#define UNIDBG_DRIVER	L"\\Device\\Diehl_DIMAINT" /* UNICODE name for kernel */
+#define DEBUG_DRIVER	"\\\\.\\" DBGDRV_NAME  /* traditional string for apps */
+#define DBGVXD_NAME		"DIMAINT"
+#define DEBUG_VXD		"\\\\.\\" DBGVXD_NAME  /* traditional string for apps */
+
+/*
+ *	Special IDI interface debug construction
+ */
+
+#define	DBG_IDI_SIG_REQ		(unsigned long)0xF479C402
+#define	DBG_IDI_SIG_IND		(unsigned long)0xF479C403
+#define	DBG_IDI_NL_REQ		(unsigned long)0xF479C404
+#define	DBG_IDI_NL_IND		(unsigned long)0xF479C405
+
+typedef struct
+{	unsigned long  magic_type ;
+	unsigned short data_len ;
+	unsigned char  layer_ID ;
+	unsigned char  entity_ID ;
+	unsigned char  request ;
+	unsigned char  ret_code ;
+	unsigned char  indication ;
+	unsigned char  complete ;
+	unsigned char  data[4] ;
+} DbgIdiAct, *DbgIdiAction ;
+
+/*
+ * We want to use the same IOCTL codes in Win95 and WinNT.
+ * The official constructor for IOCTL codes is the CTL_CODE macro
+ * from <winoctl.h> (<devioctl.h> in WinNT DDK environment).
+ * The problem here is that we don't know how to get <winioctl.h>
+ * working in a Win95 DDK environment!
+ */
+
+# ifdef CTL_CODE	/*{*/
+
+/* Assert that we have the same idea of the CTL_CODE macro.	*/
+
+#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
+    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+
+# else	/* !CTL_CODE */ /*}{*/
+
+/* Use the definitions stolen from <winioctl.h>.  */
+
+#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
+    ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+
+#define METHOD_BUFFERED                 0
+#define METHOD_IN_DIRECT                1
+#define METHOD_OUT_DIRECT               2
+#define METHOD_NEITHER                  3
+
+#define FILE_ANY_ACCESS                 0
+#define FILE_READ_ACCESS          ( 0x0001 )    // file & pipe
+#define FILE_WRITE_ACCESS         ( 0x0002 )    // file & pipe
+
+# endif	/* CTL_CODE */ /*}*/
+
+/*
+ * Now we can define WinNT/Win95 DeviceIoControl codes.
+ *
+ * These codes are defined in di_defs.h too, a possible mismatch will be
+ * detected when the dbgtool is compiled.
+ */
+
+#define IOCTL_DRIVER_LNK \
+	CTL_CODE(0x8001U,0x701,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+#define IOCTL_DRIVER_DBG \
+	CTL_CODE(0x8001U,0x702,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
+
+#endif /* __DBGIOCTL_H__ */
diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
new file mode 100644
index 0000000..6851c62
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/debug.c
@@ -0,0 +1,2133 @@
+#include "platform.h"
+#include "pc.h"
+#include "di_defs.h"
+#include "debug_if.h"
+#include "divasync.h"
+#include "kst_ifc.h"
+#include "maintidi.h"
+#include "man_defs.h"
+
+/*
+  LOCALS
+  */
+#define DBG_MAGIC (0x47114711L)
+
+static void DI_register (void *arg);
+static void DI_deregister (pDbgHandle hDbg);
+static void DI_format (int do_lock, word id, int type, char *format, va_list argument_list);
+static void DI_format_locked   (word id, int type, char *format, va_list argument_list);
+static void DI_format_old (word id, char *format, va_list ap) { }
+static void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap) { }
+static void single_p (byte * P, word * PLength, byte Id);
+static void diva_maint_xdi_cb (ENTITY* e);
+static word SuperTraceCreateReadReq (byte* P, const char* path);
+static int diva_mnt_cmp_nmbr (const char* nmbr);
+static void diva_free_dma_descriptor (IDI_CALL request, int nr);
+static int diva_get_dma_descriptor (IDI_CALL request, dword *dma_magic);
+void diva_mnt_internal_dprintf (dword drv_id, dword type, char* p, ...);
+
+static dword MaxDumpSize = 256 ;
+static dword MaxXlogSize = 2 + 128 ;
+static char  TraceFilter[DIVA_MAX_SELECTIVE_FILTER_LENGTH+1];
+static int TraceFilterIdent   = -1;
+static int TraceFilterChannel = -1;
+
+typedef struct _diva_maint_client {
+  dword       sec;
+  dword       usec;
+  pDbgHandle  hDbg;
+  char        drvName[128];
+  dword       dbgMask;
+  dword       last_dbgMask;
+  IDI_CALL    request;
+  _DbgHandle_ Dbg;
+  int         logical;
+  int         channels;
+  diva_strace_library_interface_t* pIdiLib;
+  BUFFERS     XData;
+  char        xbuffer[2048+512];
+  byte*       pmem;
+  int         request_pending;
+  int         dma_handle;
+} diva_maint_client_t;
+static diva_maint_client_t clients[MAX_DESCRIPTORS];
+
+static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword old_mask);
+
+static void diva_maint_error (void* user_context,
+                              diva_strace_library_interface_t* hLib,
+                              int Adapter,
+                              int error,
+                              const char* file,
+                              int line);
+static void diva_maint_state_change_notify (void* user_context,
+                                            diva_strace_library_interface_t* hLib,
+                                            int Adapter,
+                                            diva_trace_line_state_t* channel,
+                                            int notify_subject);
+static void diva_maint_trace_notify (void* user_context,
+                                     diva_strace_library_interface_t* hLib,
+                                     int Adapter,
+                                     void* xlog_buffer,
+                                     int length);
+
+
+
+typedef struct MSG_QUEUE {
+	dword	Size;		/* total size of queue (constant)	*/
+	byte	*Base;		/* lowest address (constant)		*/
+	byte	*High;		/* Base + Size (constant)		*/
+	byte	*Head;		/* first message in queue (if any)	*/
+	byte	*Tail;		/* first free position			*/
+	byte	*Wrap;		/* current wraparound position 		*/
+	dword	Count;		/* current no of bytes in queue		*/
+} MSG_QUEUE;
+
+typedef struct MSG_HEAD {
+	volatile dword	Size;		/* size of data following MSG_HEAD	*/
+#define	MSG_INCOMPLETE	0x8000	/* ored to Size until queueCompleteMsg 	*/
+} MSG_HEAD;
+
+#define queueCompleteMsg(p) do{ ((MSG_HEAD *)p - 1)->Size &= ~MSG_INCOMPLETE; }while(0)
+#define queueCount(q)	((q)->Count)
+#define MSG_NEED(size) \
+	( (sizeof(MSG_HEAD) + size + sizeof(dword) - 1) & ~(sizeof(dword) - 1) )
+
+static void queueInit (MSG_QUEUE *Q, byte *Buffer, dword sizeBuffer) {
+	Q->Size = sizeBuffer;
+	Q->Base = Q->Head = Q->Tail = Buffer;
+	Q->High = Buffer + sizeBuffer;
+	Q->Wrap = NULL;
+	Q->Count= 0;
+}
+
+static byte *queueAllocMsg (MSG_QUEUE *Q, word size) {
+	/* Allocate 'size' bytes at tail of queue which will be filled later
+   * directly with callers own message header info and/or message.
+   * An 'alloced' message is marked incomplete by oring the 'Size' field
+   * with MSG_INCOMPLETE.
+   * This must be reset via queueCompleteMsg() after the message is filled.
+   * As long as a message is marked incomplete queuePeekMsg() will return
+   * a 'queue empty' condition when it reaches such a message.  */
+
+	MSG_HEAD *Msg;
+	word need = MSG_NEED(size);
+
+	if (Q->Tail == Q->Head) {
+		if (Q->Wrap || need > Q->Size) {
+			return NULL; /* full */
+		}
+		goto alloc; /* empty */
+	}
+	
+	if (Q->Tail > Q->Head) {
+		if (Q->Tail + need <= Q->High) goto alloc; /* append */
+		if (Q->Base + need > Q->Head) {
+			return NULL; /* too much */
+		}
+		/* wraparound the queue (but not the message) */
+		Q->Wrap = Q->Tail;
+		Q->Tail = Q->Base;
+		goto alloc;
+	}
+
+	if (Q->Tail + need > Q->Head) {
+		return NULL; /* too much */
+	}
+
+alloc:
+	Msg = (MSG_HEAD *)Q->Tail;
+
+	Msg->Size = size | MSG_INCOMPLETE;
+
+	Q->Tail	 += need;
+	Q->Count += size;
+
+
+
+	return ((byte*)(Msg + 1));
+}
+
+static void queueFreeMsg (MSG_QUEUE *Q) {
+/* Free the message at head of queue */
+
+	word size = ((MSG_HEAD *)Q->Head)->Size & ~MSG_INCOMPLETE;
+
+	Q->Head  += MSG_NEED(size);
+	Q->Count -= size;
+
+	if (Q->Wrap) {
+		if (Q->Head >= Q->Wrap) {
+			Q->Head = Q->Base;
+			Q->Wrap = NULL;
+		}
+	} else if (Q->Head >= Q->Tail) {
+		Q->Head = Q->Tail = Q->Base;
+	}
+}
+
+static byte *queuePeekMsg (MSG_QUEUE *Q, word *size) {
+	/* Show the first valid message in queue BUT DON'T free the message.
+   * After looking on the message contents it can be freed queueFreeMsg()
+   * or simply remain in message queue.  */
+
+	MSG_HEAD *Msg = (MSG_HEAD *)Q->Head;
+
+	if (((byte *)Msg == Q->Tail && !Q->Wrap) ||
+	    (Msg->Size & MSG_INCOMPLETE)) {
+		return NULL;
+	} else {
+		*size = Msg->Size;
+		return ((byte *)(Msg + 1));
+	}
+}
+
+/*
+  Message queue header
+  */
+static MSG_QUEUE*          dbg_queue;
+static byte*               dbg_base;
+static int                 external_dbg_queue;
+static diva_os_spin_lock_t dbg_q_lock;
+static diva_os_spin_lock_t dbg_adapter_lock;
+static int                 dbg_q_busy;
+static volatile dword      dbg_sequence;
+static dword               start_sec;
+static dword               start_usec;
+
+/*
+	INTERFACE:
+    Initialize run time queue structures.
+    base:    base of the message queue
+    length:  length of the message queue
+    do_init: perfor queue reset
+
+    return:  zero on success, -1 on error
+  */
+int diva_maint_init (byte* base, unsigned long length, int do_init) {
+  if (dbg_queue || (!base) || (length < (4096*4))) {
+    return (-1);
+  }
+
+  TraceFilter[0]     =  0;
+  TraceFilterIdent   = -1;
+  TraceFilterChannel = -1;
+
+  dbg_base = base;
+
+  diva_os_get_time (&start_sec, &start_usec);
+
+  *(dword*)base  = (dword)DBG_MAGIC; /* Store Magic */
+  base   += sizeof(dword);
+  length -= sizeof(dword);
+
+  *(dword*)base = 2048; /* Extension Field Length */
+  base   += sizeof(dword);
+  length -= sizeof(dword);
+
+  strcpy (base, "KERNEL MODE BUFFER\n");
+  base   += 2048;
+  length -= 2048;
+
+  *(dword*)base = 0; /* Terminate extension */
+  base   += sizeof(dword);
+  length -= sizeof(dword);
+
+  *(void**)base  =  (void*)(base+sizeof(void*)); /* Store Base  */
+  base   += sizeof(void*);
+  length -= sizeof(void*);
+
+  dbg_queue = (MSG_QUEUE*)base;
+  queueInit (dbg_queue, base + sizeof(MSG_QUEUE), length - sizeof(MSG_QUEUE) - 512);
+  external_dbg_queue = 0;
+
+  if (!do_init) {
+    external_dbg_queue = 1; /* memory was located on the external device */
+  }
+
+
+	if (diva_os_initialize_spin_lock (&dbg_q_lock, "dbg_init")) {
+    dbg_queue = NULL;
+    dbg_base = NULL;
+    external_dbg_queue = 0;
+		return (-1);
+  }
+
+	if (diva_os_initialize_spin_lock (&dbg_adapter_lock, "dbg_init")) {
+    diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_init");
+    dbg_queue = NULL;
+    dbg_base = NULL;
+    external_dbg_queue = 0;
+		return (-1);
+  }
+
+  return (0);
+}
+
+/*
+  INTERFACE:
+    Finit at unload time
+    return address of internal queue or zero if queue
+    was external
+  */
+void* diva_maint_finit (void) {
+  void* ret = (void*)dbg_base;
+  int i;
+
+  dbg_queue = NULL;
+  dbg_base  = NULL;
+
+  if (ret) {
+    diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_finit");
+    diva_os_destroy_spin_lock(&dbg_adapter_lock, "dbg_finit");
+  }
+
+  if (external_dbg_queue) {
+    ret = NULL;
+  }
+  external_dbg_queue = 0;
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].pmem) {
+      diva_os_free (0, clients[i].pmem);
+    }
+  }
+
+  return (ret);
+}
+
+/*
+  INTERFACE:
+    Return amount of messages in debug queue
+  */
+dword diva_dbg_q_length (void) {
+	return (dbg_queue ? queueCount(dbg_queue)	: 0);
+}
+
+/*
+  INTERFACE:
+    Lock message queue and return the pointer to the first
+    entry.
+  */
+diva_dbg_entry_head_t* diva_maint_get_message (word* size,
+                                               diva_os_spin_lock_magic_t* old_irql) {
+  diva_dbg_entry_head_t*     pmsg = NULL;
+
+  diva_os_enter_spin_lock (&dbg_q_lock, old_irql, "read");
+  if (dbg_q_busy) {
+    diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_busy");
+    return NULL;
+  }
+  dbg_q_busy = 1;
+
+  if (!(pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, size))) {
+    dbg_q_busy = 0;
+    diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_empty");
+  }
+
+  return (pmsg);
+}
+
+/*
+  INTERFACE:
+    acknowledge last message and unlock queue
+  */
+void diva_maint_ack_message (int do_release,
+                             diva_os_spin_lock_magic_t* old_irql) {
+	if (!dbg_q_busy) {
+		return;
+	}
+	if (do_release) {
+		queueFreeMsg (dbg_queue);
+	}
+	dbg_q_busy = 0;
+  diva_os_leave_spin_lock (&dbg_q_lock, old_irql, "read_ack");
+}
+
+
+/*
+  INTERFACE:
+    PRT COMP function used to register
+    with MAINT adapter or log in compatibility
+    mode in case older driver version is connected too
+  */
+void diva_maint_prtComp (char *format, ...) {
+  void    *hDbg;
+  va_list ap;
+
+  if (!format)
+    return;
+
+  va_start(ap, format);
+
+  /*
+    register to new log driver functions
+   */
+  if ((format[0] == 0) && ((unsigned char)format[1] == 255)) {
+    hDbg = va_arg(ap, void *); /* ptr to DbgHandle */
+    DI_register (hDbg);
+  }
+
+  va_end (ap);
+}
+
+static void DI_register (void *arg) {
+  diva_os_spin_lock_magic_t old_irql;
+  dword sec, usec;
+  pDbgHandle  	hDbg ;
+  int id, free_id = -1, best_id = 0;
+  
+  diva_os_get_time (&sec, &usec);
+
+	hDbg = (pDbgHandle)arg ;
+  /*
+    Check for bad args, specially for the old obsolete debug handle
+    */
+  if ((hDbg == NULL) ||
+      ((hDbg->id == 0) && (((_OldDbgHandle_ *)hDbg)->id == -1)) ||
+      (hDbg->Registered != 0)) {
+		return ;
+  }
+
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register");
+
+  for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) {
+    if (clients[id].hDbg == hDbg) {
+      /*
+        driver already registered
+        */
+      diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
+      return;
+    }
+    if (clients[id].hDbg) { /* slot is busy */
+      continue;
+    }
+    free_id = id;
+    if (!strcmp (clients[id].drvName, hDbg->drvName)) {
+      /*
+        This driver was already registered with this name
+        and slot is still free - reuse it
+        */
+      best_id = 1;
+      break;
+    }
+    if (!clients[id].hDbg) { /* slot is busy */
+      break;
+    }
+  }
+
+  if (free_id != -1) {
+    diva_dbg_entry_head_t* pmsg = NULL;
+    int len;
+    char tmp[256];
+    word size;
+
+    /*
+      Register new driver with id == free_id
+      */
+    clients[free_id].hDbg = hDbg;
+    clients[free_id].sec  = sec;
+    clients[free_id].usec = usec;
+    strcpy (clients[free_id].drvName, hDbg->drvName);
+
+    clients[free_id].dbgMask = hDbg->dbgMask;
+    if (best_id) {
+      hDbg->dbgMask |= clients[free_id].last_dbgMask;
+    } else {
+      clients[free_id].last_dbgMask = 0;
+    }
+
+    hDbg->Registered = DBG_HANDLE_REG_NEW ;
+    hDbg->id         = (byte)free_id;
+    hDbg->dbg_end    = DI_deregister;
+    hDbg->dbg_prt    = DI_format_locked;
+    hDbg->dbg_ev     = DiProcessEventLog;
+    hDbg->dbg_irq    = DI_format_locked;
+    if (hDbg->Version > 0) {
+      hDbg->dbg_old  = DI_format_old;
+    }
+    hDbg->next       = (pDbgHandle)DBG_MAGIC;
+
+    /*
+      Log driver register, MAINT driver ID is '0'
+      */
+    len = sprintf (tmp, "DIMAINT - drv # %d = '%s' registered",
+                   free_id, hDbg->drvName);
+
+    while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                        (word)(len+1+sizeof(*pmsg))))) {
+      if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+        queueFreeMsg (dbg_queue);
+      } else {
+        break;
+      }
+    }
+
+    if (pmsg) {
+      pmsg->sequence    = dbg_sequence++;
+      pmsg->time_sec    = sec;
+      pmsg->time_usec   = usec;
+      pmsg->facility    = MSG_TYPE_STRING;
+      pmsg->dli         = DLI_REG;
+      pmsg->drv_id      = 0; /* id 0 - DIMAINT */
+      pmsg->di_cpu      = 0;
+      pmsg->data_length = len+1;
+
+      memcpy (&pmsg[1], tmp, len+1);
+		  queueCompleteMsg (pmsg);
+      diva_maint_wakeup_read();
+    }
+  }
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
+}
+
+static void DI_deregister (pDbgHandle hDbg) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  dword sec, usec;
+  int i;
+  word size;
+  byte* pmem = NULL;
+
+  diva_os_get_time (&sec, &usec);
+
+  diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read");
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read");
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].hDbg == hDbg) {
+      diva_dbg_entry_head_t* pmsg;
+      char tmp[256];
+      int len;
+
+      clients[i].hDbg = NULL;
+
+      hDbg->id       = -1;
+      hDbg->dbgMask  = 0;
+      hDbg->dbg_end  = NULL;
+      hDbg->dbg_prt  = NULL;
+      hDbg->dbg_irq  = NULL;
+      if (hDbg->Version > 0)
+        hDbg->dbg_old = NULL;
+      hDbg->Registered = 0;
+      hDbg->next     = NULL;
+
+      if (clients[i].pIdiLib) {
+        (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
+        clients[i].pIdiLib = NULL;
+
+        pmem = clients[i].pmem;
+        clients[i].pmem = NULL;
+      }
+
+      /*
+        Log driver register, MAINT driver ID is '0'
+        */
+      len = sprintf (tmp, "DIMAINT - drv # %d = '%s' de-registered",
+                     i, hDbg->drvName);
+
+      while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                        (word)(len+1+sizeof(*pmsg))))) {
+        if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+          queueFreeMsg (dbg_queue);
+        } else {
+          break;
+        }
+      }
+
+      if (pmsg) {
+        pmsg->sequence    = dbg_sequence++;
+        pmsg->time_sec    = sec;
+        pmsg->time_usec   = usec;
+        pmsg->facility    = MSG_TYPE_STRING;
+        pmsg->dli         = DLI_REG;
+        pmsg->drv_id      = 0; /* id 0 - DIMAINT */
+        pmsg->di_cpu      = 0;
+        pmsg->data_length = len+1;
+
+        memcpy (&pmsg[1], tmp, len+1);
+  		  queueCompleteMsg (pmsg);
+        diva_maint_wakeup_read();
+      }
+
+      break;
+    }
+  }
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_ack");
+  diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "read_ack");
+
+  if (pmem) {
+    diva_os_free (0, pmem);
+  }
+}
+
+static void DI_format_locked (unsigned short id,
+                       int type,
+                       char *format,
+                       va_list argument_list) {
+  DI_format (1, id, type, format, argument_list);
+}
+
+static void DI_format (int do_lock,
+                       unsigned short id,
+                       int type,
+                       char *format,
+                       va_list ap) {
+  diva_os_spin_lock_magic_t old_irql;
+  dword sec, usec;
+  diva_dbg_entry_head_t* pmsg = NULL;
+  dword length;
+  word size;
+  static char fmtBuf[MSG_FRAME_MAX_SIZE+sizeof(*pmsg)+1];
+  char          *data;
+  unsigned short code;
+
+  if (diva_os_in_irq()) {
+    dbg_sequence++;
+    return;
+  }
+
+	if ((!format) ||
+			((TraceFilter[0] != 0) && ((TraceFilterIdent < 0) || (TraceFilterChannel < 0)))) {
+		return;
+	}
+
+
+  
+  diva_os_get_time (&sec, &usec);
+
+  if (do_lock) {
+    diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "format");
+  }
+
+  switch (type) {
+  case DLI_MXLOG :
+  case DLI_BLK :
+  case DLI_SEND:
+  case DLI_RECV:
+    if (!(length = va_arg(ap, unsigned long))) {
+      break;
+    }
+    if (length > MaxDumpSize) {
+      length = MaxDumpSize;
+    }
+    while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                (word)length+sizeof(*pmsg)))) {
+      if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+        queueFreeMsg (dbg_queue);
+      } else {
+        break;
+      }
+    }
+    if (pmsg) {
+      memcpy (&pmsg[1], format, length);
+      pmsg->sequence    = dbg_sequence++;
+      pmsg->time_sec    = sec;
+      pmsg->time_usec   = usec;
+      pmsg->facility    = MSG_TYPE_BINARY ;
+      pmsg->dli         = type; /* DLI_XXX */
+      pmsg->drv_id      = id;   /* driver MAINT id */
+      pmsg->di_cpu      = 0;
+      pmsg->data_length = length;
+      queueCompleteMsg (pmsg);
+    }
+		break;
+
+  case DLI_XLOG: {
+    byte* p;
+    data    = va_arg(ap, char*);
+    code    = (unsigned short)va_arg(ap, unsigned int);
+    length	= (unsigned long) va_arg(ap, unsigned int);
+
+    if (length > MaxXlogSize)
+      length = MaxXlogSize;
+
+    while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                  (word)length+sizeof(*pmsg)+2))) {
+      if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+        queueFreeMsg (dbg_queue);
+      } else {
+        break;
+      }
+    }
+    if (pmsg) {
+      p = (byte*)&pmsg[1];
+      p[0] = (char)(code) ;
+      p[1] = (char)(code >> 8) ;
+      if (data && length) {
+        memcpy (&p[2], &data[0], length) ;
+      }
+      length += 2 ;
+
+      pmsg->sequence    = dbg_sequence++;
+      pmsg->time_sec    = sec;
+      pmsg->time_usec   = usec;
+      pmsg->facility    = MSG_TYPE_BINARY ;
+      pmsg->dli         = type; /* DLI_XXX */
+      pmsg->drv_id      = id;   /* driver MAINT id */
+      pmsg->di_cpu      = 0;
+      pmsg->data_length = length;
+      queueCompleteMsg (pmsg);
+    }
+  } break;
+
+  case DLI_LOG :
+  case DLI_FTL :
+  case DLI_ERR :
+  case DLI_TRC :
+  case DLI_REG :
+  case DLI_MEM :
+  case DLI_SPL :
+  case DLI_IRP :
+  case DLI_TIM :
+  case DLI_TAPI:
+  case DLI_NDIS:
+  case DLI_CONN:
+  case DLI_STAT:
+  case DLI_PRV0:
+  case DLI_PRV1:
+  case DLI_PRV2:
+  case DLI_PRV3:
+    if ((length = (unsigned long)vsprintf (&fmtBuf[0], format, ap)) > 0) {
+      length += (sizeof(*pmsg)+1);
+
+      while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                                          (word)length))) {
+        if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+          queueFreeMsg (dbg_queue);
+        } else {
+          break;
+        }
+      }
+
+      pmsg->sequence    = dbg_sequence++;
+      pmsg->time_sec    = sec;
+      pmsg->time_usec   = usec;
+      pmsg->facility    = MSG_TYPE_STRING;
+      pmsg->dli         = type; /* DLI_XXX */
+      pmsg->drv_id      = id;   /* driver MAINT id */
+      pmsg->di_cpu      = 0;
+      pmsg->data_length = length - sizeof(*pmsg);
+
+      memcpy (&pmsg[1], fmtBuf, pmsg->data_length);
+		  queueCompleteMsg (pmsg);
+    }
+    break;
+
+  } /* switch type */
+
+
+  if (queueCount(dbg_queue)) {
+    diva_maint_wakeup_read();
+  }
+
+  if (do_lock) {
+    diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "format");
+  }
+}
+
+/*
+  Write driver ID and driver revision to callers buffer
+  */
+int diva_get_driver_info (dword id, byte* data, int data_length) {
+  diva_os_spin_lock_magic_t old_irql;
+  byte* p = data;
+  int to_copy;
+
+  if (!data || !id || (data_length < 17) ||
+      (id >= (sizeof(clients)/sizeof(clients[0])))) {
+    return (-1);
+  }
+
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info");
+
+  if (clients[id].hDbg) {
+    *p++ = 1;
+    *p++ = (byte)clients[id].sec; /* save seconds */
+    *p++ = (byte)(clients[id].sec >>  8);
+    *p++ = (byte)(clients[id].sec >> 16);
+    *p++ = (byte)(clients[id].sec >> 24);
+
+    *p++ = (byte)(clients[id].usec/1000); /* save mseconds */
+    *p++ = (byte)((clients[id].usec/1000) >>  8);
+    *p++ = (byte)((clients[id].usec/1000) >> 16);
+    *p++ = (byte)((clients[id].usec/1000) >> 24);
+
+    data_length -= 9;
+
+    if ((to_copy = MIN(strlen(clients[id].drvName), data_length-1))) {
+      memcpy (p, clients[id].drvName, to_copy);
+      p += to_copy;
+      data_length -= to_copy;
+      if ((data_length >= 4) && clients[id].hDbg->drvTag[0]) {
+        *p++ = '(';
+        data_length -= 1;
+        if ((to_copy = MIN(strlen(clients[id].hDbg->drvTag), data_length-2))) {
+          memcpy (p, clients[id].hDbg->drvTag, to_copy);
+          p += to_copy;
+          data_length -= to_copy;
+          if (data_length >= 2) {
+            *p++ = ')';
+            data_length--;
+          }
+        }
+      }
+    }
+  }
+  *p++ = 0;
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "driver info");
+
+  return (p - data);
+}
+
+int diva_get_driver_dbg_mask (dword id, byte* data) {
+  diva_os_spin_lock_magic_t old_irql;
+  int ret = -1;
+
+  if (!data || !id || (id >= (sizeof(clients)/sizeof(clients[0])))) {
+    return (-1);
+  }
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info");
+
+  if (clients[id].hDbg) {
+    ret = 4;
+    *data++= (byte)(clients[id].hDbg->dbgMask);
+    *data++= (byte)(clients[id].hDbg->dbgMask >>  8);
+    *data++= (byte)(clients[id].hDbg->dbgMask >> 16);
+    *data++= (byte)(clients[id].hDbg->dbgMask >> 24);
+  }
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "driver info");
+
+  return (ret);
+}
+
+int diva_set_driver_dbg_mask (dword id, dword mask) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  int ret = -1;
+  
+
+  if (!id || (id >= (sizeof(clients)/sizeof(clients[0])))) {
+    return (-1);
+  }
+
+  diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask");
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "dbg mask");
+
+  if (clients[id].hDbg) {
+    dword old_mask = clients[id].hDbg->dbgMask;
+    mask &= 0x7fffffff;
+    clients[id].hDbg->dbgMask = mask;
+    clients[id].last_dbgMask = (clients[id].hDbg->dbgMask | clients[id].dbgMask);
+    ret = 4;
+    diva_change_management_debug_mask (&clients[id], old_mask);
+  }
+
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "dbg mask");
+
+  if (clients[id].request_pending) {
+    clients[id].request_pending = 0;
+    (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
+  }
+
+  diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask");
+
+  return (ret);
+}
+
+static int diva_get_idi_adapter_info (IDI_CALL request, dword* serial, dword* logical) {
+  IDI_SYNC_REQ sync_req;
+
+  sync_req.xdi_logical_adapter_number.Req = 0;
+  sync_req.xdi_logical_adapter_number.Rc = IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER;
+  (*request)((ENTITY *)&sync_req);
+  *logical = sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
+
+  sync_req.GetSerial.Req = 0;
+  sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
+  sync_req.GetSerial.serial = 0;
+  (*request)((ENTITY *)&sync_req);
+	*serial = sync_req.GetSerial.serial;
+
+  return (0);
+}
+
+/*
+  Register XDI adapter as MAINT compatible driver
+  */
+void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  dword sec, usec, logical, serial, org_mask;
+  int id, best_id = 0, free_id = -1;
+  char tmp[256];
+  diva_dbg_entry_head_t* pmsg = NULL;
+  int len;
+  word size;
+  byte* pmem;
+
+  diva_os_get_time (&sec, &usec);
+  diva_get_idi_adapter_info (d->request, &serial, &logical);
+  if (serial & 0xff000000) {
+    sprintf (tmp, "ADAPTER:%d SN:%u-%d",
+             (int)logical,
+             serial & 0x00ffffff,
+             (byte)(((serial & 0xff000000) >> 24) + 1));
+  } else {
+    sprintf (tmp, "ADAPTER:%d SN:%u", (int)logical, serial);
+  }
+
+  if (!(pmem = diva_os_malloc (0, DivaSTraceGetMemotyRequirement (d->channels)))) {
+    return;
+  }
+  memset (pmem, 0x00, DivaSTraceGetMemotyRequirement (d->channels));
+
+  diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register");
+
+  for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) {
+    if (clients[id].hDbg && (clients[id].request == d->request)) {
+      diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
+      diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
+      diva_os_free(0, pmem);
+      return;
+    }
+    if (clients[id].hDbg) { /* slot is busy */
+      continue;
+    }
+    if (free_id < 0) {
+      free_id = id;
+    }
+    if (!strcmp (clients[id].drvName, tmp)) {
+      /*
+        This driver was already registered with this name
+        and slot is still free - reuse it
+        */
+      free_id = id;
+      best_id = 1;
+      break;
+    }
+  }
+
+  if (free_id < 0) {
+    diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
+    diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
+    diva_os_free (0, pmem);
+    return;
+  }
+
+  id = free_id;
+  clients[id].request  = d->request;
+  clients[id].request_pending = 0;
+  clients[id].hDbg     = &clients[id].Dbg;
+  clients[id].sec      = sec;
+  clients[id].usec     = usec;
+  strcpy (clients[id].drvName,     tmp);
+  strcpy (clients[id].Dbg.drvName, tmp);
+  clients[id].Dbg.drvTag[0] = 0;
+  clients[id].logical  = (int)logical;
+  clients[id].channels = (int)d->channels;
+  clients[id].dma_handle = -1;
+
+  clients[id].Dbg.dbgMask    = 0;
+  clients[id].dbgMask        = clients[id].Dbg.dbgMask;
+  if (id) {
+    clients[id].Dbg.dbgMask |= clients[free_id].last_dbgMask;
+  } else {
+    clients[id].last_dbgMask = 0;
+  }
+  clients[id].Dbg.Registered = DBG_HANDLE_REG_NEW;
+  clients[id].Dbg.id         = (byte)id;
+  clients[id].Dbg.dbg_end    = DI_deregister;
+  clients[id].Dbg.dbg_prt    = DI_format_locked;
+  clients[id].Dbg.dbg_ev     = DiProcessEventLog;
+  clients[id].Dbg.dbg_irq    = DI_format_locked;
+  clients[id].Dbg.next       = (pDbgHandle)DBG_MAGIC;
+
+  {
+    diva_trace_library_user_interface_t diva_maint_user_ifc = { &clients[id],
+																							 diva_maint_state_change_notify,
+																							 diva_maint_trace_notify,
+																							 diva_maint_error };
+
+    /*
+      Attach to adapter management interface
+      */
+    if ((clients[id].pIdiLib =
+               DivaSTraceLibraryCreateInstance ((int)logical, &diva_maint_user_ifc, pmem))) {
+      if (((*(clients[id].pIdiLib->DivaSTraceLibraryStart))(clients[id].pIdiLib->hLib))) {
+        diva_mnt_internal_dprintf (0, DLI_ERR, "Adapter(%d) Start failed", (int)logical);
+        (*(clients[id].pIdiLib->DivaSTraceLibraryFinit))(clients[id].pIdiLib->hLib);
+        clients[id].pIdiLib = NULL;
+      }
+    } else {
+      diva_mnt_internal_dprintf (0, DLI_ERR, "A(%d) management init failed", (int)logical);
+    }
+  }
+
+  if (!clients[id].pIdiLib) {
+    clients[id].request = NULL;
+    clients[id].request_pending = 0;
+    clients[id].hDbg    = NULL;
+    diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
+    diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
+    diva_os_free (0, pmem);
+    return;
+  }
+
+  /*
+    Log driver register, MAINT driver ID is '0'
+    */
+  len = sprintf (tmp, "DIMAINT - drv # %d = '%s' registered",
+                 id, clients[id].Dbg.drvName);
+
+  while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                      (word)(len+1+sizeof(*pmsg))))) {
+    if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+      queueFreeMsg (dbg_queue);
+    } else {
+      break;
+    }
+  }
+
+  if (pmsg) {
+    pmsg->sequence    = dbg_sequence++;
+    pmsg->time_sec    = sec;
+    pmsg->time_usec   = usec;
+    pmsg->facility    = MSG_TYPE_STRING;
+    pmsg->dli         = DLI_REG;
+    pmsg->drv_id      = 0; /* id 0 - DIMAINT */
+    pmsg->di_cpu      = 0;
+    pmsg->data_length = len+1;
+
+    memcpy (&pmsg[1], tmp, len+1);
+    queueCompleteMsg (pmsg);
+    diva_maint_wakeup_read();
+  }
+
+  org_mask = clients[id].Dbg.dbgMask;
+  clients[id].Dbg.dbgMask = 0;
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
+
+  if (clients[id].request_pending) {
+    clients[id].request_pending = 0;
+    (*(clients[id].request))((ENTITY*)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
+  }
+
+  diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
+
+	diva_set_driver_dbg_mask (id, org_mask);
+}
+
+/*
+  De-Register XDI adapter
+  */
+void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  dword sec, usec;
+  int i;
+  word size;
+  byte* pmem = NULL;
+
+  diva_os_get_time (&sec, &usec);
+
+  diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read");
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read");
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].hDbg && (clients[i].request == d->request)) {
+      diva_dbg_entry_head_t* pmsg;
+      char tmp[256];
+      int len;
+
+      if (clients[i].pIdiLib) {
+        (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
+        clients[i].pIdiLib = NULL;
+
+        pmem = clients[i].pmem;
+        clients[i].pmem = NULL;
+      }
+
+      clients[i].hDbg    = NULL;
+      clients[i].request_pending = 0;
+      if (clients[i].dma_handle >= 0) {
+        /*
+          Free DMA handle
+          */
+        diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle);
+        clients[i].dma_handle = -1;
+      }
+      clients[i].request = NULL;
+
+      /*
+        Log driver register, MAINT driver ID is '0'
+        */
+      len = sprintf (tmp, "DIMAINT - drv # %d = '%s' de-registered",
+                     i, clients[i].Dbg.drvName);
+
+      memset (&clients[i].Dbg, 0x00, sizeof(clients[i].Dbg));
+
+      while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                                        (word)(len+1+sizeof(*pmsg))))) {
+        if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+          queueFreeMsg (dbg_queue);
+        } else {
+          break;
+        }
+      }
+
+      if (pmsg) {
+        pmsg->sequence    = dbg_sequence++;
+        pmsg->time_sec    = sec;
+        pmsg->time_usec   = usec;
+        pmsg->facility    = MSG_TYPE_STRING;
+        pmsg->dli         = DLI_REG;
+        pmsg->drv_id      = 0; /* id 0 - DIMAINT */
+        pmsg->di_cpu      = 0;
+        pmsg->data_length = len+1;
+
+        memcpy (&pmsg[1], tmp, len+1);
+  		  queueCompleteMsg (pmsg);
+        diva_maint_wakeup_read();
+      }
+
+      break;
+    }
+  }
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_ack");
+  diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "read_ack");
+
+  if (pmem) {
+    diva_os_free (0, pmem);
+  }
+}
+
+/* ----------------------------------------------------------------
+     Low level interface for management interface client
+   ---------------------------------------------------------------- */
+/*
+  Return handle to client structure
+  */
+void* SuperTraceOpenAdapter   (int AdapterNumber) {
+  int i;
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].hDbg && clients[i].request && (clients[i].logical == AdapterNumber)) {
+      return (&clients[i]);
+    }
+  }
+
+  return NULL;
+}
+
+int SuperTraceCloseAdapter  (void* AdapterHandle) {
+  return (0);
+}
+
+int SuperTraceReadRequest (void* AdapterHandle, const char* name, byte* data) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    byte* xdata = (byte*)&pC->xbuffer[0];
+    char tmp = 0;
+    word length;
+
+    if (!strcmp(name, "\\")) { /* Read ROOT */
+      name = &tmp;
+    }
+    length = SuperTraceCreateReadReq (xdata, name);
+    single_p (xdata, &length, 0); /* End Of Message */
+
+    e->Req        = MAN_READ;
+    e->ReqCh      = 0;
+    e->X->PLength = length;
+    e->X->P			  = (byte*)xdata;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceGetNumberOfChannels (void* AdapterHandle) {
+  if (AdapterHandle) {
+    diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+    return (pC->channels);
+  }
+
+  return (0);
+}
+
+int SuperTraceASSIGN (void* AdapterHandle, byte* data) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    IDI_SYNC_REQ* preq;
+    char buffer[((sizeof(preq->xdi_extended_features)+4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features)+4) : sizeof(ENTITY)];
+    char features[4];
+    word assign_data_length = 1;
+
+    features[0] = 0;
+    pC->xbuffer[0] = 0;
+    preq = (IDI_SYNC_REQ*)&buffer[0];
+    preq->xdi_extended_features.Req = 0;
+    preq->xdi_extended_features.Rc  = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES;
+    preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features);
+    preq->xdi_extended_features.info.features = &features[0];
+
+    (*(pC->request))((ENTITY*)preq);
+
+    if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) &&
+        (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) {
+      dword rx_dma_magic;
+      if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) {
+        pC->xbuffer[0] = LLI;
+        pC->xbuffer[1] = 8;
+        pC->xbuffer[2] = 0x40;
+        pC->xbuffer[3] = (byte)pC->dma_handle;
+        pC->xbuffer[4] = (byte)rx_dma_magic;
+        pC->xbuffer[5] = (byte)(rx_dma_magic >>  8);
+        pC->xbuffer[6] = (byte)(rx_dma_magic >> 16);
+        pC->xbuffer[7] = (byte)(rx_dma_magic >> 24);
+        pC->xbuffer[8] = (byte)DIVA_MAX_MANAGEMENT_TRANSFER_SIZE;
+        pC->xbuffer[9] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE >> 8);
+        pC->xbuffer[10] = 0;
+
+        assign_data_length = 11;
+      }
+    } else {
+      pC->dma_handle = -1;
+    }
+
+    e->Id          = MAN_ID;
+    e->callback    = diva_maint_xdi_cb;
+    e->XNum        = 1;
+    e->X           = &pC->XData;
+    e->Req         = ASSIGN;
+    e->ReqCh       = 0;
+    e->X->PLength  = assign_data_length;
+    e->X->P        = (byte*)&pC->xbuffer[0];
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceREMOVE (void* AdapterHandle) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+
+    e->XNum        = 1;
+    e->X           = &pC->XData;
+    e->Req         = REMOVE;
+    e->ReqCh       = 0;
+    e->X->PLength  = 1;
+    e->X->P        = (byte*)&pC->xbuffer[0];
+    pC->xbuffer[0] = 0;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceTraceOnRequest(void* hAdapter, const char* name, byte* data) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)hAdapter;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    byte* xdata = (byte*)&pC->xbuffer[0];
+    char tmp = 0;
+    word length;
+
+    if (!strcmp(name, "\\")) { /* Read ROOT */
+      name = &tmp;
+    }
+    length = SuperTraceCreateReadReq (xdata, name);
+    single_p (xdata, &length, 0); /* End Of Message */
+    e->Req          = MAN_EVENT_ON;
+    e->ReqCh        = 0;
+    e->X->PLength   = length;
+    e->X->P			    = (byte*)xdata;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceWriteVar (void* AdapterHandle,
+                        byte* data,
+                        const char* name,
+                        void* var,
+                        byte type,
+                        byte var_length) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    diva_man_var_header_t* pVar = (diva_man_var_header_t*)&pC->xbuffer[0];
+    word length = SuperTraceCreateReadReq ((byte*)pVar, name);
+
+    memcpy (&pC->xbuffer[length], var, var_length);
+    length += var_length;
+    pVar->length += var_length;
+    pVar->value_length = var_length;
+    pVar->type = type;
+    single_p ((byte*)pVar, &length, 0); /* End Of Message */
+
+    e->Req          = MAN_WRITE;
+    e->ReqCh			  = 0;
+    e->X->PLength   = length;
+    e->X->P			    = (byte*)pVar;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+int SuperTraceExecuteRequest (void* AdapterHandle,
+                              const char* name,
+                              byte* data) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)AdapterHandle;
+
+  if (pC && pC->pIdiLib && pC->request) {
+    ENTITY* e = (ENTITY*)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
+    byte* xdata = (byte*)&pC->xbuffer[0];
+    word length;
+
+    length = SuperTraceCreateReadReq (xdata, name);
+    single_p (xdata, &length, 0); /* End Of Message */
+
+    e->Req          = MAN_EXECUTE;
+    e->ReqCh			  = 0;
+    e->X->PLength   = length;
+    e->X->P			    = (byte*)xdata;
+
+    pC->request_pending = 1;
+
+    return (0);
+  }
+
+  return (-1);
+}
+
+static word SuperTraceCreateReadReq (byte* P, const char* path) {
+	byte var_length;
+	byte* plen;
+
+	var_length = (byte)strlen (path);
+
+	*P++ = ESC;
+	plen = P++;
+	*P++ = 0x80; /* MAN_IE */
+	*P++ = 0x00; /* Type */
+	*P++ = 0x00; /* Attribute */
+	*P++ = 0x00; /* Status */
+	*P++ = 0x00; /* Variable Length */
+	*P++ = var_length;
+	memcpy (P, path, var_length);
+	P += var_length;
+	*plen = var_length + 0x06;
+
+	return ((word)(var_length + 0x08));
+}
+
+static void single_p (byte * P, word * PLength, byte Id) {
+  P[(*PLength)++] = Id;
+}
+
+static void diva_maint_xdi_cb (ENTITY* e) {
+  diva_strace_context_t* pLib = DIVAS_CONTAINING_RECORD(e,diva_strace_context_t,e);
+  diva_maint_client_t* pC;
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+
+
+  diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "xdi_cb");
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "xdi_cb");
+
+  pC = (diva_maint_client_t*)pLib->hAdapter;
+
+  if ((e->complete == 255) || (pC->dma_handle < 0)) {
+    if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
+      diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error");
+    }
+  } else {
+    /*
+      Process combined management interface indication
+      */
+    if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
+      diva_mnt_internal_dprintf (0, DLI_ERR, "Trace internal library error (DMA mode)");
+    }
+  }
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "xdi_cb");
+
+
+	if (pC->request_pending) {
+    pC->request_pending = 0;
+    (*(pC->request))(e);
+	}
+
+  diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "xdi_cb");
+}
+
+
+static void diva_maint_error (void* user_context,
+                              diva_strace_library_interface_t* hLib,
+                              int Adapter,
+                              int error,
+                              const char* file,
+                              int line) {
+	diva_mnt_internal_dprintf (0, DLI_ERR,
+                             "Trace library error(%d) A(%d) %s %d", error, Adapter, file, line);
+}
+
+static void print_ie (diva_trace_ie_t* ie, char* buffer, int length) {
+	int i;
+
+  buffer[0] = 0;
+
+  if (length > 32) {
+    for (i = 0; ((i < ie->length) && (length > 3)); i++) {
+      sprintf (buffer, "%02x", ie->data[i]);
+      buffer += 2;
+      length -= 2;
+      if (i < (ie->length-1)) {
+        strcpy (buffer, " ");
+        buffer++;
+        length--;
+      }
+    }
+  }
+}
+
+static void diva_maint_state_change_notify (void* user_context,
+                                            diva_strace_library_interface_t* hLib,
+                                            int Adapter,
+                                            diva_trace_line_state_t* channel,
+                                            int notify_subject) {
+  diva_maint_client_t*      pC    = (diva_maint_client_t*)user_context;
+  diva_trace_fax_state_t*   fax   = &channel->fax;
+  diva_trace_modem_state_t* modem = &channel->modem;
+  char tmp[256];
+
+  if (!pC->hDbg) {
+    return;
+  }
+
+  switch (notify_subject) {
+    case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE: {
+      int view = (TraceFilter[0] == 0);
+      /*
+        Process selective Trace
+        */
+      if (channel->Line[0] == 'I' && channel->Line[1] == 'd' &&
+          channel->Line[2] == 'l' && channel->Line[3] == 'e') {
+        if ((TraceFilterIdent == pC->hDbg->id) && (TraceFilterChannel == (int)channel->ChannelNumber)) {
+          (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 0);
+          (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 0);
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG, "Selective Trace OFF for Ch=%d",
+                                     (int)channel->ChannelNumber);
+          TraceFilterIdent   = -1;
+          TraceFilterChannel = -1;
+          view = 1;
+        }
+      } else if (TraceFilter[0] && (TraceFilterIdent < 0) && !(diva_mnt_cmp_nmbr (&channel->RemoteAddress[0]) &&
+                                                               diva_mnt_cmp_nmbr (&channel->LocalAddress[0]))) {
+
+        if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0) { /* Activate B-channel trace */
+          (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 1);
+        }
+        if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0) { /* Activate AudioTap Trace */
+          (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 1);
+        }
+
+        TraceFilterIdent   = pC->hDbg->id;
+        TraceFilterChannel = (int)channel->ChannelNumber;
+
+        if (TraceFilterIdent >= 0) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG, "Selective Trace ON for Ch=%d",
+                                     (int)channel->ChannelNumber);
+          view = 1;
+        }
+      }
+      if (view && (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS)) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Ch     = %d",
+                                                                     (int)channel->ChannelNumber);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Status = <%s>", &channel->Line[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer1 = <%s>", &channel->Framing[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer2 = <%s>", &channel->Layer2[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Layer3 = <%s>", &channel->Layer3[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L RAddr  = <%s>",
+                                                                     &channel->RemoteAddress[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L RSAddr = <%s>",
+                                                                     &channel->RemoteSubAddress[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LAddr  = <%s>",
+                                                                     &channel->LocalAddress[0]);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LSAddr = <%s>",
+                                                                     &channel->LocalSubAddress[0]);
+        print_ie(&channel->call_BC, tmp, sizeof(tmp));
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L BC     = <%s>", tmp);
+        print_ie(&channel->call_HLC, tmp, sizeof(tmp));
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L HLC    = <%s>", tmp);
+        print_ie(&channel->call_LLC, tmp, sizeof(tmp));
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L LLC    = <%s>", tmp);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L CR     = 0x%x", channel->CallReference);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Disc   = 0x%x",
+                                                                    channel->LastDisconnecCause);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT, "L Owner  = <%s>", &channel->UserID[0]);
+      }
+
+		} break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_PROGRESS) {
+				{
+					int ch = TraceFilterChannel;
+					int id = TraceFilterIdent;
+
+					if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
+						(clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
+						if (ch != (int)modem->ChannelNumber) {
+							break;
+						}
+					} else if (TraceFilter[0] != 0) {
+						break;
+					}
+				}
+
+
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Ch    = %lu",
+                                                                     (int)modem->ChannelNumber);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Event = %lu",     modem->Event);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Norm  = %lu",     modem->Norm);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Opts. = 0x%08x",  modem->Options);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Tx    = %lu Bps", modem->TxSpeed);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rx    = %lu Bps", modem->RxSpeed);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RT    = %lu mSec",
+                                                                     modem->RoundtripMsec);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Sr    = %lu",     modem->SymbolRate);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rxl   = %d dBm",  modem->RxLeveldBm);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM El    = %d dBm",  modem->EchoLeveldBm);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM SNR   = %lu dB",  modem->SNRdb);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM MAE   = %lu",     modem->MAE);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRet  = %lu",
+                                                                     modem->LocalRetrains);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRet  = %lu",
+                                                                     modem->RemoteRetrains);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRes  = %lu",     modem->LocalResyncs);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRes  = %lu",
+                                                                     modem->RemoteResyncs);
+        if (modem->Event == 3) {
+          diva_mnt_internal_dprintf(pC->hDbg->id,DLI_STAT,"MDM Disc  =  %lu",    modem->DiscReason);
+        }
+      }
+      if ((modem->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_STATISTICS)) {
+        (*(pC->pIdiLib->DivaSTraceGetModemStatistics))(pC->pIdiLib);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_PROGRESS) {
+				{
+					int ch = TraceFilterChannel;
+					int id = TraceFilterIdent;
+
+					if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
+						(clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
+						if (ch != (int)fax->ChannelNumber) {
+							break;
+						}
+					} else if (TraceFilter[0] != 0) {
+						break;
+					}
+				}
+
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Ch    = %lu",(int)fax->ChannelNumber);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Event = %lu",     fax->Event);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pages = %lu",     fax->Page_Counter);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Feat. = 0x%08x",  fax->Features);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX ID    = <%s>",    &fax->Station_ID[0]);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Saddr = <%s>",    &fax->Subaddress[0]);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pwd   = <%s>",    &fax->Password[0]);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Speed = %lu",     fax->Speed);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Res.  = 0x%08x",  fax->Resolution);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Width = %lu",     fax->Paper_Width);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Length= %lu",     fax->Paper_Length);
+        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX SLT   = %lu",     fax->Scanline_Time);
+        if (fax->Event == 3) {
+          diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Disc  = %lu",     fax->Disc_Reason);
+        }
+      }
+      if ((fax->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_STATISTICS)) {
+        (*(pC->pIdiLib->DivaSTraceGetFaxStatistics))(pC->pIdiLib);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_INTERFACE_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_EVENTS) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT,
+                                 "Layer 1 -> [%s]", channel->pInterface->Layer1);
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_STAT,
+                                 "Layer 2 -> [%s]", channel->pInterface->Layer2);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE:
+      if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_STATISTICS) {
+        /*
+          Incoming Statistics
+          */
+        if (channel->pInterfaceStat->inc.Calls) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Calls                     =%lu", channel->pInterfaceStat->inc.Calls);
+        }
+        if (channel->pInterfaceStat->inc.Connected) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Connected                 =%lu", channel->pInterfaceStat->inc.Connected);
+        }
+        if (channel->pInterfaceStat->inc.User_Busy) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Busy                      =%lu", channel->pInterfaceStat->inc.User_Busy);
+        }
+        if (channel->pInterfaceStat->inc.Call_Rejected) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Rejected                  =%lu", channel->pInterfaceStat->inc.Call_Rejected);
+        }
+        if (channel->pInterfaceStat->inc.Wrong_Number) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Wrong Nr                  =%lu", channel->pInterfaceStat->inc.Wrong_Number);
+        }
+        if (channel->pInterfaceStat->inc.Incompatible_Dst) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Incomp. Dest              =%lu", channel->pInterfaceStat->inc.Incompatible_Dst);
+        }
+        if (channel->pInterfaceStat->inc.Out_of_Order) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Out of Order              =%lu", channel->pInterfaceStat->inc.Out_of_Order);
+        }
+        if (channel->pInterfaceStat->inc.Ignored) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Inc Ignored                   =%lu", channel->pInterfaceStat->inc.Ignored);
+        }
+        
+        /*
+          Outgoing Statistics
+          */
+        if (channel->pInterfaceStat->outg.Calls) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Calls                    =%lu", channel->pInterfaceStat->outg.Calls);
+        }
+        if (channel->pInterfaceStat->outg.Connected) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Connected                =%lu", channel->pInterfaceStat->outg.Connected);
+        }
+        if (channel->pInterfaceStat->outg.User_Busy) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Busy                     =%lu", channel->pInterfaceStat->outg.User_Busy);
+        }
+        if (channel->pInterfaceStat->outg.No_Answer) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg No Answer                =%lu", channel->pInterfaceStat->outg.No_Answer);
+        }
+        if (channel->pInterfaceStat->outg.Wrong_Number) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Wrong Nr                 =%lu", channel->pInterfaceStat->outg.Wrong_Number);
+        }
+        if (channel->pInterfaceStat->outg.Call_Rejected) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Rejected                 =%lu", channel->pInterfaceStat->outg.Call_Rejected);
+        }
+        if (channel->pInterfaceStat->outg.Other_Failures) {
+          diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+          "Outg Other Failures           =%lu", channel->pInterfaceStat->outg.Other_Failures);
+        }
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE:
+      if (channel->pInterfaceStat->mdm.Disc_Normal) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Normal        = %lu", channel->pInterfaceStat->mdm.Disc_Normal);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Unspecified) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Unsp.         = %lu", channel->pInterfaceStat->mdm.Disc_Unspecified);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Busy_Tone) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Busy Tone     = %lu", channel->pInterfaceStat->mdm.Disc_Busy_Tone);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Congestion) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Congestion    = %lu", channel->pInterfaceStat->mdm.Disc_Congestion);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Carr_Wait) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Carrier Wait  = %lu", channel->pInterfaceStat->mdm.Disc_Carr_Wait);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Trn_Timeout) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Trn. T.o.     = %lu", channel->pInterfaceStat->mdm.Disc_Trn_Timeout);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Incompat) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Incompatible  = %lu", channel->pInterfaceStat->mdm.Disc_Incompat);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_Frame_Rej) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc Frame Reject  = %lu", channel->pInterfaceStat->mdm.Disc_Frame_Rej);
+      }
+      if (channel->pInterfaceStat->mdm.Disc_V42bis) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "MDM Disc V.42bis       = %lu", channel->pInterfaceStat->mdm.Disc_V42bis);
+      }
+      break;
+
+    case DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE:
+      if (channel->pInterfaceStat->fax.Disc_Normal) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Normal        = %lu", channel->pInterfaceStat->fax.Disc_Normal);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Not_Ident) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Not Ident.    = %lu", channel->pInterfaceStat->fax.Disc_Not_Ident);
+      }
+      if (channel->pInterfaceStat->fax.Disc_No_Response) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc No Response   = %lu", channel->pInterfaceStat->fax.Disc_No_Response);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Retries) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Max Retries   = %lu", channel->pInterfaceStat->fax.Disc_Retries);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Unexp_Msg) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Unexp. Msg.        = %lu", channel->pInterfaceStat->fax.Disc_Unexp_Msg);
+      }
+      if (channel->pInterfaceStat->fax.Disc_No_Polling) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc No Polling    = %lu", channel->pInterfaceStat->fax.Disc_No_Polling);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Training) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Training      = %lu", channel->pInterfaceStat->fax.Disc_Training);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Unexpected) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Unexpected    = %lu", channel->pInterfaceStat->fax.Disc_Unexpected);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Application) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Application   = %lu", channel->pInterfaceStat->fax.Disc_Application);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Incompat) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Incompatible  = %lu", channel->pInterfaceStat->fax.Disc_Incompat);
+      }
+      if (channel->pInterfaceStat->fax.Disc_No_Command) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc No Command    = %lu", channel->pInterfaceStat->fax.Disc_No_Command);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Long_Msg) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Long Msg.     = %lu", channel->pInterfaceStat->fax.Disc_Long_Msg);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Supervisor) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Supervisor    = %lu", channel->pInterfaceStat->fax.Disc_Supervisor);
+      }
+      if (channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc SUP SEP PWD   = %lu", channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Invalid_Msg) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Invalid Msg.  = %lu", channel->pInterfaceStat->fax.Disc_Invalid_Msg);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Page_Coding) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Page Coding   = %lu", channel->pInterfaceStat->fax.Disc_Page_Coding);
+      }
+      if (channel->pInterfaceStat->fax.Disc_App_Timeout) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Appl. T.o.    = %lu", channel->pInterfaceStat->fax.Disc_App_Timeout);
+      }
+      if (channel->pInterfaceStat->fax.Disc_Unspecified) {
+        diva_mnt_internal_dprintf (pC->hDbg->id, DLI_LOG,
+        "FAX Disc Unspec.       = %lu", channel->pInterfaceStat->fax.Disc_Unspecified);
+      }
+      break;
+  }
+}
+
+/*
+  Receive trace information from the Management Interface and store it in the
+  internal trace buffer with MSG_TYPE_MLOG as is, without any filtering.
+  Event Filtering and formatting is done in  Management Interface self.
+  */
+static void diva_maint_trace_notify (void* user_context,
+                                     diva_strace_library_interface_t* hLib,
+                                     int Adapter,
+                                     void* xlog_buffer,
+                                     int length) {
+  diva_maint_client_t* pC = (diva_maint_client_t*)user_context;
+  diva_dbg_entry_head_t* pmsg;
+  word size;
+  dword sec, usec;
+  int ch = TraceFilterChannel;
+  int id = TraceFilterIdent;
+
+  /*
+    Selective trace
+    */
+  if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
+      (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
+    const char* p = NULL;
+    int ch_value = -1;
+    MI_XLOG_HDR *TrcData = (MI_XLOG_HDR *)xlog_buffer;
+
+    if (Adapter != clients[id].logical) {
+      return; /* Ignore all trace messages from other adapters */
+    }
+
+    if (TrcData->code == 24) {
+      p = (char*)&TrcData->code;
+      p += 2;
+    }
+
+    /*
+      All L1 messages start as [dsp,ch], so we can filter this information
+      and filter out all messages that use different channel
+      */
+    if (p && p[0] == '[') {
+      if (p[2] == ',') {
+        p += 3;
+        ch_value = *p - '0';
+      } else if (p[3] == ',') {
+        p += 4;
+        ch_value = *p - '0';
+      }
+      if (ch_value >= 0) {
+        if (p[2] == ']') {
+          ch_value = ch_value * 10 + p[1] - '0';
+        }
+        if (ch_value != ch) {
+          return; /* Ignore other channels */
+        }
+      }
+    }
+
+	} else if (TraceFilter[0] != 0) {
+    return; /* Ignore trace if trace filter is activated, but idle */
+  }
+
+  diva_os_get_time (&sec, &usec);
+
+  while (!(pmsg = (diva_dbg_entry_head_t*)queueAllocMsg (dbg_queue,
+                              (word)length+sizeof(*pmsg)))) {
+    if ((pmsg = (diva_dbg_entry_head_t*)queuePeekMsg (dbg_queue, &size))) {
+      queueFreeMsg (dbg_queue);
+    } else {
+      break;
+    }
+  }
+  if (pmsg) {
+    memcpy (&pmsg[1], xlog_buffer, length);
+    pmsg->sequence    = dbg_sequence++;
+    pmsg->time_sec    = sec;
+    pmsg->time_usec   = usec;
+    pmsg->facility    = MSG_TYPE_MLOG;
+    pmsg->dli         = pC->logical;
+    pmsg->drv_id      = pC->hDbg->id;
+    pmsg->di_cpu      = 0;
+    pmsg->data_length = length;
+    queueCompleteMsg (pmsg);
+    if (queueCount(dbg_queue)) {
+      diva_maint_wakeup_read();
+    }
+  }
+}
+
+
+/*
+  Convert MAINT trace mask to management interface trace mask/work/facility and
+  issue command to management interface
+  */
+static void diva_change_management_debug_mask (diva_maint_client_t* pC, dword old_mask) {
+  if (pC->request && pC->hDbg && pC->pIdiLib) {
+    dword changed = pC->hDbg->dbgMask ^ old_mask;
+
+    if (changed & DIVA_MGT_DBG_TRACE) {
+      (*(pC->pIdiLib->DivaSTraceSetInfo))(pC->pIdiLib,
+                                          (pC->hDbg->dbgMask & DIVA_MGT_DBG_TRACE) != 0);
+    }
+    if (changed & DIVA_MGT_DBG_DCHAN) {
+      (*(pC->pIdiLib->DivaSTraceSetDChannel))(pC->pIdiLib,
+                                              (pC->hDbg->dbgMask & DIVA_MGT_DBG_DCHAN) != 0);
+    }
+    if (!TraceFilter[0]) {
+      if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) {
+        int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
+
+        for (i = 0; i < pC->channels; i++) {
+          (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i+1, state);
+        }
+      }
+      if (changed & DIVA_MGT_DBG_IFC_AUDIO) {
+        int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0);
+
+        for (i = 0; i < pC->channels; i++) {
+          (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i+1, state);
+        }
+      }
+    }
+  }
+}
+
+
+void diva_mnt_internal_dprintf (dword drv_id, dword type, char* fmt, ...) {
+  va_list ap;
+
+	va_start(ap, fmt);
+  DI_format (0, (word)drv_id, (int)type, fmt, ap);
+	va_end(ap);
+}
+
+/*
+  Shutdown all adapters before driver removal
+  */
+int diva_mnt_shutdown_xdi_adapters (void) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  int i, fret = 0;
+  byte * pmem;
+
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    pmem = NULL;
+
+    diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "unload");
+    diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "unload");
+
+    if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
+      if ((*(clients[i].pIdiLib->DivaSTraceLibraryStop))(clients[i].pIdiLib) == 1) {
+        /*
+          Adapter removal complete
+          */
+        if (clients[i].pIdiLib) {
+          (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
+          clients[i].pIdiLib = NULL;
+
+          pmem = clients[i].pmem;
+          clients[i].pmem = NULL;
+        }
+        clients[i].hDbg    = NULL;
+        clients[i].request_pending = 0;
+
+        if (clients[i].dma_handle >= 0) {
+          /*
+            Free DMA handle
+            */
+          diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle);
+          clients[i].dma_handle = -1;
+				}
+        clients[i].request = NULL;
+      } else {
+        fret = -1;
+      }
+    }
+
+    diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "unload");
+    if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
+      clients[i].request_pending = 0;
+      (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
+      if (clients[i].dma_handle >= 0) {
+        diva_free_dma_descriptor (clients[i].request, clients[i].dma_handle);
+        clients[i].dma_handle = -1;
+      }
+    }
+    diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "unload");
+
+    if (pmem) {
+      diva_os_free (0, pmem);
+    }
+  }
+
+  return (fret);
+}
+
+/*
+  Set/Read the trace filter used for selective tracing.
+  Affects B- and Audio Tap trace mask at run time
+  */
+int diva_set_trace_filter (int filter_length, const char* filter) {
+  diva_os_spin_lock_magic_t old_irql, old_irql1;
+  int i, ch, on, client_b_on, client_atap_on;
+
+  diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask");
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
+
+  if (filter_length <= DIVA_MAX_SELECTIVE_FILTER_LENGTH) {
+    memcpy (&TraceFilter[0], filter, filter_length);
+    if (TraceFilter[filter_length]) {
+      TraceFilter[filter_length] = 0;
+    }
+    if (TraceFilter[0] == '*') {
+      TraceFilter[0] = 0;
+    }
+  } else {
+    filter_length = -1;
+  }
+
+  TraceFilterIdent   = -1;
+  TraceFilterChannel = -1;
+
+  on = (TraceFilter[0] == 0);
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
+      client_b_on    = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
+      client_atap_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO)    != 0);
+      for (ch = 0; ch < clients[i].channels; ch++) {
+        (*(clients[i].pIdiLib->DivaSTraceSetBChannel))(clients[i].pIdiLib->hLib, ch+1, client_b_on);
+        (*(clients[i].pIdiLib->DivaSTraceSetAudioTap))(clients[i].pIdiLib->hLib, ch+1, client_atap_on);
+      }
+    }
+  }
+
+  for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+    if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
+      diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
+      clients[i].request_pending = 0;
+      (*(clients[i].request))((ENTITY*)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
+      diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
+    }
+  }
+
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
+  diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "dbg mask");
+
+  return (filter_length);
+}
+
+int diva_get_trace_filter (int max_length, char* filter) {
+  diva_os_spin_lock_magic_t old_irql;
+  int len;
+
+  diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read_filter");
+  len = strlen (&TraceFilter[0]) + 1;
+  if (max_length >= len) {
+    memcpy (filter, &TraceFilter[0], len);
+  }
+  diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "read_filter");
+
+  return (len);
+}
+
+static int diva_dbg_cmp_key (const char* ref, const char* key) {
+	while (*key && (*ref++ == *key++));
+  return (!*key && !*ref);
+}
+
+/*
+  In case trace filter starts with "C" character then
+  all following characters are interpreted as command.
+  Followings commands are available:
+  - single, trace single call at time, independent from CPN/CiPN
+  */
+static int diva_mnt_cmp_nmbr (const char* nmbr) {
+  const char* ref = &TraceFilter[0];
+  int ref_len = strlen(&TraceFilter[0]), nmbr_len = strlen(nmbr);
+
+  if (ref[0] == 'C') {
+    if (diva_dbg_cmp_key (&ref[1], "single")) {
+      return (0);
+    }
+    return (-1);
+  }
+
+  if (!ref_len || (ref_len > nmbr_len)) {
+    return (-1);
+  }
+
+  nmbr = nmbr + nmbr_len - 1;
+  ref  = ref  + ref_len  - 1;
+
+  while (ref_len--) {
+    if (*nmbr-- != *ref--) {
+      return (-1);
+    }
+  }
+
+  return (0);
+}
+
+static int diva_get_dma_descriptor (IDI_CALL request, dword *dma_magic) {
+  ENTITY e;
+  IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
+
+  if (!request) {
+    return (-1);
+  }
+
+  pReq->xdi_dma_descriptor_operation.Req = 0;
+  pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
+
+  pReq->xdi_dma_descriptor_operation.info.operation =     IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_number  = -1;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
+
+  (*request)((ENTITY*)pReq);
+
+  if (!pReq->xdi_dma_descriptor_operation.info.operation &&
+      (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) &&
+      pReq->xdi_dma_descriptor_operation.info.descriptor_magic) {
+    *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic;
+    return (pReq->xdi_dma_descriptor_operation.info.descriptor_number);
+  } else {
+    return (-1);
+  }
+}
+
+static void diva_free_dma_descriptor (IDI_CALL request, int nr) {
+  ENTITY e;
+  IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
+
+  if (!request || (nr < 0)) {
+    return;
+  }
+
+  pReq->xdi_dma_descriptor_operation.Req = 0;
+  pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
+
+  pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_number  = nr;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
+
+  (*request)((ENTITY*)pReq);
+}
+
diff --git a/drivers/isdn/hardware/eicon/debug_if.h b/drivers/isdn/hardware/eicon/debug_if.h
new file mode 100644
index 0000000..4db739d
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/debug_if.h
@@ -0,0 +1,90 @@
+/*
+ *
+  Copyright (c) Eicon Technology Corporation, 2000.
+ *
+  This source file is supplied for the use with Eicon
+  Technology Corporation's range of DIVA Server Adapters.
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_DEBUG_IF_H__
+#define __DIVA_DEBUG_IF_H__
+#define MSG_TYPE_DRV_ID		0x0001
+#define MSG_TYPE_FLAGS		0x0002
+#define MSG_TYPE_STRING		0x0003
+#define MSG_TYPE_BINARY		0x0004
+#define MSG_TYPE_MLOG     0x0005
+
+#define MSG_FRAME_MAX_SIZE 2150
+
+typedef struct _diva_dbg_entry_head {
+  dword sequence;
+  dword time_sec;
+  dword time_usec;
+  dword facility;
+  dword dli;
+  dword drv_id;
+  dword di_cpu;
+  dword data_length;
+} diva_dbg_entry_head_t;
+
+int diva_maint_init (byte* base, unsigned long length, int do_init);
+void* diva_maint_finit (void);
+dword diva_dbg_q_length (void);
+diva_dbg_entry_head_t* diva_maint_get_message (word* size,
+                                               diva_os_spin_lock_magic_t* old_irql);
+void diva_maint_ack_message (int do_release,
+                             diva_os_spin_lock_magic_t* old_irql);
+void diva_maint_prtComp (char *format, ...);
+void diva_maint_wakeup_read (void);
+int diva_get_driver_info (dword id, byte* data, int data_length);
+int diva_get_driver_dbg_mask (dword id, byte* data);
+int diva_set_driver_dbg_mask (dword id, dword mask);
+void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d);
+void diva_mnt_add_xdi_adapter    (const DESCRIPTOR* d);
+int diva_mnt_shutdown_xdi_adapters (void);
+
+#define DIVA_MAX_SELECTIVE_FILTER_LENGTH 127
+int diva_set_trace_filter (int filter_length, const char* filter);
+int diva_get_trace_filter (int max_length,    char*       filter);
+
+
+#define DITRACE_CMD_GET_DRIVER_INFO   1
+#define DITRACE_READ_DRIVER_DBG_MASK  2
+#define DITRACE_WRITE_DRIVER_DBG_MASK 3
+#define DITRACE_READ_TRACE_ENTRY      4
+#define DITRACE_READ_TRACE_ENTRYS     5
+#define DITRACE_WRITE_SELECTIVE_TRACE_FILTER 6
+#define DITRACE_READ_SELECTIVE_TRACE_FILTER  7
+
+/*
+  Trace lavels for debug via management interface
+  */
+#define DIVA_MGT_DBG_TRACE          0x00000001 /* All trace messages from the card */
+#define DIVA_MGT_DBG_DCHAN          0x00000002 /* All D-channel relater trace messages */
+#define DIVA_MGT_DBG_MDM_PROGRESS   0x00000004 /* Modem progress events */
+#define DIVA_MGT_DBG_FAX_PROGRESS   0x00000008 /* Fax progress events */
+#define DIVA_MGT_DBG_IFC_STATISTICS 0x00000010 /* Interface call statistics */
+#define DIVA_MGT_DBG_MDM_STATISTICS 0x00000020 /* Global modem statistics   */
+#define DIVA_MGT_DBG_FAX_STATISTICS 0x00000040 /* Global call statistics    */
+#define DIVA_MGT_DBG_LINE_EVENTS    0x00000080 /* Line state events */
+#define DIVA_MGT_DBG_IFC_EVENTS     0x00000100 /* Interface/L1/L2 state events */
+#define DIVA_MGT_DBG_IFC_BCHANNEL   0x00000200 /* B-Channel trace for all channels */
+#define DIVA_MGT_DBG_IFC_AUDIO      0x00000400 /* Audio Tap trace for all channels */
+
+# endif /* DEBUG_IF___H */
+
+
diff --git a/drivers/isdn/hardware/eicon/debuglib.c b/drivers/isdn/hardware/eicon/debuglib.c
new file mode 100644
index 0000000..a19b7ff
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/debuglib.c
@@ -0,0 +1,156 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "debuglib.h"
+
+#ifdef DIVA_NO_DEBUGLIB
+static DIVA_DI_PRINTF dprintf;
+#else /* DIVA_NO_DEBUGLIB */
+ 
+_DbgHandle_ myDriverDebugHandle = { 0 /*!Registered*/, DBG_HANDLE_VERSION };
+DIVA_DI_PRINTF dprintf = no_printf;
+/*****************************************************************************/
+#define DBG_FUNC(name) \
+void  \
+myDbgPrint_##name (char *format, ...) \
+{ va_list ap ; \
+ if ( myDriverDebugHandle.dbg_prt ) \
+ { va_start (ap, format) ; \
+  (myDriverDebugHandle.dbg_prt) \
+   (myDriverDebugHandle.id, DLI_##name, format, ap) ; \
+  va_end (ap) ; \
+} }
+DBG_FUNC(LOG)
+DBG_FUNC(FTL)
+DBG_FUNC(ERR)
+DBG_FUNC(TRC)
+DBG_FUNC(MXLOG)
+DBG_FUNC(FTL_MXLOG)
+void 
+myDbgPrint_EVL (long msgID, ...)
+{ va_list ap ;
+ if ( myDriverDebugHandle.dbg_ev )
+ { va_start (ap, msgID) ;
+  (myDriverDebugHandle.dbg_ev)
+   (myDriverDebugHandle.id, (unsigned long)msgID, ap) ;
+  va_end (ap) ;
+} }
+DBG_FUNC(REG)
+DBG_FUNC(MEM)
+DBG_FUNC(SPL)
+DBG_FUNC(IRP)
+DBG_FUNC(TIM)
+DBG_FUNC(BLK)
+DBG_FUNC(TAPI)
+DBG_FUNC(NDIS)
+DBG_FUNC(CONN)
+DBG_FUNC(STAT)
+DBG_FUNC(SEND)
+DBG_FUNC(RECV)
+DBG_FUNC(PRV0)
+DBG_FUNC(PRV1)
+DBG_FUNC(PRV2)
+DBG_FUNC(PRV3)
+/*****************************************************************************/
+int
+DbgRegister (char *drvName, char *drvTag, unsigned long dbgMask)
+{
+ int len;
+/*
+ * deregister (if already registered) and zero out myDriverDebugHandle
+ */
+ DbgDeregister () ;
+/*
+ * initialize the debug handle
+ */
+ myDriverDebugHandle.Version = DBG_HANDLE_VERSION ;
+ myDriverDebugHandle.id  = -1 ;
+ myDriverDebugHandle.dbgMask = dbgMask | (DL_EVL | DL_FTL | DL_LOG) ;
+ len = strlen (drvName) ;
+ memcpy (myDriverDebugHandle.drvName, drvName,
+         (len < sizeof(myDriverDebugHandle.drvName)) ?
+    len : sizeof(myDriverDebugHandle.drvName) - 1) ;
+ len = strlen (drvTag) ;
+ memcpy (myDriverDebugHandle.drvTag, drvTag,
+         (len < sizeof(myDriverDebugHandle.drvTag)) ?
+    len : sizeof(myDriverDebugHandle.drvTag) - 1) ;
+/*
+ * Try to register debugging via old (and only) interface
+ */
+ dprintf("\000\377", &myDriverDebugHandle) ;
+ if ( myDriverDebugHandle.dbg_prt )
+ {
+  return (1) ;
+ }
+/*
+ * Check if we registered whith an old maint driver (see debuglib.h)
+ */
+ if ( myDriverDebugHandle.dbg_end != NULL
+   /* location of 'dbg_prt' in _OldDbgHandle_ struct */
+   && (myDriverDebugHandle.regTime.LowPart ||
+       myDriverDebugHandle.regTime.HighPart  ) )
+   /* same location as in _OldDbgHandle_ struct */
+ {
+  dprintf("%s: Cannot log to old maint driver !", drvName) ;
+  myDriverDebugHandle.dbg_end =
+  ((_OldDbgHandle_ *)&myDriverDebugHandle)->dbg_end ;
+  DbgDeregister () ;
+ }
+ return (0) ;
+}
+/*****************************************************************************/
+void
+DbgSetLevel (unsigned long dbgMask)
+{
+ myDriverDebugHandle.dbgMask = dbgMask | (DL_EVL | DL_FTL | DL_LOG) ;
+}
+/*****************************************************************************/
+void
+DbgDeregister (void)
+{
+ if ( myDriverDebugHandle.dbg_end )
+ {
+  (myDriverDebugHandle.dbg_end)(&myDriverDebugHandle) ;
+ }
+ memset (&myDriverDebugHandle, 0, sizeof(myDriverDebugHandle)) ;
+}
+void  xdi_dbg_xlog (char* x, ...) {
+ va_list ap;
+ va_start (ap, x);
+ if (myDriverDebugHandle.dbg_end &&
+   (myDriverDebugHandle.dbg_irq || myDriverDebugHandle.dbg_old) &&
+   (myDriverDebugHandle.dbgMask & DL_STAT)) {
+  if (myDriverDebugHandle.dbg_irq) {
+   (*(myDriverDebugHandle.dbg_irq))(myDriverDebugHandle.id,
+       (x[0] != 0) ? DLI_TRC : DLI_XLOG, x, ap);
+  } else {
+   (*(myDriverDebugHandle.dbg_old))(myDriverDebugHandle.id, x, ap);
+  }
+ }
+ va_end(ap);
+}
+/*****************************************************************************/
+#endif /* DIVA_NO_DEBUGLIB */
diff --git a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h
new file mode 100644
index 0000000..11b3b9e
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/debuglib.h
@@ -0,0 +1,322 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#if !defined(__DEBUGLIB_H__)
+#define __DEBUGLIB_H__
+#include <stdarg.h>
+/*
+ * define global debug priorities
+ */
+#define DL_LOG  0x00000001 /* always worth mentioning */
+#define DL_FTL  0x00000002 /* always sampled error    */
+#define DL_ERR  0x00000004 /* any kind of error       */
+#define DL_TRC  0x00000008 /* verbose information     */
+#define DL_XLOG  0x00000010 /* old xlog info           */
+#define DL_MXLOG 0x00000020 /* maestra xlog info    */
+#define DL_FTL_MXLOG 0x00000021 /* fatal maestra xlog info */
+#define DL_EVL  0x00000080 /* special NT eventlog msg */
+#define DL_COMPAT (DL_MXLOG | DL_XLOG)
+#define DL_PRIOR_MASK (DL_EVL | DL_COMPAT | DL_TRC | DL_ERR | DL_FTL | DL_LOG)
+#define DLI_LOG  0x0100
+#define DLI_FTL  0x0200
+#define DLI_ERR  0x0300
+#define DLI_TRC  0x0400
+#define DLI_XLOG 0x0500
+#define DLI_MXLOG 0x0600
+#define DLI_FTL_MXLOG 0x0600
+#define DLI_EVL  0x0800
+/*
+ * define OS (operating system interface) debuglevel
+ */
+#define DL_REG  0x00000100 /* init/query registry     */
+#define DL_MEM  0x00000200 /* memory management       */
+#define DL_SPL  0x00000400 /* event/spinlock handling */
+#define DL_IRP  0x00000800 /* I/O request handling    */
+#define DL_TIM  0x00001000 /* timer/watchdog handling */
+#define DL_BLK  0x00002000 /* raw data block contents */
+#define DL_OS_MASK (DL_BLK | DL_TIM | DL_IRP | DL_SPL | DL_MEM | DL_REG)
+#define DLI_REG  0x0900
+#define DLI_MEM  0x0A00
+#define DLI_SPL  0x0B00
+#define DLI_IRP  0x0C00
+#define DLI_TIM  0x0D00
+#define DLI_BLK  0x0E00
+/*
+ * define ISDN (connection interface) debuglevel
+ */
+#define DL_TAPI  0x00010000 /* debug TAPI interface    */
+#define DL_NDIS  0x00020000 /* debug NDIS interface    */
+#define DL_CONN  0x00040000 /* connection handling     */
+#define DL_STAT  0x00080000 /* trace state machines    */
+#define DL_SEND  0x00100000 /* trace raw xmitted data  */
+#define DL_RECV  0x00200000 /* trace raw received data */
+#define DL_DATA  (DL_SEND | DL_RECV)
+#define DL_ISDN_MASK (DL_DATA | DL_STAT | DL_CONN | DL_NDIS | DL_TAPI)
+#define DLI_TAPI 0x1100
+#define DLI_NDIS 0x1200
+#define DLI_CONN 0x1300
+#define DLI_STAT 0x1400
+#define DLI_SEND 0x1500
+#define DLI_RECV 0x1600
+/*
+ * define some private (unspecified) debuglevel
+ */
+#define DL_PRV0  0x01000000
+#define DL_PRV1  0x02000000
+#define DL_PRV2  0x04000000
+#define DL_PRV3  0x08000000
+#define DL_PRIV_MASK (DL_PRV0 | DL_PRV1 | DL_PRV2 | DL_PRV3)
+#define DLI_PRV0 0x1900
+#define DLI_PRV1 0x1A00
+#define DLI_PRV2 0x1B00
+#define DLI_PRV3 0x1C00
+#define DT_INDEX(x)  ((x) & 0x000F)
+#define DL_INDEX(x)  ((((x) >> 8) & 0x00FF) - 1)
+#define DLI_NAME(x)  ((x) & 0xFF00)
+/*
+ * Debug mask for kernel mode tracing, if set the output is also sent to
+ * the system debug function. Requires that the project is compiled
+ * with _KERNEL_DBG_PRINT_
+ */
+#define DL_TO_KERNEL    0x40000000
+
+#ifdef DIVA_NO_DEBUGLIB
+#define myDbgPrint_LOG(x...) do { } while(0);
+#define myDbgPrint_FTL(x...) do { } while(0);
+#define myDbgPrint_ERR(x...) do { } while(0);
+#define myDbgPrint_TRC(x...) do { } while(0);
+#define myDbgPrint_MXLOG(x...) do { } while(0);
+#define myDbgPrint_EVL(x...) do { } while(0);
+#define myDbgPrint_REG(x...) do { } while(0);
+#define myDbgPrint_MEM(x...) do { } while(0);
+#define myDbgPrint_SPL(x...) do { } while(0);
+#define myDbgPrint_IRP(x...) do { } while(0);
+#define myDbgPrint_TIM(x...) do { } while(0);
+#define myDbgPrint_BLK(x...) do { } while(0);
+#define myDbgPrint_TAPI(x...) do { } while(0);
+#define myDbgPrint_NDIS(x...) do { } while(0);
+#define myDbgPrint_CONN(x...) do { } while(0);
+#define myDbgPrint_STAT(x...) do { } while(0);
+#define myDbgPrint_SEND(x...) do { } while(0);
+#define myDbgPrint_RECV(x...) do { } while(0);
+#define myDbgPrint_PRV0(x...) do { } while(0);
+#define myDbgPrint_PRV1(x...) do { } while(0);
+#define myDbgPrint_PRV2(x...) do { } while(0);
+#define myDbgPrint_PRV3(x...) do { } while(0);
+#define DBG_TEST(func,args) do { } while(0);
+#define DBG_EVL_ID(args) do { } while(0);
+
+#else /* DIVA_NO_DEBUGLIB */
+/*
+ * define low level macros for formatted & raw debugging
+ */
+#define DBG_DECL(func) extern void  myDbgPrint_##func (char *, ...) ;
+DBG_DECL(LOG)
+DBG_DECL(FTL)
+DBG_DECL(ERR)
+DBG_DECL(TRC)
+DBG_DECL(MXLOG)
+DBG_DECL(FTL_MXLOG)
+extern void  myDbgPrint_EVL (long, ...) ;
+DBG_DECL(REG)
+DBG_DECL(MEM)
+DBG_DECL(SPL)
+DBG_DECL(IRP)
+DBG_DECL(TIM)
+DBG_DECL(BLK)
+DBG_DECL(TAPI)
+DBG_DECL(NDIS)
+DBG_DECL(CONN)
+DBG_DECL(STAT)
+DBG_DECL(SEND)
+DBG_DECL(RECV)
+DBG_DECL(PRV0)
+DBG_DECL(PRV1)
+DBG_DECL(PRV2)
+DBG_DECL(PRV3)
+#ifdef  _KERNEL_DBG_PRINT_
+/*
+ * tracing to maint and kernel if selected in the trace mask.
+ */
+#define DBG_TEST(func,args) \
+{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_##func ) \
+ { \
+        if ( (myDriverDebugHandle.dbgMask) & DL_TO_KERNEL ) \
+            {DbgPrint args; DbgPrint ("\r\n");} \
+        myDbgPrint_##func args ; \
+} }
+#else
+/*
+ * Standard tracing to maint driver.
+ */
+#define DBG_TEST(func,args) \
+{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_##func ) \
+ { myDbgPrint_##func args ; \
+} }
+#endif
+/*
+ * For event level debug use a separate define, the paramete are
+ * different and cause compiler errors on some systems.
+ */
+#define DBG_EVL_ID(args) \
+{ if ( (myDriverDebugHandle.dbgMask) & (unsigned long)DL_EVL ) \
+ { myDbgPrint_EVL args ; \
+} }
+
+#endif /* DIVA_NO_DEBUGLIB */
+
+#define DBG_LOG(args)  DBG_TEST(LOG, args)
+#define DBG_FTL(args)  DBG_TEST(FTL, args)
+#define DBG_ERR(args)  DBG_TEST(ERR, args)
+#define DBG_TRC(args)  DBG_TEST(TRC, args)
+#define DBG_MXLOG(args)  DBG_TEST(MXLOG, args)
+#define DBG_FTL_MXLOG(args) DBG_TEST(FTL_MXLOG, args)
+#define DBG_EVL(args)  DBG_EVL_ID(args)
+#define DBG_REG(args)  DBG_TEST(REG, args)
+#define DBG_MEM(args)  DBG_TEST(MEM, args)
+#define DBG_SPL(args)  DBG_TEST(SPL, args)
+#define DBG_IRP(args)  DBG_TEST(IRP, args)
+#define DBG_TIM(args)  DBG_TEST(TIM, args)
+#define DBG_BLK(args)  DBG_TEST(BLK, args)
+#define DBG_TAPI(args)  DBG_TEST(TAPI, args)
+#define DBG_NDIS(args)  DBG_TEST(NDIS, args)
+#define DBG_CONN(args)  DBG_TEST(CONN, args)
+#define DBG_STAT(args)  DBG_TEST(STAT, args)
+#define DBG_SEND(args)  DBG_TEST(SEND, args)
+#define DBG_RECV(args)  DBG_TEST(RECV, args)
+#define DBG_PRV0(args)  DBG_TEST(PRV0, args)
+#define DBG_PRV1(args)  DBG_TEST(PRV1, args)
+#define DBG_PRV2(args)  DBG_TEST(PRV2, args)
+#define DBG_PRV3(args)  DBG_TEST(PRV3, args)
+/*
+ * prototypes for debug register/deregister functions in "debuglib.c"
+ */
+#ifdef DIVA_NO_DEBUGLIB
+#define DbgRegister(name,tag, mask) do { } while(0)
+#define DbgDeregister() do { } while(0)
+#define DbgSetLevel(mask) do { } while(0)
+#else
+extern DIVA_DI_PRINTF dprintf;
+extern int  DbgRegister (char *drvName, char *drvTag, unsigned long dbgMask) ;
+extern void DbgDeregister (void) ;
+extern void DbgSetLevel (unsigned long dbgMask) ;
+#endif
+/*
+ * driver internal structure for debug handling;
+ * in client drivers this structure is maintained in "debuglib.c",
+ * in the debug driver "debug.c" maintains a chain of such structs.
+ */
+typedef struct _DbgHandle_ *pDbgHandle ;
+typedef void ( * DbgEnd) (pDbgHandle) ;
+typedef void ( * DbgLog) (unsigned short, int, char *, va_list) ;
+typedef void ( * DbgOld) (unsigned short, char *, va_list) ;
+typedef void ( * DbgEv)  (unsigned short, unsigned long, va_list) ;
+typedef void ( * DbgIrq) (unsigned short, int, char *, va_list) ;
+typedef struct _DbgHandle_
+{ char    Registered ; /* driver successfull registered */
+#define DBG_HANDLE_REG_NEW 0x01  /* this (new) structure    */
+#define DBG_HANDLE_REG_OLD 0x7f  /* old structure (see below)  */
+ char    Version;  /* version of this structure  */
+#define DBG_HANDLE_VERSION 1   /* contains dbg_old function now */
+#define DBG_HANDLE_VER_EXT  2           /* pReserved points to extended info*/
+ short               id ;   /* internal id of registered driver */
+  struct _DbgHandle_ *next ;   /* ptr to next registered driver    */
+ struct /*LARGE_INTEGER*/ {
+  unsigned long LowPart;
+  long          HighPart;
+ }     regTime ;  /* timestamp for registration       */
+ void               *pIrp ;   /* ptr to pending i/o request       */
+ unsigned long       dbgMask ;  /* current debug mask               */
+ char                drvName[16] ; /* ASCII name of registered driver  */
+ char                drvTag[64] ; /* revision string     */
+ DbgEnd              dbg_end ;  /* function for debug closing       */
+ DbgLog              dbg_prt ;  /* function for debug appending     */
+ DbgOld              dbg_old ;  /* function for old debug appending */
+ DbgEv       dbg_ev ;  /* function for Windows NT Eventlog */
+ DbgIrq    dbg_irq ;  /* function for irql checked debug  */
+ void      *pReserved3 ;
+} _DbgHandle_ ;
+extern _DbgHandle_ myDriverDebugHandle ;
+typedef struct _OldDbgHandle_
+{ struct _OldDbgHandle_ *next ;
+ void                *pIrp ;
+ long    regTime[2] ;
+ unsigned long       dbgMask ;
+ short               id ;
+ char                drvName[78] ;
+ DbgEnd              dbg_end ;
+ DbgLog              dbg_prt ;
+} _OldDbgHandle_ ;
+/* the differences in DbgHandles
+   old:    tmp:     new:
+ 0 long next  char Registered  char Registered
+       char filler   char Version
+       short id    short id
+ 4 long pIrp  long    regTime.lo  long next
+ 8 long    regTime.lo long    regTime.hi  long    regTime.lo
+ 12 long    regTime.hi long next   long regTime.hi
+ 16 long dbgMask  long pIrp   long pIrp
+ 20 short id   long dbgMask   long dbgMask
+ 22 char    drvName[78] ..
+ 24 ..     char drvName[16]  char drvName[16]
+ 40 ..     char drvTag[64]  char drvTag[64]
+ 100 void *dbg_end ..      ..
+ 104 void *dbg_prt void *dbg_end  void *dbg_end
+ 108 ..     void *dbg_prt  void *dbg_prt
+ 112 ..     ..      void *dbg_old
+ 116 ..     ..      void *dbg_ev
+ 120 ..     ..      void *dbg_irq
+ 124 ..     ..      void *pReserved3
+ ( new->id == 0 && *((short *)&new->dbgMask) == -1 ) identifies "old",
+ new->Registered and new->Version overlay old->next,
+ new->next overlays old->pIrp, new->regTime matches old->regTime and
+ thus these fields can be maintained in new struct whithout trouble;
+ id, dbgMask, drvName, dbg_end and dbg_prt need special handling !
+*/
+#define DBG_EXT_TYPE_CARD_TRACE     0x00000001
+typedef struct
+{
+    unsigned long       ExtendedType;
+    union
+    {
+        /* DBG_EXT_TYPE_CARD_TRACE */
+        struct
+        {
+            void ( * MaskChangedNotify) (void *pContext);
+            unsigned long   ModuleTxtMask;
+            unsigned long   DebugLevel;
+            unsigned long   B_ChannelMask;
+            unsigned long   LogBufferSize;
+        } CardTrace;
+    }Data;     
+} _DbgExtendedInfo_;
+#ifndef DIVA_NO_DEBUGLIB
+/* -------------------------------------------------------------
+    Function used for xlog-style debug
+   ------------------------------------------------------------- */
+#define XDI_USE_XLOG 1
+void  xdi_dbg_xlog (char* x, ...);
+#endif /* DIVA_NO_DEBUGLIB */
+#endif /* __DEBUGLIB_H__ */
diff --git a/drivers/isdn/hardware/eicon/dfifo.h b/drivers/isdn/hardware/eicon/dfifo.h
new file mode 100644
index 0000000..9a109c7
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dfifo.h
@@ -0,0 +1,54 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_IDI_DFIFO_INC__
+#define __DIVA_IDI_DFIFO_INC__
+#define DIVA_DFIFO_CACHE_SZ   64 /* Used to isolate pipe from
+                    rest of the world
+                   should be divisible by 4
+                   */
+#define DIVA_DFIFO_RAW_SZ    (2512*8)
+#define DIVA_DFIFO_DATA_SZ   68
+#define DIVA_DFIFO_HDR_SZ    4
+#define DIVA_DFIFO_SEGMENT_SZ  (DIVA_DFIFO_DATA_SZ+DIVA_DFIFO_HDR_SZ)
+#define DIVA_DFIFO_SEGMENTS   ((DIVA_DFIFO_RAW_SZ)/(DIVA_DFIFO_SEGMENT_SZ)+1)
+#define DIVA_DFIFO_MEM_SZ (\
+        (DIVA_DFIFO_SEGMENT_SZ)*(DIVA_DFIFO_SEGMENTS)+\
+        (DIVA_DFIFO_CACHE_SZ)*2\
+             )
+#define DIVA_DFIFO_STEP DIVA_DFIFO_SEGMENT_SZ
+/* -------------------------------------------------------------------------
+  Block header layout is:
+   byte[0] -> flags
+   byte[1] -> length of data in block
+   byte[2] -> reserved
+   byte[4] -> reserved
+  ------------------------------------------------------------------------- */
+#define DIVA_DFIFO_WRAP   0x80 /* This is the last block in fifo   */
+#define DIVA_DFIFO_READY  0x40 /* This block is ready for processing */
+#define DIVA_DFIFO_LAST   0x20 /* This block is last in message      */
+#define DIVA_DFIFO_AUTO   0x10 /* Don't look for 'ready', don't ack */
+int diva_dfifo_create (void* start, int length);
+#endif
diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c
new file mode 100644
index 0000000..0617d7c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/di.c
@@ -0,0 +1,835 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "di.h"
+#if !defined USE_EXTENDED_DEBUGS
+  #include "dimaint.h"
+#else
+  #define dprintf
+#endif
+#include "io.h"
+#include "dfifo.h"
+#define PR_RAM  ((struct pr_ram *)0)
+#define RAM ((struct dual *)0)
+/*------------------------------------------------------------------*/
+/* local function prototypes                                        */
+/*------------------------------------------------------------------*/
+void pr_out(ADAPTER * a);
+byte pr_dpc(ADAPTER * a);
+static byte pr_ready(ADAPTER * a);
+static byte isdn_rc(ADAPTER *, byte, byte, byte, word, dword, dword);
+static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
+/* -----------------------------------------------------------------
+    Functions used for the extended XDI Debug
+    macros
+    global convergence counter (used by all adapters)
+    Look by the implementation part of the functions
+    about the parameters.
+    If you change the dubugging parameters, then you should update
+    the aididbg.doc in the IDI doc's.
+   ----------------------------------------------------------------- */
+#if defined(XDI_USE_XLOG)
+#define XDI_A_NR(_x_) ((byte)(((ISDN_ADAPTER *)(_x_->io))->ANum))
+static void xdi_xlog (byte *msg, word code, int length);
+static byte xdi_xlog_sec = 0;
+#else
+#define XDI_A_NR(_x_) ((byte)0)
+#endif
+static void xdi_xlog_rc_event (byte Adapter,
+                               byte Id, byte Ch, byte Rc, byte cb, byte type);
+static void xdi_xlog_request (byte Adapter, byte Id,
+                              byte Ch, byte Req, byte type);
+static void xdi_xlog_ind (byte Adapter,
+                          byte Id,
+                          byte Ch,
+                          byte Ind,
+                          byte rnr_valid,
+                          byte rnr,
+                          byte type);
+/*------------------------------------------------------------------*/
+/* output function                                                  */
+/*------------------------------------------------------------------*/
+void pr_out(ADAPTER * a)
+{
+  byte e_no;
+  ENTITY  * this = NULL;
+  BUFFERS  *X;
+  word length;
+  word i;
+  word clength;
+  REQ * ReqOut;
+  byte more;
+  byte ReadyCount;
+  byte ReqCount;
+  byte Id;
+  dtrc(dprintf("pr_out"));
+        /* while a request is pending ...                           */
+  e_no = look_req(a);
+  if(!e_no)
+  {
+    dtrc(dprintf("no_req"));
+    return;
+  }
+  ReadyCount = pr_ready(a);
+  if(!ReadyCount)
+  {
+    dtrc(dprintf("not_ready"));
+    return;
+  }
+  ReqCount = 0;
+  while(e_no && ReadyCount) {
+    next_req(a);
+    this = entity_ptr(a, e_no);
+#ifdef USE_EXTENDED_DEBUGS
+    if ( !this )
+    {
+      DBG_FTL(("XDI: [%02x] !A%d ==> NULL entity ptr - try to ignore",
+               xdi_xlog_sec++, (int)((ISDN_ADAPTER *)a->io)->ANum))
+      e_no = look_req(a) ;
+      ReadyCount-- ;
+      continue ;
+    }
+    {
+      DBG_TRC((">A%d Id=0x%x Req=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, this->Id, this->Req))
+    }
+#else
+    dbug(dprintf("out:Req=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
+#endif
+        /* get address of next available request buffer             */
+    ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
+#if defined(DIVA_ISTREAM)
+    if (!(a->tx_stream[this->Id]   &&
+        this->Req == N_DATA)) {
+#endif
+        /* now copy the data from the current data buffer into the  */
+        /* adapters request buffer                                  */
+    length = 0;
+    i = this->XCurrent;
+    X = PTR_X(a,this);
+    while(i<this->XNum && length<270) {
+      clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+      a->ram_out_buffer(a,
+                        &ReqOut->XBuffer.P[length],
+                        PTR_P(a,this,&X[i].P[this->XOffset]),
+                        clength);
+      length +=clength;
+      this->XOffset +=clength;
+      if(this->XOffset==X[i].PLength) {
+        this->XCurrent = (byte)++i;
+        this->XOffset = 0;
+      }
+    }
+#if defined(DIVA_ISTREAM)
+   } else { /* Use CMA extension in order to transfer data to the card */
+      i = this->XCurrent;
+      X = PTR_X(a,this);
+      while (i < this->XNum) {
+        diva_istream_write (a,
+                            this->Id,
+                            PTR_P(a,this,&X[i].P[0]),
+                            X[i].PLength,
+                            ((i+1) == this->XNum),
+                            0, 0);
+        this->XCurrent = (byte)++i;
+      }
+      length = 0;
+   }
+#endif
+    a->ram_outw(a, &ReqOut->XBuffer.length, length);
+    a->ram_out(a, &ReqOut->ReqId, this->Id);
+    a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
+        /* if it's a specific request (no ASSIGN) ...                */
+    if(this->Id &0x1f) {
+        /* if buffers are left in the list of data buffers do       */
+        /* do chaining (LL_MDATA, N_MDATA)                          */
+      this->More++;
+      if(i<this->XNum && this->MInd) {
+        xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->MInd,
+                          a->IdTypeTable[this->No]);
+        a->ram_out(a, &ReqOut->Req, this->MInd);
+        more = TRUE;
+      }
+      else {
+        xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->Req,
+                          a->IdTypeTable[this->No]);
+        this->More |=XMOREF;
+        a->ram_out(a, &ReqOut->Req, this->Req);
+        more = FALSE;
+        if (a->FlowControlIdTable[this->ReqCh] == this->Id)
+          a->FlowControlSkipTable[this->ReqCh] = TRUE;
+        /*
+           Note that remove request was sent to the card
+           */
+        if (this->Req == REMOVE) {
+          a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_REMOVE_PENDING;
+        }
+      }
+        /* if we did chaining, this entity is put back into the     */
+        /* request queue                                            */
+      if(more) {
+        req_queue(a,this->No);
+      }
+    }
+        /* else it's a ASSIGN                                       */
+    else {
+        /* save the request code used for buffer chaining           */
+      this->MInd = 0;
+      if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
+      if (this->Id==NL_ID   ||
+          this->Id==TASK_ID ||
+          this->Id==MAN_ID
+        ) this->MInd = N_MDATA;
+        /* send the ASSIGN                                          */
+      a->IdTypeTable[this->No] = this->Id;
+      xdi_xlog_request (XDI_A_NR(a),this->Id,this->ReqCh,this->Req, this->Id);
+      this->More |=XMOREF;
+      a->ram_out(a, &ReqOut->Req, this->Req);
+        /* save the reference of the ASSIGN                         */
+      assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
+    }
+    a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
+    ReadyCount--;
+    ReqCount++;
+    e_no = look_req(a);
+  }
+        /* send the filled request buffers to the ISDN adapter      */
+  a->ram_out(a, &PR_RAM->ReqInput,
+             (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
+        /* if it is a 'unreturncoded' UREMOVE request, remove the  */
+        /* Id from our table after sending the request             */
+  if(this && (this->Req==UREMOVE) && this->Id) {
+    Id = this->Id;
+    e_no = a->IdTable[Id];
+    free_entity(a, e_no);
+    for (i = 0; i < 256; i++)
+    {
+      if (a->FlowControlIdTable[i] == Id)
+        a->FlowControlIdTable[i] = 0;
+    }
+    a->IdTable[Id] = 0;
+    this->Id = 0;
+  }
+}
+static byte pr_ready(ADAPTER * a)
+{
+  byte ReadyCount;
+  ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
+                      a->ram_in(a, &PR_RAM->ReqInput));
+  if(!ReadyCount) {
+    if(!a->ReadyInt) {
+      a->ram_inc(a, &PR_RAM->ReadyInt);
+      a->ReadyInt++;
+    }
+  }
+  return ReadyCount;
+}
+/*------------------------------------------------------------------*/
+/* isdn interrupt handler                                           */
+/*------------------------------------------------------------------*/
+byte pr_dpc(ADAPTER * a)
+{
+  byte Count;
+  RC * RcIn;
+  IND * IndIn;
+  byte c;
+  byte RNRId;
+  byte Rc;
+  byte Ind;
+        /* if return codes are available ...                        */
+  if((Count = a->ram_in(a, &PR_RAM->RcOutput)) != 0) {
+    dtrc(dprintf("#Rc=%x",Count));
+        /* get the buffer address of the first return code          */
+    RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
+        /* for all return codes do ...                              */
+    while(Count--) {
+      if((Rc=a->ram_in(a, &RcIn->Rc)) != 0) {
+        dword tmp[2];
+        /*
+          Get extended information, associated with return code
+          */
+        a->ram_in_buffer(a,
+                         &RcIn->Reserved2[0],
+                         (byte*)&tmp[0],
+                         8);
+        /* call return code handler, if it is not our return code   */
+        /* the handler returns 2                                    */
+        /* for all return codes we process, we clear the Rc field   */
+        isdn_rc(a,
+                Rc,
+                a->ram_in(a, &RcIn->RcId),
+                a->ram_in(a, &RcIn->RcCh),
+                a->ram_inw(a, &RcIn->Reference),
+                tmp[0],  /* type of extended informtion */
+                tmp[1]); /* extended information        */
+        a->ram_out(a, &RcIn->Rc, 0);
+      }
+        /* get buffer address of next return code                   */
+      RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
+    }
+        /* clear all return codes (no chaining!)                    */
+    a->ram_out(a, &PR_RAM->RcOutput ,0);
+        /* call output function                                     */
+    pr_out(a);
+  }
+        /* clear RNR flag                                           */
+  RNRId = 0;
+        /* if indications are available ...                         */
+  if((Count = a->ram_in(a, &PR_RAM->IndOutput)) != 0) {
+    dtrc(dprintf("#Ind=%x",Count));
+        /* get the buffer address of the first indication           */
+    IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
+        /* for all indications do ...                               */
+    while(Count--) {
+        /* if the application marks an indication as RNR, all       */
+        /* indications from the same Id delivered in this interrupt */
+        /* are marked RNR                                           */
+      if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
+        a->ram_out(a, &IndIn->Ind, 0);
+        a->ram_out(a, &IndIn->RNR, TRUE);
+      }
+      else {
+        Ind = a->ram_in(a, &IndIn->Ind);
+        if(Ind) {
+          RNRId = 0;
+        /* call indication handler, a return value of 2 means chain */
+        /* a return value of 1 means RNR                            */
+        /* for all indications we process, we clear the Ind field   */
+          c = isdn_ind(a,
+                       Ind,
+                       a->ram_in(a, &IndIn->IndId),
+                       a->ram_in(a, &IndIn->IndCh),
+                       &IndIn->RBuffer,
+                       a->ram_in(a, &IndIn->MInd),
+                       a->ram_inw(a, &IndIn->MLength));
+          if(c==1) {
+            dtrc(dprintf("RNR"));
+            a->ram_out(a, &IndIn->Ind, 0);
+            RNRId = a->ram_in(a, &IndIn->IndId);
+            a->ram_out(a, &IndIn->RNR, TRUE);
+          }
+        }
+      }
+        /* get buffer address of next indication                    */
+      IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
+    }
+    a->ram_out(a, &PR_RAM->IndOutput, 0);
+  }
+  return FALSE;
+}
+byte scom_test_int(ADAPTER * a)
+{
+  return a->ram_in(a,(void *)0x3fe);
+}
+void scom_clear_int(ADAPTER * a)
+{
+  a->ram_out(a,(void *)0x3fe,0);
+}
+/*------------------------------------------------------------------*/
+/* return code handler                                              */
+/*------------------------------------------------------------------*/
+byte isdn_rc(ADAPTER * a,
+             byte Rc,
+             byte Id,
+             byte Ch,
+             word Ref,
+             dword extended_info_type,
+             dword extended_info)
+{
+  ENTITY  * this;
+  byte e_no;
+  word i;
+  int cancel_rc;
+#ifdef USE_EXTENDED_DEBUGS
+  {
+    DBG_TRC(("<A%d Id=0x%x Rc=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Rc))
+  }
+#else
+  dbug(dprintf("isdn_rc(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
+#endif
+        /* check for ready interrupt                                */
+  if(Rc==READY_INT) {
+    xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, 0);
+    if(a->ReadyInt) {
+      a->ReadyInt--;
+      return 0;
+    }
+    return 2;
+  }
+        /* if we know this Id ...                                   */
+  e_no = a->IdTable[Id];
+  if(e_no) {
+    this = entity_ptr(a,e_no);
+    xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, a->IdTypeTable[this->No]);
+    this->RcCh = Ch;
+        /* if it is a return code to a REMOVE request, remove the   */
+        /* Id from our table                                        */
+    if ((a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_REMOVE_PENDING) &&
+        (Rc==OK)) {
+      if (a->IdTypeTable[e_no] == NL_ID) {
+        if (a->RcExtensionSupported &&
+            (extended_info_type != DIVA_RC_TYPE_REMOVE_COMPLETE)) {
+        dtrc(dprintf("XDI: N-REMOVE, A(%02x) Id:%02x, ignore RC=OK",
+                        XDI_A_NR(a),Id));
+          return (0);
+        }
+        if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE)
+          a->RcExtensionSupported = TRUE;
+      }
+      a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING;
+      a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING;
+      free_entity(a, e_no);
+      for (i = 0; i < 256; i++)
+      {
+        if (a->FlowControlIdTable[i] == Id)
+          a->FlowControlIdTable[i] = 0;
+      }
+      a->IdTable[Id] = 0;
+      this->Id = 0;
+      /* ---------------------------------------------------------------
+        If we send N_DISC or N_DISK_ACK after we have received OK_FC
+        then the card will respond with OK_FC and later with RC==OK.
+        If we send N_REMOVE in this state we will receive only RC==OK
+        This will create the state in that the XDI is waiting for the
+        additional RC and does not delivery the RC to the client. This
+        code corrects the counter of outstanding RC's in this case.
+      --------------------------------------------------------------- */
+      if ((this->More & XMOREC) > 1) {
+        this->More &= ~XMOREC;
+        this->More |= 1;
+        dtrc(dprintf("XDI: correct MORE on REMOVE A(%02x) Id:%02x",
+                     XDI_A_NR(a),Id));
+      }
+    }
+    if (Rc==OK_FC) {
+      a->FlowControlIdTable[Ch] = Id;
+      a->FlowControlSkipTable[Ch] = FALSE;
+      this->Rc = Rc;
+      this->More &= ~(XBUSY | XMOREC);
+      this->complete=0xff;
+      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
+      CALLBACK(a, this);
+      return 0;
+    }
+    /*
+      New protocol code sends return codes that comes from release
+      of flow control condition marked with DIVA_RC_TYPE_OK_FC extended
+      information element type.
+      If like return code arrives then application is able to process
+      all return codes self and XDI should not cances return codes.
+      This return code does not decrement XMOREC partial return code
+      counter due to fact that it was no request for this return code,
+      also XMOREC was not incremented.
+      */
+    if (extended_info_type == DIVA_RC_TYPE_OK_FC) {
+      a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_NO_RC_CANCELLING;
+      this->Rc = Rc;
+      this->complete=0xff;
+      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
+      DBG_TRC(("XDI OK_FC A(%02x) Id:%02x Ch:%02x Rc:%02x",
+      XDI_A_NR(a), Id, Ch, Rc))
+      CALLBACK(a, this);
+      return 0;
+    }
+    cancel_rc = !(a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_NO_RC_CANCELLING);
+    if (cancel_rc && (a->FlowControlIdTable[Ch] == Id))
+    {
+      a->FlowControlIdTable[Ch] = 0;
+      if ((Rc != OK) || !a->FlowControlSkipTable[Ch])
+      {
+        this->Rc = Rc;
+        if (Ch == this->ReqCh)
+        {
+          this->More &=~(XBUSY | XMOREC);
+          this->complete=0xff;
+        }
+        xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
+        CALLBACK(a, this);
+      }
+      return 0;
+    }
+    if (this->More &XMOREC)
+      this->More--;
+        /* call the application callback function                   */
+    if (((!cancel_rc) || (this->More & XMOREF)) && !(this->More & XMOREC)) {
+      this->Rc = Rc;
+      this->More &=~XBUSY;
+      this->complete=0xff;
+      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
+      CALLBACK(a, this);
+    }
+    return 0;
+  }
+        /* if it's an ASSIGN return code check if it's a return     */
+        /* code to an ASSIGN request from us                        */
+  if((Rc &0xf0)==ASSIGN_RC) {
+    e_no = get_assign(a, Ref);
+    if(e_no) {
+      this = entity_ptr(a,e_no);
+      this->Id = Id;
+      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 2, a->IdTypeTable[this->No]);
+        /* call the application callback function                   */
+      this->Rc = Rc;
+      this->More &=~XBUSY;
+      this->complete=0xff;
+#if defined(DIVA_ISTREAM) /* { */
+      if ((Rc == ASSIGN_OK) && a->ram_offset &&
+          (a->IdTypeTable[this->No] == NL_ID) &&
+          ((extended_info_type == DIVA_RC_TYPE_RX_DMA) ||
+          (extended_info_type == DIVA_RC_TYPE_CMA_PTR)) &&
+          extended_info) {
+        dword offset = (*(a->ram_offset)) (a);
+        dword tmp[2];
+        extended_info -= offset;
+#ifdef PLATFORM_GT_32BIT
+        a->ram_in_dw(a, (void*)ULongToPtr(extended_info), (dword*)&tmp[0], 2);
+#else
+        a->ram_in_dw(a, (void*)extended_info, (dword*)&tmp[0], 2);
+#endif
+        a->tx_stream[Id]  = tmp[0];
+        a->rx_stream[Id]  = tmp[1];
+        if (extended_info_type == DIVA_RC_TYPE_RX_DMA) {
+          DBG_TRC(("Id=0x%x RxDMA=%08x:%08x",
+                    Id, a->tx_stream[Id], a->rx_stream[Id]))
+          a->misc_flags_table[this->No] |= DIVA_MISC_FLAGS_RX_DMA;
+        } else {
+          DBG_TRC(("Id=0x%x CMA=%08x:%08x",
+                    Id, a->tx_stream[Id], a->rx_stream[Id]))
+          a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
+          a->rx_pos[Id]     = 0;
+          a->rx_stream[Id] -= offset;
+        }
+        a->tx_pos[Id]     = 0;
+        a->tx_stream[Id] -= offset;
+      } else {
+        a->tx_stream[Id] = 0;
+        a->rx_stream[Id] = 0;
+        a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
+      }
+#endif /* } */
+      CALLBACK(a, this);
+      if(Rc==ASSIGN_OK) {
+        a->IdTable[Id] = e_no;
+      }
+      else
+      {
+        free_entity(a, e_no);
+        for (i = 0; i < 256; i++)
+        {
+          if (a->FlowControlIdTable[i] == Id)
+            a->FlowControlIdTable[i] = 0;
+        }
+        a->IdTable[Id] = 0;
+        this->Id = 0;
+      }
+      return 1;
+    }
+  }
+  return 2;
+}
+/*------------------------------------------------------------------*/
+/* indication handler                                               */
+/*------------------------------------------------------------------*/
+byte isdn_ind(ADAPTER * a,
+              byte Ind,
+              byte Id,
+              byte Ch,
+              PBUFFER * RBuffer,
+              byte MInd,
+              word MLength)
+{
+  ENTITY  * this;
+  word clength;
+  word offset;
+  BUFFERS  *R;
+  byte* cma = NULL;
+#ifdef USE_EXTENDED_DEBUGS
+  {
+    DBG_TRC(("<A%d Id=0x%x Ind=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Ind))
+  }
+#else
+  dbug(dprintf("isdn_ind(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
+#endif
+  if(a->IdTable[Id]) {
+    this = entity_ptr(a,a->IdTable[Id]);
+    this->IndCh = Ch;
+    xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
+                  0/* rnr_valid */, 0 /* rnr */, a->IdTypeTable[this->No]);
+        /* if the Receive More flag is not yet set, this is the     */
+        /* first buffer of the packet                               */
+    if(this->RCurrent==0xff) {
+        /* check for receive buffer chaining                        */
+      if(Ind==this->MInd) {
+        this->complete = 0;
+        this->Ind = MInd;
+      }
+      else {
+        this->complete = 1;
+        this->Ind = Ind;
+      }
+        /* call the application callback function for the receive   */
+        /* look ahead                                               */
+      this->RLength = MLength;
+#if defined(DIVA_ISTREAM)
+      if ((a->rx_stream[this->Id] ||
+           (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA)) &&
+          ((Ind == N_DATA) ||
+           (a->protocol_capabilities & PROTCAP_CMA_ALLPR))) {
+        PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ;
+        if (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA) {
+#if defined(DIVA_IDI_RX_DMA)
+          dword d;
+          diva_get_dma_map_entry (\
+                   (struct _diva_dma_map_entry*)IoAdapter->dma_map,
+                   (int)a->rx_stream[this->Id], (void**)&cma, &d);
+#else
+          cma = &a->stream_buffer[0];
+          cma[0] = cma[1] = cma[2] = cma[3] = 0;
+#endif
+          this->RLength = MLength = (word)*(dword*)cma;
+          cma += 4;
+        } else {
+        int final = 0;
+        cma = &a->stream_buffer[0];
+        this->RLength = MLength = (word)diva_istream_read (a,
+                                                     Id,
+                                                     cma,
+                                                     sizeof(a->stream_buffer),
+                                                     &final, NULL, NULL);
+        }
+        IoAdapter->RBuffer.length = MIN(MLength, 270);
+        if (IoAdapter->RBuffer.length != MLength) {
+          this->complete = 0;
+        } else {
+          this->complete = 1;
+        }
+        memcpy (IoAdapter->RBuffer.P, cma, IoAdapter->RBuffer.length) ;
+        this->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ;
+      }
+#endif
+      if (!cma) {
+        a->ram_look_ahead(a, RBuffer, this);
+      }
+      this->RNum = 0;
+      CALLBACK(a, this);
+        /* map entity ptr, selector could be re-mapped by call to   */
+        /* IDI from within callback                                 */
+      this = entity_ptr(a,a->IdTable[Id]);
+      xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
+          1/* rnr_valid */, this->RNR/* rnr */, a->IdTypeTable[this->No]);
+        /* check for RNR                                            */
+      if(this->RNR==1) {
+        this->RNR = 0;
+        return 1;
+      }
+        /* if no buffers are provided by the application, the       */
+        /* application want to copy the data itself including       */
+        /* N_MDATA/LL_MDATA chaining                                */
+      if(!this->RNR && !this->RNum) {
+        xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
+            2/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
+        return 0;
+      }
+        /* if there is no RNR, set the More flag                    */
+      this->RCurrent = 0;
+      this->ROffset = 0;
+    }
+    if(this->RNR==2) {
+      if(Ind!=this->MInd) {
+        this->RCurrent = 0xff;
+        this->RNR = 0;
+      }
+      return 0;
+    }
+        /* if we have received buffers from the application, copy   */
+        /* the data into these buffers                              */
+    offset = 0;
+    R = PTR_R(a,this);
+    do {
+      if(this->ROffset==R[this->RCurrent].PLength) {
+        this->ROffset = 0;
+        this->RCurrent++;
+      }
+      if (cma) {
+        clength = MIN(MLength, R[this->RCurrent].PLength-this->ROffset);
+      } else {
+        clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
+                      R[this->RCurrent].PLength-this->ROffset);
+      }
+      if(R[this->RCurrent].P) {
+        if (cma) {
+          memcpy (PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
+                  &cma[offset],
+                  clength);
+        } else {
+          a->ram_in_buffer(a,
+                           &RBuffer->P[offset],
+                           PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
+                           clength);
+        }
+      }
+      offset +=clength;
+      this->ROffset +=clength;
+      if (cma) {
+        if (offset >= MLength) {
+          break;
+        }
+        continue;
+      }
+    } while(offset<(a->ram_inw(a, &RBuffer->length)));
+        /* if it's the last buffer of the packet, call the          */
+        /* application callback function for the receive complete   */
+        /* call                                                     */
+    if(Ind!=this->MInd) {
+      R[this->RCurrent].PLength = this->ROffset;
+      if(this->ROffset) this->RCurrent++;
+      this->RNum = this->RCurrent;
+      this->RCurrent = 0xff;
+      this->Ind = Ind;
+      this->complete = 2;
+      xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
+          3/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
+      CALLBACK(a, this);
+    }
+    return 0;
+  }
+  return 2;
+}
+#if defined(XDI_USE_XLOG)
+/* -----------------------------------------------------------
+   This function works in the same way as xlog on the
+   active board
+   ----------------------------------------------------------- */
+static void xdi_xlog (byte *msg, word code, int length) {
+  xdi_dbg_xlog ("\x00\x02", msg, code, length);
+}
+#endif
+/* -----------------------------------------------------------
+    This function writes the information about the Return Code
+    processing in the trace buffer. Trace ID is 221.
+    INPUT:
+        Adapter - system unicue adapter number (0 ... 255)
+        Id      - Id of the entity that had sent this return code
+        Ch      - Channel of the entity that had sent this return code
+        Rc      - return code value
+        cb:       (0...2)
+                  switch (cb) {
+                   case 0: printf ("DELIVERY"); break;
+                   case 1: printf ("CALLBACK"); break;
+                   case 2: printf ("ASSIGN"); break;
+                  }
+                  DELIVERY - have entered isdn_rc with this RC
+                  CALLBACK - about to make callback to the application
+                             for this RC
+                  ASSIGN   - about to make callback for RC that is result
+                             of ASSIGN request. It is no DELIVERY message
+                             before of this message
+        type   - the Id that was sent by the ASSIGN of this entity.
+                 This should be global Id like NL_ID, DSIG_ID, MAN_ID.
+                 An unknown Id will cause "?-" in the front of the request.
+                 In this case the log.c is to be extended.
+   ----------------------------------------------------------- */
+static void xdi_xlog_rc_event (byte Adapter,
+                               byte Id, byte Ch, byte Rc, byte cb, byte type) {
+#if defined(XDI_USE_XLOG)
+  word LogInfo[4];
+  PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
+  PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
+  PUT_WORD(&LogInfo[2], ((word)Rc | (word)(type << 8)));
+  PUT_WORD(&LogInfo[3], cb);
+  xdi_xlog ((byte*)&LogInfo[0], 221, sizeof(LogInfo));
+#endif
+}
+/* ------------------------------------------------------------------------
+    This function writes the information about the request processing
+    in the trace buffer. Trace ID is 220.
+    INPUT:
+        Adapter - system unicue adapter number (0 ... 255)
+        Id      - Id of the entity that had sent this request
+        Ch      - Channel of the entity that had sent this request
+        Req     - Code of the request
+        type    - the Id that was sent by the ASSIGN of this entity.
+                  This should be global Id like NL_ID, DSIG_ID, MAN_ID.
+                  An unknown Id will cause "?-" in the front of the request.
+                  In this case the log.c is to be extended.
+   ------------------------------------------------------------------------ */
+static void xdi_xlog_request (byte Adapter, byte Id,
+                              byte Ch, byte Req, byte type) {
+#if defined(XDI_USE_XLOG)
+  word LogInfo[3];
+  PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
+  PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
+  PUT_WORD(&LogInfo[2], ((word)Req | (word)(type << 8)));
+  xdi_xlog ((byte*)&LogInfo[0], 220, sizeof(LogInfo));
+#endif
+}
+/* ------------------------------------------------------------------------
+    This function writes the information about the indication processing
+    in the trace buffer. Trace ID is 222.
+    INPUT:
+        Adapter - system unicue adapter number (0 ... 255)
+        Id      - Id of the entity that had sent this indication
+        Ch      - Channel of the entity that had sent this indication
+        Ind     - Code of the indication
+        rnr_valid: (0 .. 3) supported
+          switch (rnr_valid) {
+            case 0: printf ("DELIVERY"); break;
+            case 1: printf ("RNR=%d", rnr);
+            case 2: printf ("RNum=0");
+            case 3: printf ("COMPLETE");
+          }
+          DELIVERY - indication entered isdn_rc function
+          RNR=...  - application had returned RNR=... after the
+                     look ahead callback
+          RNum=0   - aplication had not returned any buffer to copy
+                     this indication and will copy it self
+          COMPLETE - XDI had copied the data to the buffers provided
+                     bu the application and is about to issue the
+                     final callback
+        rnr:  Look case 1 of the rnr_valid
+        type: the Id that was sent by the ASSIGN of this entity. This should
+              be global Id like NL_ID, DSIG_ID, MAN_ID. An unknown Id will
+              cause "?-" in the front of the request. In this case the
+              log.c is to be extended.
+   ------------------------------------------------------------------------ */
+static void xdi_xlog_ind (byte Adapter,
+                          byte Id,
+                          byte Ch,
+                          byte Ind,
+                          byte rnr_valid,
+                          byte rnr,
+                          byte type) {
+#if defined(XDI_USE_XLOG)
+  word LogInfo[4];
+  PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
+  PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
+  PUT_WORD(&LogInfo[2], ((word)Ind | (word)(type << 8)));
+  PUT_WORD(&LogInfo[3], ((word)rnr | (word)(rnr_valid << 8)));
+  xdi_xlog ((byte*)&LogInfo[0], 222, sizeof(LogInfo));
+#endif
+}
diff --git a/drivers/isdn/hardware/eicon/di.h b/drivers/isdn/hardware/eicon/di.h
new file mode 100644
index 0000000..dcf37b1
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/di.h
@@ -0,0 +1,118 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*
+ *  some macros for detailed trace management
+ */
+#include "di_dbg.h"
+/*****************************************************************************/
+#define XMOREC 0x1f
+#define XMOREF 0x20
+#define XBUSY  0x40
+#define RMORE  0x80
+#define DIVA_MISC_FLAGS_REMOVE_PENDING    0x01
+#define DIVA_MISC_FLAGS_NO_RC_CANCELLING  0x02
+#define DIVA_MISC_FLAGS_RX_DMA            0x04
+        /* structure for all information we have to keep on a per   */
+        /* adapater basis                                           */
+typedef struct adapter_s ADAPTER;
+struct adapter_s {
+  void * io;
+  byte IdTable[256];
+  byte IdTypeTable[256];
+  byte FlowControlIdTable[256];
+  byte FlowControlSkipTable[256];
+  byte ReadyInt;
+  byte RcExtensionSupported;
+  byte misc_flags_table[256];
+  dword protocol_capabilities;
+  byte ( * ram_in)(ADAPTER * a, void * adr);
+  word ( * ram_inw)(ADAPTER * a, void * adr);
+  void (* ram_in_buffer)(ADAPTER * a, void * adr, void  * P, word length);
+  void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY  * e);
+  void ( * ram_out)(ADAPTER * a, void * adr, byte data);
+  void ( * ram_outw)(ADAPTER * a, void * adr, word data);
+  void (* ram_out_buffer)(ADAPTER * a, void * adr, void  * P, word length);
+  void ( * ram_inc)(ADAPTER * a, void * adr);
+#if defined(DIVA_ISTREAM)
+  dword rx_stream[256];
+  dword tx_stream[256];
+  word tx_pos[256];
+  word rx_pos[256];
+  byte stream_buffer[2512];
+  dword ( * ram_offset)(ADAPTER * a);
+  void ( * ram_out_dw) (ADAPTER *a,
+                                    void *addr,
+                                    const dword* data,
+                                    int dwords);
+  void ( * ram_in_dw) (ADAPTER *a,
+                                   void *addr,
+                                   dword* data,
+                                   int dwords);
+  void ( * istream_wakeup)(ADAPTER* a);
+#else
+  byte stream_buffer[4];
+#endif
+};
+/*------------------------------------------------------------------*/
+/* public functions of IDI common code                              */
+/*------------------------------------------------------------------*/
+void pr_out(ADAPTER * a);
+byte pr_dpc(ADAPTER * a);
+byte scom_test_int(ADAPTER * a);
+void scom_clear_int(ADAPTER * a);
+/*------------------------------------------------------------------*/
+/* OS specific functions used by IDI common code                    */
+/*------------------------------------------------------------------*/
+void free_entity(ADAPTER * a, byte e_no);
+void assign_queue(ADAPTER * a, byte e_no, word ref);
+byte get_assign(ADAPTER * a, word ref);
+void req_queue(ADAPTER * a, byte e_no);
+byte look_req(ADAPTER * a);
+void next_req(ADAPTER * a);
+ENTITY  * entity_ptr(ADAPTER * a, byte e_no);
+#if defined(DIVA_ISTREAM)
+struct _diva_xdi_stream_interface;
+void diva_xdi_provide_istream_info (ADAPTER* a,
+                                    struct _diva_xdi_stream_interface* pI);
+void pr_stream (ADAPTER * a);
+int diva_istream_write (void* context,
+                        int Id,
+                        void* data,
+                        int length,
+                        int final,
+                        byte usr1,
+                        byte usr2);
+int diva_istream_read (void* context,
+                        int Id,
+                        void* data,
+                        int max_length,
+                        int* final,
+                        byte* usr1,
+                        byte* usr2);
+#if defined(DIVA_IDI_RX_DMA)
+#include "diva_dma.h"
+#endif
+#endif
diff --git a/drivers/isdn/hardware/eicon/di_dbg.h b/drivers/isdn/hardware/eicon/di_dbg.h
new file mode 100644
index 0000000..d576ff3
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/di_dbg.h
@@ -0,0 +1,37 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_DI_DBG_INC__
+#define __DIVA_DI_DBG_INC__
+#if !defined (dtrc)
+#define dtrc(a)
+#endif
+#if !defined (dbug)
+#define dbug(a)
+#endif
+#if !defined USE_EXTENDED_DEBUGS
+extern void (*dprintf)(char*, ...);
+#endif
+#endif
diff --git a/drivers/isdn/hardware/eicon/di_defs.h b/drivers/isdn/hardware/eicon/di_defs.h
new file mode 100644
index 0000000..4c2f612
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/di_defs.h
@@ -0,0 +1,181 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef _DI_DEFS_  
+#define _DI_DEFS_
+        /* typedefs for our data structures                         */
+typedef struct get_name_s GET_NAME;
+/*  The entity_s structure is used to pass all
+    parameters between application and IDI   */
+typedef struct entity_s ENTITY;
+typedef struct buffers_s BUFFERS;
+typedef struct postcall_s POSTCALL;
+typedef struct get_para_s GET_PARA;
+#define BOARD_NAME_LENGTH 9
+#define IDI_CALL_LINK_T
+#define IDI_CALL_ENTITY_T
+/* typedef void ( * IDI_CALL)(ENTITY *); */
+/* --------------------------------------------------------
+    IDI_CALL
+   -------------------------------------------------------- */
+typedef void (IDI_CALL_LINK_T * IDI_CALL)(ENTITY IDI_CALL_ENTITY_T *);
+typedef struct {
+  word length;          /* length of data/parameter field           */
+  byte P[270];          /* data/parameter field                     */
+} DBUFFER;
+struct get_name_s {
+  word command;         /* command = 0x0100 */
+  byte name[BOARD_NAME_LENGTH];
+};
+struct postcall_s {
+  word      command;                           /* command = 0x0300 */
+  word      dummy;                             /* not used */
+  void      (  * callback)(void   *);      /* call back */
+  void    *context;                          /* context pointer */
+};
+#define REQ_PARA            0x0600   /* request command line parameters */
+#define REQ_PARA_LEN             1   /* number of data bytes */
+#define L1_STARTUP_DOWN_POS      0   /* '-y' command line parameter in......*/
+#define L1_STARTUP_DOWN_MSK   0x01   /* first byte position (index 0) with value 0x01 */
+struct get_para_s {
+  word  command;            /* command = 0x0600 */
+  byte  len;                /* max length of para field in bytes */
+  byte  para[REQ_PARA_LEN]; /* parameter field */
+};
+struct buffers_s {
+  word PLength;
+  byte   * P;
+};
+struct entity_s {
+  byte                  Req;            /* pending request          */
+  byte                  Rc;             /* return code received     */
+  byte                  Ind;            /* indication received      */
+  byte                  ReqCh;          /* channel of current Req   */
+  byte                  RcCh;           /* channel of current Rc    */
+  byte                  IndCh;          /* channel of current Ind   */
+  byte                  Id;             /* ID used by this entity   */
+  byte                  GlobalId;       /* reserved field           */
+  byte                  XNum;           /* number of X-buffers      */
+  byte                  RNum;           /* number of R-buffers      */
+  BUFFERS                 * X;        /* pointer to X-buffer list */
+  BUFFERS                 * R;        /* pointer to R-buffer list */
+  word                  RLength;        /* length of current R-data */
+  DBUFFER   *         RBuffer;        /* buffer of current R-data */
+  byte                  RNR;            /* receive not ready flag   */
+  byte                  complete;       /* receive complete status  */
+  IDI_CALL              callback;
+  word                  user[2];
+        /* fields used by the driver internally                     */
+  byte                  No;             /* entity number            */
+  byte                  reserved2;      /* reserved field           */
+  byte                  More;           /* R/X More flags           */
+  byte                  MInd;           /* MDATA coding for this ID */
+  byte                  XCurrent;       /* current transmit buffer  */
+  byte                  RCurrent;       /* current receive buffer   */
+  word                  XOffset;        /* offset in x-buffer       */
+  word                  ROffset;        /* offset in r-buffer       */
+};
+typedef struct {
+  byte                  type;
+  byte                  channels;
+  word                  features;
+  IDI_CALL              request;
+} DESCRIPTOR;
+        /* descriptor type field coding */
+#define IDI_ADAPTER_S           1
+#define IDI_ADAPTER_PR          2
+#define IDI_ADAPTER_DIVA        3
+#define IDI_ADAPTER_MAESTRA     4
+#define IDI_VADAPTER            0x40
+#define IDI_DRIVER              0x80
+#define IDI_DADAPTER            0xfd
+#define IDI_DIDDPNP             0xfe
+#define IDI_DIMAINT             0xff
+        /* Hardware IDs ISA PNP */
+#define HW_ID_DIVA_PRO     3    /* same as IDI_ADAPTER_DIVA    */
+#define HW_ID_MAESTRA      4    /* same as IDI_ADAPTER_MAESTRA */
+#define HW_ID_PICCOLA      5
+#define HW_ID_DIVA_PRO20   6
+#define HW_ID_DIVA20       7
+#define HW_ID_DIVA_PRO20_U 8
+#define HW_ID_DIVA20_U     9
+#define HW_ID_DIVA30       10
+#define HW_ID_DIVA30_U     11
+        /* Hardware IDs PCI */
+#define HW_ID_EICON_PCI              0x1133
+#define HW_ID_SIEMENS_PCI            0x8001 /* unused SubVendor ID for Siemens Cornet-N cards */
+#define HW_ID_PROTTYPE_CORNETN       0x0014 /* SubDevice ID for Siemens Cornet-N cards */
+#define HW_ID_FUJITSU_SIEMENS_PCI    0x110A /* SubVendor ID for Fujitsu Siemens */
+#define HW_ID_GS03_PCI               0x0021 /* SubDevice ID for Fujitsu Siemens ISDN S0 card */
+#define HW_ID_DIVA_PRO20_PCI         0xe001
+#define HW_ID_DIVA20_PCI             0xe002
+#define HW_ID_DIVA_PRO20_PCI_U       0xe003
+#define HW_ID_DIVA20_PCI_U           0xe004
+#define HW_ID_DIVA201_PCI            0xe005
+#define HW_ID_DIVA_CT_ST             0xe006
+#define HW_ID_DIVA_CT_U              0xe007
+#define HW_ID_DIVA_CTL_ST            0xe008
+#define HW_ID_DIVA_CTL_U             0xe009
+#define HW_ID_DIVA_ISDN_V90_PCI      0xe00a
+#define HW_ID_DIVA202_PCI_ST         0xe00b
+#define HW_ID_DIVA202_PCI_U          0xe00c
+#define HW_ID_DIVA_PRO30_PCI         0xe00d
+#define HW_ID_MAESTRA_PCI            0xe010
+#define HW_ID_MAESTRAQ_PCI           0xe012
+#define HW_ID_DSRV_Q8M_V2_PCI        0xe013
+#define HW_ID_MAESTRAP_PCI           0xe014
+#define HW_ID_DSRV_P30M_V2_PCI       0xe015
+#define HW_ID_DSRV_VOICE_Q8M_PCI     0xe016
+#define HW_ID_DSRV_VOICE_Q8M_V2_PCI  0xe017
+#define HW_ID_DSRV_B2M_V2_PCI        0xe018
+#define HW_ID_DSRV_VOICE_P30M_V2_PCI 0xe019
+#define HW_ID_DSRV_B2F_PCI           0xe01a
+#define HW_ID_DSRV_VOICE_B2M_V2_PCI  0xe01b
+        /* Hardware IDs USB */
+#define EICON_USB_VENDOR_ID          0x071D
+#define HW_ID_DIVA_USB_REV1          0x1000
+#define HW_ID_DIVA_USB_REV2          0x1003
+#define HW_ID_TELEDAT_SURF_USB_REV2  0x1004
+#define HW_ID_TELEDAT_SURF_USB_REV1  0x2000
+/* --------------------------------------------------------------------------
+  Adapter array change notification framework
+  -------------------------------------------------------------------------- */
+typedef void (IDI_CALL_LINK_T* didd_adapter_change_callback_t)(     void IDI_CALL_ENTITY_T * context, DESCRIPTOR* adapter, int removal);
+/* -------------------------------------------------------------------------- */
+#define DI_VOICE          0x0 /* obsolete define */
+#define DI_FAX3           0x1
+#define DI_MODEM          0x2
+#define DI_POST           0x4
+#define DI_V110           0x8
+#define DI_V120           0x10
+#define DI_POTS           0x20
+#define DI_CODEC          0x40
+#define DI_MANAGE         0x80
+#define DI_V_42           0x0100
+#define DI_EXTD_FAX       0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
+#define DI_AT_PARSER      0x0400 /* Build-in AT Parser in the L2 */
+#define DI_VOICE_OVER_IP  0x0800 /* Voice over IP support */
+typedef void (IDI_CALL_LINK_T* _IDI_CALL)(void*, ENTITY*);  
+#endif  
diff --git a/drivers/isdn/hardware/eicon/did_vers.h b/drivers/isdn/hardware/eicon/did_vers.h
new file mode 100644
index 0000000..538c590f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/did_vers.h
@@ -0,0 +1,26 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+static char diva_didd_common_code_build[] = "102-51";  
diff --git a/drivers/isdn/hardware/eicon/diddfunc.c b/drivers/isdn/hardware/eicon/diddfunc.c
new file mode 100644
index 0000000..3029234
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diddfunc.c
@@ -0,0 +1,115 @@
+/* $Id: diddfunc.c,v 1.14.6.2 2004/08/28 20:03:53 armin Exp $
+ *
+ * DIDD Interface module for Eicon active cards.
+ * 
+ * Functions are in dadapter.c 
+ * 
+ * Copyright 2002-2003 by Armin Schindler (mac@melware.de) 
+ * Copyright 2002-2003 Cytronics & Melware (info@melware.de)
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "platform.h"
+#include "di_defs.h"
+#include "dadapter.h"
+#include "divasync.h"
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+
+extern void DIVA_DIDD_Read(void *, int);
+extern char *DRIVERRELEASE_DIDD;
+static dword notify_handle;
+static DESCRIPTOR _DAdapter;
+
+/*
+ * didd callback function
+ */
+static void *didd_callback(void *context, DESCRIPTOR * adapter,
+			   int removal)
+{
+	if (adapter->type == IDI_DADAPTER) {
+		DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."))
+		return (NULL);
+	} else if (adapter->type == IDI_DIMAINT) {
+		if (removal) {
+			DbgDeregister();
+		} else {
+			DbgRegister("DIDD", DRIVERRELEASE_DIDD, DBG_DEFAULT);
+		}
+	}
+	return (NULL);
+}
+
+/*
+ * connect to didd
+ */
+static int DIVA_INIT_FUNCTION connect_didd(void)
+{
+	int x = 0;
+	int dadapter = 0;
+	IDI_SYNC_REQ req;
+	DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+	DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+	for (x = 0; x < MAX_DESCRIPTORS; x++) {
+		if (DIDD_Table[x].type == IDI_DADAPTER) {	/* DADAPTER found */
+			dadapter = 1;
+			memcpy(&_DAdapter, &DIDD_Table[x], sizeof(_DAdapter));
+			req.didd_notify.e.Req = 0;
+			req.didd_notify.e.Rc =
+			    IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+			req.didd_notify.info.callback = (void *)didd_callback;
+			req.didd_notify.info.context = NULL;
+			_DAdapter.request((ENTITY *) & req);
+			if (req.didd_notify.e.Rc != 0xff)
+				return (0);
+			notify_handle = req.didd_notify.info.handle;
+		} else if (DIDD_Table[x].type == IDI_DIMAINT) {	/* MAINT found */
+			DbgRegister("DIDD", DRIVERRELEASE_DIDD, DBG_DEFAULT);
+		}
+	}
+	return (dadapter);
+}
+
+/*
+ * disconnect from didd
+ */
+static void DIVA_EXIT_FUNCTION disconnect_didd(void)
+{
+	IDI_SYNC_REQ req;
+
+	req.didd_notify.e.Req = 0;
+	req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+	req.didd_notify.info.handle = notify_handle;
+	_DAdapter.request((ENTITY *) & req);
+}
+
+/*
+ * init
+ */
+int DIVA_INIT_FUNCTION diddfunc_init(void)
+{
+	diva_didd_load_time_init();
+
+	if (!connect_didd()) {
+		DBG_ERR(("init: failed to connect to DIDD."))
+		diva_didd_load_time_finit();
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * finit
+ */
+void DIVA_EXIT_FUNCTION diddfunc_finit(void)
+{
+	DbgDeregister();
+	disconnect_didd();
+	diva_didd_load_time_finit();
+}
diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c
new file mode 100644
index 0000000..8ab8027
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva.c
@@ -0,0 +1,660 @@
+/* $Id: diva.c,v 1.21.4.1 2004/05/08 14:33:43 armin Exp $ */
+
+#define CARDTYPE_H_WANT_DATA            1
+#define CARDTYPE_H_WANT_IDI_DATA        0
+#define CARDTYPE_H_WANT_RESOURCE_DATA   0
+#define CARDTYPE_H_WANT_FILE_DATA       0
+
+#include "platform.h"
+#include "debuglib.h"
+#include "cardtype.h"
+#include "pc.h"
+#include "di_defs.h"
+#include "di.h"
+#include "io.h"
+#include "pc_maint.h"
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "diva_pci.h"
+#include "diva.h"
+
+#ifdef CONFIG_ISDN_DIVAS_PRIPCI
+#include "os_pri.h"
+#endif
+#ifdef CONFIG_ISDN_DIVAS_BRIPCI
+#include "os_bri.h"
+#include "os_4bri.h"
+#endif
+
+PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
+extern IDI_CALL Requests[MAX_ADAPTER];
+extern int create_adapter_proc(diva_os_xdi_adapter_t * a);
+extern void remove_adapter_proc(diva_os_xdi_adapter_t * a);
+
+#define DivaIdiReqFunc(N) \
+static void DivaIdiRequest##N(ENTITY *e) \
+{ if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }
+
+/*
+**  Create own 32 Adapters
+*/
+DivaIdiReqFunc(0)
+DivaIdiReqFunc(1)
+DivaIdiReqFunc(2)
+DivaIdiReqFunc(3)
+DivaIdiReqFunc(4)
+DivaIdiReqFunc(5)
+DivaIdiReqFunc(6)
+DivaIdiReqFunc(7)
+DivaIdiReqFunc(8)
+DivaIdiReqFunc(9)
+DivaIdiReqFunc(10)
+DivaIdiReqFunc(11)
+DivaIdiReqFunc(12)
+DivaIdiReqFunc(13)
+DivaIdiReqFunc(14)
+DivaIdiReqFunc(15)
+DivaIdiReqFunc(16)
+DivaIdiReqFunc(17)
+DivaIdiReqFunc(18)
+DivaIdiReqFunc(19)
+DivaIdiReqFunc(20)
+DivaIdiReqFunc(21)
+DivaIdiReqFunc(22)
+DivaIdiReqFunc(23)
+DivaIdiReqFunc(24)
+DivaIdiReqFunc(25)
+DivaIdiReqFunc(26)
+DivaIdiReqFunc(27)
+DivaIdiReqFunc(28)
+DivaIdiReqFunc(29)
+DivaIdiReqFunc(30)
+DivaIdiReqFunc(31)
+
+struct pt_regs;
+
+/*
+**  LOCALS
+*/
+static LIST_HEAD(adapter_queue);
+
+typedef struct _diva_get_xlog {
+	word command;
+	byte req;
+	byte rc;
+	byte data[sizeof(struct mi_pc_maint)];
+} diva_get_xlog_t;
+
+typedef struct _diva_supported_cards_info {
+	int CardOrdinal;
+	diva_init_card_proc_t init_card;
+} diva_supported_cards_info_t;
+
+static diva_supported_cards_info_t divas_supported_cards[] = {
+#ifdef CONFIG_ISDN_DIVAS_PRIPCI
+	/*
+	   PRI Cards
+	 */
+	{CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},
+	/*
+	   PRI Rev.2 Cards
+	 */
+	{CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},
+	/*
+	   PRI Rev.2 VoIP Cards
+	 */
+	{CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},
+#endif
+#ifdef CONFIG_ISDN_DIVAS_BRIPCI
+	/*
+	   4BRI Rev 1 Cards
+	 */
+	{CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},
+	{CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},
+	/*
+	   4BRI Rev 2 Cards
+	 */
+	{CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card},
+	{CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card},
+	/*
+	   4BRI Based BRI Rev 2 Cards
+	 */
+	{CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card},
+	{CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card},
+	{CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card},
+	/*
+	   BRI
+	 */
+	{CARDTYPE_MAESTRA_PCI, diva_bri_init_card},
+#endif
+
+	/*
+	   EOL
+	 */
+	{-1}
+};
+
+static void diva_init_request_array(void);
+static void *divas_create_pci_card(int handle, void *pci_dev_handle);
+
+static diva_os_spin_lock_t adapter_lock;
+
+static int diva_find_free_adapters(int base, int nr)
+{
+	int i;
+
+	for (i = 0; i < nr; i++) {
+		if (IoAdapters[base + i]) {
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head * what)
+{
+	diva_os_xdi_adapter_t *a = NULL;
+
+	if (what && (what->next != &adapter_queue))
+		a = list_entry(what->next, diva_os_xdi_adapter_t, link);
+
+	return(a);
+}
+
+/* --------------------------------------------------------------------------
+    Add card to the card list
+   -------------------------------------------------------------------------- */
+void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	diva_os_xdi_adapter_t *pdiva, *pa;
+	int i, j, max, nr;
+
+	for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {
+		if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {
+			if (!(pdiva = divas_create_pci_card(i, pdev))) {
+				return NULL;
+			}
+			switch (CardOrdinal) {
+			case CARDTYPE_DIVASRV_Q_8M_PCI:
+			case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI:
+			case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
+			case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
+				max = MAX_ADAPTER - 4;
+				nr = 4;
+				break;
+
+			default:
+				max = MAX_ADAPTER;
+				nr = 1;
+			}
+
+			diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
+
+			for (i = 0; i < max; i++) {
+				if (!diva_find_free_adapters(i, nr)) {
+					pdiva->controller = i + 1;
+					pdiva->xdi_adapter.ANum = pdiva->controller;
+					IoAdapters[i] = &pdiva->xdi_adapter;
+					diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
+					create_adapter_proc(pdiva);	/* add adapter to proc file system */
+
+					DBG_LOG(("add %s:%d",
+						 CardProperties
+						 [CardOrdinal].Name,
+						 pdiva->controller))
+
+					diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
+					pa = pdiva;
+					for (j = 1; j < nr; j++) {	/* slave adapters, if any */
+						pa = diva_q_get_next(&pa->link);
+						if (pa && !pa->interface.cleanup_adapter_proc) {
+							pa->controller = i + 1 + j;
+							pa->xdi_adapter.ANum = pa->controller;
+							IoAdapters[i + j] = &pa->xdi_adapter;
+							diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
+							DBG_LOG(("add slave adapter (%d)",
+								 pa->controller))
+							create_adapter_proc(pa);	/* add adapter to proc file system */
+							diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
+						} else {
+							DBG_ERR(("slave adapter problem"))
+							break;
+						}
+					}
+
+					diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
+					return (pdiva);
+				}
+			}
+
+			diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
+
+			/*
+			   Not able to add adapter - remove it and return error
+			 */
+			DBG_ERR(("can not alloc request array"))
+			diva_driver_remove_card(pdiva);
+
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+/* --------------------------------------------------------------------------
+    Called on driver load, MAIN, main, DriverEntry
+   -------------------------------------------------------------------------- */
+int divasa_xdi_driver_entry(void)
+{
+	diva_os_initialize_spin_lock(&adapter_lock, "adapter");
+	memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));
+	diva_init_request_array();
+
+	return (0);
+}
+
+/* --------------------------------------------------------------------------
+    Remove adapter from list
+   -------------------------------------------------------------------------- */
+static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	diva_os_xdi_adapter_t *a = NULL;
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");
+
+	if (!list_empty(&adapter_queue)) {
+		a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);
+		list_del(adapter_queue.next);
+	}
+
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
+	return (a);
+}
+
+/* --------------------------------------------------------------------------
+    Remove card from the card list
+   -------------------------------------------------------------------------- */
+void diva_driver_remove_card(void *pdiva)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	diva_os_xdi_adapter_t *a[4];
+	diva_os_xdi_adapter_t *pa;
+	int i;
+
+	pa = a[0] = (diva_os_xdi_adapter_t *) pdiva;
+	a[1] = a[2] = a[3] = NULL;
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");
+
+	for (i = 1; i < 4; i++) {
+		if ((pa = diva_q_get_next(&pa->link))
+		    && !pa->interface.cleanup_adapter_proc) {
+			a[i] = pa;
+		} else {
+			break;
+		}
+	}
+
+	for (i = 0; ((i < 4) && a[i]); i++) {
+		list_del(&a[i]->link);
+	}
+
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
+
+	(*(a[0]->interface.cleanup_adapter_proc)) (a[0]);
+
+	for (i = 0; i < 4; i++) {
+		if (a[i]) {
+			if (a[i]->controller) {
+				DBG_LOG(("remove adapter (%d)",
+					 a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL;
+				remove_adapter_proc(a[i]);
+			}
+			diva_os_free(0, a[i]);
+		}
+	}
+}
+
+/* --------------------------------------------------------------------------
+    Create diva PCI adapter and init internal adapter structures
+   -------------------------------------------------------------------------- */
+static void *divas_create_pci_card(int handle, void *pci_dev_handle)
+{
+	diva_supported_cards_info_t *pI = &divas_supported_cards[handle];
+	diva_os_spin_lock_magic_t old_irql;
+	diva_os_xdi_adapter_t *a;
+
+	DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))
+
+	if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) {
+		DBG_ERR(("A: can't alloc adapter"));
+		return NULL;
+	}
+
+	memset(a, 0x00, sizeof(*a));
+
+	a->CardIndex = handle;
+	a->CardOrdinal = pI->CardOrdinal;
+	a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;
+	a->xdi_adapter.cardType = a->CardOrdinal;
+	a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle);
+	a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);
+	a->resources.pci.hdev = pci_dev_handle;
+
+	/*
+	   Add master adapter first, so slave adapters will receive higher
+	   numbers as master adapter
+	 */
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
+	list_add_tail(&a->link, &adapter_queue);
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
+
+	if ((*(pI->init_card)) (a)) {
+		diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
+		list_del(&a->link);
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
+		diva_os_free(0, a);
+		DBG_ERR(("A: can't get adapter resources"));
+		return NULL;
+	}
+
+	return (a);
+}
+
+/* --------------------------------------------------------------------------
+    Called on driver unload FINIT, finit, Unload
+   -------------------------------------------------------------------------- */
+void divasa_xdi_driver_unload(void)
+{
+	diva_os_xdi_adapter_t *a;
+
+	while ((a = get_and_remove_from_queue())) {
+		if (a->interface.cleanup_adapter_proc) {
+			(*(a->interface.cleanup_adapter_proc)) (a);
+		}
+		if (a->controller) {
+			IoAdapters[a->controller - 1] = NULL;
+			remove_adapter_proc(a);
+		}
+		diva_os_free(0, a);
+	}
+	diva_os_destroy_spin_lock(&adapter_lock, "adapter");
+}
+
+/*
+**  Receive and process command from user mode utility
+*/
+void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
+			    int length,
+			    divas_xdi_copy_from_user_fn_t cp_fn)
+{
+	diva_xdi_um_cfg_cmd_t msg;
+	diva_os_xdi_adapter_t *a = NULL;
+	diva_os_spin_lock_magic_t old_irql;
+	struct list_head *tmp;
+
+	if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
+		DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
+			 length, sizeof(diva_xdi_um_cfg_cmd_t)))
+		return NULL;
+	}
+	if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
+		DBG_ERR(("A: A(?) open, write error"))
+		return NULL;
+	}
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
+	list_for_each(tmp, &adapter_queue) {
+		a = list_entry(tmp, diva_os_xdi_adapter_t, link);
+		if (a->controller == (int)msg.adapter)
+			break;
+		a = NULL;
+	}
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
+
+	if (!a) {
+		DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
+	}
+
+	return (a);
+}
+
+/*
+**  Easy cleanup mailbox status
+*/
+void diva_xdi_close_adapter(void *adapter, void *os_handle)
+{
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
+
+	a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
+	if (a->xdi_mbox.data) {
+		diva_os_free(0, a->xdi_mbox.data);
+		a->xdi_mbox.data = NULL;
+	}
+}
+
+int
+diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
+	       int length, divas_xdi_copy_from_user_fn_t cp_fn)
+{
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
+	void *data;
+
+	if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
+		DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
+		return (-1);
+	}
+
+	if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
+		DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
+			 a->controller, length,
+			 sizeof(diva_xdi_um_cfg_cmd_t)))
+		return (-3);
+	}
+
+	if (!(data = diva_os_malloc(0, length))) {
+		DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
+		return (-2);
+	}
+
+	length = (*cp_fn) (os_handle, data, src, length);
+	if (length > 0) {
+		if ((*(a->interface.cmd_proc))
+		    (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
+			length = -3;
+		}
+	} else {
+		DBG_ERR(("A: A(%d) write error (%d)", a->controller,
+			 length))
+	}
+
+	diva_os_free(0, data);
+
+	return (length);
+}
+
+/*
+**  Write answers to user mode utility, if any
+*/
+int
+diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
+	      int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
+{
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
+	int ret;
+
+	if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
+		DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
+		return (-1);
+	}
+	if (!a->xdi_mbox.data) {
+		a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
+		DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
+		return (-2);
+	}
+
+	if (max_length < a->xdi_mbox.data_length) {
+		DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",
+			 a->controller, max_length,
+			 a->xdi_mbox.data_length))
+		return (-3);
+	}
+
+	ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
+		      a->xdi_mbox.data_length);
+	if (ret > 0) {
+		diva_os_free(0, a->xdi_mbox.data);
+		a->xdi_mbox.data = NULL;
+		a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
+	}
+
+	return (ret);
+}
+
+
+irqreturn_t diva_os_irq_wrapper(int irq, void *context, struct pt_regs *regs)
+{
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
+	diva_xdi_clear_interrupts_proc_t clear_int_proc;
+
+	if (!a || !a->xdi_adapter.diva_isr_handler) {
+		return IRQ_NONE;
+	}
+
+	if ((clear_int_proc = a->clear_interrupts_proc)) {
+		(*clear_int_proc) (a);
+		a->clear_interrupts_proc = NULL;
+		return IRQ_HANDLED;
+	}
+
+	(*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
+	return IRQ_HANDLED;
+}
+
+static void diva_init_request_array(void)
+{
+	Requests[0] = DivaIdiRequest0;
+	Requests[1] = DivaIdiRequest1;
+	Requests[2] = DivaIdiRequest2;
+	Requests[3] = DivaIdiRequest3;
+	Requests[4] = DivaIdiRequest4;
+	Requests[5] = DivaIdiRequest5;
+	Requests[6] = DivaIdiRequest6;
+	Requests[7] = DivaIdiRequest7;
+	Requests[8] = DivaIdiRequest8;
+	Requests[9] = DivaIdiRequest9;
+	Requests[10] = DivaIdiRequest10;
+	Requests[11] = DivaIdiRequest11;
+	Requests[12] = DivaIdiRequest12;
+	Requests[13] = DivaIdiRequest13;
+	Requests[14] = DivaIdiRequest14;
+	Requests[15] = DivaIdiRequest15;
+	Requests[16] = DivaIdiRequest16;
+	Requests[17] = DivaIdiRequest17;
+	Requests[18] = DivaIdiRequest18;
+	Requests[19] = DivaIdiRequest19;
+	Requests[20] = DivaIdiRequest20;
+	Requests[21] = DivaIdiRequest21;
+	Requests[22] = DivaIdiRequest22;
+	Requests[23] = DivaIdiRequest23;
+	Requests[24] = DivaIdiRequest24;
+	Requests[25] = DivaIdiRequest25;
+	Requests[26] = DivaIdiRequest26;
+	Requests[27] = DivaIdiRequest27;
+	Requests[28] = DivaIdiRequest28;
+	Requests[29] = DivaIdiRequest29;
+	Requests[30] = DivaIdiRequest30;
+	Requests[31] = DivaIdiRequest31;
+}
+
+void diva_xdi_display_adapter_features(int card)
+{
+	dword features;
+	if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
+		return;
+	}
+	card--;
+	features = IoAdapters[card]->Properties.Features;
+
+	DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))
+	DBG_LOG((" DI_FAX3          :  %s",
+		     (features & DI_FAX3) ? "Y" : "N"))
+	DBG_LOG((" DI_MODEM         :  %s",
+		     (features & DI_MODEM) ? "Y" : "N"))
+	DBG_LOG((" DI_POST          :  %s",
+		     (features & DI_POST) ? "Y" : "N"))
+	DBG_LOG((" DI_V110          :  %s",
+		     (features & DI_V110) ? "Y" : "N"))
+	DBG_LOG((" DI_V120          :  %s",
+		     (features & DI_V120) ? "Y" : "N"))
+	DBG_LOG((" DI_POTS          :  %s",
+		     (features & DI_POTS) ? "Y" : "N"))
+	DBG_LOG((" DI_CODEC         :  %s",
+		     (features & DI_CODEC) ? "Y" : "N"))
+	DBG_LOG((" DI_MANAGE        :  %s",
+		     (features & DI_MANAGE) ? "Y" : "N"))
+	DBG_LOG((" DI_V_42          :  %s",
+		     (features & DI_V_42) ? "Y" : "N"))
+	DBG_LOG((" DI_EXTD_FAX      :  %s",
+		     (features & DI_EXTD_FAX) ? "Y" : "N"))
+	DBG_LOG((" DI_AT_PARSER     :  %s",
+		     (features & DI_AT_PARSER) ? "Y" : "N"))
+	DBG_LOG((" DI_VOICE_OVER_IP :  %s",
+		     (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
+}
+
+void diva_add_slave_adapter(diva_os_xdi_adapter_t * a)
+{
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
+	list_add_tail(&a->link, &adapter_queue);
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
+}
+
+int diva_card_read_xlog(diva_os_xdi_adapter_t * a)
+{
+	diva_get_xlog_t *req;
+	byte *data;
+
+	if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
+		return (-1);
+	}
+	if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
+		return (-1);
+	}
+	memset(data, 0x00, sizeof(struct mi_pc_maint));
+
+	if (!(req = diva_os_malloc(0, sizeof(*req)))) {
+		diva_os_free(0, data);
+		return (-1);
+	}
+	req->command = 0x0400;
+	req->req = LOG;
+	req->rc = 0x00;
+
+	(*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);
+
+	if (!req->rc || req->req) {
+		diva_os_free(0, data);
+		diva_os_free(0, req);
+		return (-1);
+	}
+
+	memcpy(data, &req->req, sizeof(struct mi_pc_maint));
+
+	diva_os_free(0, req);
+
+	a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
+	a->xdi_mbox.data = data;
+	a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+
+	return (0);
+}
+
+void xdiFreeFile(void *handle)
+{
+}
diff --git a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h
new file mode 100644
index 0000000..e979085
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva.h
@@ -0,0 +1,31 @@
+/* $Id: diva.h,v 1.1.2.2 2001/02/08 12:25:43 armin Exp $ */
+
+#ifndef __DIVA_XDI_OS_PART_H__
+#define __DIVA_XDI_OS_PART_H__
+
+
+int divasa_xdi_driver_entry(void);
+void divasa_xdi_driver_unload(void);
+void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal);
+void diva_driver_remove_card(void *pdiva);
+
+typedef int (*divas_xdi_copy_to_user_fn_t) (void *os_handle, void __user *dst,
+					    const void *src, int length);
+
+typedef int (*divas_xdi_copy_from_user_fn_t) (void *os_handle, void *dst,
+					      const void __user *src, int length);
+
+int diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
+		  int max_length, divas_xdi_copy_to_user_fn_t cp_fn);
+
+int diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
+		   int length, divas_xdi_copy_from_user_fn_t cp_fn);
+
+void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
+			    int length,
+			    divas_xdi_copy_from_user_fn_t cp_fn);
+
+void diva_xdi_close_adapter(void *adapter, void *os_handle);
+
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c
new file mode 100644
index 0000000..7fdf8ae
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva_didd.c
@@ -0,0 +1,151 @@
+/* $Id: diva_didd.c,v 1.13.6.4 2005/02/11 19:40:25 armin Exp $
+ *
+ * DIDD Interface module for Eicon active cards.
+ * 
+ * Functions are in dadapter.c 
+ * 
+ * Copyright 2002-2003 by Armin Schindler (mac@melware.de) 
+ * Copyright 2002-2003 Cytronics & Melware (info@melware.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/init.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+
+#include "platform.h"
+#include "di_defs.h"
+#include "dadapter.h"
+#include "divasync.h"
+#include "did_vers.h"
+
+static char *main_revision = "$Revision: 1.13.6.4 $";
+
+static char *DRIVERNAME =
+    "Eicon DIVA - DIDD table (http://www.melware.net)";
+static char *DRIVERLNAME = "divadidd";
+char *DRIVERRELEASE_DIDD = "2.0";
+
+static char *main_proc_dir = "eicon";
+
+MODULE_DESCRIPTION("DIDD table driver for diva drivers");
+MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
+MODULE_SUPPORTED_DEVICE("Eicon diva drivers");
+MODULE_LICENSE("GPL");
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+extern int diddfunc_init(void);
+extern void diddfunc_finit(void);
+
+extern void DIVA_DIDD_Read(void *, int);
+
+static struct proc_dir_entry *proc_didd;
+struct proc_dir_entry *proc_net_eicon = NULL;
+
+EXPORT_SYMBOL(DIVA_DIDD_Read);
+EXPORT_SYMBOL(proc_net_eicon);
+
+static char *getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "1.0";
+	return rev;
+}
+
+static int
+proc_read(char *page, char **start, off_t off, int count, int *eof,
+	  void *data)
+{
+	int len = 0;
+	char tmprev[32];
+
+	strcpy(tmprev, main_revision);
+	len += sprintf(page + len, "%s\n", DRIVERNAME);
+	len += sprintf(page + len, "name     : %s\n", DRIVERLNAME);
+	len += sprintf(page + len, "release  : %s\n", DRIVERRELEASE_DIDD);
+	len += sprintf(page + len, "build    : %s(%s)\n",
+		       diva_didd_common_code_build, DIVA_BUILD);
+	len += sprintf(page + len, "revision : %s\n", getrev(tmprev));
+
+	if (off + count >= len)
+		*eof = 1;
+	if (len < off)
+		return 0;
+	*start = page + off;
+	return ((count < len - off) ? count : len - off);
+}
+
+static int DIVA_INIT_FUNCTION create_proc(void)
+{
+	proc_net_eicon = create_proc_entry(main_proc_dir, S_IFDIR, proc_net);
+
+	if (proc_net_eicon) {
+		if ((proc_didd =
+		     create_proc_entry(DRIVERLNAME, S_IFREG | S_IRUGO,
+				       proc_net_eicon))) {
+			proc_didd->read_proc = proc_read;
+		}
+		return (1);
+	}
+	return (0);
+}
+
+static void DIVA_EXIT_FUNCTION remove_proc(void)
+{
+	remove_proc_entry(DRIVERLNAME, proc_net_eicon);
+	remove_proc_entry(main_proc_dir, proc_net);
+}
+
+static int DIVA_INIT_FUNCTION divadidd_init(void)
+{
+	char tmprev[32];
+	int ret = 0;
+
+	printk(KERN_INFO "%s\n", DRIVERNAME);
+	printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE_DIDD);
+	strcpy(tmprev, main_revision);
+	printk("%s  Build:%s(%s)\n", getrev(tmprev),
+	       diva_didd_common_code_build, DIVA_BUILD);
+
+	if (!create_proc()) {
+		printk(KERN_ERR "%s: could not create proc entry\n",
+		       DRIVERLNAME);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (!diddfunc_init()) {
+		printk(KERN_ERR "%s: failed to connect to DIDD.\n",
+		       DRIVERLNAME);
+#ifdef MODULE
+		remove_proc();
+#endif
+		ret = -EIO;
+		goto out;
+	}
+
+      out:
+	return (ret);
+}
+
+static void DIVA_EXIT_FUNCTION divadidd_exit(void)
+{
+	diddfunc_finit();
+	remove_proc();
+	printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(divadidd_init);
+module_exit(divadidd_exit);
diff --git a/drivers/isdn/hardware/eicon/diva_dma.c b/drivers/isdn/hardware/eicon/diva_dma.c
new file mode 100644
index 0000000..f53a740
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva_dma.c
@@ -0,0 +1,94 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "diva_dma.h"
+/*
+  Every entry has length of PAGE_SIZE
+  and represents one single physical page
+  */
+struct _diva_dma_map_entry {
+  int   busy;
+  dword phys_bus_addr;  /* 32bit address as seen by the card */
+  void* local_ram_addr; /* local address as seen by the host */
+  void* addr_handle;    /* handle uset to free allocated memory */
+};
+/*
+  Create local mapping structure and init it to default state
+  */
+struct _diva_dma_map_entry* diva_alloc_dma_map (void* os_context, int nentries) {
+  diva_dma_map_entry_t* pmap = diva_os_malloc(0, sizeof(*pmap)*(nentries+1));
+  if (pmap)
+	  memset (pmap, 0, sizeof(*pmap)*(nentries+1));
+  return pmap;
+}
+/*
+  Free local map (context should be freed before) if any
+  */
+void diva_free_dma_mapping (struct _diva_dma_map_entry* pmap) {
+  if (pmap) {
+    diva_os_free (0, pmap);
+  }
+}
+/*
+  Set information saved on the map entry
+  */
+void diva_init_dma_map_entry (struct _diva_dma_map_entry* pmap,
+                              int nr, void* virt, dword phys,
+                              void* addr_handle) {
+  pmap[nr].phys_bus_addr  = phys;
+  pmap[nr].local_ram_addr = virt;
+  pmap[nr].addr_handle    = addr_handle;
+}
+/*
+  Allocate one single entry in the map
+  */
+int diva_alloc_dma_map_entry (struct _diva_dma_map_entry* pmap) {
+  int i;
+  for (i = 0; (pmap && pmap[i].local_ram_addr); i++) {
+    if (!pmap[i].busy) {
+      pmap[i].busy = 1;
+      return (i);
+    }
+  }
+  return (-1);
+}
+/*
+  Free one single entry in the map
+  */
+void diva_free_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr) {
+  pmap[nr].busy = 0;
+}
+/*
+  Get information saved on the map entry
+  */
+void diva_get_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr,
+                             void** pvirt, dword* pphys) {
+  *pphys = pmap[nr].phys_bus_addr;
+  *pvirt = pmap[nr].local_ram_addr;
+}
+void* diva_get_entry_handle (struct _diva_dma_map_entry* pmap, int nr) {
+  return (pmap[nr].addr_handle);
+}
diff --git a/drivers/isdn/hardware/eicon/diva_dma.h b/drivers/isdn/hardware/eicon/diva_dma.h
new file mode 100644
index 0000000..dff8072
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva_dma.h
@@ -0,0 +1,48 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_DMA_MAPPING_IFC_H__
+#define __DIVA_DMA_MAPPING_IFC_H__
+typedef struct _diva_dma_map_entry  diva_dma_map_entry_t;
+struct _diva_dma_map_entry* diva_alloc_dma_map (void* os_context, int nentries);
+void diva_init_dma_map_entry (struct _diva_dma_map_entry* pmap,
+                              int nr, void* virt, dword phys,
+                              void* addr_handle);
+int diva_alloc_dma_map_entry (struct _diva_dma_map_entry* pmap);
+void diva_free_dma_map_entry (struct _diva_dma_map_entry* pmap, int entry);
+void diva_get_dma_map_entry (struct _diva_dma_map_entry* pmap, int nr,
+                             void** pvirt, dword* pphys);
+void diva_free_dma_mapping (struct _diva_dma_map_entry* pmap);
+/*
+  Functionality to be implemented by OS wrapper
+  and running in process context
+  */
+void diva_init_dma_map (void* hdev,
+                        struct _diva_dma_map_entry** ppmap,
+                        int nentries);
+void diva_free_dma_map (void* hdev,
+                        struct _diva_dma_map_entry* pmap);
+void* diva_get_entry_handle (struct _diva_dma_map_entry* pmap, int nr);
+#endif
diff --git a/drivers/isdn/hardware/eicon/diva_pci.h b/drivers/isdn/hardware/eicon/diva_pci.h
new file mode 100644
index 0000000..cc0d510
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/diva_pci.h
@@ -0,0 +1,19 @@
+/* $Id: diva_pci.h,v 1.6 2003/01/04 15:29:45 schindler Exp $ */
+
+#ifndef __DIVA_PCI_INTERFACE_H__
+#define __DIVA_PCI_INTERFACE_H__
+
+void __iomem *divasa_remap_pci_bar(diva_os_xdi_adapter_t *a,
+			   int id,
+			   unsigned long bar,
+			   unsigned long area_length);
+void divasa_unmap_pci_bar(void __iomem *bar);
+unsigned long divasa_get_pci_irq(unsigned char bus,
+				 unsigned char func, void *pci_dev_handle);
+unsigned long divasa_get_pci_bar(unsigned char bus,
+				 unsigned char func,
+				 int bar, void *pci_dev_handle);
+byte diva_os_get_pci_bus(void *pci_dev_handle);
+byte diva_os_get_pci_func(void *pci_dev_handle);
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/divacapi.h b/drivers/isdn/hardware/eicon/divacapi.h
new file mode 100644
index 0000000..9f5b680
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divacapi.h
@@ -0,0 +1,1360 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*#define DEBUG */
+
+
+
+
+  
+  
+
+
+
+
+
+#define IMPLEMENT_DTMF 1
+#define IMPLEMENT_LINE_INTERCONNECT2 1
+#define IMPLEMENT_ECHO_CANCELLER 1
+#define IMPLEMENT_RTP 1
+#define IMPLEMENT_T38 1
+#define IMPLEMENT_FAX_SUB_SEP_PWD 1
+#define IMPLEMENT_V18 1
+#define IMPLEMENT_DTMF_TONE 1
+#define IMPLEMENT_PIAFS 1
+#define IMPLEMENT_FAX_PAPER_FORMATS 1
+#define IMPLEMENT_VOWN 1
+#define IMPLEMENT_CAPIDTMF 1
+#define IMPLEMENT_FAX_NONSTANDARD 1
+#define VSWITCH_SUPPORT 1
+
+
+#define IMPLEMENT_LINE_INTERCONNECT 0
+#define IMPLEMENT_MARKED_OK_AFTER_FC 1
+
+#include "capidtmf.h"
+
+/*------------------------------------------------------------------*/
+/* Common API internal definitions                                  */
+/*------------------------------------------------------------------*/
+
+#define MAX_APPL 240
+#define MAX_NCCI           127
+
+#define MSG_IN_QUEUE_SIZE  ((4096 + 3) & 0xfffc)  /* must be multiple of 4 */
+
+
+#define MSG_IN_OVERHEAD    sizeof(APPL   *)
+
+#define MAX_NL_CHANNEL     255
+#define MAX_DATA_B3        8
+#define MAX_DATA_ACK       MAX_DATA_B3
+#define MAX_MULTI_IE       6
+#define MAX_MSG_SIZE       256
+#define MAX_MSG_PARMS      10
+#define MAX_CPN_MASK_SIZE  16
+#define MAX_MSN_CONFIG     10
+#define EXT_CONTROLLER     0x80
+#define CODEC              0x01
+#define CODEC_PERMANENT    0x02
+#define ADV_VOICE          0x03
+#define MAX_CIP_TYPES      5  /* kind of CIP types for group optimization */
+#define C_IND_MASK_DWORDS  ((MAX_APPL+32) >> 5)
+
+
+#define FAX_CONNECT_INFO_BUFFER_SIZE  256
+#define NCPI_BUFFER_SIZE              256
+
+#define MAX_CHANNELS_PER_PLCI         8
+#define MAX_INTERNAL_COMMAND_LEVELS   4
+#define INTERNAL_REQ_BUFFER_SIZE      272
+
+#define INTERNAL_IND_BUFFER_SIZE      768
+
+#define DTMF_PARAMETER_BUFFER_SIZE    12
+#define ADV_VOICE_COEF_BUFFER_SIZE    50
+
+#define LI_PLCI_B_QUEUE_ENTRIES       256
+
+
+
+typedef struct _APPL APPL;
+typedef struct _PLCI PLCI;
+typedef struct _NCCI NCCI;
+typedef struct _DIVA_CAPI_ADAPTER DIVA_CAPI_ADAPTER;
+typedef struct _DATA_B3_DESC DATA_B3_DESC;
+typedef struct _DATA_ACK_DESC DATA_ACK_DESC;
+typedef struct manufacturer_profile_s MANUFACTURER_PROFILE;
+typedef struct fax_ncpi_s FAX_NCPI;
+typedef struct api_parse_s API_PARSE;
+typedef struct api_save_s API_SAVE;
+typedef struct msn_config_s MSN_CONFIG;
+typedef struct msn_config_max_s MSN_CONFIG_MAX;
+typedef struct msn_ld_s MSN_LD;
+
+struct manufacturer_profile_s {
+  dword private_options;
+  dword rtp_primary_payloads;
+  dword rtp_additional_payloads;
+};
+
+struct fax_ncpi_s {
+  word options;
+  word format;
+};
+
+struct msn_config_s {
+  byte msn[MAX_CPN_MASK_SIZE];
+};
+
+struct msn_config_max_s {
+  MSN_CONFIG    msn_conf[MAX_MSN_CONFIG];
+};
+
+struct msn_ld_s {
+  dword low;
+  dword high;
+};
+
+struct api_parse_s {
+  word          length;
+  byte   *    info;
+};
+
+struct api_save_s {
+  API_PARSE     parms[MAX_MSG_PARMS+1];
+  byte          info[MAX_MSG_SIZE];
+};
+
+struct _DATA_B3_DESC {
+  word          Handle;
+  word          Number;
+  word          Flags;
+  word          Length;
+  void   *    P;
+};
+
+struct _DATA_ACK_DESC {
+  word          Handle;
+  word          Number;
+};
+
+typedef void (* t_std_internal_command)(dword Id, PLCI   *plci, byte Rc);
+
+/************************************************************************/
+/* Don't forget to adapt dos.asm after changing the _APPL structure!!!! */
+struct _APPL {
+  word          Id;
+  word          NullCREnable;
+  word          CDEnable;
+  dword         S_Handle;
+
+
+
+
+
+
+  LIST_ENTRY    s_function;
+  dword         s_context;
+  word          s_count;
+  APPL *        s_next;
+  byte *        xbuffer_used;
+  void **       xbuffer_internal;
+  void **       xbuffer_ptr;
+
+
+
+
+
+
+  byte   *    queue;
+  word          queue_size;
+  word          queue_free;
+  word          queue_read;
+  word          queue_write;
+  word          queue_signal;
+  byte          msg_lost;
+  byte          appl_flags;
+  word          Number;
+
+  word          MaxBuffer;
+  byte          MaxNCCI;
+  byte          MaxNCCIData;
+  word          MaxDataLength;
+  word          NCCIDataFlowCtrlTimer;
+  byte   *    ReceiveBuffer;
+  word   *    DataNCCI;
+  word   *    DataFlags;
+};
+
+
+struct _PLCI {
+  ENTITY        Sig;
+  ENTITY        NL;
+  word          RNum;
+  word          RFlags;
+  BUFFERS       RData[2];
+  BUFFERS       XData[1];
+  BUFFERS       NData[2];
+
+  DIVA_CAPI_ADAPTER   *adapter;
+  APPL      *appl;
+  PLCI      *relatedPTYPLCI;
+  byte          Id;
+  byte          State;
+  byte          sig_req;
+  byte          nl_req;
+  byte          SuppState;
+  byte          channels;
+  byte          tel;
+  byte          B1_resource;
+  byte          B2_prot;
+  byte          B3_prot;
+
+  word          command;
+  word          m_command;
+  word          internal_command;
+  word          number;
+  word          req_in_start;
+  word          req_in;
+  word          req_out;
+  word          msg_in_write_pos;
+  word          msg_in_read_pos;
+  word          msg_in_wrap_pos;
+
+  void   *    data_sent_ptr;
+  byte          data_sent;
+  byte          send_disc;
+  byte          sig_global_req;
+  byte          sig_remove_id;
+  byte          nl_global_req;
+  byte          nl_remove_id;
+  byte          b_channel;
+  byte          adv_nl;
+  byte          manufacturer;
+  byte          call_dir;
+  byte          hook_state;
+  byte          spoofed_msg;
+  byte          ptyState;
+  byte          cr_enquiry;
+  word          hangup_flow_ctrl_timer;
+
+  word          ncci_ring_list;
+  byte          inc_dis_ncci_table[MAX_CHANNELS_PER_PLCI];
+  t_std_internal_command internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS];
+  dword         c_ind_mask_table[C_IND_MASK_DWORDS];
+  dword         group_optimization_mask_table[C_IND_MASK_DWORDS];
+  byte          RBuffer[200];
+  dword         msg_in_queue[MSG_IN_QUEUE_SIZE/sizeof(dword)];
+  API_SAVE      saved_msg;
+  API_SAVE      B_protocol;
+  byte          fax_connect_info_length;
+  byte          fax_connect_info_buffer[FAX_CONNECT_INFO_BUFFER_SIZE];
+  byte          fax_edata_ack_length;
+  word          nsf_control_bits;
+  byte          ncpi_state;
+  byte          ncpi_buffer[NCPI_BUFFER_SIZE];
+
+  byte          internal_req_buffer[INTERNAL_REQ_BUFFER_SIZE];
+  byte          internal_ind_buffer[INTERNAL_IND_BUFFER_SIZE + 3];
+  dword         requested_options_conn;
+  dword         requested_options;
+  word          B1_facilities;
+  API_SAVE   *adjust_b_parms_msg;
+  word          adjust_b_facilities;
+  word          adjust_b_command;
+  word          adjust_b_ncci;
+  word          adjust_b_mode;
+  word          adjust_b_state;
+  byte          adjust_b_restore;
+
+  byte          dtmf_rec_active;
+  word          dtmf_rec_pulse_ms;
+  word          dtmf_rec_pause_ms;
+  byte          dtmf_send_requests;
+  word          dtmf_send_pulse_ms;
+  word          dtmf_send_pause_ms;
+  word          dtmf_cmd;
+  word          dtmf_msg_number_queue[8];
+  byte          dtmf_parameter_length;
+  byte          dtmf_parameter_buffer[DTMF_PARAMETER_BUFFER_SIZE];
+
+
+  t_capidtmf_state capidtmf_state;
+
+
+  byte          li_bchannel_id;    /* BRI: 1..2, PRI: 1..32 */
+  byte          li_channel_bits;
+  byte          li_notify_update;
+  word          li_cmd;
+  word          li_write_command;
+  word          li_write_channel;
+  word          li_plci_b_write_pos;
+  word          li_plci_b_read_pos;
+  word          li_plci_b_req_pos;
+  dword         li_plci_b_queue[LI_PLCI_B_QUEUE_ENTRIES];
+
+
+  word          ec_cmd;
+  word          ec_idi_options;
+  word          ec_tail_length;
+
+
+  byte          tone_last_indication_code;
+
+  byte          vswitchstate;
+  byte          vsprot;
+  byte          vsprotdialect;
+  byte          notifiedcall; /* Flag if it is a spoofed call */
+
+  int           rx_dma_descriptor;
+  dword         rx_dma_magic;
+};
+
+
+struct _NCCI {
+  byte          data_out;
+  byte          data_pending;
+  byte          data_ack_out;
+  byte          data_ack_pending;
+  DATA_B3_DESC  DBuffer[MAX_DATA_B3];
+  DATA_ACK_DESC DataAck[MAX_DATA_ACK];
+};
+
+
+struct _DIVA_CAPI_ADAPTER {
+  IDI_CALL      request;
+  byte          Id;
+  byte          max_plci;
+  byte          max_listen;
+  byte          listen_active;
+  PLCI      *plci;
+  byte          ch_ncci[MAX_NL_CHANNEL+1];
+  byte          ncci_ch[MAX_NCCI+1];
+  byte          ncci_plci[MAX_NCCI+1];
+  byte          ncci_state[MAX_NCCI+1];
+  byte          ncci_next[MAX_NCCI+1];
+  NCCI          ncci[MAX_NCCI+1];
+
+  byte          ch_flow_control[MAX_NL_CHANNEL+1];  /* Used by XON protocol */
+  byte          ch_flow_control_pending;
+  byte          ch_flow_plci[MAX_NL_CHANNEL+1];
+  int           last_flow_control_ch;
+
+  dword         Info_Mask[MAX_APPL];
+  dword         CIP_Mask[MAX_APPL];
+
+  dword         Notification_Mask[MAX_APPL];
+  PLCI      *codec_listen[MAX_APPL];
+  dword         requested_options_table[MAX_APPL];
+  API_PROFILE   profile;
+  MANUFACTURER_PROFILE man_profile;
+  dword         manufacturer_features;
+
+  byte          AdvCodecFLAG;
+  PLCI      *AdvCodecPLCI;
+  PLCI      *AdvSignalPLCI;
+  APPL      *AdvSignalAppl;
+  byte          TelOAD[23];
+  byte          TelOSA[23];
+  byte          scom_appl_disable;
+  PLCI      *automatic_lawPLCI;
+  byte          automatic_law;
+  byte          u_law;
+
+  byte          adv_voice_coef_length;
+  byte          adv_voice_coef_buffer[ADV_VOICE_COEF_BUFFER_SIZE];
+
+  byte          li_pri;
+  byte          li_channels;
+  word          li_base;
+
+  byte adapter_disabled;
+  byte group_optimization_enabled; /* use application groups if enabled */
+  dword sdram_bar;
+  byte flag_dynamic_l1_down; /* for hunt groups:down layer 1 if no appl present*/
+  byte FlowControlIdTable[256];
+  byte FlowControlSkipTable[256];
+  void* os_card; /* pointer to associated OS dependent adapter structure */
+};
+
+
+/*------------------------------------------------------------------*/
+/* Application flags                                                */
+/*------------------------------------------------------------------*/
+
+#define APPL_FLAG_OLD_LI_SPEC           0x01
+#define APPL_FLAG_PRIV_EC_SPEC          0x02
+
+
+/*------------------------------------------------------------------*/
+/* API parameter definitions                                        */
+/*------------------------------------------------------------------*/
+
+#define X75_TTX         1       /* x.75 for ttx                     */
+#define TRF             2       /* transparent with hdlc framing    */
+#define TRF_IN          3       /* transparent with hdlc fr. inc.   */
+#define SDLC            4       /* sdlc, sna layer-2                */
+#define X75_BTX         5       /* x.75 for btx                     */
+#define LAPD            6       /* lapd (Q.921)                     */
+#define X25_L2          7       /* x.25 layer-2                     */
+#define V120_L2         8       /* V.120 layer-2 protocol           */
+#define V42_IN          9       /* V.42 layer-2 protocol, incomming */
+#define V42            10       /* V.42 layer-2 protocol            */
+#define MDM_ATP        11       /* AT Parser built in the L2        */
+#define X75_V42BIS     12       /* ISO7776 (X.75 SLP) modified to support V.42 bis compression */
+#define RTPL2_IN       13       /* RTP layer-2 protocol, incomming  */
+#define RTPL2          14       /* RTP layer-2 protocol             */
+#define V120_V42BIS    15       /* V.120 layer-2 protocol supporting V.42 bis compression */
+
+#define T70NL           1
+#define X25PLP          2
+#define T70NLX          3
+#define TRANSPARENT_NL  4
+#define ISO8208         5
+#define T30             6
+
+
+/*------------------------------------------------------------------*/
+/* FAX interface to IDI                                             */
+/*------------------------------------------------------------------*/
+
+#define CAPI_MAX_HEAD_LINE_SPACE        89
+#define CAPI_MAX_DATE_TIME_LENGTH       18
+
+#define T30_MAX_STATION_ID_LENGTH       20
+#define T30_MAX_SUBADDRESS_LENGTH       20
+#define T30_MAX_PASSWORD_LENGTH         20
+
+typedef struct t30_info_s T30_INFO;
+struct t30_info_s {
+  byte          code;
+  byte          rate_div_2400;
+  byte          resolution;
+  byte          data_format;
+  byte          pages_low;
+  byte          pages_high;
+  byte          operating_mode;
+  byte          control_bits_low;
+  byte          control_bits_high;
+  byte          feature_bits_low;
+  byte          feature_bits_high;
+  byte          recording_properties;
+  byte          universal_6;
+  byte          universal_7;
+  byte          station_id_len;
+  byte          head_line_len;
+  byte          station_id[T30_MAX_STATION_ID_LENGTH];
+/* byte          head_line[];      */
+/* byte          sub_sep_length;   */
+/* byte          sub_sep_field[];  */
+/* byte          pwd_length;       */
+/* byte          pwd_field[];      */
+/* byte          nsf_info_length;   */
+/* byte          nsf_info_field[];  */
+};
+
+
+#define T30_RESOLUTION_R8_0385          0x00
+#define T30_RESOLUTION_R8_0770_OR_200   0x01
+#define T30_RESOLUTION_R8_1540          0x02
+#define T30_RESOLUTION_R16_1540_OR_400  0x04
+#define T30_RESOLUTION_R4_0385_OR_100   0x08
+#define T30_RESOLUTION_300_300          0x10
+#define T30_RESOLUTION_INCH_BASED       0x40
+#define T30_RESOLUTION_METRIC_BASED     0x80
+
+#define T30_RECORDING_WIDTH_ISO_A4      0
+#define T30_RECORDING_WIDTH_ISO_B4      1
+#define T30_RECORDING_WIDTH_ISO_A3      2
+#define T30_RECORDING_WIDTH_COUNT       3
+
+#define T30_RECORDING_LENGTH_ISO_A4     0
+#define T30_RECORDING_LENGTH_ISO_B4     1
+#define T30_RECORDING_LENGTH_UNLIMITED  2
+#define T30_RECORDING_LENGTH_COUNT      3
+
+#define T30_MIN_SCANLINE_TIME_00_00_00  0
+#define T30_MIN_SCANLINE_TIME_05_05_05  1
+#define T30_MIN_SCANLINE_TIME_10_05_05  2
+#define T30_MIN_SCANLINE_TIME_10_10_10  3
+#define T30_MIN_SCANLINE_TIME_20_10_10  4
+#define T30_MIN_SCANLINE_TIME_20_20_20  5
+#define T30_MIN_SCANLINE_TIME_40_20_20  6
+#define T30_MIN_SCANLINE_TIME_40_40_40  7
+#define T30_MIN_SCANLINE_TIME_RES_8     8
+#define T30_MIN_SCANLINE_TIME_RES_9     9
+#define T30_MIN_SCANLINE_TIME_RES_10    10
+#define T30_MIN_SCANLINE_TIME_10_10_05  11
+#define T30_MIN_SCANLINE_TIME_20_10_05  12
+#define T30_MIN_SCANLINE_TIME_20_20_10  13
+#define T30_MIN_SCANLINE_TIME_40_20_10  14
+#define T30_MIN_SCANLINE_TIME_40_40_20  15
+#define T30_MIN_SCANLINE_TIME_COUNT     16
+
+#define T30_DATA_FORMAT_SFF             0
+#define T30_DATA_FORMAT_ASCII           1
+#define T30_DATA_FORMAT_NATIVE          2
+#define T30_DATA_FORMAT_COUNT           3
+
+
+#define T30_OPERATING_MODE_STANDARD     0
+#define T30_OPERATING_MODE_CLASS2       1
+#define T30_OPERATING_MODE_CLASS1       2
+#define T30_OPERATING_MODE_CAPI         3
+#define T30_OPERATING_MODE_CAPI_NEG     4
+#define T30_OPERATING_MODE_COUNT        5
+
+        /* EDATA transmit messages */
+#define EDATA_T30_DIS         0x01
+#define EDATA_T30_FTT         0x02
+#define EDATA_T30_MCF         0x03
+#define EDATA_T30_PARAMETERS  0x04
+
+        /* EDATA receive messages */
+#define EDATA_T30_DCS         0x81
+#define EDATA_T30_TRAIN_OK    0x82
+#define EDATA_T30_EOP         0x83
+#define EDATA_T30_MPS         0x84
+#define EDATA_T30_EOM         0x85
+#define EDATA_T30_DTC         0x86
+#define EDATA_T30_PAGE_END    0x87   /* Indicates end of page data. Reserved, but not implemented ! */
+#define EDATA_T30_EOP_CAPI    0x88
+
+
+#define T30_SUCCESS                        0
+#define T30_ERR_NO_DIS_RECEIVED            1
+#define T30_ERR_TIMEOUT_NO_RESPONSE        2
+#define T30_ERR_RETRY_NO_RESPONSE          3
+#define T30_ERR_TOO_MANY_REPEATS           4
+#define T30_ERR_UNEXPECTED_MESSAGE         5
+#define T30_ERR_UNEXPECTED_DCN             6
+#define T30_ERR_DTC_UNSUPPORTED            7
+#define T30_ERR_ALL_RATES_FAILED           8
+#define T30_ERR_TOO_MANY_TRAINS            9
+#define T30_ERR_RECEIVE_CORRUPTED          10
+#define T30_ERR_UNEXPECTED_DISC            11
+#define T30_ERR_APPLICATION_DISC           12
+#define T30_ERR_INCOMPATIBLE_DIS           13
+#define T30_ERR_INCOMPATIBLE_DCS           14
+#define T30_ERR_TIMEOUT_NO_COMMAND         15
+#define T30_ERR_RETRY_NO_COMMAND           16
+#define T30_ERR_TIMEOUT_COMMAND_TOO_LONG   17
+#define T30_ERR_TIMEOUT_RESPONSE_TOO_LONG  18
+#define T30_ERR_NOT_IDENTIFIED             19
+#define T30_ERR_SUPERVISORY_TIMEOUT        20
+#define T30_ERR_TOO_LONG_SCAN_LINE         21
+/* #define T30_ERR_RETRY_NO_PAGE_AFTER_MPS    22 */
+#define T30_ERR_RETRY_NO_PAGE_RECEIVED     23
+#define T30_ERR_RETRY_NO_DCS_AFTER_FTT     24
+#define T30_ERR_RETRY_NO_DCS_AFTER_EOM     25
+#define T30_ERR_RETRY_NO_DCS_AFTER_MPS     26
+#define T30_ERR_RETRY_NO_DCN_AFTER_MCF     27
+#define T30_ERR_RETRY_NO_DCN_AFTER_RTN     28
+#define T30_ERR_RETRY_NO_CFR               29
+#define T30_ERR_RETRY_NO_MCF_AFTER_EOP     30
+#define T30_ERR_RETRY_NO_MCF_AFTER_EOM     31
+#define T30_ERR_RETRY_NO_MCF_AFTER_MPS     32
+#define T30_ERR_SUB_SEP_UNSUPPORTED        33
+#define T30_ERR_PWD_UNSUPPORTED            34
+#define T30_ERR_SUB_SEP_PWD_UNSUPPORTED    35
+#define T30_ERR_INVALID_COMMAND_FRAME      36
+#define T30_ERR_UNSUPPORTED_PAGE_CODING    37
+#define T30_ERR_INVALID_PAGE_CODING        38
+#define T30_ERR_INCOMPATIBLE_PAGE_CONFIG   39
+#define T30_ERR_TIMEOUT_FROM_APPLICATION   40
+#define T30_ERR_V34FAX_NO_REACTION_ON_MARK 41
+#define T30_ERR_V34FAX_TRAINING_TIMEOUT    42
+#define T30_ERR_V34FAX_UNEXPECTED_V21      43
+#define T30_ERR_V34FAX_PRIMARY_CTS_ON      44
+#define T30_ERR_V34FAX_TURNAROUND_POLLING  45
+#define T30_ERR_V34FAX_V8_INCOMPATIBILITY  46
+
+
+#define T30_CONTROL_BIT_DISABLE_FINE       0x0001
+#define T30_CONTROL_BIT_ENABLE_ECM         0x0002
+#define T30_CONTROL_BIT_ECM_64_BYTES       0x0004
+#define T30_CONTROL_BIT_ENABLE_2D_CODING   0x0008
+#define T30_CONTROL_BIT_ENABLE_T6_CODING   0x0010
+#define T30_CONTROL_BIT_ENABLE_UNCOMPR     0x0020
+#define T30_CONTROL_BIT_ACCEPT_POLLING     0x0040
+#define T30_CONTROL_BIT_REQUEST_POLLING    0x0080
+#define T30_CONTROL_BIT_MORE_DOCUMENTS     0x0100
+#define T30_CONTROL_BIT_ACCEPT_SUBADDRESS  0x0200
+#define T30_CONTROL_BIT_ACCEPT_SEL_POLLING 0x0400
+#define T30_CONTROL_BIT_ACCEPT_PASSWORD    0x0800
+#define T30_CONTROL_BIT_ENABLE_V34FAX      0x1000
+#define T30_CONTROL_BIT_EARLY_CONNECT      0x2000
+
+#define T30_CONTROL_BIT_ALL_FEATURES  (T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING |   T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR |   T30_CONTROL_BIT_ENABLE_V34FAX)
+
+#define T30_FEATURE_BIT_FINE               0x0001
+#define T30_FEATURE_BIT_ECM                0x0002
+#define T30_FEATURE_BIT_ECM_64_BYTES       0x0004
+#define T30_FEATURE_BIT_2D_CODING          0x0008
+#define T30_FEATURE_BIT_T6_CODING          0x0010
+#define T30_FEATURE_BIT_UNCOMPR_ENABLED    0x0020
+#define T30_FEATURE_BIT_POLLING            0x0040
+#define T30_FEATURE_BIT_MORE_DOCUMENTS     0x0100
+#define T30_FEATURE_BIT_V34FAX             0x1000
+
+
+#define T30_NSF_CONTROL_BIT_ENABLE_NSF     0x0001
+#define T30_NSF_CONTROL_BIT_RAW_INFO       0x0002
+#define T30_NSF_CONTROL_BIT_NEGOTIATE_IND  0x0004
+#define T30_NSF_CONTROL_BIT_NEGOTIATE_RESP 0x0008
+
+#define T30_NSF_ELEMENT_NSF_FIF            0x00
+#define T30_NSF_ELEMENT_NSC_FIF            0x01
+#define T30_NSF_ELEMENT_NSS_FIF            0x02
+#define T30_NSF_ELEMENT_COMPANY_NAME       0x03
+
+
+/*------------------------------------------------------------------*/
+/* Analog modem definitions                                         */
+/*------------------------------------------------------------------*/
+
+typedef struct async_s ASYNC_FORMAT;
+struct async_s {
+  unsigned pe:    1;
+  unsigned parity:2;
+  unsigned spare: 2;
+  unsigned stp:   1;
+  unsigned ch_len:2;   /* 3th octett in CAI */
+};
+
+
+/*------------------------------------------------------------------*/
+/* PLCI/NCCI states                                                 */
+/*------------------------------------------------------------------*/
+
+#define IDLE                    0
+#define OUTG_CON_PENDING        1
+#define INC_CON_PENDING         2
+#define INC_CON_ALERT           3
+#define INC_CON_ACCEPT          4
+#define INC_ACT_PENDING         5
+#define LISTENING               6
+#define CONNECTED               7
+#define OUTG_DIS_PENDING        8
+#define INC_DIS_PENDING         9
+#define LOCAL_CONNECT           10
+#define INC_RES_PENDING         11
+#define OUTG_RES_PENDING        12
+#define SUSPENDING              13
+#define ADVANCED_VOICE_SIG      14
+#define ADVANCED_VOICE_NOSIG    15
+#define RESUMING                16
+#define INC_CON_CONNECTED_ALERT 17
+#define OUTG_REJ_PENDING        18
+
+
+/*------------------------------------------------------------------*/
+/* auxilliary states for supplementary services                     */
+/*------------------------------------------------------------------*/
+
+#define IDLE                0
+#define HOLD_REQUEST        1
+#define HOLD_INDICATE       2
+#define CALL_HELD           3
+#define RETRIEVE_REQUEST    4
+#define RETRIEVE_INDICATION 5
+
+/*------------------------------------------------------------------*/
+/* Capi IE + Msg types                                              */
+/*------------------------------------------------------------------*/
+#define ESC_CAUSE        0x800|CAU          /* Escape cause element */
+#define ESC_MSGTYPE      0x800|MSGTYPEIE    /* Escape message type  */
+#define ESC_CHI          0x800|CHI          /* Escape channel id    */
+#define ESC_LAW          0x800|BC           /* Escape law info      */
+#define ESC_CR           0x800|CRIE         /* Escape CallReference */
+#define ESC_PROFILE      0x800|PROFILEIE    /* Escape profile       */
+#define ESC_SSEXT        0x800|SSEXTIE      /* Escape Supplem. Serv.*/
+#define ESC_VSWITCH      0x800|VSWITCHIE    /* Escape VSwitch       */
+#define CST              0x14               /* Call State i.e.      */
+#define PI               0x1E               /* Progress Indicator   */
+#define NI               0x27               /* Notification Ind     */
+#define CONN_NR          0x4C               /* Connected Number     */
+#define CONG_RNR         0xBF               /* Congestion RNR       */
+#define CONG_RR          0xB0               /* Congestion RR        */
+#define RESERVED         0xFF               /* Res. for future use  */
+#define ON_BOARD_CODEC   0x02               /* external controller  */
+#define HANDSET          0x04               /* Codec+Handset(Pro11) */
+#define HOOK_SUPPORT     0x01               /* activate Hook signal */
+#define SCR              0x7a               /* unscreened number    */
+
+#define HOOK_OFF_REQ     0x9001             /* internal conn req    */
+#define HOOK_ON_REQ      0x9002             /* internal disc req    */
+#define SUSPEND_REQ      0x9003             /* internal susp req    */
+#define RESUME_REQ       0x9004             /* internal resume req  */
+#define USELAW_REQ       0x9005             /* internal law    req  */
+#define LISTEN_SIG_ASSIGN_PEND  0x9006
+#define PERM_LIST_REQ    0x900a             /* permanent conn DCE   */
+#define C_HOLD_REQ       0x9011
+#define C_RETRIEVE_REQ   0x9012
+#define C_NCR_FAC_REQ    0x9013
+#define PERM_COD_ASSIGN  0x9014
+#define PERM_COD_CALL    0x9015
+#define PERM_COD_HOOK    0x9016
+#define PERM_COD_CONN_PEND 0x9017           /* wait for connect_con */
+#define PTY_REQ_PEND     0x9018
+#define CD_REQ_PEND      0x9019
+#define CF_START_PEND    0x901a
+#define CF_STOP_PEND     0x901b
+#define ECT_REQ_PEND     0x901c
+#define GETSERV_REQ_PEND 0x901d
+#define BLOCK_PLCI       0x901e
+#define INTERR_NUMBERS_REQ_PEND         0x901f
+#define INTERR_DIVERSION_REQ_PEND       0x9020
+#define MWI_ACTIVATE_REQ_PEND           0x9021
+#define MWI_DEACTIVATE_REQ_PEND         0x9022
+#define SSEXT_REQ_COMMAND               0x9023
+#define SSEXT_NC_REQ_COMMAND            0x9024
+#define START_L1_SIG_ASSIGN_PEND        0x9025
+#define REM_L1_SIG_ASSIGN_PEND          0x9026
+#define CONF_BEGIN_REQ_PEND             0x9027
+#define CONF_ADD_REQ_PEND               0x9028
+#define CONF_SPLIT_REQ_PEND             0x9029
+#define CONF_DROP_REQ_PEND              0x902a
+#define CONF_ISOLATE_REQ_PEND           0x902b
+#define CONF_REATTACH_REQ_PEND          0x902c
+#define VSWITCH_REQ_PEND                0x902d
+#define GET_MWI_STATE                   0x902e
+#define CCBS_REQUEST_REQ_PEND           0x902f
+#define CCBS_DEACTIVATE_REQ_PEND        0x9030
+#define CCBS_INTERROGATE_REQ_PEND       0x9031
+
+#define NO_INTERNAL_COMMAND             0
+#define DTMF_COMMAND_1                  1
+#define DTMF_COMMAND_2                  2
+#define DTMF_COMMAND_3                  3
+#define MIXER_COMMAND_1                 4
+#define MIXER_COMMAND_2                 5
+#define MIXER_COMMAND_3                 6
+#define ADV_VOICE_COMMAND_CONNECT_1     7
+#define ADV_VOICE_COMMAND_CONNECT_2     8
+#define ADV_VOICE_COMMAND_CONNECT_3     9
+#define ADV_VOICE_COMMAND_DISCONNECT_1  10
+#define ADV_VOICE_COMMAND_DISCONNECT_2  11
+#define ADV_VOICE_COMMAND_DISCONNECT_3  12
+#define ADJUST_B_RESTORE_1              13
+#define ADJUST_B_RESTORE_2              14
+#define RESET_B3_COMMAND_1              15
+#define SELECT_B_COMMAND_1              16
+#define FAX_CONNECT_INFO_COMMAND_1      17
+#define FAX_CONNECT_INFO_COMMAND_2      18
+#define FAX_ADJUST_B23_COMMAND_1        19
+#define FAX_ADJUST_B23_COMMAND_2        20
+#define EC_COMMAND_1                    21
+#define EC_COMMAND_2                    22
+#define EC_COMMAND_3                    23
+#define RTP_CONNECT_B3_REQ_COMMAND_1    24
+#define RTP_CONNECT_B3_REQ_COMMAND_2    25
+#define RTP_CONNECT_B3_REQ_COMMAND_3    26
+#define RTP_CONNECT_B3_RES_COMMAND_1    27
+#define RTP_CONNECT_B3_RES_COMMAND_2    28
+#define RTP_CONNECT_B3_RES_COMMAND_3    29
+#define HOLD_SAVE_COMMAND_1             30
+#define RETRIEVE_RESTORE_COMMAND_1      31
+#define FAX_DISCONNECT_COMMAND_1        32
+#define FAX_DISCONNECT_COMMAND_2        33
+#define FAX_DISCONNECT_COMMAND_3        34
+#define FAX_EDATA_ACK_COMMAND_1         35
+#define FAX_EDATA_ACK_COMMAND_2         36
+#define FAX_CONNECT_ACK_COMMAND_1       37
+#define FAX_CONNECT_ACK_COMMAND_2       38
+#define STD_INTERNAL_COMMAND_COUNT      39
+
+#define UID              0x2d               /* User Id for Mgmt      */
+
+#define CALL_DIR_OUT             0x01       /* call direction of initial call */
+#define CALL_DIR_IN              0x02
+#define CALL_DIR_ORIGINATE       0x04       /* DTE/DCE direction according to */
+#define CALL_DIR_ANSWER          0x08       /*   state of B-Channel Operation */
+#define CALL_DIR_FORCE_OUTG_NL   0x10       /* for RESET_B3 reconnect, after DISC_B3... */
+
+#define AWAITING_MANUF_CON 0x80             /* command spoofing flags */
+#define SPOOFING_REQUIRED  0xff
+#define AWAITING_SELECT_B  0xef
+
+/*------------------------------------------------------------------*/
+/* B_CTRL / DSP_CTRL                                                */
+/*------------------------------------------------------------------*/
+
+#define DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS     0x01
+#define DSP_CTRL_SET_BCHANNEL_PASSIVATION_BRI   0x02
+#define DSP_CTRL_SET_DTMF_PARAMETERS            0x03
+
+#define MANUFACTURER_FEATURE_SLAVE_CODEC          0x00000001L
+#define MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS   0x00000002L
+#define MANUFACTURER_FEATURE_HARDDTMF             0x00000004L
+#define MANUFACTURER_FEATURE_SOFTDTMF_SEND        0x00000008L
+#define MANUFACTURER_FEATURE_DTMF_PARAMETERS      0x00000010L
+#define MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE     0x00000020L
+#define MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD      0x00000040L
+#define MANUFACTURER_FEATURE_V18                  0x00000080L
+#define MANUFACTURER_FEATURE_MIXER_CH_CH          0x00000100L
+#define MANUFACTURER_FEATURE_MIXER_CH_PC          0x00000200L
+#define MANUFACTURER_FEATURE_MIXER_PC_CH          0x00000400L
+#define MANUFACTURER_FEATURE_MIXER_PC_PC          0x00000800L
+#define MANUFACTURER_FEATURE_ECHO_CANCELLER       0x00001000L
+#define MANUFACTURER_FEATURE_RTP                  0x00002000L
+#define MANUFACTURER_FEATURE_T38                  0x00004000L
+#define MANUFACTURER_FEATURE_TRANSP_DELIVERY_CONF 0x00008000L
+#define MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL  0x00010000L
+#define MANUFACTURER_FEATURE_OOB_CHANNEL          0x00020000L
+#define MANUFACTURER_FEATURE_IN_BAND_CHANNEL      0x00040000L
+#define MANUFACTURER_FEATURE_IN_BAND_FEATURE      0x00080000L
+#define MANUFACTURER_FEATURE_PIAFS                0x00100000L
+#define MANUFACTURER_FEATURE_DTMF_TONE            0x00200000L
+#define MANUFACTURER_FEATURE_FAX_PAPER_FORMATS    0x00400000L
+#define MANUFACTURER_FEATURE_OK_FC_LABEL          0x00800000L
+#define MANUFACTURER_FEATURE_VOWN                 0x01000000L
+#define MANUFACTURER_FEATURE_XCONNECT             0x02000000L
+#define MANUFACTURER_FEATURE_DMACONNECT           0x04000000L
+#define MANUFACTURER_FEATURE_AUDIO_TAP            0x08000000L
+#define MANUFACTURER_FEATURE_FAX_NONSTANDARD      0x10000000L
+
+/*------------------------------------------------------------------*/
+/* DTMF interface to IDI                                            */
+/*------------------------------------------------------------------*/
+
+
+#define DTMF_DIGIT_TONE_LOW_GROUP_697_HZ        0x00
+#define DTMF_DIGIT_TONE_LOW_GROUP_770_HZ        0x01
+#define DTMF_DIGIT_TONE_LOW_GROUP_852_HZ        0x02
+#define DTMF_DIGIT_TONE_LOW_GROUP_941_HZ        0x03
+#define DTMF_DIGIT_TONE_LOW_GROUP_MASK          0x03
+#define DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ      0x00
+#define DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ      0x04
+#define DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ      0x08
+#define DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ      0x0c
+#define DTMF_DIGIT_TONE_HIGH_GROUP_MASK         0x0c
+#define DTMF_DIGIT_TONE_CODE_0                  0x07
+#define DTMF_DIGIT_TONE_CODE_1                  0x00
+#define DTMF_DIGIT_TONE_CODE_2                  0x04
+#define DTMF_DIGIT_TONE_CODE_3                  0x08
+#define DTMF_DIGIT_TONE_CODE_4                  0x01
+#define DTMF_DIGIT_TONE_CODE_5                  0x05
+#define DTMF_DIGIT_TONE_CODE_6                  0x09
+#define DTMF_DIGIT_TONE_CODE_7                  0x02
+#define DTMF_DIGIT_TONE_CODE_8                  0x06
+#define DTMF_DIGIT_TONE_CODE_9                  0x0a
+#define DTMF_DIGIT_TONE_CODE_STAR               0x03
+#define DTMF_DIGIT_TONE_CODE_HASHMARK           0x0b
+#define DTMF_DIGIT_TONE_CODE_A                  0x0c
+#define DTMF_DIGIT_TONE_CODE_B                  0x0d
+#define DTMF_DIGIT_TONE_CODE_C                  0x0e
+#define DTMF_DIGIT_TONE_CODE_D                  0x0f
+
+#define DTMF_UDATA_REQUEST_SEND_DIGITS            16
+#define DTMF_UDATA_REQUEST_ENABLE_RECEIVER        17
+#define DTMF_UDATA_REQUEST_DISABLE_RECEIVER       18
+#define DTMF_UDATA_INDICATION_DIGITS_SENT         16
+#define DTMF_UDATA_INDICATION_DIGITS_RECEIVED     17
+#define DTMF_UDATA_INDICATION_MODEM_CALLING_TONE  18
+#define DTMF_UDATA_INDICATION_FAX_CALLING_TONE    19
+#define DTMF_UDATA_INDICATION_ANSWER_TONE         20
+
+#define UDATA_REQUEST_MIXER_TAP_DATA        27
+#define UDATA_INDICATION_MIXER_TAP_DATA     27
+
+#define DTMF_LISTEN_ACTIVE_FLAG        0x01
+#define DTMF_SEND_DIGIT_FLAG           0x01
+
+
+/*------------------------------------------------------------------*/
+/* Mixer interface to IDI                                           */
+/*------------------------------------------------------------------*/
+
+
+#define LI2_FLAG_PCCONNECT_A_B 0x40000000
+#define LI2_FLAG_PCCONNECT_B_A 0x80000000
+
+#define MIXER_BCHANNELS_BRI    2
+#define MIXER_IC_CHANNELS_BRI  MIXER_BCHANNELS_BRI
+#define MIXER_IC_CHANNEL_BASE  MIXER_BCHANNELS_BRI
+#define MIXER_CHANNELS_BRI     (MIXER_BCHANNELS_BRI + MIXER_IC_CHANNELS_BRI)
+#define MIXER_CHANNELS_PRI     32
+
+typedef struct li_config_s LI_CONFIG;
+
+struct xconnect_card_address_s {
+  dword low;
+  dword high;
+};
+
+struct xconnect_transfer_address_s {
+  struct xconnect_card_address_s card_address;
+  dword offset;
+};
+
+struct li_config_s {
+  DIVA_CAPI_ADAPTER   *adapter;
+  PLCI   *plci;
+  struct xconnect_transfer_address_s send_b;
+  struct xconnect_transfer_address_s send_pc;
+  byte   *flag_table;  /* dword aligned and sized */
+  byte   *coef_table;  /* dword aligned and sized */
+  byte channel;
+  byte curchnl;
+  byte chflags;
+};
+
+extern LI_CONFIG   *li_config_table;
+extern word li_total_channels;
+
+#define LI_CHANNEL_INVOLVED        0x01
+#define LI_CHANNEL_ACTIVE          0x02
+#define LI_CHANNEL_TX_DATA         0x04
+#define LI_CHANNEL_RX_DATA         0x08
+#define LI_CHANNEL_CONFERENCE      0x10
+#define LI_CHANNEL_ADDRESSES_SET   0x80
+
+#define LI_CHFLAG_MONITOR          0x01
+#define LI_CHFLAG_MIX              0x02
+#define LI_CHFLAG_LOOP             0x04
+
+#define LI_FLAG_INTERCONNECT       0x01
+#define LI_FLAG_MONITOR            0x02
+#define LI_FLAG_MIX                0x04
+#define LI_FLAG_PCCONNECT          0x08
+#define LI_FLAG_CONFERENCE         0x10
+#define LI_FLAG_ANNOUNCEMENT       0x20
+
+#define LI_COEF_CH_CH              0x01
+#define LI_COEF_CH_PC              0x02
+#define LI_COEF_PC_CH              0x04
+#define LI_COEF_PC_PC              0x08
+#define LI_COEF_CH_CH_SET          0x10
+#define LI_COEF_CH_PC_SET          0x20
+#define LI_COEF_PC_CH_SET          0x40
+#define LI_COEF_PC_PC_SET          0x80
+
+#define LI_REQ_SILENT_UPDATE       0xffff
+
+#define LI_PLCI_B_LAST_FLAG        ((dword) 0x80000000L)
+#define LI_PLCI_B_DISC_FLAG        ((dword) 0x40000000L)
+#define LI_PLCI_B_SKIP_FLAG        ((dword) 0x20000000L)
+#define LI_PLCI_B_FLAG_MASK        ((dword) 0xe0000000L)
+
+#define UDATA_REQUEST_SET_MIXER_COEFS_BRI       24
+#define UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC  25
+#define UDATA_REQUEST_SET_MIXER_COEFS_PRI_ASYN  26
+#define UDATA_INDICATION_MIXER_COEFS_SET        24
+
+#define MIXER_FEATURE_ENABLE_TX_DATA        0x0001
+#define MIXER_FEATURE_ENABLE_RX_DATA        0x0002
+
+#define MIXER_COEF_LINE_CHANNEL_MASK        0x1f
+#define MIXER_COEF_LINE_FROM_PC_FLAG        0x20
+#define MIXER_COEF_LINE_TO_PC_FLAG          0x40
+#define MIXER_COEF_LINE_ROW_FLAG            0x80
+
+#define UDATA_REQUEST_XCONNECT_FROM         28
+#define UDATA_INDICATION_XCONNECT_FROM      28
+#define UDATA_REQUEST_XCONNECT_TO           29
+#define UDATA_INDICATION_XCONNECT_TO        29
+
+#define XCONNECT_CHANNEL_PORT_B             0x0000
+#define XCONNECT_CHANNEL_PORT_PC            0x8000
+#define XCONNECT_CHANNEL_PORT_MASK          0x8000
+#define XCONNECT_CHANNEL_NUMBER_MASK        0x7fff
+#define XCONNECT_CHANNEL_PORT_COUNT         2
+
+#define XCONNECT_SUCCESS           0x0000
+#define XCONNECT_ERROR             0x0001
+
+
+/*------------------------------------------------------------------*/
+/* Echo canceller interface to IDI                                  */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_ECHO_CANCELLER         0
+
+#define PRIV_SELECTOR_ECHO_CANCELLER   255
+
+#define EC_ENABLE_OPERATION            1
+#define EC_DISABLE_OPERATION           2
+#define EC_FREEZE_COEFFICIENTS         3
+#define EC_RESUME_COEFFICIENT_UPDATE   4
+#define EC_RESET_COEFFICIENTS          5
+
+#define EC_DISABLE_NON_LINEAR_PROCESSING     0x0001
+#define EC_DO_NOT_REQUIRE_REVERSALS          0x0002
+#define EC_DETECT_DISABLE_TONE               0x0004
+
+#define EC_SUCCESS                           0
+#define EC_UNSUPPORTED_OPERATION             1
+
+#define EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ   1
+#define EC_BYPASS_DUE_TO_REVERSED_2100HZ     2
+#define EC_BYPASS_RELEASED                   3
+
+#define DSP_CTRL_SET_LEC_PARAMETERS          0x05
+
+#define LEC_ENABLE_ECHO_CANCELLER            0x0001
+#define LEC_ENABLE_2100HZ_DETECTOR           0x0002
+#define LEC_REQUIRE_2100HZ_REVERSALS         0x0004
+#define LEC_MANUAL_DISABLE                   0x0008
+#define LEC_ENABLE_NONLINEAR_PROCESSING      0x0010
+#define LEC_FREEZE_COEFFICIENTS              0x0020
+#define LEC_RESET_COEFFICIENTS               0x8000
+
+#define LEC_MAX_SUPPORTED_TAIL_LENGTH        32
+
+#define LEC_UDATA_INDICATION_DISABLE_DETECT  9
+
+#define LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ  0x00
+#define LEC_DISABLE_TYPE_REVERSED_2100HZ     0x01
+#define LEC_DISABLE_RELEASED                 0x02
+
+
+/*------------------------------------------------------------------*/
+/* RTP interface to IDI                                             */
+/*------------------------------------------------------------------*/
+
+
+#define B1_RTP                  31
+#define B2_RTP                  31
+#define B3_RTP                  31
+
+#define PRIVATE_RTP                    1
+
+#define RTP_PRIM_PAYLOAD_PCMU_8000     0
+#define RTP_PRIM_PAYLOAD_1016_8000     1
+#define RTP_PRIM_PAYLOAD_G726_32_8000  2
+#define RTP_PRIM_PAYLOAD_GSM_8000      3
+#define RTP_PRIM_PAYLOAD_G723_8000     4
+#define RTP_PRIM_PAYLOAD_DVI4_8000     5
+#define RTP_PRIM_PAYLOAD_DVI4_16000    6
+#define RTP_PRIM_PAYLOAD_LPC_8000      7
+#define RTP_PRIM_PAYLOAD_PCMA_8000     8
+#define RTP_PRIM_PAYLOAD_G722_16000    9
+#define RTP_PRIM_PAYLOAD_QCELP_8000    12
+#define RTP_PRIM_PAYLOAD_G728_8000     14
+#define RTP_PRIM_PAYLOAD_G729_8000     18
+#define RTP_PRIM_PAYLOAD_GSM_HR_8000   30
+#define RTP_PRIM_PAYLOAD_GSM_EFR_8000  31
+
+#define RTP_ADD_PAYLOAD_BASE           32
+#define RTP_ADD_PAYLOAD_RED            32
+#define RTP_ADD_PAYLOAD_CN_8000        33
+#define RTP_ADD_PAYLOAD_DTMF           34
+
+#define RTP_SUCCESS                         0
+#define RTP_ERR_SSRC_OR_PAYLOAD_CHANGE      1
+
+#define UDATA_REQUEST_RTP_RECONFIGURE       64
+#define UDATA_INDICATION_RTP_CHANGE         65
+#define BUDATA_REQUEST_QUERY_RTCP_REPORT    1
+#define BUDATA_INDICATION_RTCP_REPORT       1
+
+#define RTP_CONNECT_OPTION_DISC_ON_SSRC_CHANGE    0x00000001L
+#define RTP_CONNECT_OPTION_DISC_ON_PT_CHANGE      0x00000002L
+#define RTP_CONNECT_OPTION_DISC_ON_UNKNOWN_PT     0x00000004L
+#define RTP_CONNECT_OPTION_NO_SILENCE_TRANSMIT    0x00010000L
+
+#define RTP_PAYLOAD_OPTION_VOICE_ACTIVITY_DETECT  0x0001
+#define RTP_PAYLOAD_OPTION_DISABLE_POST_FILTER    0x0002
+#define RTP_PAYLOAD_OPTION_G723_LOW_CODING_RATE   0x0100
+
+#define RTP_PACKET_FILTER_IGNORE_UNKNOWN_SSRC     0x00000001L
+
+#define RTP_CHANGE_FLAG_SSRC_CHANGE               0x00000001L
+#define RTP_CHANGE_FLAG_PAYLOAD_TYPE_CHANGE       0x00000002L
+#define RTP_CHANGE_FLAG_UNKNOWN_PAYLOAD_TYPE      0x00000004L
+
+
+/*------------------------------------------------------------------*/
+/* T.38 interface to IDI                                            */
+/*------------------------------------------------------------------*/
+
+
+#define B1_T38                  30
+#define B2_T38                  30
+#define B3_T38                  30
+
+#define PRIVATE_T38                    2
+
+
+/*------------------------------------------------------------------*/
+/* PIAFS interface to IDI                                            */
+/*------------------------------------------------------------------*/
+
+
+#define B1_PIAFS                29
+#define B2_PIAFS                29
+
+#define PRIVATE_PIAFS           29 
+
+/*
+  B2 configuration for PIAFS:
++---------------------+------+-----------------------------------------+
+| PIAFS Protocol      | byte | Bit 1 - Protocol Speed                  |
+| Speed configuration |      |         0 - 32K                         |
+|                     |      |         1 - 64K (default)               |
+|                     |      | Bit 2 - Variable Protocol Speed         |
+|                     |      |         0 - Speed is fix                |
+|                     |      |         1 - Speed is variable (default) |
++---------------------+------+-----------------------------------------+
+| Direction           | word | Enable compression/decompression for    |
+|                     |      | 0: All direction                        |
+|                     |      | 1: disable outgoing data                |
+|                     |      | 2: disable incomming data               |
+|                     |      | 3: disable both direction (default)     |
++---------------------+------+-----------------------------------------+
+| Number of code      | word | Parameter P1 of V.42bis in accordance   |
+| words               |      | with V.42bis                            |
++---------------------+------+-----------------------------------------+
+| Maximum String      | word | Parameter P2 of V.42bis in accordance   |
+| Length              |      | with V.42bis                            |
++---------------------+------+-----------------------------------------+
+| control (UDATA)     | byte | enable PIAFS control communication      |
+| abilities           |      |                                         |
++---------------------+------+-----------------------------------------+
+*/
+#define PIAFS_UDATA_ABILITIES  0x80
+
+/*------------------------------------------------------------------*/
+/* FAX SUB/SEP/PWD extension                                        */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_FAX_SUB_SEP_PWD        3
+
+
+
+/*------------------------------------------------------------------*/
+/* V.18 extension                                                   */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_V18                    4
+
+
+
+/*------------------------------------------------------------------*/
+/* DTMF TONE extension                                              */
+/*------------------------------------------------------------------*/
+
+
+#define DTMF_GET_SUPPORTED_DETECT_CODES  0xf8
+#define DTMF_GET_SUPPORTED_SEND_CODES    0xf9
+#define DTMF_LISTEN_TONE_START           0xfa
+#define DTMF_LISTEN_TONE_STOP            0xfb
+#define DTMF_SEND_TONE                   0xfc
+#define DTMF_LISTEN_MF_START             0xfd
+#define DTMF_LISTEN_MF_STOP              0xfe
+#define DTMF_SEND_MF                     0xff
+
+#define DTMF_MF_DIGIT_TONE_CODE_1               0x10
+#define DTMF_MF_DIGIT_TONE_CODE_2               0x11
+#define DTMF_MF_DIGIT_TONE_CODE_3               0x12
+#define DTMF_MF_DIGIT_TONE_CODE_4               0x13
+#define DTMF_MF_DIGIT_TONE_CODE_5               0x14
+#define DTMF_MF_DIGIT_TONE_CODE_6               0x15
+#define DTMF_MF_DIGIT_TONE_CODE_7               0x16
+#define DTMF_MF_DIGIT_TONE_CODE_8               0x17
+#define DTMF_MF_DIGIT_TONE_CODE_9               0x18
+#define DTMF_MF_DIGIT_TONE_CODE_0               0x19
+#define DTMF_MF_DIGIT_TONE_CODE_K1              0x1a
+#define DTMF_MF_DIGIT_TONE_CODE_K2              0x1b
+#define DTMF_MF_DIGIT_TONE_CODE_KP              0x1c
+#define DTMF_MF_DIGIT_TONE_CODE_S1              0x1d
+#define DTMF_MF_DIGIT_TONE_CODE_ST              0x1e
+
+#define DTMF_DIGIT_CODE_COUNT                   16
+#define DTMF_MF_DIGIT_CODE_BASE                 DSP_DTMF_DIGIT_CODE_COUNT
+#define DTMF_MF_DIGIT_CODE_COUNT                15
+#define DTMF_TOTAL_DIGIT_CODE_COUNT             (DSP_MF_DIGIT_CODE_BASE + DSP_MF_DIGIT_CODE_COUNT)
+
+#define DTMF_TONE_DIGIT_BASE                    0x80
+
+#define DTMF_SIGNAL_NO_TONE                     (DTMF_TONE_DIGIT_BASE + 0)
+#define DTMF_SIGNAL_UNIDENTIFIED_TONE           (DTMF_TONE_DIGIT_BASE + 1)
+
+#define DTMF_SIGNAL_DIAL_TONE                   (DTMF_TONE_DIGIT_BASE + 2)
+#define DTMF_SIGNAL_PABX_INTERNAL_DIAL_TONE     (DTMF_TONE_DIGIT_BASE + 3)
+#define DTMF_SIGNAL_SPECIAL_DIAL_TONE           (DTMF_TONE_DIGIT_BASE + 4)   /* stutter dial tone */
+#define DTMF_SIGNAL_SECOND_DIAL_TONE            (DTMF_TONE_DIGIT_BASE + 5)
+#define DTMF_SIGNAL_RINGING_TONE                (DTMF_TONE_DIGIT_BASE + 6)
+#define DTMF_SIGNAL_SPECIAL_RINGING_TONE        (DTMF_TONE_DIGIT_BASE + 7)
+#define DTMF_SIGNAL_BUSY_TONE                   (DTMF_TONE_DIGIT_BASE + 8)
+#define DTMF_SIGNAL_CONGESTION_TONE             (DTMF_TONE_DIGIT_BASE + 9)   /* reorder tone */
+#define DTMF_SIGNAL_SPECIAL_INFORMATION_TONE    (DTMF_TONE_DIGIT_BASE + 10)
+#define DTMF_SIGNAL_COMFORT_TONE                (DTMF_TONE_DIGIT_BASE + 11)
+#define DTMF_SIGNAL_HOLD_TONE                   (DTMF_TONE_DIGIT_BASE + 12)
+#define DTMF_SIGNAL_RECORD_TONE                 (DTMF_TONE_DIGIT_BASE + 13)
+#define DTMF_SIGNAL_CALLER_WAITING_TONE         (DTMF_TONE_DIGIT_BASE + 14)
+#define DTMF_SIGNAL_CALL_WAITING_TONE           (DTMF_TONE_DIGIT_BASE + 15)
+#define DTMF_SIGNAL_PAY_TONE                    (DTMF_TONE_DIGIT_BASE + 16)
+#define DTMF_SIGNAL_POSITIVE_INDICATION_TONE    (DTMF_TONE_DIGIT_BASE + 17)
+#define DTMF_SIGNAL_NEGATIVE_INDICATION_TONE    (DTMF_TONE_DIGIT_BASE + 18)
+#define DTMF_SIGNAL_WARNING_TONE                (DTMF_TONE_DIGIT_BASE + 19)
+#define DTMF_SIGNAL_INTRUSION_TONE              (DTMF_TONE_DIGIT_BASE + 20)
+#define DTMF_SIGNAL_CALLING_CARD_SERVICE_TONE   (DTMF_TONE_DIGIT_BASE + 21)
+#define DTMF_SIGNAL_PAYPHONE_RECOGNITION_TONE   (DTMF_TONE_DIGIT_BASE + 22)
+#define DTMF_SIGNAL_CPE_ALERTING_SIGNAL         (DTMF_TONE_DIGIT_BASE + 23)
+#define DTMF_SIGNAL_OFF_HOOK_WARNING_TONE       (DTMF_TONE_DIGIT_BASE + 24)
+
+#define DTMF_SIGNAL_INTERCEPT_TONE              (DTMF_TONE_DIGIT_BASE + 63)
+
+#define DTMF_SIGNAL_MODEM_CALLING_TONE          (DTMF_TONE_DIGIT_BASE + 64)
+#define DTMF_SIGNAL_FAX_CALLING_TONE            (DTMF_TONE_DIGIT_BASE + 65)
+#define DTMF_SIGNAL_ANSWER_TONE                 (DTMF_TONE_DIGIT_BASE + 66)
+#define DTMF_SIGNAL_REVERSED_ANSWER_TONE        (DTMF_TONE_DIGIT_BASE + 67)
+#define DTMF_SIGNAL_ANSAM_TONE                  (DTMF_TONE_DIGIT_BASE + 68)
+#define DTMF_SIGNAL_REVERSED_ANSAM_TONE         (DTMF_TONE_DIGIT_BASE + 69)
+#define DTMF_SIGNAL_BELL103_ANSWER_TONE         (DTMF_TONE_DIGIT_BASE + 70)
+#define DTMF_SIGNAL_FAX_FLAGS                   (DTMF_TONE_DIGIT_BASE + 71)
+#define DTMF_SIGNAL_G2_FAX_GROUP_ID             (DTMF_TONE_DIGIT_BASE + 72)
+#define DTMF_SIGNAL_HUMAN_SPEECH                (DTMF_TONE_DIGIT_BASE + 73)
+#define DTMF_SIGNAL_ANSWERING_MACHINE_390       (DTMF_TONE_DIGIT_BASE + 74)
+
+#define DTMF_MF_LISTEN_ACTIVE_FLAG     0x02
+#define DTMF_SEND_MF_FLAG              0x02
+#define DTMF_TONE_LISTEN_ACTIVE_FLAG   0x04
+#define DTMF_SEND_TONE_FLAG            0x04
+
+#define PRIVATE_DTMF_TONE              5
+
+
+/*------------------------------------------------------------------*/
+/* FAX paper format extension                                       */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_FAX_PAPER_FORMATS      6
+
+
+
+/*------------------------------------------------------------------*/
+/* V.OWN extension                                                  */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_VOWN                   7
+
+
+
+/*------------------------------------------------------------------*/
+/* FAX non-standard facilities extension                            */
+/*------------------------------------------------------------------*/
+
+
+#define PRIVATE_FAX_NONSTANDARD        8
+
+
+
+/*------------------------------------------------------------------*/
+/* Advanced voice                                                   */
+/*------------------------------------------------------------------*/
+
+#define ADV_VOICE_WRITE_ACTIVATION    0
+#define ADV_VOICE_WRITE_DEACTIVATION  1
+#define ADV_VOICE_WRITE_UPDATE        2
+
+#define ADV_VOICE_OLD_COEF_COUNT    6
+#define ADV_VOICE_NEW_COEF_BASE     (ADV_VOICE_OLD_COEF_COUNT * sizeof(word))
+
+/*------------------------------------------------------------------*/
+/* B1 resource switching                                            */
+/*------------------------------------------------------------------*/
+
+#define B1_FACILITY_LOCAL  0x01
+#define B1_FACILITY_MIXER  0x02
+#define B1_FACILITY_DTMFX  0x04
+#define B1_FACILITY_DTMFR  0x08
+#define B1_FACILITY_VOICE  0x10
+#define B1_FACILITY_EC     0x20
+
+#define ADJUST_B_MODE_SAVE          0x0001
+#define ADJUST_B_MODE_REMOVE_L23    0x0002
+#define ADJUST_B_MODE_SWITCH_L1     0x0004
+#define ADJUST_B_MODE_NO_RESOURCE   0x0008
+#define ADJUST_B_MODE_ASSIGN_L23    0x0010
+#define ADJUST_B_MODE_USER_CONNECT  0x0020
+#define ADJUST_B_MODE_CONNECT       0x0040
+#define ADJUST_B_MODE_RESTORE       0x0080
+
+#define ADJUST_B_START                     0
+#define ADJUST_B_SAVE_MIXER_1              1
+#define ADJUST_B_SAVE_DTMF_1               2
+#define ADJUST_B_REMOVE_L23_1              3
+#define ADJUST_B_REMOVE_L23_2              4
+#define ADJUST_B_SAVE_EC_1                 5
+#define ADJUST_B_SAVE_DTMF_PARAMETER_1     6
+#define ADJUST_B_SAVE_VOICE_1              7
+#define ADJUST_B_SWITCH_L1_1               8
+#define ADJUST_B_SWITCH_L1_2               9
+#define ADJUST_B_RESTORE_VOICE_1           10
+#define ADJUST_B_RESTORE_VOICE_2           11
+#define ADJUST_B_RESTORE_DTMF_PARAMETER_1  12
+#define ADJUST_B_RESTORE_DTMF_PARAMETER_2  13
+#define ADJUST_B_RESTORE_EC_1              14
+#define ADJUST_B_RESTORE_EC_2              15
+#define ADJUST_B_ASSIGN_L23_1              16
+#define ADJUST_B_ASSIGN_L23_2              17
+#define ADJUST_B_CONNECT_1                 18
+#define ADJUST_B_CONNECT_2                 19
+#define ADJUST_B_CONNECT_3                 20
+#define ADJUST_B_CONNECT_4                 21
+#define ADJUST_B_RESTORE_DTMF_1            22
+#define ADJUST_B_RESTORE_DTMF_2            23
+#define ADJUST_B_RESTORE_MIXER_1           24
+#define ADJUST_B_RESTORE_MIXER_2           25
+#define ADJUST_B_RESTORE_MIXER_3           26
+#define ADJUST_B_RESTORE_MIXER_4           27
+#define ADJUST_B_RESTORE_MIXER_5           28
+#define ADJUST_B_RESTORE_MIXER_6           29
+#define ADJUST_B_RESTORE_MIXER_7           30
+#define ADJUST_B_END                       31
+
+/*------------------------------------------------------------------*/
+/* XON Protocol def's                                               */
+/*------------------------------------------------------------------*/
+#define N_CH_XOFF               0x01
+#define N_XON_SENT              0x02
+#define N_XON_REQ               0x04
+#define N_XON_CONNECT_IND       0x08
+#define N_RX_FLOW_CONTROL_MASK  0x3f
+#define N_OK_FC_PENDING         0x80
+#define N_TX_FLOW_CONTROL_MASK  0xc0
+
+/*------------------------------------------------------------------*/
+/* NCPI state                                                       */
+/*------------------------------------------------------------------*/
+#define NCPI_VALID_CONNECT_B3_IND  0x01
+#define NCPI_VALID_CONNECT_B3_ACT  0x02
+#define NCPI_VALID_DISC_B3_IND     0x04
+#define NCPI_CONNECT_B3_ACT_SENT   0x08
+#define NCPI_NEGOTIATE_B3_SENT     0x10
+#define NCPI_MDM_CTS_ON_RECEIVED   0x40
+#define NCPI_MDM_DCD_ON_RECEIVED   0x80
+
+/*------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
new file mode 100644
index 0000000..6146f76
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divamnt.c
@@ -0,0 +1,257 @@
+/* $Id: divamnt.c,v 1.32.6.10 2005/02/11 19:40:25 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * Maint module
+ *
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.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/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/poll.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/uaccess.h>
+
+#include "platform.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "debug_if.h"
+
+static char *main_revision = "$Revision: 1.32.6.10 $";
+
+static int major;
+
+MODULE_DESCRIPTION("Maint driver for Eicon DIVA Server cards");
+MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
+MODULE_SUPPORTED_DEVICE("DIVA card driver");
+MODULE_LICENSE("GPL");
+
+static int buffer_length = 128;
+module_param(buffer_length, int, 0);
+static unsigned long diva_dbg_mem = 0;
+module_param(diva_dbg_mem, ulong, 0);
+
+static char *DRIVERNAME =
+    "Eicon DIVA - MAINT module (http://www.melware.net)";
+static char *DRIVERLNAME = "diva_mnt";
+static char *DEVNAME = "DivasMAINT";
+char *DRIVERRELEASE_MNT = "2.0";
+
+static wait_queue_head_t msgwaitq;
+static unsigned long opened;
+static struct timeval start_time;
+
+extern int mntfunc_init(int *, void **, unsigned long);
+extern void mntfunc_finit(void);
+extern int maint_read_write(void __user *buf, int count);
+
+/*
+ *  helper functions
+ */
+static char *getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "1.0";
+
+	return rev;
+}
+
+/*
+ * kernel/user space copy functions
+ */
+int diva_os_copy_to_user(void *os_handle, void __user *dst, const void *src,
+			 int length)
+{
+	return (copy_to_user(dst, src, length));
+}
+int diva_os_copy_from_user(void *os_handle, void *dst, const void __user *src,
+			   int length)
+{
+	return (copy_from_user(dst, src, length));
+}
+
+/*
+ * get time
+ */
+void diva_os_get_time(dword * sec, dword * usec)
+{
+	struct timeval tv;
+
+	do_gettimeofday(&tv);
+
+	if (tv.tv_sec > start_time.tv_sec) {
+		if (start_time.tv_usec > tv.tv_usec) {
+			tv.tv_sec--;
+			tv.tv_usec += 1000000;
+		}
+		*sec = (dword) (tv.tv_sec - start_time.tv_sec);
+		*usec = (dword) (tv.tv_usec - start_time.tv_usec);
+	} else if (tv.tv_sec == start_time.tv_sec) {
+		*sec = 0;
+		if (start_time.tv_usec < tv.tv_usec) {
+			*usec = (dword) (tv.tv_usec - start_time.tv_usec);
+		} else {
+			*usec = 0;
+		}
+	} else {
+		*sec = (dword) tv.tv_sec;
+		*usec = (dword) tv.tv_usec;
+	}
+}
+
+/*
+ * device node operations
+ */
+static unsigned int maint_poll(struct file *file, poll_table * wait)
+{
+	unsigned int mask = 0;
+
+	poll_wait(file, &msgwaitq, wait);
+	mask = POLLOUT | POLLWRNORM;
+	if (file->private_data || diva_dbg_q_length()) {
+		mask |= POLLIN | POLLRDNORM;
+	}
+	return (mask);
+}
+
+static int maint_open(struct inode *ino, struct file *filep)
+{
+	/* only one open is allowed, so we test
+	   it atomically */
+	if (test_and_set_bit(0, &opened))
+		return (-EBUSY);
+
+	filep->private_data = NULL;
+
+	return nonseekable_open(ino, filep);
+}
+
+static int maint_close(struct inode *ino, struct file *filep)
+{
+	if (filep->private_data) {
+		diva_os_free(0, filep->private_data);
+		filep->private_data = NULL;
+	}
+
+	/* clear 'used' flag */
+	clear_bit(0, &opened);
+	
+	return (0);
+}
+
+static ssize_t divas_maint_write(struct file *file, const char __user *buf,
+				 size_t count, loff_t * ppos)
+{
+	return (maint_read_write((char __user *) buf, (int) count));
+}
+
+static ssize_t divas_maint_read(struct file *file, char __user *buf,
+				size_t count, loff_t * ppos)
+{
+	return (maint_read_write(buf, (int) count));
+}
+
+static struct file_operations divas_maint_fops = {
+	.owner   = THIS_MODULE,
+	.llseek  = no_llseek,
+	.read    = divas_maint_read,
+	.write   = divas_maint_write,
+	.poll    = maint_poll,
+	.open    = maint_open,
+	.release = maint_close
+};
+
+static void divas_maint_unregister_chrdev(void)
+{
+	devfs_remove(DEVNAME);
+	unregister_chrdev(major, DEVNAME);
+}
+
+static int DIVA_INIT_FUNCTION divas_maint_register_chrdev(void)
+{
+	if ((major = register_chrdev(0, DEVNAME, &divas_maint_fops)) < 0)
+	{
+		printk(KERN_ERR "%s: failed to create /dev entry.\n",
+		       DRIVERLNAME);
+		return (0);
+	}
+	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
+
+	return (1);
+}
+
+/*
+ * wake up reader
+ */
+void diva_maint_wakeup_read(void)
+{
+	wake_up_interruptible(&msgwaitq);
+}
+
+/*
+ *  Driver Load
+ */
+static int DIVA_INIT_FUNCTION maint_init(void)
+{
+	char tmprev[50];
+	int ret = 0;
+	void *buffer = NULL;
+
+	do_gettimeofday(&start_time);
+	init_waitqueue_head(&msgwaitq);
+
+	printk(KERN_INFO "%s\n", DRIVERNAME);
+	printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE_MNT);
+	strcpy(tmprev, main_revision);
+	printk("%s  Build: %s \n", getrev(tmprev), DIVA_BUILD);
+
+	if (!divas_maint_register_chrdev()) {
+		ret = -EIO;
+		goto out;
+	}
+
+	if (!(mntfunc_init(&buffer_length, &buffer, diva_dbg_mem))) {
+		printk(KERN_ERR "%s: failed to connect to DIDD.\n",
+		       DRIVERLNAME);
+		divas_maint_unregister_chrdev();
+		ret = -EIO;
+		goto out;
+	}
+
+	printk(KERN_INFO "%s: trace buffer = %p - %d kBytes, %s (Major: %d)\n",
+	       DRIVERLNAME, buffer, (buffer_length / 1024),
+	       (diva_dbg_mem == 0) ? "internal" : "external", major);
+
+      out:
+	return (ret);
+}
+
+/*
+**  Driver Unload
+*/
+static void DIVA_EXIT_FUNCTION maint_exit(void)
+{
+	divas_maint_unregister_chrdev();
+	mntfunc_finit();
+
+	printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(maint_init);
+module_exit(maint_exit);
+
diff --git a/drivers/isdn/hardware/eicon/divasfunc.c b/drivers/isdn/hardware/eicon/divasfunc.c
new file mode 100644
index 0000000..df61e51
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasfunc.c
@@ -0,0 +1,238 @@
+/* $Id: divasfunc.c,v 1.23.4.2 2004/08/28 20:03:53 armin Exp $
+ *
+ * Low level driver for Eicon DIVA Server ISDN cards.
+ *
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "di.h"
+#include "io.h"
+#include "divasync.h"
+#include "diva.h"
+#include "xdi_vers.h"
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+static int debugmask;
+
+extern void DIVA_DIDD_Read(void *, int);
+
+extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
+
+extern char *DRIVERRELEASE_DIVAS;
+
+static dword notify_handle;
+static DESCRIPTOR DAdapter;
+static DESCRIPTOR MAdapter;
+
+/* --------------------------------------------------------------------------
+    MAINT driver connector section
+   -------------------------------------------------------------------------- */
+static void no_printf(unsigned char *x, ...)
+{
+	/* dummy debug function */
+}
+
+#include "debuglib.c"
+
+/*
+ * get the adapters serial number
+ */
+void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf)
+{
+	int contr = 0;
+
+	if ((contr = ((IoAdapter->serialNo & 0xff000000) >> 24))) {
+		sprintf(buf, "%d-%d",
+			IoAdapter->serialNo & 0x00ffffff, contr + 1);
+	} else {
+		sprintf(buf, "%d", IoAdapter->serialNo);
+	}
+}
+
+/*
+ * register a new adapter
+ */
+void diva_xdi_didd_register_adapter(int card)
+{
+	DESCRIPTOR d;
+	IDI_SYNC_REQ req;
+
+	if (card && ((card - 1) < MAX_ADAPTER) &&
+	    IoAdapters[card - 1] && Requests[card - 1]) {
+		d.type = IoAdapters[card - 1]->Properties.DescType;
+		d.request = Requests[card - 1];
+		d.channels = IoAdapters[card - 1]->Properties.Channels;
+		d.features = IoAdapters[card - 1]->Properties.Features;
+		DBG_TRC(("DIDD register A(%d) channels=%d", card,
+			 d.channels))
+		    /* workaround for different Name in structure */
+		    strlcpy(IoAdapters[card - 1]->Name,
+			    IoAdapters[card - 1]->Properties.Name,
+			    sizeof(IoAdapters[card - 1]->Name));
+		req.didd_remove_adapter.e.Req = 0;
+		req.didd_add_adapter.e.Rc = IDI_SYNC_REQ_DIDD_ADD_ADAPTER;
+		req.didd_add_adapter.info.descriptor = (void *) &d;
+		DAdapter.request((ENTITY *) & req);
+		if (req.didd_add_adapter.e.Rc != 0xff) {
+			DBG_ERR(("DIDD register A(%d) failed !", card))
+		}
+		IoAdapters[card - 1]->os_trap_nfy_Fnc = NULL;
+	}
+}
+
+/*
+ * remove an adapter
+ */
+void diva_xdi_didd_remove_adapter(int card)
+{
+	IDI_SYNC_REQ req;
+	ADAPTER *a = &IoAdapters[card - 1]->a;
+
+	IoAdapters[card - 1]->os_trap_nfy_Fnc = NULL;
+	DBG_TRC(("DIDD de-register A(%d)", card))
+	req.didd_remove_adapter.e.Req = 0;
+	req.didd_remove_adapter.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER;
+	req.didd_remove_adapter.info.p_request =
+	    (IDI_CALL) Requests[card - 1];
+	DAdapter.request((ENTITY *) & req);
+	memset(&(a->IdTable), 0x00, 256);
+}
+
+/*
+ * start debug
+ */
+static void start_dbg(void)
+{
+	DbgRegister("DIVAS", DRIVERRELEASE_DIVAS, (debugmask) ? debugmask : DBG_DEFAULT);
+	DBG_LOG(("DIVA ISDNXDI BUILD (%s[%s]-%s-%s)",
+		 DIVA_BUILD, diva_xdi_common_code_build, __DATE__,
+		 __TIME__))
+}
+
+/*
+ * stop debug
+ */
+static void stop_dbg(void)
+{
+	DbgDeregister();
+	memset(&MAdapter, 0, sizeof(MAdapter));
+	dprintf = no_printf;
+}
+
+/*
+ * didd callback function
+ */
+static void *didd_callback(void *context, DESCRIPTOR * adapter,
+			   int removal)
+{
+	if (adapter->type == IDI_DADAPTER) {
+		DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
+		return (NULL);
+	}
+
+	if (adapter->type == IDI_DIMAINT) {
+		if (removal) {
+			stop_dbg();
+		} else {
+			memcpy(&MAdapter, adapter, sizeof(MAdapter));
+			dprintf = (DIVA_DI_PRINTF) MAdapter.request;
+			start_dbg();
+		}
+	}
+	return (NULL);
+}
+
+/*
+ * connect to didd
+ */
+static int DIVA_INIT_FUNCTION connect_didd(void)
+{
+	int x = 0;
+	int dadapter = 0;
+	IDI_SYNC_REQ req;
+	DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+	DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+	for (x = 0; x < MAX_DESCRIPTORS; x++) {
+		if (DIDD_Table[x].type == IDI_DADAPTER) {	/* DADAPTER found */
+			dadapter = 1;
+			memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+			req.didd_notify.e.Req = 0;
+			req.didd_notify.e.Rc =
+			    IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+			req.didd_notify.info.callback = (void *)didd_callback;
+			req.didd_notify.info.context = NULL;
+			DAdapter.request((ENTITY *) & req);
+			if (req.didd_notify.e.Rc != 0xff) {
+				stop_dbg();
+				return (0);
+			}
+			notify_handle = req.didd_notify.info.handle;
+		} else if (DIDD_Table[x].type == IDI_DIMAINT) {	/* MAINT found */
+			memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
+			dprintf = (DIVA_DI_PRINTF) MAdapter.request;
+			start_dbg();
+		}
+	}
+
+	if (!dadapter) {
+		stop_dbg();
+	}
+
+	return (dadapter);
+}
+
+/*
+ * disconnect from didd
+ */
+static void DIVA_EXIT_FUNCTION disconnect_didd(void)
+{
+	IDI_SYNC_REQ req;
+
+	stop_dbg();
+
+	req.didd_notify.e.Req = 0;
+	req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+	req.didd_notify.info.handle = notify_handle;
+	DAdapter.request((ENTITY *) & req);
+}
+
+/*
+ * init
+ */
+int DIVA_INIT_FUNCTION divasfunc_init(int dbgmask)
+{
+	char *version;
+
+	debugmask = dbgmask;
+	
+	if (!connect_didd()) {
+		DBG_ERR(("divasfunc: failed to connect to DIDD."))
+		return (0);
+	}
+
+	version = diva_xdi_common_code_build;
+
+	divasa_xdi_driver_entry();
+
+	return (1);
+}
+
+/*
+ * exit
+ */
+void DIVA_EXIT_FUNCTION divasfunc_exit(void)
+{
+	divasa_xdi_driver_unload();
+	disconnect_didd();
+}
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
new file mode 100644
index 0000000..df715b4
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -0,0 +1,581 @@
+/* $Id: divasi.c,v 1.25.6.2 2005/01/31 12:22:20 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * User Mode IDI Interface 
+ *
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.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/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/uaccess.h>
+
+#include "platform.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "um_xdi.h"
+#include "um_idi.h"
+
+static char *main_revision = "$Revision: 1.25.6.2 $";
+
+static int major;
+
+MODULE_DESCRIPTION("User IDI Interface for Eicon ISDN cards");
+MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
+MODULE_SUPPORTED_DEVICE("DIVA card driver");
+MODULE_LICENSE("GPL");
+
+typedef struct _diva_um_idi_os_context {
+	wait_queue_head_t read_wait;
+	wait_queue_head_t close_wait;
+	struct timer_list diva_timer_id;
+	int aborted;
+	int adapter_nr;
+} diva_um_idi_os_context_t;
+
+static char *DRIVERNAME = "Eicon DIVA - User IDI (http://www.melware.net)";
+static char *DRIVERLNAME = "diva_idi";
+static char *DEVNAME = "DivasIDI";
+char *DRIVERRELEASE_IDI = "2.0";
+
+extern int idifunc_init(void);
+extern void idifunc_finit(void);
+
+/*
+ *  helper functions
+ */
+static char *getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "1.0";
+	return rev;
+}
+
+/*
+ *  LOCALS
+ */
+static ssize_t um_idi_read(struct file *file, char __user *buf, size_t count,
+			   loff_t * offset);
+static ssize_t um_idi_write(struct file *file, const char __user *buf,
+			    size_t count, loff_t * offset);
+static unsigned int um_idi_poll(struct file *file, poll_table * wait);
+static int um_idi_open(struct inode *inode, struct file *file);
+static int um_idi_release(struct inode *inode, struct file *file);
+static int remove_entity(void *entity);
+static void diva_um_timer_function(unsigned long data);
+
+/*
+ * proc entry
+ */
+extern struct proc_dir_entry *proc_net_eicon;
+static struct proc_dir_entry *um_idi_proc_entry = NULL;
+
+static int
+um_idi_proc_read(char *page, char **start, off_t off, int count, int *eof,
+		 void *data)
+{
+	int len = 0;
+	char tmprev[32];
+
+	len += sprintf(page + len, "%s\n", DRIVERNAME);
+	len += sprintf(page + len, "name     : %s\n", DRIVERLNAME);
+	len += sprintf(page + len, "release  : %s\n", DRIVERRELEASE_IDI);
+	strcpy(tmprev, main_revision);
+	len += sprintf(page + len, "revision : %s\n", getrev(tmprev));
+	len += sprintf(page + len, "build    : %s\n", DIVA_BUILD);
+	len += sprintf(page + len, "major    : %d\n", major);
+
+	if (off + count >= len)
+		*eof = 1;
+	if (len < off)
+		return 0;
+	*start = page + off;
+	return ((count < len - off) ? count : len - off);
+}
+
+static int DIVA_INIT_FUNCTION create_um_idi_proc(void)
+{
+	um_idi_proc_entry = create_proc_entry(DRIVERLNAME,
+					      S_IFREG | S_IRUGO | S_IWUSR,
+					      proc_net_eicon);
+	if (!um_idi_proc_entry)
+		return (0);
+
+	um_idi_proc_entry->read_proc = um_idi_proc_read;
+	um_idi_proc_entry->owner = THIS_MODULE;
+
+	return (1);
+}
+
+static void remove_um_idi_proc(void)
+{
+	if (um_idi_proc_entry) {
+		remove_proc_entry(DRIVERLNAME, proc_net_eicon);
+		um_idi_proc_entry = NULL;
+	}
+}
+
+static struct file_operations divas_idi_fops = {
+	.owner   = THIS_MODULE,
+	.llseek  = no_llseek,
+	.read    = um_idi_read,
+	.write   = um_idi_write,
+	.poll    = um_idi_poll,
+	.open    = um_idi_open,
+	.release = um_idi_release
+};
+
+static void divas_idi_unregister_chrdev(void)
+{
+	devfs_remove(DEVNAME);
+	unregister_chrdev(major, DEVNAME);
+}
+
+static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void)
+{
+	if ((major = register_chrdev(0, DEVNAME, &divas_idi_fops)) < 0)
+	{
+		printk(KERN_ERR "%s: failed to create /dev entry.\n",
+		       DRIVERLNAME);
+		return (0);
+	}
+	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
+
+	return (1);
+}
+
+/*
+** Driver Load
+*/
+static int DIVA_INIT_FUNCTION divasi_init(void)
+{
+	char tmprev[50];
+	int ret = 0;
+
+	printk(KERN_INFO "%s\n", DRIVERNAME);
+	printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE_IDI);
+	strcpy(tmprev, main_revision);
+	printk("%s  Build: %s\n", getrev(tmprev), DIVA_BUILD);
+
+	if (!divas_idi_register_chrdev()) {
+		ret = -EIO;
+		goto out;
+	}
+
+	if (!create_um_idi_proc()) {
+		divas_idi_unregister_chrdev();
+		printk(KERN_ERR "%s: failed to create proc entry.\n",
+		       DRIVERLNAME);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (!(idifunc_init())) {
+		remove_um_idi_proc();
+		divas_idi_unregister_chrdev();
+		printk(KERN_ERR "%s: failed to connect to DIDD.\n",
+		       DRIVERLNAME);
+		ret = -EIO;
+		goto out;
+	}
+	printk(KERN_INFO "%s: started with major %d\n", DRIVERLNAME, major);
+
+      out:
+	return (ret);
+}
+
+
+/*
+** Driver Unload
+*/
+static void DIVA_EXIT_FUNCTION divasi_exit(void)
+{
+	idifunc_finit();
+	remove_um_idi_proc();
+	divas_idi_unregister_chrdev();
+
+	printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(divasi_init);
+module_exit(divasi_exit);
+
+
+/*
+ *  FILE OPERATIONS
+ */
+
+static int
+divas_um_idi_copy_to_user(void *os_handle, void *dst, const void *src,
+			  int length)
+{
+	memcpy(dst, src, length);
+	return (length);
+}
+
+static ssize_t
+um_idi_read(struct file *file, char __user *buf, size_t count, loff_t * offset)
+{
+	diva_um_idi_os_context_t *p_os;
+	int ret = -EINVAL;
+	void *data;
+
+	if (!file->private_data) {
+		return (-ENODEV);
+	}
+
+	if (!
+	    (p_os =
+	     (diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->
+								    private_data)))
+	{
+		return (-ENODEV);
+	}
+	if (p_os->aborted) {
+		return (-ENODEV);
+	}
+
+	if (!(data = diva_os_malloc(0, count))) {
+		return (-ENOMEM);
+	}
+
+	ret = diva_um_idi_read(file->private_data,
+			       file, data, count,
+			       divas_um_idi_copy_to_user);
+	switch (ret) {
+	case 0:		/* no message available */
+		ret = (-EAGAIN);
+		break;
+	case (-1):		/* adapter was removed */
+		ret = (-ENODEV);
+		break;
+	case (-2):		/* message_length > length of user buffer */
+		ret = (-EFAULT);
+		break;
+	}
+
+	if (ret > 0) {
+		if (copy_to_user(buf, data, ret)) {
+			ret = (-EFAULT);
+		}
+	}
+
+	diva_os_free(0, data);
+	DBG_TRC(("read: ret %d", ret));
+	return (ret);
+}
+
+
+static int
+divas_um_idi_copy_from_user(void *os_handle, void *dst, const void *src,
+			    int length)
+{
+	memcpy(dst, src, length);
+	return (length);
+}
+
+static int um_idi_open_adapter(struct file *file, int adapter_nr)
+{
+	diva_um_idi_os_context_t *p_os;
+	void *e =
+	    divas_um_idi_create_entity((dword) adapter_nr, (void *) file);
+
+	if (!(file->private_data = e)) {
+		return (0);
+	}
+	p_os = (diva_um_idi_os_context_t *) diva_um_id_get_os_context(e);
+	init_waitqueue_head(&p_os->read_wait);
+	init_waitqueue_head(&p_os->close_wait);
+	init_timer(&p_os->diva_timer_id);
+	p_os->diva_timer_id.function = (void *) diva_um_timer_function;
+	p_os->diva_timer_id.data = (unsigned long) p_os;
+	p_os->aborted = 0;
+	p_os->adapter_nr = adapter_nr;
+	return (1);
+}
+
+static ssize_t
+um_idi_write(struct file *file, const char __user *buf, size_t count,
+	     loff_t * offset)
+{
+	diva_um_idi_os_context_t *p_os;
+	int ret = -EINVAL;
+	void *data;
+	int adapter_nr = 0;
+
+	if (!file->private_data) {
+		/* the first write() selects the adapter_nr */
+		if (count == sizeof(int)) {
+			if (copy_from_user
+			    ((void *) &adapter_nr, buf,
+			     count)) return (-EFAULT);
+			if (!(um_idi_open_adapter(file, adapter_nr)))
+				return (-ENODEV);
+			return (count);
+		} else
+			return (-ENODEV);
+	}
+
+	if (!(p_os =
+	     (diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->
+								    private_data)))
+	{
+		return (-ENODEV);
+	}
+	if (p_os->aborted) {
+		return (-ENODEV);
+	}
+
+	if (!(data = diva_os_malloc(0, count))) {
+		return (-ENOMEM);
+	}
+
+	if (copy_from_user(data, buf, count)) {
+		ret = -EFAULT;
+	} else {
+		ret = diva_um_idi_write(file->private_data,
+					file, data, count,
+					divas_um_idi_copy_from_user);
+		switch (ret) {
+		case 0:	/* no space available */
+			ret = (-EAGAIN);
+			break;
+		case (-1):	/* adapter was removed */
+			ret = (-ENODEV);
+			break;
+		case (-2):	/* length of user buffer > max message_length */
+			ret = (-EFAULT);
+			break;
+		}
+	}
+	diva_os_free(0, data);
+	DBG_TRC(("write: ret %d", ret));
+	return (ret);
+}
+
+static unsigned int um_idi_poll(struct file *file, poll_table * wait)
+{
+	diva_um_idi_os_context_t *p_os;
+
+	if (!file->private_data) {
+		return (POLLERR);
+	}
+
+	if ((!(p_os =
+	       (diva_um_idi_os_context_t *)
+	       diva_um_id_get_os_context(file->private_data)))
+	    || p_os->aborted) {
+		return (POLLERR);
+	}
+
+	poll_wait(file, &p_os->read_wait, wait);
+
+	if (p_os->aborted) {
+		return (POLLERR);
+	}
+
+	switch (diva_user_mode_idi_ind_ready(file->private_data, file)) {
+	case (-1):
+		return (POLLERR);
+
+	case 0:
+		return (0);
+	}
+
+	return (POLLIN | POLLRDNORM);
+}
+
+static int um_idi_open(struct inode *inode, struct file *file)
+{
+	return (0);
+}
+
+
+static int um_idi_release(struct inode *inode, struct file *file)
+{
+	diva_um_idi_os_context_t *p_os;
+	unsigned int adapter_nr;
+	int ret = 0;
+
+	if (!(file->private_data)) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	if (!(p_os =
+		(diva_um_idi_os_context_t *) diva_um_id_get_os_context(file->private_data))) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	adapter_nr = p_os->adapter_nr;
+
+	if ((ret = remove_entity(file->private_data))) {
+		goto out;
+	}
+
+	if (divas_um_idi_delete_entity
+	    ((int) adapter_nr, file->private_data)) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+      out:
+	return (ret);
+}
+
+int diva_os_get_context_size(void)
+{
+	return (sizeof(diva_um_idi_os_context_t));
+}
+
+void diva_os_wakeup_read(void *os_context)
+{
+	diva_um_idi_os_context_t *p_os =
+	    (diva_um_idi_os_context_t *) os_context;
+	wake_up_interruptible(&p_os->read_wait);
+}
+
+void diva_os_wakeup_close(void *os_context)
+{
+	diva_um_idi_os_context_t *p_os =
+	    (diva_um_idi_os_context_t *) os_context;
+	wake_up_interruptible(&p_os->close_wait);
+}
+
+static
+void diva_um_timer_function(unsigned long data)
+{
+	diva_um_idi_os_context_t *p_os = (diva_um_idi_os_context_t *) data;
+
+	p_os->aborted = 1;
+	wake_up_interruptible(&p_os->read_wait);
+	wake_up_interruptible(&p_os->close_wait);
+	DBG_ERR(("entity removal watchdog"))
+}
+
+/*
+**  If application exits without entity removal this function will remove
+**  entity and block until removal is complete
+*/
+static int remove_entity(void *entity)
+{
+	struct task_struct *curtask = current;
+	diva_um_idi_os_context_t *p_os;
+
+	diva_um_idi_stop_wdog(entity);
+
+	if (!entity) {
+		DBG_FTL(("Zero entity on remove"))
+		return (0);
+	}
+
+	if (!(p_os =
+	     (diva_um_idi_os_context_t *)
+	     diva_um_id_get_os_context(entity))) {
+		DBG_FTL(("Zero entity os context on remove"))
+		return (0);
+	}
+
+	if (!divas_um_idi_entity_assigned(entity) || p_os->aborted) {
+		/*
+		   Entity is not assigned, also can be removed
+		 */
+		return (0);
+	}
+
+	DBG_TRC(("E(%08x) check remove", entity))
+
+	/*
+	   If adapter not answers on remove request inside of
+	   10 Sec, then adapter is dead
+	 */
+	diva_um_idi_start_wdog(entity);
+
+	{
+		DECLARE_WAITQUEUE(wait, curtask);
+
+		add_wait_queue(&p_os->close_wait, &wait);
+		for (;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!divas_um_idi_entity_start_remove(entity)
+			    || p_os->aborted) {
+				break;
+			}
+			schedule();
+		}
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&p_os->close_wait, &wait);
+	}
+
+	DBG_TRC(("E(%08x) start remove", entity))
+	{
+		DECLARE_WAITQUEUE(wait, curtask);
+
+		add_wait_queue(&p_os->close_wait, &wait);
+		for (;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!divas_um_idi_entity_assigned(entity)
+			    || p_os->aborted) {
+				break;
+			}
+			schedule();
+		}
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&p_os->close_wait, &wait);
+	}
+
+	DBG_TRC(("E(%08x) remove complete, aborted:%d", entity,
+		 p_os->aborted))
+
+	diva_um_idi_stop_wdog(entity);
+
+	p_os->aborted = 0;
+
+	return (0);
+}
+
+/*
+ * timer watchdog
+ */
+void diva_um_idi_start_wdog(void *entity)
+{
+	diva_um_idi_os_context_t *p_os;
+
+	if (entity &&
+	    ((p_os =
+	      (diva_um_idi_os_context_t *)
+	      diva_um_id_get_os_context(entity)))) {
+		mod_timer(&p_os->diva_timer_id, jiffies + 10 * HZ);
+	}
+}
+
+void diva_um_idi_stop_wdog(void *entity)
+{
+	diva_um_idi_os_context_t *p_os;
+
+	if (entity &&
+	    ((p_os =
+	      (diva_um_idi_os_context_t *)
+	      diva_um_id_get_os_context(entity)))) {
+		del_timer(&p_os->diva_timer_id);
+	}
+}
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
new file mode 100644
index 0000000..c9b26e8
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -0,0 +1,856 @@
+/* $Id: divasmain.c,v 1.55.4.6 2005/02/09 19:28:20 armin Exp $
+ *
+ * Low level driver for Eicon DIVA Server ISDN cards.
+ *
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.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/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/workqueue.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/kmod.h>
+
+#include "platform.h"
+#undef ID_MASK
+#undef N_DATA
+#include "pc.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "diva.h"
+#include "di.h"
+#include "io.h"
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "xdi_vers.h"
+#include "diva_dma.h"
+#include "diva_pci.h"
+
+static char *main_revision = "$Revision: 1.55.4.6 $";
+
+static int major;
+
+static int dbgmask;
+
+MODULE_DESCRIPTION("Kernel driver for Eicon DIVA Server cards");
+MODULE_AUTHOR("Cytronics & Melware, Eicon Networks");
+MODULE_LICENSE("GPL");
+
+module_param(dbgmask, int, 0);
+MODULE_PARM_DESC(dbgmask, "initial debug mask");
+
+static char *DRIVERNAME =
+    "Eicon DIVA Server driver (http://www.melware.net)";
+static char *DRIVERLNAME = "divas";
+static char *DEVNAME = "Divas";
+char *DRIVERRELEASE_DIVAS = "2.0";
+
+extern irqreturn_t diva_os_irq_wrapper(int irq, void *context,
+				struct pt_regs *regs);
+extern int create_divas_proc(void);
+extern void remove_divas_proc(void);
+extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
+extern int divasfunc_init(int dbgmask);
+extern void divasfunc_exit(void);
+
+typedef struct _diva_os_thread_dpc {
+	struct tasklet_struct divas_task;
+	diva_os_soft_isr_t *psoft_isr;
+} diva_os_thread_dpc_t;
+
+/* --------------------------------------------------------------------------
+    PCI driver interface section
+   -------------------------------------------------------------------------- */
+/*
+  vendor, device	Vendor and device ID to match (or PCI_ANY_ID)
+  subvendor,	Subsystem vendor and device ID to match (or PCI_ANY_ID)
+  subdevice
+  class,		Device class to match. The class_mask tells which bits
+  class_mask	of the class are honored during the comparison.
+  driver_data	Data private to the driver.
+  */
+
+#if !defined(PCI_DEVICE_ID_EICON_MAESTRAP_2)
+#define PCI_DEVICE_ID_EICON_MAESTRAP_2       0xE015
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_4BRI_VOIP)
+#define PCI_DEVICE_ID_EICON_4BRI_VOIP        0xE016
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_4BRI_2_VOIP)
+#define PCI_DEVICE_ID_EICON_4BRI_2_VOIP      0xE017
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_BRI2M_2)
+#define PCI_DEVICE_ID_EICON_BRI2M_2          0xE018
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP)
+#define PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP  0xE019
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_2F)
+#define PCI_DEVICE_ID_EICON_2F               0xE01A
+#endif
+
+#if !defined(PCI_DEVICE_ID_EICON_BRI2M_2_VOIP)
+#define PCI_DEVICE_ID_EICON_BRI2M_2_VOIP     0xE01B
+#endif
+
+/*
+  This table should be sorted by PCI device ID
+  */
+static struct pci_device_id divas_pci_tbl[] = {
+/* Diva Server BRI-2M PCI 0xE010 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRA,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_MAESTRA_PCI},
+/* Diva Server 4BRI-8M PCI 0xE012 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAQ,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_PCI},
+/* Diva Server 4BRI-8M 2.0 PCI 0xE013 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAQ_U,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_Q_8M_V2_PCI},
+/* Diva Server PRI-30M PCI 0xE014 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_PCI},
+/* Diva Server PRI 2.0 adapter 0xE015 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_P_30M_V2_PCI},
+/* Diva Server Voice 4BRI-8M PCI 0xE016 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_VOIP,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_PCI},
+/* Diva Server Voice 4BRI-8M 2.0 PCI 0xE017 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_4BRI_2_VOIP,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI},
+/* Diva Server BRI-2M 2.0 PCI 0xE018 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2M_V2_PCI},
+/* Diva Server Voice PRI 2.0 PCI 0xE019 */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_MAESTRAP_2_VOIP,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI},
+/* Diva Server 2FX 0xE01A */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_2F,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_B_2F_PCI},
+/* Diva Server Voice BRI-2M 2.0 PCI 0xE01B */
+	{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_BRI2M_2_VOIP,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI},
+	{0,}			/* 0 terminated list. */
+};
+MODULE_DEVICE_TABLE(pci, divas_pci_tbl);
+
+static int divas_init_one(struct pci_dev *pdev,
+			  const struct pci_device_id *ent);
+static void __devexit divas_remove_one(struct pci_dev *pdev);
+
+static struct pci_driver diva_pci_driver = {
+	.name     = "divas",
+	.probe    = divas_init_one,
+	.remove   = __devexit_p(divas_remove_one),
+	.id_table = divas_pci_tbl,
+};
+
+/*********************************************************
+ ** little helper functions
+ *********************************************************/
+static char *getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "1.0";
+	return rev;
+}
+
+void diva_log_info(unsigned char *format, ...)
+{
+	va_list args;
+	unsigned char line[160];
+
+	va_start(args, format);
+	vsprintf(line, format, args);
+	va_end(args);
+
+	printk(KERN_INFO "%s: %s\n", DRIVERLNAME, line);
+}
+
+void divas_get_version(char *p)
+{
+	char tmprev[32];
+
+	strcpy(tmprev, main_revision);
+	sprintf(p, "%s: %s(%s) %s(%s) major=%d\n", DRIVERLNAME, DRIVERRELEASE_DIVAS,
+		getrev(tmprev), diva_xdi_common_code_build, DIVA_BUILD, major);
+}
+
+/* --------------------------------------------------------------------------
+    PCI Bus services  
+   -------------------------------------------------------------------------- */
+byte diva_os_get_pci_bus(void *pci_dev_handle)
+{
+	struct pci_dev *pdev = (struct pci_dev *) pci_dev_handle;
+	return ((byte) pdev->bus->number);
+}
+
+byte diva_os_get_pci_func(void *pci_dev_handle)
+{
+	struct pci_dev *pdev = (struct pci_dev *) pci_dev_handle;
+	return ((byte) pdev->devfn);
+}
+
+unsigned long divasa_get_pci_irq(unsigned char bus, unsigned char func,
+				 void *pci_dev_handle)
+{
+	unsigned char irq = 0;
+	struct pci_dev *dev = (struct pci_dev *) pci_dev_handle;
+
+	irq = dev->irq;
+
+	return ((unsigned long) irq);
+}
+
+unsigned long divasa_get_pci_bar(unsigned char bus, unsigned char func,
+				 int bar, void *pci_dev_handle)
+{
+	unsigned long ret = 0;
+	struct pci_dev *dev = (struct pci_dev *) pci_dev_handle;
+
+	if (bar < 6) {
+		ret = dev->resource[bar].start;
+	}
+
+	DBG_TRC(("GOT BAR[%d]=%08x", bar, ret));
+
+	{
+		unsigned long type = (ret & 0x00000001);
+		if (type & PCI_BASE_ADDRESS_SPACE_IO) {
+			DBG_TRC(("  I/O"));
+			ret &= PCI_BASE_ADDRESS_IO_MASK;
+		} else {
+			DBG_TRC(("  memory"));
+			ret &= PCI_BASE_ADDRESS_MEM_MASK;
+		}
+		DBG_TRC(("  final=%08x", ret));
+	}
+
+	return (ret);
+}
+
+void PCIwrite(byte bus, byte func, int offset, void *data, int length,
+	      void *pci_dev_handle)
+{
+	struct pci_dev *dev = (struct pci_dev *) pci_dev_handle;
+
+	switch (length) {
+	case 1:		/* byte */
+		pci_write_config_byte(dev, offset,
+				      *(unsigned char *) data);
+		break;
+	case 2:		/* word */
+		pci_write_config_word(dev, offset,
+				      *(unsigned short *) data);
+		break;
+	case 4:		/* dword */
+		pci_write_config_dword(dev, offset,
+				       *(unsigned int *) data);
+		break;
+
+	default:		/* buffer */
+		if (!(length % 4) && !(length & 0x03)) {	/* Copy as dword */
+			dword *p = (dword *) data;
+			length /= 4;
+
+			while (length--) {
+				pci_write_config_dword(dev, offset,
+						       *(unsigned int *)
+						       p++);
+			}
+		} else {	/* copy as byte stream */
+			byte *p = (byte *) data;
+
+			while (length--) {
+				pci_write_config_byte(dev, offset,
+						      *(unsigned char *)
+						      p++);
+			}
+		}
+	}
+}
+
+void PCIread(byte bus, byte func, int offset, void *data, int length,
+	     void *pci_dev_handle)
+{
+	struct pci_dev *dev = (struct pci_dev *) pci_dev_handle;
+
+	switch (length) {
+	case 1:		/* byte */
+		pci_read_config_byte(dev, offset, (unsigned char *) data);
+		break;
+	case 2:		/* word */
+		pci_read_config_word(dev, offset, (unsigned short *) data);
+		break;
+	case 4:		/* dword */
+		pci_read_config_dword(dev, offset, (unsigned int *) data);
+		break;
+
+	default:		/* buffer */
+		if (!(length % 4) && !(length & 0x03)) {	/* Copy as dword */
+			dword *p = (dword *) data;
+			length /= 4;
+
+			while (length--) {
+				pci_read_config_dword(dev, offset,
+						      (unsigned int *)
+						      p++);
+			}
+		} else {	/* copy as byte stream */
+			byte *p = (byte *) data;
+
+			while (length--) {
+				pci_read_config_byte(dev, offset,
+						     (unsigned char *)
+						     p++);
+			}
+		}
+	}
+}
+
+/*
+  Init map with DMA pages. It is not problem if some allocations fail -
+  the channels that will not get one DMA page will use standard PIO
+  interface
+  */
+static void *diva_pci_alloc_consistent(struct pci_dev *hwdev,
+				       size_t size,
+				       dma_addr_t * dma_handle,
+				       void **addr_handle)
+{
+	void *addr = pci_alloc_consistent(hwdev, size, dma_handle);
+
+	*addr_handle = addr;
+
+	return (addr);
+}
+
+void diva_init_dma_map(void *hdev,
+		       struct _diva_dma_map_entry **ppmap, int nentries)
+{
+	struct pci_dev *pdev = (struct pci_dev *) hdev;
+	struct _diva_dma_map_entry *pmap =
+	    diva_alloc_dma_map(hdev, nentries);
+
+	if (pmap) {
+		int i;
+		dma_addr_t dma_handle;
+		void *cpu_addr;
+		void *addr_handle;
+
+		for (i = 0; i < nentries; i++) {
+			if (!(cpu_addr = diva_pci_alloc_consistent(pdev,
+								   PAGE_SIZE,
+								   &dma_handle,
+								   &addr_handle)))
+			{
+				break;
+			}
+			diva_init_dma_map_entry(pmap, i, cpu_addr,
+						(dword) dma_handle,
+						addr_handle);
+			DBG_TRC(("dma map alloc [%d]=(%08lx:%08x:%08lx)",
+				 i, (unsigned long) cpu_addr,
+				 (dword) dma_handle,
+				 (unsigned long) addr_handle))}
+	}
+
+	*ppmap = pmap;
+}
+
+/*
+  Free all contained in the map entries and memory used by the map
+  Should be always called after adapter removal from DIDD array
+  */
+void diva_free_dma_map(void *hdev, struct _diva_dma_map_entry *pmap)
+{
+	struct pci_dev *pdev = (struct pci_dev *) hdev;
+	int i;
+	dword phys_addr;
+	void *cpu_addr;
+	dma_addr_t dma_handle;
+	void *addr_handle;
+
+	for (i = 0; (pmap != 0); i++) {
+		diva_get_dma_map_entry(pmap, i, &cpu_addr, &phys_addr);
+		if (!cpu_addr) {
+			break;
+		}
+		addr_handle = diva_get_entry_handle(pmap, i);
+		dma_handle = (dma_addr_t) phys_addr;
+		pci_free_consistent(pdev, PAGE_SIZE, addr_handle,
+				    dma_handle);
+		DBG_TRC(("dma map free [%d]=(%08lx:%08x:%08lx)", i,
+			 (unsigned long) cpu_addr, (dword) dma_handle,
+			 (unsigned long) addr_handle))
+	}
+
+	diva_free_dma_mapping(pmap);
+}
+
+
+/*********************************************************
+ ** I/O port utilities  
+ *********************************************************/
+
+int
+diva_os_register_io_port(void *adapter, int on, unsigned long port,
+			 unsigned long length, const char *name, int id)
+{
+	if (on) {
+		if (!request_region(port, length, name)) {
+			DBG_ERR(("A: I/O: can't register port=%08x", port))
+			return (-1);
+		}
+	} else {
+		release_region(port, length);
+	}
+	return (0);
+}
+
+void __iomem *divasa_remap_pci_bar(diva_os_xdi_adapter_t *a, int id, unsigned long bar, unsigned long area_length)
+{
+	void __iomem *ret = ioremap(bar, area_length);
+	DBG_TRC(("remap(%08x)->%p", bar, ret));
+	return (ret);
+}
+
+void divasa_unmap_pci_bar(void __iomem *bar)
+{
+	if (bar) {
+		iounmap(bar);
+	}
+}
+
+/*********************************************************
+ ** I/O port access 
+ *********************************************************/
+byte __inline__ inpp(void __iomem *addr)
+{
+	return (inb((unsigned long) addr));
+}
+
+word __inline__ inppw(void __iomem *addr)
+{
+	return (inw((unsigned long) addr));
+}
+
+void __inline__ inppw_buffer(void __iomem *addr, void *P, int length)
+{
+	insw((unsigned long) addr, (word *) P, length >> 1);
+}
+
+void __inline__ outppw_buffer(void __iomem *addr, void *P, int length)
+{
+	outsw((unsigned long) addr, (word *) P, length >> 1);
+}
+
+void __inline__ outppw(void __iomem *addr, word w)
+{
+	outw(w, (unsigned long) addr);
+}
+
+void __inline__ outpp(void __iomem *addr, word p)
+{
+	outb(p, (unsigned long) addr);
+}
+
+/* --------------------------------------------------------------------------
+    IRQ request / remove  
+   -------------------------------------------------------------------------- */
+int diva_os_register_irq(void *context, byte irq, const char *name)
+{
+	int result = request_irq(irq, diva_os_irq_wrapper,
+				 SA_INTERRUPT | SA_SHIRQ, name, context);
+	return (result);
+}
+
+void diva_os_remove_irq(void *context, byte irq)
+{
+	free_irq(irq, context);
+}
+
+/* --------------------------------------------------------------------------
+    DPC framework implementation
+   -------------------------------------------------------------------------- */
+static void diva_os_dpc_proc(unsigned long context)
+{
+	diva_os_thread_dpc_t *psoft_isr = (diva_os_thread_dpc_t *) context;
+	diva_os_soft_isr_t *pisr = psoft_isr->psoft_isr;
+
+	(*(pisr->callback)) (pisr, pisr->callback_context);
+}
+
+int diva_os_initialize_soft_isr(diva_os_soft_isr_t * psoft_isr,
+				diva_os_soft_isr_callback_t callback,
+				void *callback_context)
+{
+	diva_os_thread_dpc_t *pdpc;
+
+	pdpc = (diva_os_thread_dpc_t *) diva_os_malloc(0, sizeof(*pdpc));
+	if (!(psoft_isr->object = pdpc)) {
+		return (-1);
+	}
+	memset(pdpc, 0x00, sizeof(*pdpc));
+	psoft_isr->callback = callback;
+	psoft_isr->callback_context = callback_context;
+	pdpc->psoft_isr = psoft_isr;
+	tasklet_init(&pdpc->divas_task, diva_os_dpc_proc, (unsigned long)pdpc);
+
+	return (0);
+}
+
+int diva_os_schedule_soft_isr(diva_os_soft_isr_t * psoft_isr)
+{
+	if (psoft_isr && psoft_isr->object) {
+		diva_os_thread_dpc_t *pdpc =
+		    (diva_os_thread_dpc_t *) psoft_isr->object;
+
+		tasklet_schedule(&pdpc->divas_task);
+	}
+
+	return (1);
+}
+
+int diva_os_cancel_soft_isr(diva_os_soft_isr_t * psoft_isr)
+{
+	return (0);
+}
+
+void diva_os_remove_soft_isr(diva_os_soft_isr_t * psoft_isr)
+{
+	if (psoft_isr && psoft_isr->object) {
+		diva_os_thread_dpc_t *pdpc =
+		    (diva_os_thread_dpc_t *) psoft_isr->object;
+		void *mem;
+
+		tasklet_kill(&pdpc->divas_task);
+		flush_scheduled_work();
+		mem = psoft_isr->object;
+		psoft_isr->object = NULL;
+		diva_os_free(0, mem);
+	}
+}
+
+/*
+ * kernel/user space copy functions
+ */
+static int
+xdi_copy_to_user(void *os_handle, void __user *dst, const void *src, int length)
+{
+	if (copy_to_user(dst, src, length)) {
+		return (-EFAULT);
+	}
+	return (length);
+}
+
+static int
+xdi_copy_from_user(void *os_handle, void *dst, const void __user *src, int length)
+{
+	if (copy_from_user(dst, src, length)) {
+		return (-EFAULT);
+	}
+	return (length);
+}
+
+/*
+ * device node operations
+ */
+static int divas_open(struct inode *inode, struct file *file)
+{
+	return (0);
+}
+
+static int divas_release(struct inode *inode, struct file *file)
+{
+	if (file->private_data) {
+		diva_xdi_close_adapter(file->private_data, file);
+	}
+	return (0);
+}
+
+static ssize_t divas_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t * ppos)
+{
+	int ret = -EINVAL;
+
+	if (!file->private_data) {
+		file->private_data = diva_xdi_open_adapter(file, buf,
+							   count,
+							   xdi_copy_from_user);
+	}
+	if (!file->private_data) {
+		return (-ENODEV);
+	}
+
+	ret = diva_xdi_write(file->private_data, file,
+			     buf, count, xdi_copy_from_user);
+	switch (ret) {
+	case -1:		/* Message should be removed from rx mailbox first */
+		ret = -EBUSY;
+		break;
+	case -2:		/* invalid adapter was specified in this call */
+		ret = -ENOMEM;
+		break;
+	case -3:
+		ret = -ENXIO;
+		break;
+	}
+	DBG_TRC(("write: ret %d", ret));
+	return (ret);
+}
+
+static ssize_t divas_read(struct file *file, char __user *buf,
+			  size_t count, loff_t * ppos)
+{
+	int ret = -EINVAL;
+
+	if (!file->private_data) {
+		file->private_data = diva_xdi_open_adapter(file, buf,
+							   count,
+							   xdi_copy_from_user);
+	}
+	if (!file->private_data) {
+		return (-ENODEV);
+	}
+
+	ret = diva_xdi_read(file->private_data, file,
+			    buf, count, xdi_copy_to_user);
+	switch (ret) {
+	case -1:		/* RX mailbox is empty */
+		ret = -EAGAIN;
+		break;
+	case -2:		/* no memory, mailbox was cleared, last command is failed */
+		ret = -ENOMEM;
+		break;
+	case -3:		/* can't copy to user, retry */
+		ret = -EFAULT;
+		break;
+	}
+	DBG_TRC(("read: ret %d", ret));
+	return (ret);
+}
+
+static unsigned int divas_poll(struct file *file, poll_table * wait)
+{
+	if (!file->private_data) {
+		return (POLLERR);
+	}
+	return (POLLIN | POLLRDNORM);
+}
+
+static struct file_operations divas_fops = {
+	.owner   = THIS_MODULE,
+	.llseek  = no_llseek,
+	.read    = divas_read,
+	.write   = divas_write,
+	.poll    = divas_poll,
+	.open    = divas_open,
+	.release = divas_release
+};
+
+static void divas_unregister_chrdev(void)
+{
+	devfs_remove(DEVNAME);
+	unregister_chrdev(major, DEVNAME);
+}
+
+static int DIVA_INIT_FUNCTION divas_register_chrdev(void)
+{
+	if ((major = register_chrdev(0, DEVNAME, &divas_fops)) < 0)
+	{
+		printk(KERN_ERR "%s: failed to create /dev entry.\n",
+		       DRIVERLNAME);
+		return (0);
+	}
+	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
+
+	return (1);
+}
+
+/* --------------------------------------------------------------------------
+    PCI driver section
+   -------------------------------------------------------------------------- */
+static int __devinit divas_init_one(struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
+{
+	void *pdiva = NULL;
+	u8 pci_latency;
+	u8 new_latency = 32;
+
+	DBG_TRC(("%s bus: %08x fn: %08x insertion.\n",
+		 CardProperties[ent->driver_data].Name,
+		 pdev->bus->number, pdev->devfn))
+	printk(KERN_INFO "%s: %s bus: %08x fn: %08x insertion.\n",
+		DRIVERLNAME, CardProperties[ent->driver_data].Name,
+		pdev->bus->number, pdev->devfn);
+
+	if (pci_enable_device(pdev)) {
+		DBG_TRC(("%s: %s bus: %08x fn: %08x device init failed.\n",
+			 DRIVERLNAME,
+			 CardProperties[ent->driver_data].Name,
+			 pdev->bus->number,
+			 pdev->devfn))
+		printk(KERN_ERR
+			"%s: %s bus: %08x fn: %08x device init failed.\n",
+			DRIVERLNAME,
+			CardProperties[ent->driver_data].
+			Name, pdev->bus->number,
+			pdev->devfn);
+		return (-EIO);
+	}
+
+	pci_set_master(pdev);
+
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
+	if (!pci_latency) {
+		DBG_TRC(("%s: bus: %08x fn: %08x fix latency.\n",
+			 DRIVERLNAME, pdev->bus->number, pdev->devfn))
+		printk(KERN_INFO
+			"%s: bus: %08x fn: %08x fix latency.\n",
+			 DRIVERLNAME, pdev->bus->number, pdev->devfn);
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
+	}
+
+	if (!(pdiva = diva_driver_add_card(pdev, ent->driver_data))) {
+		DBG_TRC(("%s: %s bus: %08x fn: %08x card init failed.\n",
+			 DRIVERLNAME,
+			 CardProperties[ent->driver_data].Name,
+			 pdev->bus->number,
+			 pdev->devfn))
+		printk(KERN_ERR
+			"%s: %s bus: %08x fn: %08x card init failed.\n",
+			DRIVERLNAME,
+			CardProperties[ent->driver_data].
+			Name, pdev->bus->number,
+			pdev->devfn);
+		return (-EIO);
+	}
+
+	pci_set_drvdata(pdev, pdiva);
+
+	return (0);
+}
+
+static void __devexit divas_remove_one(struct pci_dev *pdev)
+{
+	void *pdiva = pci_get_drvdata(pdev);
+
+	DBG_TRC(("bus: %08x fn: %08x removal.\n",
+		 pdev->bus->number, pdev->devfn))
+	printk(KERN_INFO "%s: bus: %08x fn: %08x removal.\n",
+		DRIVERLNAME, pdev->bus->number, pdev->devfn);
+
+	if (pdiva) {
+		diva_driver_remove_card(pdiva);
+	}
+
+}
+
+/* --------------------------------------------------------------------------
+    Driver Load / Startup  
+   -------------------------------------------------------------------------- */
+static int DIVA_INIT_FUNCTION divas_init(void)
+{
+	char tmprev[50];
+	int ret = 0;
+
+	printk(KERN_INFO "%s\n", DRIVERNAME);
+	printk(KERN_INFO "%s: Rel:%s  Rev:", DRIVERLNAME, DRIVERRELEASE_DIVAS);
+	strcpy(tmprev, main_revision);
+	printk("%s  Build: %s(%s)\n", getrev(tmprev),
+	       diva_xdi_common_code_build, DIVA_BUILD);
+	printk(KERN_INFO "%s: support for: ", DRIVERLNAME);
+#ifdef CONFIG_ISDN_DIVAS_BRIPCI
+	printk("BRI/PCI ");
+#endif
+#ifdef CONFIG_ISDN_DIVAS_PRIPCI
+	printk("PRI/PCI ");
+#endif
+	printk("adapters\n");
+
+	if (!divasfunc_init(dbgmask)) {
+		printk(KERN_ERR "%s: failed to connect to DIDD.\n",
+		       DRIVERLNAME);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (!divas_register_chrdev()) {
+#ifdef MODULE
+		divasfunc_exit();
+#endif
+		ret = -EIO;
+		goto out;
+	}
+
+	if (!create_divas_proc()) {
+#ifdef MODULE
+		remove_divas_proc();
+		divas_unregister_chrdev();
+		divasfunc_exit();
+#endif
+		printk(KERN_ERR "%s: failed to create proc entry.\n",
+		       DRIVERLNAME);
+		ret = -EIO;
+		goto out;
+	}
+
+	if ((ret = pci_register_driver(&diva_pci_driver))) {
+#ifdef MODULE
+		remove_divas_proc();
+		divas_unregister_chrdev();
+		divasfunc_exit();
+#endif
+		printk(KERN_ERR "%s: failed to init pci driver.\n",
+		       DRIVERLNAME);
+		goto out;
+	}
+	printk(KERN_INFO "%s: started with major %d\n", DRIVERLNAME, major);
+
+      out:
+	return (ret);
+}
+
+/* --------------------------------------------------------------------------
+    Driver Unload
+   -------------------------------------------------------------------------- */
+static void DIVA_EXIT_FUNCTION divas_exit(void)
+{
+	pci_unregister_driver(&diva_pci_driver);
+	remove_divas_proc();
+	divas_unregister_chrdev();
+	divasfunc_exit();
+
+	printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
+}
+
+module_init(divas_init);
+module_exit(divas_exit);
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
new file mode 100644
index 0000000..b643558
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasproc.c
@@ -0,0 +1,441 @@
+/* $Id: divasproc.c,v 1.19.4.3 2005/01/31 12:22:20 armin Exp $
+ *
+ * Low level driver for Eicon DIVA Server ISDN cards.
+ * /proc functions
+ *
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.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/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+
+#include "platform.h"
+#include "debuglib.h"
+#undef ID_MASK
+#undef N_DATA
+#include "pc.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "di.h"
+#include "io.h"
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "diva.h"
+#include "diva_pci.h"
+
+
+extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
+extern void divas_get_version(char *);
+extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
+
+/*********************************************************
+ ** Functions for /proc interface / File operations
+ *********************************************************/
+
+static char *divas_proc_name = "divas";
+static char *adapter_dir_name = "adapter";
+static char *info_proc_name = "info";
+static char *grp_opt_proc_name = "group_optimization";
+static char *d_l1_down_proc_name = "dynamic_l1_down";
+
+/*
+** "divas" entry
+*/
+
+extern struct proc_dir_entry *proc_net_eicon;
+static struct proc_dir_entry *divas_proc_entry = NULL;
+
+static ssize_t
+divas_read(struct file *file, char __user *buf, size_t count, loff_t * off)
+{
+	int len = 0;
+	int cadapter;
+	char tmpbuf[80];
+	char tmpser[16];
+
+	if (*off)
+		return 0;
+
+	divas_get_version(tmpbuf);
+	if (copy_to_user(buf + len, &tmpbuf, strlen(tmpbuf)))
+		return -EFAULT;
+	len += strlen(tmpbuf);
+
+	for (cadapter = 0; cadapter < MAX_ADAPTER; cadapter++) {
+		if (IoAdapters[cadapter]) {
+			diva_get_vserial_number(IoAdapters[cadapter],
+						tmpser);
+			sprintf(tmpbuf,
+				"%2d: %-30s Serial:%-10s IRQ:%2d\n",
+				cadapter + 1,
+				IoAdapters[cadapter]->Properties.Name,
+				tmpser,
+				IoAdapters[cadapter]->irq_info.irq_nr);
+			if ((strlen(tmpbuf) + len) > count)
+				break;
+			if (copy_to_user
+			    (buf + len, &tmpbuf,
+			     strlen(tmpbuf))) return -EFAULT;
+			len += strlen(tmpbuf);
+		}
+	}
+
+	*off += len;
+	return (len);
+}
+
+static ssize_t
+divas_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
+{
+	return (-ENODEV);
+}
+
+static unsigned int divas_poll(struct file *file, poll_table * wait)
+{
+	return (POLLERR);
+}
+
+static int divas_open(struct inode *inode, struct file *file)
+{
+	return nonseekable_open(inode, file);
+}
+
+static int divas_close(struct inode *inode, struct file *file)
+{
+	return (0);
+}
+
+static struct file_operations divas_fops = {
+	.owner   = THIS_MODULE,
+	.llseek  = no_llseek,
+	.read    = divas_read,
+	.write   = divas_write,
+	.poll    = divas_poll,
+	.open    = divas_open,
+	.release = divas_close
+};
+
+int create_divas_proc(void)
+{
+	divas_proc_entry = create_proc_entry(divas_proc_name,
+					     S_IFREG | S_IRUGO,
+					     proc_net_eicon);
+	if (!divas_proc_entry)
+		return (0);
+
+	divas_proc_entry->proc_fops = &divas_fops;
+	divas_proc_entry->owner = THIS_MODULE;
+
+	return (1);
+}
+
+void remove_divas_proc(void)
+{
+	if (divas_proc_entry) {
+		remove_proc_entry(divas_proc_name, proc_net_eicon);
+		divas_proc_entry = NULL;
+	}
+}
+
+/*
+** write group_optimization 
+*/
+static int
+write_grp_opt(struct file *file, const char __user *buffer, unsigned long count,
+	      void *data)
+{
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+	PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
+
+	if ((count == 1) || (count == 2)) {
+		char c;
+		if (get_user(c, buffer))
+			return -EFAULT;
+		switch (c) {
+		case '0':
+			IoAdapter->capi_cfg.cfg_1 &=
+			    ~DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON;
+			break;
+		case '1':
+			IoAdapter->capi_cfg.cfg_1 |=
+			    DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON;
+			break;
+		default:
+			return (-EINVAL);
+		}
+		return (count);
+	}
+	return (-EINVAL);
+}
+
+/*
+** write dynamic_l1_down
+*/
+static int
+write_d_l1_down(struct file *file, const char __user *buffer, unsigned long count,
+		void *data)
+{
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+	PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
+
+	if ((count == 1) || (count == 2)) {
+		char c;
+		if (get_user(c, buffer))
+			return -EFAULT;
+		switch (c) {
+		case '0':
+			IoAdapter->capi_cfg.cfg_1 &=
+			    ~DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON;
+			break;
+		case '1':
+			IoAdapter->capi_cfg.cfg_1 |=
+			    DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON;
+			break;
+		default:
+			return (-EINVAL);
+		}
+		return (count);
+	}
+	return (-EINVAL);
+}
+
+
+/*
+** read dynamic_l1_down 
+*/
+static int
+read_d_l1_down(char *page, char **start, off_t off, int count, int *eof,
+	       void *data)
+{
+	int len = 0;
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+	PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
+
+	len += sprintf(page + len, "%s\n",
+		       (IoAdapter->capi_cfg.
+			cfg_1 & DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? "1" :
+		       "0");
+
+	if (off + count >= len)
+		*eof = 1;
+	if (len < off)
+		return 0;
+	*start = page + off;
+	return ((count < len - off) ? count : len - off);
+}
+
+/*
+** read group_optimization
+*/
+static int
+read_grp_opt(char *page, char **start, off_t off, int count, int *eof,
+	     void *data)
+{
+	int len = 0;
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+	PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
+
+	len += sprintf(page + len, "%s\n",
+		       (IoAdapter->capi_cfg.
+			cfg_1 & DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON)
+		       ? "1" : "0");
+
+	if (off + count >= len)
+		*eof = 1;
+	if (len < off)
+		return 0;
+	*start = page + off;
+	return ((count < len - off) ? count : len - off);
+}
+
+/*
+** info write
+*/
+static int
+info_write(struct file *file, const char __user *buffer, unsigned long count,
+	   void *data)
+{
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+	PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
+	char c[4];
+
+	if (count <= 4)
+		return -EINVAL;
+
+	if (copy_from_user(c, buffer, 4))
+		return -EFAULT;
+
+	/* this is for test purposes only */
+	if (!memcmp(c, "trap", 4)) {
+		(*(IoAdapter->os_trap_nfy_Fnc)) (IoAdapter, IoAdapter->ANum);
+		return (count);
+	}
+	return (-EINVAL);
+}
+
+/*
+** info read
+*/
+static int
+info_read(char *page, char **start, off_t off, int count, int *eof,
+	  void *data)
+{
+	int i = 0;
+	int len = 0;
+	char *p;
+	char tmpser[16];
+	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data;
+	PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1];
+
+	len +=
+	    sprintf(page + len, "Name        : %s\n",
+		    IoAdapter->Properties.Name);
+	len += sprintf(page + len, "DSP state   : %08x\n", a->dsp_mask);
+	len += sprintf(page + len, "Channels    : %02d\n",
+		       IoAdapter->Properties.Channels);
+	len += sprintf(page + len, "E. max/used : %03d/%03d\n",
+		       IoAdapter->e_max, IoAdapter->e_count);
+	diva_get_vserial_number(IoAdapter, tmpser);
+	len += sprintf(page + len, "Serial      : %s\n", tmpser);
+	len +=
+	    sprintf(page + len, "IRQ         : %d\n",
+		    IoAdapter->irq_info.irq_nr);
+	len += sprintf(page + len, "CardIndex   : %d\n", a->CardIndex);
+	len += sprintf(page + len, "CardOrdinal : %d\n", a->CardOrdinal);
+	len += sprintf(page + len, "Controller  : %d\n", a->controller);
+	len += sprintf(page + len, "Bus-Type    : %s\n",
+		       (a->Bus ==
+			DIVAS_XDI_ADAPTER_BUS_ISA) ? "ISA" : "PCI");
+	len += sprintf(page + len, "Port-Name   : %s\n", a->port_name);
+	if (a->Bus == DIVAS_XDI_ADAPTER_BUS_PCI) {
+		len +=
+		    sprintf(page + len, "PCI-bus     : %d\n",
+			    a->resources.pci.bus);
+		len +=
+		    sprintf(page + len, "PCI-func    : %d\n",
+			    a->resources.pci.func);
+		for (i = 0; i < 8; i++) {
+			if (a->resources.pci.bar[i]) {
+				len +=
+				    sprintf(page + len,
+					    "Mem / I/O %d : 0x%x / mapped : 0x%lx",
+					    i, a->resources.pci.bar[i],
+					    (unsigned long) a->resources.
+					    pci.addr[i]);
+				if (a->resources.pci.length[i]) {
+					len +=
+					    sprintf(page + len,
+						    " / length : %d",
+						    a->resources.pci.
+						    length[i]);
+				}
+				len += sprintf(page + len, "\n");
+			}
+		}
+	}
+	if ((!a->xdi_adapter.port) &&
+	    ((!a->xdi_adapter.ram) ||
+	    (!a->xdi_adapter.reset)
+	     || (!a->xdi_adapter.cfg))) {
+		if (!IoAdapter->irq_info.irq_nr) {
+			p = "slave";
+		} else {
+			p = "out of service";
+		}
+	} else if (a->xdi_adapter.trapped) {
+		p = "trapped";
+	} else if (a->xdi_adapter.Initialized) {
+		p = "active";
+	} else {
+		p = "ready";
+	}
+	len += sprintf(page + len, "State       : %s\n", p);
+
+	if (off + count >= len)
+		*eof = 1;
+	if (len < off)
+		return 0;
+	*start = page + off;
+	return ((count < len - off) ? count : len - off);
+}
+
+/*
+** adapter proc init/de-init
+*/
+
+/* --------------------------------------------------------------------------
+    Create adapter directory and files in proc file system
+   -------------------------------------------------------------------------- */
+int create_adapter_proc(diva_os_xdi_adapter_t * a)
+{
+	struct proc_dir_entry *de, *pe;
+	char tmp[16];
+
+	sprintf(tmp, "%s%d", adapter_dir_name, a->controller);
+	if (!(de = create_proc_entry(tmp, S_IFDIR, proc_net_eicon)))
+		return (0);
+	a->proc_adapter_dir = (void *) de;
+
+	if (!(pe =
+	     create_proc_entry(info_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de)))
+		return (0);
+	a->proc_info = (void *) pe;
+	pe->write_proc = info_write;
+	pe->read_proc = info_read;
+	pe->data = a;
+
+	if ((pe = create_proc_entry(grp_opt_proc_name,
+			       S_IFREG | S_IRUGO | S_IWUSR, de))) {
+		a->proc_grp_opt = (void *) pe;
+		pe->write_proc = write_grp_opt;
+		pe->read_proc = read_grp_opt;
+		pe->data = a;
+	}
+	if ((pe = create_proc_entry(d_l1_down_proc_name,
+			       S_IFREG | S_IRUGO | S_IWUSR, de))) {
+		a->proc_d_l1_down = (void *) pe;
+		pe->write_proc = write_d_l1_down;
+		pe->read_proc = read_d_l1_down;
+		pe->data = a;
+	}
+
+	DBG_TRC(("proc entry %s created", tmp));
+
+	return (1);
+}
+
+/* --------------------------------------------------------------------------
+    Remove adapter directory and files in proc file system
+   -------------------------------------------------------------------------- */
+void remove_adapter_proc(diva_os_xdi_adapter_t * a)
+{
+	char tmp[16];
+
+	if (a->proc_adapter_dir) {
+		if (a->proc_d_l1_down) {
+			remove_proc_entry(d_l1_down_proc_name,
+					  (struct proc_dir_entry *) a->proc_adapter_dir);
+		}
+		if (a->proc_grp_opt) {
+			remove_proc_entry(grp_opt_proc_name,
+					  (struct proc_dir_entry *) a->proc_adapter_dir);
+		}
+		if (a->proc_info) {
+			remove_proc_entry(info_proc_name,
+					  (struct proc_dir_entry *) a->proc_adapter_dir);
+		}
+		sprintf(tmp, "%s%d", adapter_dir_name, a->controller);
+		remove_proc_entry(tmp, proc_net_eicon);
+		DBG_TRC(("proc entry %s%d removed", adapter_dir_name,
+			 a->controller));
+	}
+}
diff --git a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h
new file mode 100644
index 0000000..0a5be7f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/divasync.h
@@ -0,0 +1,490 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_SYNC__H  
+#define __DIVA_SYNC__H
+#define IDI_SYNC_REQ_REMOVE             0x00
+#define IDI_SYNC_REQ_GET_NAME           0x01
+#define IDI_SYNC_REQ_GET_SERIAL         0x02
+#define IDI_SYNC_REQ_SET_POSTCALL       0x03
+#define IDI_SYNC_REQ_GET_XLOG           0x04
+#define IDI_SYNC_REQ_GET_FEATURES       0x05
+#define IDI_SYNC_REQ_USB_REGISTER       0x06
+#define IDI_SYNC_REQ_USB_RELEASE        0x07
+#define IDI_SYNC_REQ_USB_ADD_DEVICE     0x08
+#define IDI_SYNC_REQ_USB_START_DEVICE   0x09
+#define IDI_SYNC_REQ_USB_STOP_DEVICE    0x0A
+#define IDI_SYNC_REQ_USB_REMOVE_DEVICE  0x0B
+#define IDI_SYNC_REQ_GET_CARDTYPE       0x0C
+#define IDI_SYNC_REQ_GET_DBG_XLOG       0x0D
+#define DIVA_USB
+#define DIVA_USB_REQ                    0xAC
+#define DIVA_USB_TEST                   0xAB
+#define DIVA_USB_ADD_ADAPTER            0xAC
+#define DIVA_USB_REMOVE_ADAPTER         0xAD
+#define IDI_SYNC_REQ_SERIAL_HOOK        0x80
+#define IDI_SYNC_REQ_XCHANGE_STATUS     0x81
+#define IDI_SYNC_REQ_USB_HOOK           0x82
+#define IDI_SYNC_REQ_PORTDRV_HOOK       0x83
+#define IDI_SYNC_REQ_SLI                0x84   /*  SLI request from 3signal modem drivers */
+#define IDI_SYNC_REQ_RECONFIGURE        0x85
+#define IDI_SYNC_REQ_RESET              0x86
+#define IDI_SYNC_REQ_GET_85X_DEVICE_DATA     0x87
+#define IDI_SYNC_REQ_LOCK_85X                   0x88
+#define IDI_SYNC_REQ_DIVA_85X_USB_DATA_EXCHANGE 0x99
+#define IDI_SYNC_REQ_DIPORT_EXCHANGE_REQ   0x98
+#define IDI_SYNC_REQ_GET_85X_EXT_PORT_TYPE      0xA0
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES  0x92
+/*
+   To receive XDI features:
+   1. set 'buffer_length_in_bytes' to length of you buffer
+   2. set 'features' to pointer to your buffer
+   3. issue synchronous request to XDI
+   4. Check that feature 'DIVA_XDI_EXTENDED_FEATURES_VALID' is present
+      after call. This feature does indicate that your request
+      was processed and XDI does support this synchronous request
+   5. if on return bit 31 (0x80000000) in 'buffer_length_in_bytes' is
+      set then provided buffer was too small, and bits 30-0 does
+      contain necessary length of buffer.
+      in this case only features that do find place in the buffer
+      are indicated to caller
+*/
+typedef struct _diva_xdi_get_extended_xdi_features {
+  dword buffer_length_in_bytes;
+  byte  *features;
+} diva_xdi_get_extended_xdi_features_t;
+/*
+   features[0]
+  */
+#define DIVA_XDI_EXTENDED_FEATURES_VALID          0x01
+#define DIVA_XDI_EXTENDED_FEATURE_CMA             0x02
+#define DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR       0x04
+#define DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS       0x08
+#define DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC    0x10
+#define DIVA_XDI_EXTENDED_FEATURE_RX_DMA          0x20
+#define DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA  0x40
+#define DIVA_XDI_EXTENDED_FEATURE_WIDE_ID         0x80
+#define DIVA_XDI_EXTENDED_FEATURES_MAX_SZ    1
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR   0x93
+typedef struct _diva_xdi_get_adapter_sdram_bar {
+ dword bar;
+} diva_xdi_get_adapter_sdram_bar_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS   0x94
+/*
+  CAPI Parameters will be written in the caller's buffer
+  */
+typedef struct _diva_xdi_get_capi_parameters {
+  dword structure_length;
+  byte flag_dynamic_l1_down;
+  byte group_optimization_enabled;
+} diva_xdi_get_capi_parameters_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER   0x95
+/*
+  Get logical adapter number, as assigned by XDI
+  'controller' is starting with zero 'sub' controller number
+  in case of one adapter that supports multiple interfaces
+  'controller' is zero for Master adapter (and adapter that supports
+  only one interface)
+  */
+typedef struct _diva_xdi_get_logical_adapter_number {
+  dword logical_adapter_number;
+  dword controller;
+  dword total_controllers;
+} diva_xdi_get_logical_adapter_number_s_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_UP1DM_OPERATION   0x96
+/******************************************************************************/
+#define IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION 0x97
+#define IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC     0x01
+#define IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE      0x02
+typedef struct _diva_xdi_dma_descriptor_operation {
+  int   operation;
+  int   descriptor_number;
+  void* descriptor_address;
+  dword descriptor_magic;
+} diva_xdi_dma_descriptor_operation_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY   0x01
+#define IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY     0x02
+#define IDI_SYNC_REQ_DIDD_ADD_ADAPTER               0x03
+#define IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER            0x04
+#define IDI_SYNC_REQ_DIDD_READ_ADAPTER_ARRAY        0x05
+#define IDI_SYNC_REQ_DIDD_GET_CFG_LIB_IFC           0x10
+typedef struct _diva_didd_adapter_notify {
+ dword handle; /* Notification handle */
+ void   * callback;
+ void   * context;
+} diva_didd_adapter_notify_t;
+typedef struct _diva_didd_add_adapter {
+ void   * descriptor;
+} diva_didd_add_adapter_t;
+typedef struct _diva_didd_remove_adapter {
+ IDI_CALL p_request;
+} diva_didd_remove_adapter_t;
+typedef struct _diva_didd_read_adapter_array {
+ void   * buffer;
+ dword length;
+} diva_didd_read_adapter_array_t;
+typedef struct _diva_didd_get_cfg_lib_ifc {
+ void* ifc;
+} diva_didd_get_cfg_lib_ifc_t;
+/******************************************************************************/
+#define IDI_SYNC_REQ_XDI_GET_STREAM    0x91
+#define DIVA_XDI_SYNCHRONOUS_SERVICE   0x01
+#define DIVA_XDI_DMA_SERVICE           0x02
+#define DIVA_XDI_AUTO_SERVICE          0x03
+#define DIVA_ISTREAM_COMPLETE_NOTIFY   0
+#define DIVA_ISTREAM_COMPLETE_READ     1
+#define DIVA_ISTREAM_COMPLETE_WRITE    2
+typedef struct _diva_xdi_stream_interface {
+  unsigned char  Id;                 /* filled by XDI client */
+ unsigned char provided_service;    /* filled by XDI        */
+ unsigned char requested_service;   /* filled by XDI Client */
+ void* xdi_context;    /* filled by XDI     */
+ void* client_context;   /* filled by XDI client */
+ int (*write)(void* context,
+               int Id,
+               void* data,
+               int length,
+               int final,
+               byte usr1,
+               byte usr2);
+ int (*read)(void* context,
+              int Id,
+              void* data,
+              int max_length,
+              int* final,
+              byte* usr1,
+              byte* usr2);
+ int (*complete)(void* client_context,
+         int Id,
+          int what,
+         void* data,
+         int length,
+         int* final);
+} diva_xdi_stream_interface_t;
+/******************************************************************************/
+/*
+ * IDI_SYNC_REQ_SERIAL_HOOK - special interface for the DIVA Mobile card
+ */
+typedef struct
+{ unsigned char LineState;         /* Modem line state (STATUS_R) */
+#define SERIAL_GSM_CELL 0x01   /* GSM or CELL cable attached  */
+ unsigned char CardState;          /* PCMCIA card state (0 = down) */
+ unsigned char IsdnState;          /* ISDN layer 1 state (0 = down)*/
+ unsigned char HookState;          /* current logical hook state */
+#define SERIAL_ON_HOOK 0x02   /* set in DIVA CTRL_R register */
+} SERIAL_STATE;
+typedef int (  * SERIAL_INT_CB) (void *Context) ;
+typedef int (  * SERIAL_DPC_CB) (void *Context) ;
+typedef unsigned char (  * SERIAL_I_SYNC) (void *Context) ;
+typedef struct
+{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
+ unsigned char Req;             /* request (must be always 0) */
+ unsigned char Rc;              /* return code (is the request) */
+ unsigned char Function;           /* private function code  */
+#define SERIAL_HOOK_ATTACH 0x81
+#define SERIAL_HOOK_STATUS 0x82
+#define SERIAL_HOOK_I_SYNC 0x83
+#define SERIAL_HOOK_NOECHO 0x84
+#define SERIAL_HOOK_RING 0x85
+#define SERIAL_HOOK_DETACH 0x8f
+ unsigned char Flags;           /* function refinements   */
+ /* parameters passed by the the ATTACH request      */
+ SERIAL_INT_CB InterruptHandler; /* called on each interrupt  */
+ SERIAL_DPC_CB DeferredHandler; /* called on hook state changes */
+ void   *HandlerContext; /* context for both handlers */
+ /* return values for both the ATTACH and the STATUS request   */
+ unsigned long IoBase;    /* IO port assigned to UART  */
+ SERIAL_STATE State;
+ /* parameters and return values for the I_SYNC function    */
+ SERIAL_I_SYNC SyncFunction;  /* to be called synchronized */
+ void   *SyncContext;  /* context for this function */
+ unsigned char SyncResult;   /* return value of function  */
+} SERIAL_HOOK;
+/*
+ * IDI_SYNC_REQ_XCHANGE_STATUS - exchange the status between IDI and WMP
+ * IDI_SYNC_REQ_RECONFIGURE - reconfiguration of IDI from WMP
+ */
+typedef struct
+{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
+ unsigned char Req;             /* request (must be always 0) */
+ unsigned char Rc;              /* return code (is the request) */
+#define DRIVER_STATUS_BOOT  0xA1
+#define DRIVER_STATUS_INIT_DEV 0xA2
+#define DRIVER_STATUS_RUNNING 0xA3
+#define DRIVER_STATUS_SHUTDOWN 0xAF
+#define DRIVER_STATUS_TRAPPED 0xAE
+ unsigned char wmpStatus;          /* exported by WMP              */
+ unsigned char idiStatus;   /* exported by IDI              */
+ unsigned long wizProto ;   /* from WMP registry to IDI     */
+ /* the cardtype value is defined by cardtype.h */
+ unsigned long cardType ;   /* from IDI registry to WMP     */
+ unsigned long nt2 ;    /* from IDI registry to WMP     */
+ unsigned long permanent ;   /* from IDI registry to WMP     */
+ unsigned long stableL2 ;   /* from IDI registry to WMP     */
+ unsigned long tei ;    /* from IDI registry to WMP     */
+#define CRC4_MASK   0x00000003
+#define L1_TRISTATE_MASK 0x00000004
+#define WATCHDOG_MASK  0x00000008
+#define NO_ORDER_CHECK_MASK 0x00000010
+#define LOW_CHANNEL_MASK 0x00000020
+#define NO_HSCX30_MASK  0x00000040
+#define MODE_MASK   0x00000080
+#define SET_BOARD   0x00001000
+#define SET_CRC4   0x00030000
+#define SET_L1_TRISTATE  0x00040000
+#define SET_WATCHDOG  0x00080000
+#define SET_NO_ORDER_CHECK 0x00100000
+#define SET_LOW_CHANNEL  0x00200000
+#define SET_NO_HSCX30  0x00400000
+#define SET_MODE   0x00800000
+#define SET_PROTO   0x02000000
+#define SET_CARDTYPE  0x04000000
+#define SET_NT2    0x08000000
+#define SET_PERMANENT  0x10000000
+#define SET_STABLEL2  0x20000000
+#define SET_TEI    0x40000000
+#define SET_NUMBERLEN  0x80000000
+ unsigned long Flag ;  /* |31-Type-16|15-Mask-0| */
+ unsigned long NumberLen ; /* reconfiguration: union is empty */
+ union {
+  struct {    /* possible reconfiguration, but ... ; SET_BOARD */
+   unsigned long SerialNumber ;
+   char     *pCardname ; /* di_defs.h: BOARD_NAME_LENGTH */
+  } board ;
+  struct {      /* reset: need resources */
+   void * pRawResources ;
+   void * pXlatResources ;
+  } res ;
+  struct { /* reconfiguration: wizProto == PROTTYPE_RBSCAS */
+#define GLARE_RESOLVE_MASK 0x00000001
+#define DID_MASK   0x00000002
+#define BEARER_CAP_MASK  0x0000000c
+#define SET_GLARE_RESOLVE 0x00010000
+#define SET_DID    0x00020000
+#define SET_BEARER_CAP  0x000c0000
+   unsigned long Flag ;  /* |31-Type-16|15-VALUE-0| */
+   unsigned short DigitTimeout ;
+   unsigned short AnswerDelay ;
+  } rbs ;
+  struct { /* reconfiguration: wizProto == PROTTYPE_QSIG */
+#define CALL_REF_LENGTH1_MASK 0x00000001
+#define BRI_CHANNEL_ID_MASK  0x00000002
+#define SET_CALL_REF_LENGTH  0x00010000
+#define SET_BRI_CHANNEL_ID  0x00020000
+   unsigned long Flag ;  /* |31-Type-16|15-VALUE-0| */
+  } qsig ;
+  struct { /* reconfiguration: NumberLen != 0 */
+#define SET_SPID1   0x00010000
+#define SET_NUMBER1   0x00020000
+#define SET_SUBADDRESS1  0x00040000
+#define SET_SPID2   0x00100000
+#define SET_NUMBER2   0x00200000
+#define SET_SUBADDRESS2  0x00400000
+#define MASK_SET   0xffff0000
+   unsigned long Flag ;   /* |31-Type-16|15-Channel-0| */
+   unsigned char *pBuffer ; /* number value */
+  } isdnNo ;
+ }
+parms
+;
+} isdnProps ;
+/*
+ * IDI_SYNC_REQ_PORTDRV_HOOK - signal plug/unplug (Award Cardware only)
+ */
+typedef void (  * PORTDRV_HOOK_CB) (void *Context, int Plug) ;
+typedef struct
+{ /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
+ unsigned char Req;             /* request (must be always 0) */
+ unsigned char Rc;              /* return code (is the request) */
+ unsigned char Function;           /* private function code  */
+ unsigned char Flags;           /* function refinements   */
+ PORTDRV_HOOK_CB Callback;   /* to be called on plug/unplug */
+ void   *Context;   /* context for callback   */
+ unsigned long Info;    /* more info if needed   */
+} PORTDRV_HOOK ;
+/*  Codes for the 'Rc' element in structure below. */
+#define SLI_INSTALL     (0xA1)
+#define SLI_UNINSTALL   (0xA2)
+typedef int ( * SLIENTRYPOINT)(void* p3SignalAPI, void* pContext);
+typedef struct
+{   /* 'Req' and 'Rc' must be at the same place as in the ENTITY struct */
+    unsigned char   Req;                /* request (must be always 0)   */
+    unsigned char   Rc;                 /* return code (is the request) */
+    unsigned char   Function;           /* private function code        */
+    unsigned char   Flags;              /* function refinements         */
+    SLIENTRYPOINT   Callback;           /* to be called on plug/unplug  */
+    void            *Context;           /* context for callback         */
+    unsigned long   Info;               /* more info if needed          */
+} SLIENTRYPOINT_REQ ;
+/******************************************************************************/
+/*
+ *  Definitions for DIVA USB
+ */
+typedef int  (  * USB_SEND_REQ) (unsigned char PipeIndex, unsigned char Type,void *Data, int sizeData);
+typedef int  (  * USB_START_DEV) (void *Adapter, void *Ipac) ;
+/* called from WDM */
+typedef void (  * USB_RECV_NOTIFY) (void *Ipac, void *msg) ;
+typedef void (  * USB_XMIT_NOTIFY) (void *Ipac, unsigned char PipeIndex) ;
+/******************************************************************************/
+/*
+ * Parameter description for synchronous requests.
+ *
+ * Sorry, must repeat some parts of di_defs.h here because
+ * they are not defined for all operating environments
+ */
+typedef union
+{ ENTITY Entity;
+ struct
+ { /* 'Req' and 'Rc' are at the same place as in the ENTITY struct */
+  unsigned char   Req; /* request (must be always 0) */
+  unsigned char   Rc;  /* return code (is the request) */
+ }   Request;
+ struct
+ { unsigned char   Req; /* request (must be always 0) */
+  unsigned char   Rc;  /* return code (0x01)   */
+  unsigned char   name[BOARD_NAME_LENGTH];
+ }   GetName;
+ struct
+ { unsigned char   Req; /* request (must be always 0) */
+  unsigned char   Rc;  /* return code (0x02)   */
+  unsigned long   serial; /* serial number    */
+ }   GetSerial;
+ struct
+ { unsigned char   Req; /* request (must be always 0) */
+  unsigned char   Rc;  /* return code (0x02)   */
+  unsigned long   lineIdx;/* line, 0 if card has only one */
+ }   GetLineIdx;
+ struct
+ { unsigned char  Req;     /* request (must be always 0) */
+  unsigned char  Rc;      /* return code (0x02)   */
+  unsigned long  cardtype;/* card type        */
+ }   GetCardType;
+ struct
+ { unsigned short command;/* command = 0x0300 */
+  unsigned short dummy; /* not used */
+  IDI_CALL       callback;/* routine to call back */
+  ENTITY      *contxt; /* ptr to entity to use */
+ }   PostCall;
+ struct
+ { unsigned char  Req;  /* request (must be always 0) */
+  unsigned char  Rc;   /* return code (0x04)   */
+  unsigned char  pcm[1]; /* buffer (a pc_maint struct) */
+ }   GetXlog;
+ struct
+ { unsigned char  Req;  /* request (must be always 0) */
+  unsigned char  Rc;   /* return code (0x05)   */
+  unsigned short features;/* feature defines see below */
+ }   GetFeatures;
+ SERIAL_HOOK  SerialHook;
+/* Added for DIVA USB */
+ struct
+ { unsigned char   Req;
+  unsigned char   Rc;
+  USB_SEND_REQ    UsbSendRequest; /* function in Diva Usb WDM driver in usb_os.c, */
+                                        /* called from usb_drv.c to send a message to our device */
+                                        /* eg UsbSendRequest (USB_PIPE_SIGNAL, USB_IPAC_START, 0, 0) ; */
+  USB_RECV_NOTIFY usb_recv;       /* called from usb_os.c to pass a received message and ptr to IPAC */
+                                        /* on to usb_drv.c by a call to usb_recv(). */
+  USB_XMIT_NOTIFY usb_xmit;       /* called from usb_os.c in DivaUSB.sys WDM to indicate a completed transmit */
+                                        /* to usb_drv.c by a call to usb_xmit(). */
+  USB_START_DEV   UsbStartDevice; /* Start the USB Device, in usb_os.c */
+  IDI_CALL        callback;       /* routine to call back */
+  ENTITY          *contxt;     /* ptr to entity to use */
+  void            ** ipac_ptr;    /* pointer to struct IPAC in VxD */
+ } Usb_Msg_old;
+/* message used by WDM and VXD to pass pointers of function and IPAC* */
+ struct
+ { unsigned char Req;
+  unsigned char Rc;
+        USB_SEND_REQ    pUsbSendRequest;/* function in Diva Usb WDM driver in usb_os.c, */
+                                        /* called from usb_drv.c to send a message to our device */
+                                        /* eg UsbSendRequest (USB_PIPE_SIGNAL, USB_IPAC_START, 0, 0) ; */
+        USB_RECV_NOTIFY p_usb_recv;     /* called from usb_os.c to pass a received message and ptr to IPAC */
+                                        /* on to usb_drv.c by a call to usb_recv(). */
+        USB_XMIT_NOTIFY p_usb_xmit;     /* called from usb_os.c in DivaUSB.sys WDM to indicate a completed transmit */
+                                        /* to usb_drv.c by a call to usb_xmit().*/
+  void            *ipac_ptr;      /* &Diva.ipac pointer to struct IPAC in VxD */
+ } Usb_Msg;
+ PORTDRV_HOOK PortdrvHook;
+    SLIENTRYPOINT_REQ   sliEntryPointReq;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_stream_interface_t info;
+  } xdi_stream_info;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_get_extended_xdi_features_t info;
+  } xdi_extended_features;
+ struct {
+    unsigned char Req;
+    unsigned char Rc;
+  diva_xdi_get_adapter_sdram_bar_t info;
+ } xdi_sdram_bar;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_get_capi_parameters_t info;
+  } xdi_capi_prms;
+ struct {
+  ENTITY           e;
+  diva_didd_adapter_notify_t info;
+ } didd_notify;
+ struct {
+  ENTITY           e;
+  diva_didd_add_adapter_t   info;
+ } didd_add_adapter;
+ struct {
+  ENTITY           e;
+  diva_didd_remove_adapter_t info;
+ } didd_remove_adapter;
+ struct {
+  ENTITY             e;
+  diva_didd_read_adapter_array_t info;
+ } didd_read_adapter_array;
+ struct {
+  ENTITY             e;
+  diva_didd_get_cfg_lib_ifc_t     info;
+ } didd_get_cfg_lib_ifc;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_get_logical_adapter_number_s_t info;
+  } xdi_logical_adapter_number;
+  struct {
+    unsigned char Req;
+    unsigned char Rc;
+    diva_xdi_dma_descriptor_operation_t info;
+  } xdi_dma_descriptor_operation;
+} IDI_SYNC_REQ;
+/******************************************************************************/
+#endif /* __DIVA_SYNC__H */  
diff --git a/drivers/isdn/hardware/eicon/dqueue.c b/drivers/isdn/hardware/eicon/dqueue.c
new file mode 100644
index 0000000..9822582
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dqueue.c
@@ -0,0 +1,110 @@
+/* $Id: dqueue.c,v 1.5 2003/04/12 21:40:49 schindler Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * User Mode IDI Interface
+ *
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "platform.h"
+#include "dqueue.h"
+
+int
+diva_data_q_init(diva_um_idi_data_queue_t * q,
+		 int max_length, int max_segments)
+{
+	int i;
+
+	q->max_length = max_length;
+	q->segments = max_segments;
+
+	for (i = 0; i < q->segments; i++) {
+		q->data[i] = NULL;
+		q->length[i] = 0;
+	}
+	q->read = q->write = q->count = q->segment_pending = 0;
+
+	for (i = 0; i < q->segments; i++) {
+		if (!(q->data[i] = diva_os_malloc(0, q->max_length))) {
+			diva_data_q_finit(q);
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+int diva_data_q_finit(diva_um_idi_data_queue_t * q)
+{
+	int i;
+
+	for (i = 0; i < q->segments; i++) {
+		if (q->data[i]) {
+			diva_os_free(0, q->data[i]);
+		}
+		q->data[i] = NULL;
+		q->length[i] = 0;
+	}
+	q->read = q->write = q->count = q->segment_pending = 0;
+
+	return (0);
+}
+
+int diva_data_q_get_max_length(const diva_um_idi_data_queue_t * q)
+{
+	return (q->max_length);
+}
+
+void *diva_data_q_get_segment4write(diva_um_idi_data_queue_t * q)
+{
+	if ((!q->segment_pending) && (q->count < q->segments)) {
+		q->segment_pending = 1;
+		return (q->data[q->write]);
+	}
+
+	return NULL;
+}
+
+void
+diva_data_q_ack_segment4write(diva_um_idi_data_queue_t * q, int length)
+{
+	if (q->segment_pending) {
+		q->length[q->write] = length;
+		q->count++;
+		q->write++;
+		if (q->write >= q->segments) {
+			q->write = 0;
+		}
+		q->segment_pending = 0;
+	}
+}
+
+const void *diva_data_q_get_segment4read(const diva_um_idi_data_queue_t *
+					 q)
+{
+	if (q->count) {
+		return (q->data[q->read]);
+	}
+	return NULL;
+}
+
+int diva_data_q_get_segment_length(const diva_um_idi_data_queue_t * q)
+{
+	return (q->length[q->read]);
+}
+
+void diva_data_q_ack_segment4read(diva_um_idi_data_queue_t * q)
+{
+	if (q->count) {
+		q->length[q->read] = 0;
+		q->count--;
+		q->read++;
+		if (q->read >= q->segments) {
+			q->read = 0;
+		}
+	}
+}
diff --git a/drivers/isdn/hardware/eicon/dqueue.h b/drivers/isdn/hardware/eicon/dqueue.h
new file mode 100644
index 0000000..72d21c9
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dqueue.h
@@ -0,0 +1,31 @@
+/* $Id: dqueue.h,v 1.1.2.2 2001/02/08 12:25:43 armin Exp $ */
+
+#ifndef _DIVA_USER_MODE_IDI_DATA_QUEUE_H__
+#define _DIVA_USER_MODE_IDI_DATA_QUEUE_H__
+
+#define DIVA_UM_IDI_MAX_MSGS 64
+
+typedef struct _diva_um_idi_data_queue {
+	int segments;
+	int max_length;
+	int read;
+	int write;
+	int count;
+	int segment_pending;
+	void *data[DIVA_UM_IDI_MAX_MSGS];
+	int length[DIVA_UM_IDI_MAX_MSGS];
+} diva_um_idi_data_queue_t;
+
+int diva_data_q_init(diva_um_idi_data_queue_t * q,
+		     int max_length, int max_segments);
+int diva_data_q_finit(diva_um_idi_data_queue_t * q);
+int diva_data_q_get_max_length(const diva_um_idi_data_queue_t * q);
+void *diva_data_q_get_segment4write(diva_um_idi_data_queue_t * q);
+void diva_data_q_ack_segment4write(diva_um_idi_data_queue_t * q,
+				   int length);
+const void *diva_data_q_get_segment4read(const diva_um_idi_data_queue_t *
+					 q);
+int diva_data_q_get_segment_length(const diva_um_idi_data_queue_t * q);
+void diva_data_q_ack_segment4read(diva_um_idi_data_queue_t * q);
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/dsp_defs.h b/drivers/isdn/hardware/eicon/dsp_defs.h
new file mode 100644
index 0000000..b44950e
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsp_defs.h
@@ -0,0 +1,304 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef DSP_DEFS_H_  
+#define DSP_DEFS_H_
+#include "dspdids.h"
+/*---------------------------------------------------------------------------*/
+#define dsp_download_reserve_space(fp,length)
+/*****************************************************************************/
+/*
+ * OS file access abstraction layer
+ *
+ * I/O functions returns -1 on error, 0 on EOF
+ */
+#define OS_SEEK_SET 0
+#define OS_SEEK_CUR 1
+#define OS_SEEK_END 2
+struct _OsFileHandle_;
+typedef long (  * OsFileIo)  (struct _OsFileHandle_    *handle,
+                                void                     *buffer,
+                                long                       size) ;
+typedef long (  * OsFileSeek)(struct _OsFileHandle_    *handle,
+                                long                       position,
+                                int                        mode) ;
+typedef long (  * OsCardLoad)(struct _OsFileHandle_    *handle,
+                                long                       length,
+                                void                         *   *addr) ;
+typedef struct _OsFileHandle_
+{ void       *sysFileDesc ;
+ unsigned long sysFileSize ;
+ OsFileIo      sysFileRead ;
+ OsFileSeek    sysFileSeek ;
+ void       *sysLoadDesc ;
+ OsCardLoad    sysCardLoad ;
+} OsFileHandle ;
+extern OsFileHandle *OsOpenFile (char *path_name) ;
+extern void          OsCloseFile (OsFileHandle *fp) ;
+/*****************************************************************************/
+#define DSP_TELINDUS_FILE "dspdload.bin"
+/* special DSP file for BRI cards for Qsig and CornetN because of missing memory */
+#define DSP_QSIG_TELINDUS_FILE "dspdqsig.bin"
+#define DSP_MDM_TELINDUS_FILE "dspdvmdm.bin"
+#define DSP_FAX_TELINDUS_FILE "dspdvfax.bin"
+#define DSP_DIRECTORY_ENTRIES 64
+#define DSP_MEMORY_TYPE_EXTERNAL_DM         0
+#define DSP_MEMORY_TYPE_EXTERNAL_PM         1
+#define DSP_MEMORY_TYPE_INTERNAL_DM         2
+#define DSP_MEMORY_TYPE_INTERNAL_PM         3
+#define DSP_DOWNLOAD_FLAG_BOOTABLE          0x0001
+#define DSP_DOWNLOAD_FLAG_2181              0x0002
+#define DSP_DOWNLOAD_FLAG_TIMECRITICAL      0x0004
+#define DSP_DOWNLOAD_FLAG_COMPAND           0x0008
+#define DSP_MEMORY_BLOCK_COUNT              16
+#define DSP_SEGMENT_PM_FLAG                 0x0001
+#define DSP_SEGMENT_SHARED_FLAG             0x0002
+#define DSP_SEGMENT_EXTERNAL_DM             DSP_MEMORY_TYPE_EXTERNAL_DM
+#define DSP_SEGMENT_EXTERNAL_PM             DSP_MEMORY_TYPE_EXTERNAL_PM
+#define DSP_SEGMENT_INTERNAL_DM             DSP_MEMORY_TYPE_INTERNAL_DM
+#define DSP_SEGMENT_INTERNAL_PM             DSP_MEMORY_TYPE_INTERNAL_PM
+#define DSP_SEGMENT_FIRST_RELOCATABLE       4
+#define DSP_DATA_BLOCK_PM_FLAG              0x0001
+#define DSP_DATA_BLOCK_DWORD_FLAG           0x0002
+#define DSP_DATA_BLOCK_RESOLVE_FLAG         0x0004
+#define DSP_RELOC_NONE                      0x00
+#define DSP_RELOC_SEGMENT_MASK              0x3f
+#define DSP_RELOC_TYPE_MASK                 0xc0
+#define DSP_RELOC_TYPE_0                    0x00  /* relocation of address in DM word / high part of PM word */
+#define DSP_RELOC_TYPE_1                    0x40  /* relocation of address in low part of PM data word */
+#define DSP_RELOC_TYPE_2                    0x80  /* relocation of address in standard command */
+#define DSP_RELOC_TYPE_3                    0xc0  /* relocation of address in call/jump on flag in */
+#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_COMBIFILE_FORMAT_VERSION_BCD    0x0100
+#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_FILE_FORMAT_VERSION_BCD         0x0100
+typedef struct tag_dsp_combifile_header
+{
+  char                  format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE];
+  word                  format_version_bcd;
+  word                  header_size;
+  word                  combifile_description_size;
+  word                  directory_entries;
+  word                  directory_size;
+  word                  download_count;
+  word                  usage_mask_size;
+} t_dsp_combifile_header;
+typedef struct tag_dsp_combifile_directory_entry
+{
+  word                  card_type_number;
+  word                  file_set_number;
+} t_dsp_combifile_directory_entry;
+typedef struct tag_dsp_file_header
+{
+  char                  format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE];
+  word                  format_version_bcd;
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  header_size;
+  word                  download_description_size;
+  word                  memory_block_table_size;
+  word                  memory_block_count;
+  word                  segment_table_size;
+  word                  segment_count;
+  word                  symbol_table_size;
+  word                  symbol_count;
+  word                  total_data_size_dm;
+  word                  data_block_count_dm;
+  word                  total_data_size_pm;
+  word                  data_block_count_pm;
+} t_dsp_file_header;
+typedef struct tag_dsp_memory_block_desc
+{
+  word                  alias_memory_block;
+  word                  memory_type;
+  word                  address;
+  word                  size;             /* DSP words */
+} t_dsp_memory_block_desc;
+typedef struct tag_dsp_segment_desc
+{
+  word                  memory_block;
+  word                  attributes;
+  word                  base;
+  word                  size;
+  word                  alignment;        /* ==0 -> no other legal start address than base */
+} t_dsp_segment_desc;
+typedef struct tag_dsp_symbol_desc
+{
+  word                  symbol_id;
+  word                  segment;
+  word                  offset;
+  word                  size;             /* DSP words */
+} t_dsp_symbol_desc;
+typedef struct tag_dsp_data_block_header
+{
+  word                  attributes;
+  word                  segment;
+  word                  offset;
+  word                  size;             /* DSP words */
+} t_dsp_data_block_header;
+typedef struct tag_dsp_download_desc
+{
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  excess_header_size;
+  word                  memory_block_count;
+  word                  segment_count;
+  word                  symbol_count;
+  word                  data_block_count_dm;
+  word                  data_block_count_pm;
+  byte   *            p_excess_header_data;
+  char   *            p_download_description;
+  t_dsp_memory_block_desc   *p_memory_block_table;
+  t_dsp_segment_desc   *p_segment_table;
+  t_dsp_symbol_desc   *p_symbol_table;
+  word   *            p_data_blocks_dm;
+  word   *            p_data_blocks_pm;
+} t_dsp_desc;
+typedef struct tag_dsp_portable_download_desc /* be sure to keep native alignment for MAESTRA's */
+{
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  excess_header_size;
+  word                  memory_block_count;
+  word                  segment_count;
+  word                  symbol_count;
+  word                  data_block_count_dm;
+  word                  data_block_count_pm;
+  dword                 p_excess_header_data;
+  dword                 p_download_description;
+  dword                 p_memory_block_table;
+  dword                 p_segment_table;
+  dword                 p_symbol_table;
+  dword                 p_data_blocks_dm;
+  dword                 p_data_blocks_pm;
+} t_dsp_portable_desc;
+#define DSP_DOWNLOAD_INDEX_KERNEL               0
+#define DSP30TX_DOWNLOAD_INDEX_KERNEL           1
+#define DSP30RX_DOWNLOAD_INDEX_KERNEL           2
+#define DSP_MAX_DOWNLOAD_COUNT                  64
+#define DSP_DOWNLOAD_MAX_SEGMENTS         16
+#define DSP_UDATA_REQUEST_RECONFIGURE     0
+/*
+parameters:
+  <word> reconfigure delay (in 8kHz samples)
+  <word> reconfigure code
+  <byte> reconfigure hdlc preamble flags
+*/
+#define DSP_RECONFIGURE_TX_FLAG           0x8000
+#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG  0x4000
+#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000
+#define DSP_RECONFIGURE_HDLC_FLAG         0x1000
+#define DSP_RECONFIGURE_SYNC_FLAG         0x0800
+#define DSP_RECONFIGURE_PROTOCOL_MASK     0x00ff
+#define DSP_RECONFIGURE_IDLE              0
+#define DSP_RECONFIGURE_V25               1
+#define DSP_RECONFIGURE_V21_CH2           2
+#define DSP_RECONFIGURE_V27_2400          3
+#define DSP_RECONFIGURE_V27_4800          4
+#define DSP_RECONFIGURE_V29_7200          5
+#define DSP_RECONFIGURE_V29_9600          6
+#define DSP_RECONFIGURE_V33_12000         7
+#define DSP_RECONFIGURE_V33_14400         8
+#define DSP_RECONFIGURE_V17_7200          9
+#define DSP_RECONFIGURE_V17_9600          10
+#define DSP_RECONFIGURE_V17_12000         11
+#define DSP_RECONFIGURE_V17_14400         12
+/*
+data indications if transparent framer
+  <byte> data 0
+  <byte> data 1
+  ...
+data indications if HDLC framer
+  <byte> data 0
+  <byte> data 1
+  ...
+  <byte> CRC 0
+  <byte> CRC 1
+  <byte> preamble flags
+*/
+#define DSP_UDATA_INDICATION_SYNC         0
+/*
+returns:
+  <word> time of sync (sampled from counter at 8kHz)
+*/
+#define DSP_UDATA_INDICATION_DCD_OFF      1
+/*
+returns:
+  <word> time of DCD off (sampled from counter at 8kHz)
+*/
+#define DSP_UDATA_INDICATION_DCD_ON       2
+/*
+returns:
+  <word> time of DCD on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s)
+*/
+#define DSP_UDATA_INDICATION_CTS_OFF      3
+/*
+returns:
+  <word> time of CTS off (sampled from counter at 8kHz)
+*/
+#define DSP_UDATA_INDICATION_CTS_ON       4
+/*
+returns:
+  <word> time of CTS on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s)
+*/
+#define DSP_CONNECTED_NORM_UNSPECIFIED      0
+#define DSP_CONNECTED_NORM_V21              1
+#define DSP_CONNECTED_NORM_V23              2
+#define DSP_CONNECTED_NORM_V22              3
+#define DSP_CONNECTED_NORM_V22_BIS          4
+#define DSP_CONNECTED_NORM_V32_BIS          5
+#define DSP_CONNECTED_NORM_V34              6
+#define DSP_CONNECTED_NORM_V8               7
+#define DSP_CONNECTED_NORM_BELL_212A        8
+#define DSP_CONNECTED_NORM_BELL_103         9
+#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
+#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
+#define DSP_CONNECTED_NORM_TFAST            12
+#define DSP_CONNECTED_NORM_V21_CH2          13
+#define DSP_CONNECTED_NORM_V27_TER          14
+#define DSP_CONNECTED_NORM_V29              15
+#define DSP_CONNECTED_NORM_V33              16
+#define DSP_CONNECTED_NORM_V17              17
+#define DSP_CONNECTED_OPTION_TRELLIS        0x0001
+/*---------------------------------------------------------------------------*/
+extern char *dsp_read_file (OsFileHandle          *fp,
+                            word                     card_type_number,
+                            word                  *p_dsp_download_count,
+                            t_dsp_desc            *p_dsp_download_table,
+                            t_dsp_portable_desc   *p_dsp_portable_download_table) ;
+/*---------------------------------------------------------------------------*/
+#endif /* DSP_DEFS_H_ */  
diff --git a/drivers/isdn/hardware/eicon/dsp_tst.h b/drivers/isdn/hardware/eicon/dsp_tst.h
new file mode 100644
index 0000000..a6021e5b
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsp_tst.h
@@ -0,0 +1,47 @@
+/* $Id: dsp_tst.h,v 1.1.2.2 2001/02/08 12:25:43 armin Exp $ */
+
+#ifndef __DIVA_PRI_HOST_TEST_DSPS_H__
+#define __DIVA_PRI_HOST_TEST_DSPS_H__
+
+/*
+   DSP registers on maestra pri
+   */
+#define DSP1_PORT       (0x00)
+#define DSP2_PORT       (0x8)
+#define DSP3_PORT       (0x800)
+#define DSP4_PORT       (0x808)
+#define DSP5_PORT       (0x810)
+#define DSP6_PORT       (0x818)
+#define DSP7_PORT       (0x820)
+#define DSP8_PORT       (0x828)
+#define DSP9_PORT       (0x830)
+#define DSP10_PORT      (0x840)
+#define DSP11_PORT      (0x848)
+#define DSP12_PORT      (0x850)
+#define DSP13_PORT      (0x858)
+#define DSP14_PORT      (0x860)
+#define DSP15_PORT      (0x868)
+#define DSP16_PORT      (0x870)
+#define DSP17_PORT      (0x1000)
+#define DSP18_PORT      (0x1008)
+#define DSP19_PORT      (0x1010)
+#define DSP20_PORT      (0x1018)
+#define DSP21_PORT      (0x1020)
+#define DSP22_PORT      (0x1028)
+#define DSP23_PORT      (0x1030)
+#define DSP24_PORT      (0x1040)
+#define DSP25_PORT      (0x1048)
+#define DSP26_PORT      (0x1050)
+#define DSP27_PORT      (0x1058)
+#define DSP28_PORT      (0x1060)
+#define DSP29_PORT      (0x1068)
+#define DSP30_PORT      (0x1070)
+#define DSP_ADR_OFFS    0x80
+
+/*------------------------------------------------------------------
+		Dsp related definitions
+  ------------------------------------------------------------------ */
+#define DSP_SIGNATURE_PROBE_WORD 0x5a5a
+#define dsp_make_address_ex(pm,address) ((word)((pm) ? (address) : (address) + 0x4000))
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/dspdids.h b/drivers/isdn/hardware/eicon/dspdids.h
new file mode 100644
index 0000000..ebe131a
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dspdids.h
@@ -0,0 +1,75 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef DSPDIDS_H_
+#define DSPDIDS_H_
+/*---------------------------------------------------------------------------*/
+#define DSP_DID_INVALID   0
+#define DSP_DID_DIVA   1
+#define DSP_DID_DIVA_PRO  2
+#define DSP_DID_DIVA_PRO_20  3
+#define DSP_DID_DIVA_PRO_PCCARD  4
+#define DSP_DID_DIVA_SERVER_BRI_1M 5
+#define DSP_DID_DIVA_SERVER_BRI_2M 6
+#define DSP_DID_DIVA_SERVER_PRI_2M_TX 7
+#define DSP_DID_DIVA_SERVER_PRI_2M_RX 8
+#define DSP_DID_DIVA_SERVER_PRI_30M 9
+#define DSP_DID_TASK_HSCX  100
+#define DSP_DID_TASK_HSCX_PRI_2M_TX 101
+#define DSP_DID_TASK_HSCX_PRI_2M_RX 102
+#define DSP_DID_TASK_V110KRNL  200
+#define DSP_DID_OVERLAY_V1100  201
+#define DSP_DID_OVERLAY_V1101  202
+#define DSP_DID_OVERLAY_V1102  203
+#define DSP_DID_OVERLAY_V1103  204
+#define DSP_DID_OVERLAY_V1104  205
+#define DSP_DID_OVERLAY_V1105  206
+#define DSP_DID_OVERLAY_V1106  207
+#define DSP_DID_OVERLAY_V1107  208
+#define DSP_DID_OVERLAY_V1108  209
+#define DSP_DID_OVERLAY_V1109  210
+#define DSP_DID_TASK_V110_PRI_2M_TX 220
+#define DSP_DID_TASK_V110_PRI_2M_RX 221
+#define DSP_DID_TASK_MODEM  300
+#define DSP_DID_TASK_FAX05  400
+#define DSP_DID_TASK_VOICE  500
+#define DSP_DID_TASK_TIKRNL81  600
+#define DSP_DID_OVERLAY_DIAL  601
+#define DSP_DID_OVERLAY_V22  602
+#define DSP_DID_OVERLAY_V32  603
+#define DSP_DID_OVERLAY_FSK  604
+#define DSP_DID_OVERLAY_FAX  605
+#define DSP_DID_OVERLAY_VXX  606
+#define DSP_DID_OVERLAY_V8  607
+#define DSP_DID_OVERLAY_INFO  608
+#define DSP_DID_OVERLAY_V34  609
+#define DSP_DID_OVERLAY_DFX  610
+#define DSP_DID_PARTIAL_OVERLAY_DIAL 611
+#define DSP_DID_PARTIAL_OVERLAY_FSK 612
+#define DSP_DID_PARTIAL_OVERLAY_FAX 613
+#define DSP_DID_TASK_TIKRNL05  700
+/*---------------------------------------------------------------------------*/
+#endif
+/*---------------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/dsrv4bri.h b/drivers/isdn/hardware/eicon/dsrv4bri.h
new file mode 100644
index 0000000..732d22d
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsrv4bri.h
@@ -0,0 +1,40 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_XDI_DSRV_4_BRI_INC__
+#define __DIVA_XDI_DSRV_4_BRI_INC__
+/*
+ * Some special registers in the PLX 9054
+ */
+#define PLX9054_P2LDBELL    0x60
+#define PLX9054_L2PDBELL    0x64
+#define PLX9054_INTCSR      0x69
+#define PLX9054_INT_ENABLE  0x09
+#define PLX9054_SOFT_RESET 0x4000
+#define PLX9054_RELOAD_EEPROM 0x2000
+#define DIVA_4BRI_REVISION(__x__) (((__x__)->cardType == CARDTYPE_DIVASRV_Q_8M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_B_2M_V2_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_B_2F_PCI) || ((__x__)->cardType == CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI))
+void diva_os_set_qBri_functions (PISDN_ADAPTER IoAdapter);
+void diva_os_set_qBri2_functions (PISDN_ADAPTER IoAdapter);
+#endif
diff --git a/drivers/isdn/hardware/eicon/dsrv_bri.h b/drivers/isdn/hardware/eicon/dsrv_bri.h
new file mode 100644
index 0000000..f38ebbe
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsrv_bri.h
@@ -0,0 +1,37 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_XDI_DSRV_BRI_INC__
+#define __DIVA_XDI_DSRV_BRI_INC__
+/*
+ Functions exported from os dependent part of
+ BRI card configuration and used in
+ OS independed part
+ */
+/*
+ Prepare OS dependent part of BRI functions
+ */
+void diva_os_prepare_maestra_functions (PISDN_ADAPTER IoAdapter);
+#endif
diff --git a/drivers/isdn/hardware/eicon/dsrv_pri.h b/drivers/isdn/hardware/eicon/dsrv_pri.h
new file mode 100644
index 0000000..8611826
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/dsrv_pri.h
@@ -0,0 +1,38 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_XDI_DSRV_PRI_INC__
+#define __DIVA_XDI_DSRV_PRI_INC__
+/*
+ Functions exported from os dependent part of
+ PRI card configuration and used in
+ OS independed part
+ */
+/*
+ Prepare OS dependent part of PRI/PRI Rev.2 functions
+ */
+void diva_os_prepare_pri_functions (PISDN_ADAPTER IoAdapter);
+void diva_os_prepare_pri2_functions (PISDN_ADAPTER IoAdapter);
+#endif
diff --git a/drivers/isdn/hardware/eicon/entity.h b/drivers/isdn/hardware/eicon/entity.h
new file mode 100644
index 0000000..16252cf
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/entity.h
@@ -0,0 +1,28 @@
+/* $Id: entity.h,v 1.4 2004/03/21 17:26:01 armin Exp $ */
+
+#ifndef __DIVAS_USER_MODE_IDI_ENTITY__
+#define __DIVAS_USER_MODE_IDI_ENTITY__
+
+#define DIVA_UM_IDI_RC_PENDING      0x00000001
+#define DIVA_UM_IDI_REMOVE_PENDING  0x00000002
+#define DIVA_UM_IDI_TX_FLOW_CONTROL 0x00000004
+#define DIVA_UM_IDI_REMOVED         0x00000008
+#define DIVA_UM_IDI_ASSIGN_PENDING  0x00000010
+
+typedef struct _divas_um_idi_entity {
+	struct list_head          link;
+	diva_um_idi_adapter_t*    adapter; /* Back to adapter */
+	ENTITY                    e;
+	void*                     os_ref;
+	dword                     status;
+	void*                     os_context;
+	int                       rc_count;
+	diva_um_idi_data_queue_t  data; /* definad by user 1 ... MAX */
+	diva_um_idi_data_queue_t  rc;   /* two entries */
+	BUFFERS                   XData;
+	BUFFERS                   RData;
+	byte                      buffer[2048+512];
+} divas_um_idi_entity_t;
+
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/helpers.h b/drivers/isdn/hardware/eicon/helpers.h
new file mode 100644
index 0000000..b212311
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/helpers.h
@@ -0,0 +1,51 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_XDI_CARD_CONFIG_HELPERS_INC__
+#define __DIVA_XDI_CARD_CONFIG_HELPERS_INC__
+dword diva_get_protocol_file_features  (byte* File,
+                      int offset,
+                      char *IdStringBuffer,
+                      dword IdBufferSize);
+void diva_configure_protocol (PISDN_ADAPTER IoAdapter);
+/*
+ Low level file access system abstraction
+ */
+/* -------------------------------------------------------------------------
+  Access to single file
+  Return pointer to the image of the requested file,
+  write image length to 'FileLength'
+  ------------------------------------------------------------------------- */
+void *xdiLoadFile (char *FileName, dword *FileLength, unsigned long MaxLoadSize) ;
+/* -------------------------------------------------------------------------
+  Dependent on the protocol settings does read return pointer
+  to the image of appropriate protocol file
+  ------------------------------------------------------------------------- */
+void *xdiLoadArchive (PISDN_ADAPTER IoAdapter, dword *FileLength, unsigned long MaxLoadSize) ;
+/* --------------------------------------------------------------------------
+  Free all system resources accessed by xdiLoadFile and xdiLoadArchive
+  -------------------------------------------------------------------------- */
+void xdiFreeFile (void* handle);
+#endif
diff --git a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c
new file mode 100644
index 0000000..4cbc68c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/idifunc.c
@@ -0,0 +1,267 @@
+/* $Id: idifunc.c,v 1.14.4.4 2004/08/28 20:03:53 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * User Mode IDI Interface 
+ *
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "platform.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "um_xdi.h"
+#include "um_idi.h"
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+extern char *DRIVERRELEASE_IDI;
+
+extern void DIVA_DIDD_Read(void *, int);
+extern int diva_user_mode_idi_create_adapter(const DESCRIPTOR *, int);
+extern void diva_user_mode_idi_remove_adapter(int);
+
+static dword notify_handle;
+static DESCRIPTOR DAdapter;
+static DESCRIPTOR MAdapter;
+
+static void no_printf(unsigned char *x, ...)
+{
+	/* dummy debug function */
+}
+
+#include "debuglib.c"
+
+/*
+ * stop debug
+ */
+static void stop_dbg(void)
+{
+	DbgDeregister();
+	memset(&MAdapter, 0, sizeof(MAdapter));
+	dprintf = no_printf;
+}
+
+typedef struct _udiva_card {
+	struct list_head list;
+	int Id;
+	DESCRIPTOR d;
+} udiva_card;
+
+static LIST_HEAD(cards);
+static diva_os_spin_lock_t ll_lock;
+
+/*
+ * find card in list
+ */
+static udiva_card *find_card_in_list(DESCRIPTOR * d)
+{
+	udiva_card *card;
+	struct list_head *tmp;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock(&ll_lock, &old_irql, "find card");
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, udiva_card, list);
+		if (card->d.request == d->request) {
+			diva_os_leave_spin_lock(&ll_lock, &old_irql,
+						"find card");
+			return (card);
+		}
+	}
+	diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card");
+	return ((udiva_card *) NULL);
+}
+
+/*
+ * new card
+ */
+static void um_new_card(DESCRIPTOR * d)
+{
+	int adapter_nr = 0;
+	udiva_card *card = NULL;
+	IDI_SYNC_REQ sync_req;
+	diva_os_spin_lock_magic_t old_irql;
+
+	if (!(card = diva_os_malloc(0, sizeof(udiva_card)))) {
+		DBG_ERR(("cannot get buffer for card"));
+		return;
+	}
+	memcpy(&card->d, d, sizeof(DESCRIPTOR));
+	sync_req.xdi_logical_adapter_number.Req = 0;
+	sync_req.xdi_logical_adapter_number.Rc =
+	    IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER;
+	card->d.request((ENTITY *) & sync_req);
+	adapter_nr =
+	    sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
+	card->Id = adapter_nr;
+	if (!(diva_user_mode_idi_create_adapter(d, adapter_nr))) {
+		diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card");
+		list_add_tail(&card->list, &cards);
+		diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card");
+	} else {
+		DBG_ERR(("could not create user mode idi card %d",
+			 adapter_nr));
+	}
+}
+
+/*
+ * remove card
+ */
+static void um_remove_card(DESCRIPTOR * d)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	udiva_card *card = NULL;
+
+	if (!(card = find_card_in_list(d))) {
+		DBG_ERR(("cannot find card to remove"));
+		return;
+	}
+	diva_user_mode_idi_remove_adapter(card->Id);
+	diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card");
+	list_del(&card->list);
+	diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card");
+	DBG_LOG(("idi proc entry removed for card %d", card->Id));
+	diva_os_free(0, card);
+}
+
+/*
+ * remove all adapter
+ */
+static void DIVA_EXIT_FUNCTION remove_all_idi_proc(void)
+{
+	udiva_card *card;
+	diva_os_spin_lock_magic_t old_irql;
+
+rescan:
+	diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove all");
+	if (!list_empty(&cards)) {
+		card = list_entry(cards.next, udiva_card, list);
+		list_del(&card->list);
+		diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all");
+		diva_user_mode_idi_remove_adapter(card->Id);
+		diva_os_free(0, card);
+		goto rescan;
+	}
+	diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all");
+}
+
+/*
+ * DIDD notify callback
+ */
+static void *didd_callback(void *context, DESCRIPTOR * adapter,
+			   int removal)
+{
+	if (adapter->type == IDI_DADAPTER) {
+		DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
+		return (NULL);
+	} else if (adapter->type == IDI_DIMAINT) {
+		if (removal) {
+			stop_dbg();
+		} else {
+			memcpy(&MAdapter, adapter, sizeof(MAdapter));
+			dprintf = (DIVA_DI_PRINTF) MAdapter.request;
+			DbgRegister("User IDI", DRIVERRELEASE_IDI, DBG_DEFAULT);
+		}
+	} else if ((adapter->type > 0) && (adapter->type < 16)) {	/* IDI Adapter */
+		if (removal) {
+			um_remove_card(adapter);
+		} else {
+			um_new_card(adapter);
+		}
+	}
+	return (NULL);
+}
+
+/*
+ * connect DIDD
+ */
+static int DIVA_INIT_FUNCTION connect_didd(void)
+{
+	int x = 0;
+	int dadapter = 0;
+	IDI_SYNC_REQ req;
+	DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+	DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+	for (x = 0; x < MAX_DESCRIPTORS; x++) {
+		if (DIDD_Table[x].type == IDI_DADAPTER) {	/* DADAPTER found */
+			dadapter = 1;
+			memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+			req.didd_notify.e.Req = 0;
+			req.didd_notify.e.Rc =
+			    IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+			req.didd_notify.info.callback = (void *)didd_callback;
+			req.didd_notify.info.context = NULL;
+			DAdapter.request((ENTITY *) & req);
+			if (req.didd_notify.e.Rc != 0xff) {
+				stop_dbg();
+				return (0);
+			}
+			notify_handle = req.didd_notify.info.handle;
+		} else if (DIDD_Table[x].type == IDI_DIMAINT) {	/* MAINT found */
+			memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
+			dprintf = (DIVA_DI_PRINTF) MAdapter.request;
+			DbgRegister("User IDI", DRIVERRELEASE_IDI, DBG_DEFAULT);
+		} else if ((DIDD_Table[x].type > 0)
+			   && (DIDD_Table[x].type < 16)) {	/* IDI Adapter found */
+			um_new_card(&DIDD_Table[x]);
+		}
+	}
+
+	if (!dadapter) {
+		stop_dbg();
+	}
+
+	return (dadapter);
+}
+
+/*
+ *  Disconnect from DIDD
+ */
+static void DIVA_EXIT_FUNCTION disconnect_didd(void)
+{
+	IDI_SYNC_REQ req;
+
+	stop_dbg();
+
+	req.didd_notify.e.Req = 0;
+	req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+	req.didd_notify.info.handle = notify_handle;
+	DAdapter.request((ENTITY *) & req);
+}
+
+/*
+ * init
+ */
+int DIVA_INIT_FUNCTION idifunc_init(void)
+{
+	diva_os_initialize_spin_lock(&ll_lock, "idifunc");
+
+	if (diva_user_mode_idi_init()) {
+		DBG_ERR(("init: init failed."));
+		return (0);
+	}
+
+	if (!connect_didd()) {
+		diva_user_mode_idi_finit();
+		DBG_ERR(("init: failed to connect to DIDD."));
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * finit
+ */
+void DIVA_EXIT_FUNCTION idifunc_finit(void)
+{
+	diva_user_mode_idi_finit();
+	disconnect_didd();
+	remove_all_idi_proc();
+}
diff --git a/drivers/isdn/hardware/eicon/io.c b/drivers/isdn/hardware/eicon/io.c
new file mode 100644
index 0000000..4a27e23
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/io.c
@@ -0,0 +1,852 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "divasync.h"
+#define MIPS_SCOM
+#include "pkmaint.h" /* pc_main.h, packed in os-dependent fashion */
+#include "di.h"
+#include "mi_pc.h"
+#include "io.h"
+extern ADAPTER * adapter[MAX_ADAPTER];
+extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
+void request (PISDN_ADAPTER, ENTITY *);
+static void pcm_req (PISDN_ADAPTER, ENTITY *);
+/* --------------------------------------------------------------------------
+  local functions
+  -------------------------------------------------------------------------- */
+#define ReqFunc(N) \
+static void Request##N(ENTITY *e) \
+{ if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }
+ReqFunc(0)
+ReqFunc(1)
+ReqFunc(2)
+ReqFunc(3)
+ReqFunc(4)
+ReqFunc(5)
+ReqFunc(6)
+ReqFunc(7)
+ReqFunc(8)
+ReqFunc(9)
+ReqFunc(10)
+ReqFunc(11)
+ReqFunc(12)
+ReqFunc(13)
+ReqFunc(14)
+ReqFunc(15)
+IDI_CALL Requests[MAX_ADAPTER] =
+{ &Request0, &Request1, &Request2, &Request3,
+ &Request4, &Request5, &Request6, &Request7,
+ &Request8, &Request9, &Request10, &Request11,
+ &Request12, &Request13, &Request14, &Request15
+};
+/*****************************************************************************/
+/*
+  This array should indicate all new services, that this version of XDI
+  is able to provide to his clients
+  */
+static byte extended_xdi_features[DIVA_XDI_EXTENDED_FEATURES_MAX_SZ+1] = {
+ (DIVA_XDI_EXTENDED_FEATURES_VALID       |
+  DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR    |
+  DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS    |
+#if defined(DIVA_IDI_RX_DMA)
+  DIVA_XDI_EXTENDED_FEATURE_CMA          |
+  DIVA_XDI_EXTENDED_FEATURE_RX_DMA       |
+  DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA |
+#endif
+  DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC),
+ 0
+};
+/*****************************************************************************/
+void
+dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc)
+{
+ dword   logLen ;
+ word *Xlog   = xlogDesc->buf ;
+ word  logCnt = xlogDesc->cnt ;
+ word  logOut = xlogDesc->out / sizeof(*Xlog) ;
+ DBG_FTL(("%s: ************* XLOG recovery (%d) *************",
+          &IoAdapter->Name[0], (int)logCnt))
+ DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0]))
+ for ( ; logCnt > 0 ; --logCnt )
+ {
+  if ( !GET_WORD(&Xlog[logOut]) )
+  {
+   if ( --logCnt == 0 )
+    break ;
+   logOut = 0 ;
+  }
+  if ( GET_WORD(&Xlog[logOut]) <= (logOut * sizeof(*Xlog)) )
+  {
+   if ( logCnt > 2 )
+   {
+    DBG_FTL(("Possibly corrupted XLOG: %d entries left",
+             (int)logCnt))
+   }
+   break ;
+  }
+  logLen = (dword)(GET_WORD(&Xlog[logOut]) - (logOut * sizeof(*Xlog))) ;
+  DBG_FTL_MXLOG(( (char *)&Xlog[logOut + 1], (dword)(logLen - 2) ))
+  logOut = (GET_WORD(&Xlog[logOut]) + 1) / sizeof(*Xlog) ;
+ }
+ DBG_FTL(("%s: ***************** end of XLOG *****************",
+          &IoAdapter->Name[0]))
+}
+/*****************************************************************************/
+#if defined(XDI_USE_XLOG)
+static char *(ExceptionCauseTable[]) =
+{
+ "Interrupt",
+ "TLB mod /IBOUND",
+ "TLB load /DBOUND",
+ "TLB store",
+ "Address error load",
+ "Address error store",
+ "Instruction load bus error",
+ "Data load/store bus error",
+ "Syscall",
+ "Breakpoint",
+ "Reverd instruction",
+ "Coprocessor unusable",
+ "Overflow",
+ "TRAP",
+ "VCEI",
+ "Floating Point Exception",
+ "CP2",
+ "Reserved 17",
+ "Reserved 18",
+ "Reserved 19",
+ "Reserved 20",
+ "Reserved 21",
+ "Reserved 22",
+ "WATCH",
+ "Reserved 24",
+ "Reserved 25",
+ "Reserved 26",
+ "Reserved 27",
+ "Reserved 28",
+ "Reserved 29",
+ "Reserved 30",
+ "VCED"
+} ;
+#endif
+void
+dump_trap_frame (PISDN_ADAPTER IoAdapter, byte __iomem *exceptionFrame)
+{
+ MP_XCPTC __iomem *xcept = (MP_XCPTC __iomem *)exceptionFrame ;
+ dword    __iomem *regs;
+ regs  = &xcept->regs[0] ;
+ DBG_FTL(("%s: ***************** CPU TRAPPED *****************",
+          &IoAdapter->Name[0]))
+ DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0]))
+ DBG_FTL(("Cause: %s",
+          ExceptionCauseTable[(READ_DWORD(&xcept->cr) & 0x0000007c) >> 2]))
+ DBG_FTL(("sr    0x%08x cr    0x%08x epc   0x%08x vaddr 0x%08x",
+          READ_DWORD(&xcept->sr), READ_DWORD(&xcept->cr),
+					READ_DWORD(&xcept->epc), READ_DWORD(&xcept->vaddr)))
+ DBG_FTL(("zero  0x%08x at    0x%08x v0    0x%08x v1    0x%08x",
+          READ_DWORD(&regs[ 0]), READ_DWORD(&regs[ 1]),
+					READ_DWORD(&regs[ 2]), READ_DWORD(&regs[ 3])))
+ DBG_FTL(("a0    0x%08x a1    0x%08x a2    0x%08x a3    0x%08x",
+          READ_DWORD(&regs[ 4]), READ_DWORD(&regs[ 5]),
+					READ_DWORD(&regs[ 6]), READ_DWORD(&regs[ 7])))
+ DBG_FTL(("t0    0x%08x t1    0x%08x t2    0x%08x t3    0x%08x",
+          READ_DWORD(&regs[ 8]), READ_DWORD(&regs[ 9]),
+					READ_DWORD(&regs[10]), READ_DWORD(&regs[11])))
+ DBG_FTL(("t4    0x%08x t5    0x%08x t6    0x%08x t7    0x%08x",
+          READ_DWORD(&regs[12]), READ_DWORD(&regs[13]),
+					READ_DWORD(&regs[14]), READ_DWORD(&regs[15])))
+ DBG_FTL(("s0    0x%08x s1    0x%08x s2    0x%08x s3    0x%08x",
+          READ_DWORD(&regs[16]), READ_DWORD(&regs[17]),
+					READ_DWORD(&regs[18]), READ_DWORD(&regs[19])))
+ DBG_FTL(("s4    0x%08x s5    0x%08x s6    0x%08x s7    0x%08x",
+          READ_DWORD(&regs[20]), READ_DWORD(&regs[21]),
+					READ_DWORD(&regs[22]), READ_DWORD(&regs[23])))
+ DBG_FTL(("t8    0x%08x t9    0x%08x k0    0x%08x k1    0x%08x",
+          READ_DWORD(&regs[24]), READ_DWORD(&regs[25]),
+					READ_DWORD(&regs[26]), READ_DWORD(&regs[27])))
+ DBG_FTL(("gp    0x%08x sp    0x%08x s8    0x%08x ra    0x%08x",
+          READ_DWORD(&regs[28]), READ_DWORD(&regs[29]),
+					READ_DWORD(&regs[30]), READ_DWORD(&regs[31])))
+ DBG_FTL(("md    0x%08x|%08x         resvd 0x%08x class 0x%08x",
+          READ_DWORD(&xcept->mdhi), READ_DWORD(&xcept->mdlo),
+					READ_DWORD(&xcept->reseverd), READ_DWORD(&xcept->xclass)))
+}
+/* --------------------------------------------------------------------------
+  Real XDI Request function
+  -------------------------------------------------------------------------- */
+void request(PISDN_ADAPTER IoAdapter, ENTITY * e)
+{
+ byte i;
+ diva_os_spin_lock_magic_t irql;
+/*
+ * if the Req field in the entity structure is 0,
+ * we treat this request as a special function call
+ */
+ if ( !e->Req )
+ {
+  IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e ;
+  switch (e->Rc)
+  {
+#if defined(DIVA_IDI_RX_DMA)
+    case IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION: {
+      diva_xdi_dma_descriptor_operation_t* pI = \
+                                   &syncReq->xdi_dma_descriptor_operation.info;
+      if (!IoAdapter->dma_map) {
+        pI->operation         = -1;
+        pI->descriptor_number = -1;
+        return;
+      }
+      diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "dma_op");
+      if (pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC) {
+        pI->descriptor_number = diva_alloc_dma_map_entry (\
+                               (struct _diva_dma_map_entry*)IoAdapter->dma_map);
+        if (pI->descriptor_number >= 0) {
+          dword dma_magic;
+          void* local_addr;
+          diva_get_dma_map_entry (\
+                               (struct _diva_dma_map_entry*)IoAdapter->dma_map,
+                               pI->descriptor_number,
+                               &local_addr, &dma_magic);
+          pI->descriptor_address  = local_addr;
+          pI->descriptor_magic    = dma_magic;
+          pI->operation           = 0;
+        } else {
+          pI->operation           = -1;
+        }
+      } else if ((pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE) &&
+                 (pI->descriptor_number >= 0)) {
+        diva_free_dma_map_entry((struct _diva_dma_map_entry*)IoAdapter->dma_map,
+                                pI->descriptor_number);
+        pI->descriptor_number = -1;
+        pI->operation         = 0;
+      } else {
+        pI->descriptor_number = -1;
+        pI->operation         = -1;
+      }
+      diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "dma_op");
+    } return;
+#endif
+    case IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER: {
+      diva_xdi_get_logical_adapter_number_s_t *pI = \
+                                     &syncReq->xdi_logical_adapter_number.info;
+      pI->logical_adapter_number = IoAdapter->ANum;
+      pI->controller = IoAdapter->ControllerNumber;
+      pI->total_controllers = IoAdapter->Properties.Adapters;
+    } return;
+    case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: {
+       diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info;
+       memset (&prms, 0x00, sizeof(prms));
+       prms.structure_length = MIN(sizeof(prms), pI->structure_length);
+       memset (pI, 0x00, pI->structure_length);
+       prms.flag_dynamic_l1_down    = (IoAdapter->capi_cfg.cfg_1 & \
+         DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? 1 : 0;
+       prms.group_optimization_enabled = (IoAdapter->capi_cfg.cfg_1 & \
+         DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) ? 1 : 0;
+       memcpy (pI, &prms, prms.structure_length);
+      } return;
+    case IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR:
+      syncReq->xdi_sdram_bar.info.bar = IoAdapter->sdram_bar;
+      return;
+    case IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES: {
+      dword i;
+      diva_xdi_get_extended_xdi_features_t* pI =\
+                                 &syncReq->xdi_extended_features.info;
+      pI->buffer_length_in_bytes &= ~0x80000000;
+      if (pI->buffer_length_in_bytes && pI->features) {
+        memset (pI->features, 0x00, pI->buffer_length_in_bytes);
+      }
+      for (i = 0; ((pI->features) && (i < pI->buffer_length_in_bytes) &&
+                   (i < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ)); i++) {
+        pI->features[i] = extended_xdi_features[i];
+      }
+      if ((pI->buffer_length_in_bytes < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ) ||
+          (!pI->features)) {
+        pI->buffer_length_in_bytes =\
+                           (0x80000000 | DIVA_XDI_EXTENDED_FEATURES_MAX_SZ);
+      }
+     } return;
+    case IDI_SYNC_REQ_XDI_GET_STREAM:
+      if (IoAdapter) {
+        diva_xdi_provide_istream_info (&IoAdapter->a,
+                                       &syncReq->xdi_stream_info.info);
+      } else {
+        syncReq->xdi_stream_info.info.provided_service = 0;
+      }
+      return;
+  case IDI_SYNC_REQ_GET_NAME:
+   if ( IoAdapter )
+   {
+    strcpy (&syncReq->GetName.name[0], IoAdapter->Name) ;
+    DBG_TRC(("xdi: Adapter %d / Name '%s'",
+             IoAdapter->ANum, IoAdapter->Name))
+    return ;
+   }
+   syncReq->GetName.name[0] = '\0' ;
+   break ;
+  case IDI_SYNC_REQ_GET_SERIAL:
+   if ( IoAdapter )
+   {
+    syncReq->GetSerial.serial = IoAdapter->serialNo ;
+    DBG_TRC(("xdi: Adapter %d / SerialNo %ld",
+             IoAdapter->ANum, IoAdapter->serialNo))
+    return ;
+   }
+   syncReq->GetSerial.serial = 0 ;
+   break ;
+  case IDI_SYNC_REQ_GET_CARDTYPE:
+   if ( IoAdapter )
+   {
+    syncReq->GetCardType.cardtype = IoAdapter->cardType ;
+    DBG_TRC(("xdi: Adapter %d / CardType %ld",
+             IoAdapter->ANum, IoAdapter->cardType))
+    return ;
+   }
+   syncReq->GetCardType.cardtype = 0 ;
+   break ;
+  case IDI_SYNC_REQ_GET_XLOG:
+   if ( IoAdapter )
+   {
+    pcm_req (IoAdapter, e) ;
+    return ;
+   }
+   e->Ind = 0 ;
+   break ;
+  case IDI_SYNC_REQ_GET_DBG_XLOG:
+   if ( IoAdapter )
+   {
+    pcm_req (IoAdapter, e) ;
+    return ;
+   }
+   e->Ind = 0 ;
+   break ;
+  case IDI_SYNC_REQ_GET_FEATURES:
+   if ( IoAdapter )
+   {
+    syncReq->GetFeatures.features =
+      (unsigned short)IoAdapter->features ;
+    return ;
+   }
+   syncReq->GetFeatures.features = 0 ;
+   break ;
+        case IDI_SYNC_REQ_PORTDRV_HOOK:
+            if ( IoAdapter )
+            {
+                DBG_TRC(("Xdi:IDI_SYNC_REQ_PORTDRV_HOOK - ignored"))
+                return ;
+            }
+            break;
+  }
+  if ( IoAdapter )
+  {
+   return ;
+  }
+ }
+ DBG_TRC(("xdi: Id 0x%x / Req 0x%x / Rc 0x%x", e->Id, e->Req, e->Rc))
+ if ( !IoAdapter )
+ {
+  DBG_FTL(("xdi: uninitialized Adapter used - ignore request"))
+  return ;
+ }
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
+/*
+ * assign an entity
+ */
+ if ( !(e->Id &0x1f) )
+ {
+  if ( IoAdapter->e_count >= IoAdapter->e_max )
+  {
+   DBG_FTL(("xdi: all Ids in use (max=%d) --> Req ignored",
+            IoAdapter->e_max))
+   diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
+   return ;
+  }
+/*
+ * find a new free id
+ */
+  for ( i = 1 ; IoAdapter->e_tbl[i].e ; ++i ) ;
+  IoAdapter->e_tbl[i].e = e ;
+  IoAdapter->e_count++ ;
+  e->No = (byte)i ;
+  e->More = 0 ;
+  e->RCurrent = 0xff ;
+ }
+ else
+ {
+  i = e->No ;
+ }
+/*
+ * if the entity is still busy, ignore the request call
+ */
+ if ( e->More & XBUSY )
+ {
+  DBG_FTL(("xdi: Id 0x%x busy --> Req 0x%x ignored", e->Id, e->Req))
+  if ( !IoAdapter->trapped && IoAdapter->trapFnc )
+  {
+   IoAdapter->trapFnc (IoAdapter) ;
+      /*
+        Firs trap, also notify user if supported
+       */
+      if (IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) {
+        (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum);
+      }
+  }
+  diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
+  return ;
+ }
+/*
+ * initialize transmit status variables
+ */
+ e->More |= XBUSY ;
+ e->More &= ~XMOREF ;
+ e->XCurrent = 0 ;
+ e->XOffset = 0 ;
+/*
+ * queue this entity in the adapter request queue
+ */
+ IoAdapter->e_tbl[i].next = 0 ;
+ if ( IoAdapter->head )
+ {
+  IoAdapter->e_tbl[IoAdapter->tail].next = i ;
+  IoAdapter->tail = i ;
+ }
+ else
+ {
+  IoAdapter->head = i ;
+  IoAdapter->tail = i ;
+ }
+/*
+ * queue the DPC to process the request
+ */
+ diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req");
+}
+/* ---------------------------------------------------------------------
+  Main DPC routine
+   --------------------------------------------------------------------- */
+void DIDpcRoutine (struct _diva_os_soft_isr* psoft_isr, void* Context) {
+ PISDN_ADAPTER IoAdapter  = (PISDN_ADAPTER)Context ;
+ ADAPTER* a        = &IoAdapter->a ;
+ diva_os_atomic_t* pin_dpc = &IoAdapter->in_dpc;
+ if (diva_os_atomic_increment (pin_dpc) == 1) {
+  do {
+   if ( IoAdapter->tst_irq (a) )
+   {
+    if ( !IoAdapter->Unavailable )
+     IoAdapter->dpc (a) ;
+    IoAdapter->clr_irq (a) ;
+   }
+   IoAdapter->out (a) ;
+  } while (diva_os_atomic_decrement (pin_dpc) > 0);
+  /* ----------------------------------------------------------------
+    Look for XLOG request (cards with indirect addressing)
+    ---------------------------------------------------------------- */
+  if (IoAdapter->pcm_pending) {
+   struct pc_maint *pcm;
+   diva_os_spin_lock_magic_t OldIrql ;
+   diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+                &OldIrql,
+                "data_dpc");
+   pcm = (struct pc_maint *)IoAdapter->pcm_data;
+   switch (IoAdapter->pcm_pending) {
+    case 1: /* ask card for XLOG */
+     a->ram_out (a, &IoAdapter->pcm->rc, 0) ;
+     a->ram_out (a, &IoAdapter->pcm->req, pcm->req) ;
+     IoAdapter->pcm_pending = 2;
+     break;
+    case 2: /* Try to get XLOG from the card */
+     if ((int)(a->ram_in (a, &IoAdapter->pcm->rc))) {
+      a->ram_in_buffer (a, IoAdapter->pcm, pcm, sizeof(*pcm)) ;
+      IoAdapter->pcm_pending = 3;
+     }
+     break;
+    case 3: /* let XDI recovery XLOG */
+     break;
+   }
+   diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+                &OldIrql,
+                "data_dpc");
+  }
+  /* ---------------------------------------------------------------- */
+ }
+}
+/* --------------------------------------------------------------------------
+  XLOG interface
+  -------------------------------------------------------------------------- */
+static void
+pcm_req (PISDN_ADAPTER IoAdapter, ENTITY *e)
+{
+ diva_os_spin_lock_magic_t OldIrql ;
+ int              i, rc ;
+ ADAPTER         *a = &IoAdapter->a ;
+ struct pc_maint *pcm = (struct pc_maint *)&e->Ind ;
+/*
+ * special handling of I/O based card interface
+ * the memory access isn't an atomic operation !
+ */
+ if ( IoAdapter->Properties.Card == CARD_MAE )
+ {
+  diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+               &OldIrql,
+               "data_pcm_1");
+  IoAdapter->pcm_data = (void *)pcm;
+  IoAdapter->pcm_pending = 1;
+  diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
+  diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+               &OldIrql,
+               "data_pcm_1");
+  for ( rc = 0, i = (IoAdapter->trapped ? 3000 : 250) ; !rc && (i > 0) ; --i )
+  {
+   diva_os_sleep (1) ;
+   if (IoAdapter->pcm_pending == 3) {
+    diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+                 &OldIrql,
+                 "data_pcm_3");
+    IoAdapter->pcm_pending = 0;
+    IoAdapter->pcm_data    = NULL ;
+    diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+                 &OldIrql,
+                 "data_pcm_3");
+    return ;
+   }
+   diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+                &OldIrql,
+                "data_pcm_2");
+   diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr);
+   diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+                &OldIrql,
+                "data_pcm_2");
+  }
+  diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+               &OldIrql,
+               "data_pcm_4");
+  IoAdapter->pcm_pending = 0;
+  IoAdapter->pcm_data    = NULL ;
+  diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+               &OldIrql,
+               "data_pcm_4");
+  goto Trapped ;
+ }
+/*
+ * memory based shared ram is accessible from different
+ * processors without disturbing concurrent processes.
+ */
+ a->ram_out (a, &IoAdapter->pcm->rc, 0) ;
+ a->ram_out (a, &IoAdapter->pcm->req, pcm->req) ;
+ for ( i = (IoAdapter->trapped ? 3000 : 250) ; --i > 0 ; )
+ {
+  diva_os_sleep (1) ;
+  rc = (int)(a->ram_in (a, &IoAdapter->pcm->rc)) ;
+  if ( rc )
+  {
+   a->ram_in_buffer (a, IoAdapter->pcm, pcm, sizeof(*pcm)) ;
+   return ;
+  }
+ }
+Trapped:
+ if ( IoAdapter->trapFnc )
+ {
+    int trapped = IoAdapter->trapped;
+  IoAdapter->trapFnc (IoAdapter) ;
+    /*
+      Firs trap, also notify user if supported
+     */
+    if (!trapped && IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) {
+      (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum);
+    }
+ }
+}
+/*------------------------------------------------------------------*/
+/* ram access functions for memory mapped cards                     */
+/*------------------------------------------------------------------*/
+byte mem_in (ADAPTER *a, void *addr)
+{
+ byte val;
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ val = READ_BYTE(Base + (unsigned long)addr);
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+ return (val);
+}
+word mem_inw (ADAPTER *a, void *addr)
+{
+ word val;
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ val = READ_WORD((Base + (unsigned long)addr));
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+ return (val);
+}
+void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords)
+{
+ volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ while (dwords--) {
+  *data++ = READ_DWORD((Base + (unsigned long)addr));
+  addr+=4;
+ }
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+}
+void mem_in_buffer (ADAPTER *a, void *addr, void *buffer, word length)
+{
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ memcpy_fromio(buffer, (Base + (unsigned long)addr), length);
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+}
+void mem_look_ahead (ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
+{
+ PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ;
+ IoAdapter->RBuffer.length = mem_inw (a, &RBuffer->length) ;
+ mem_in_buffer (a, RBuffer->P, IoAdapter->RBuffer.P,
+                IoAdapter->RBuffer.length) ;
+ e->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ;
+}
+void mem_out (ADAPTER *a, void *addr, byte data)
+{
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ WRITE_BYTE(Base + (unsigned long)addr, data);
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+}
+void mem_outw (ADAPTER *a, void *addr, word data)
+{
+ volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ WRITE_WORD((Base + (unsigned long)addr), data);
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+}
+void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords)
+{
+ volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ while (dwords--) {
+	WRITE_DWORD((Base + (unsigned long)addr), *data);
+  	addr+=4;
+	data++;
+ }
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+}
+void mem_out_buffer (ADAPTER *a, void *addr, void *buffer, word length)
+{
+ volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ memcpy_toio((Base + (unsigned long)addr), buffer, length) ;
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+}
+void mem_inc (ADAPTER *a, void *addr)
+{
+ volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io);
+ byte  x = READ_BYTE(Base + (unsigned long)addr);
+ WRITE_BYTE(Base + (unsigned long)addr, x + 1);
+ DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base);
+}
+/*------------------------------------------------------------------*/
+/* ram access functions for io-mapped cards                         */
+/*------------------------------------------------------------------*/
+byte io_in(ADAPTER * a, void * adr)
+{
+  byte val;
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  outppw(Port + 4, (word)(unsigned long)adr);
+  val = inpp(Port);
+  DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+  return(val);
+}
+word io_inw(ADAPTER * a, void * adr)
+{
+  word val;
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  outppw(Port + 4, (word)(unsigned long)adr);
+  val = inppw(Port);
+  DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+  return(val);
+}
+void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len)
+{
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte* P = (byte*)buffer;
+  if ((long)adr & 1) {
+    outppw(Port+4, (word)(unsigned long)adr);
+    *P = inpp(Port);
+    P++;
+    adr = ((byte *) adr) + 1;
+    len--;
+    if (!len) {
+	DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+	return;
+    }
+  }
+  outppw(Port+4, (word)(unsigned long)adr);
+  inppw_buffer (Port, P, len+1);
+  DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+}
+void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e)
+{
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  outppw(Port+4, (word)(unsigned long)RBuffer);
+  ((PISDN_ADAPTER)a->io)->RBuffer.length = inppw(Port);
+  inppw_buffer (Port, ((PISDN_ADAPTER)a->io)->RBuffer.P, ((PISDN_ADAPTER)a->io)->RBuffer.length + 1);
+  e->RBuffer = (DBUFFER *) &(((PISDN_ADAPTER)a->io)->RBuffer);
+  DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+}
+void io_out(ADAPTER * a, void * adr, byte data)
+{
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  outppw(Port+4, (word)(unsigned long)adr);
+  outpp(Port, data);
+  DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+}
+void io_outw(ADAPTER * a, void * adr, word data)
+{
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  outppw(Port+4, (word)(unsigned long)adr);
+  outppw(Port, data);
+  DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+}
+void io_out_buffer(ADAPTER * a, void * adr, void * buffer, word len)
+{
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  byte* P = (byte*)buffer;
+  if ((long)adr & 1) {
+    outppw(Port+4, (word)(unsigned long)adr);
+    outpp(Port, *P);
+    P++;
+    adr = ((byte *) adr) + 1;
+    len--;
+    if (!len) {
+	DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+	return;
+    }
+  }
+  outppw(Port+4, (word)(unsigned long)adr);
+  outppw_buffer (Port, P, len+1);
+  DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+}
+void io_inc(ADAPTER * a, void * adr)
+{
+  byte x;
+  byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io);
+  outppw(Port+4, (word)(unsigned long)adr);
+  x = inpp(Port);
+  outppw(Port+4, (word)(unsigned long)adr);
+  outpp(Port, x+1);
+  DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port);
+}
+/*------------------------------------------------------------------*/
+/* OS specific functions related to queuing of entities             */
+/*------------------------------------------------------------------*/
+void free_entity(ADAPTER * a, byte e_no)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_free");
+  IoAdapter->e_tbl[e_no].e = NULL;
+  IoAdapter->e_count--;
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_free");
+}
+void assign_queue(ADAPTER * a, byte e_no, word ref)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_assign");
+  IoAdapter->e_tbl[e_no].assign_ref = ref;
+  IoAdapter->e_tbl[e_no].next = (byte)IoAdapter->assign;
+  IoAdapter->assign = e_no;
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_assign");
+}
+byte get_assign(ADAPTER * a, word ref)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  byte e_no;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock,
+              &irql,
+              "data_assign_get");
+  for(e_no = (byte)IoAdapter->assign;
+      e_no && IoAdapter->e_tbl[e_no].assign_ref!=ref;
+      e_no = IoAdapter->e_tbl[e_no].next);
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock,
+              &irql,
+              "data_assign_get");
+  return e_no;
+}
+void req_queue(ADAPTER * a, byte e_no)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_q");
+  IoAdapter->e_tbl[e_no].next = 0;
+  if(IoAdapter->head) {
+    IoAdapter->e_tbl[IoAdapter->tail].next = e_no;
+    IoAdapter->tail = e_no;
+  }
+  else {
+    IoAdapter->head = e_no;
+    IoAdapter->tail = e_no;
+  }
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_q");
+}
+byte look_req(ADAPTER * a)
+{
+  PISDN_ADAPTER IoAdapter;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+  return ((byte)IoAdapter->head) ;
+}
+void next_req(ADAPTER * a)
+{
+  PISDN_ADAPTER IoAdapter;
+ diva_os_spin_lock_magic_t irql;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+ diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_next");
+  IoAdapter->head = IoAdapter->e_tbl[IoAdapter->head].next;
+  if(!IoAdapter->head) IoAdapter->tail = 0;
+ diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_next");
+}
+/*------------------------------------------------------------------*/
+/* memory map functions                                             */
+/*------------------------------------------------------------------*/
+ENTITY * entity_ptr(ADAPTER * a, byte e_no)
+{
+  PISDN_ADAPTER IoAdapter;
+  IoAdapter = (PISDN_ADAPTER) a->io;
+  return (IoAdapter->e_tbl[e_no].e);
+}
+void * PTR_X(ADAPTER * a, ENTITY * e)
+{
+  return ((void *) e->X);
+}
+void * PTR_R(ADAPTER * a, ENTITY * e)
+{
+  return ((void *) e->R);
+}
+void * PTR_P(ADAPTER * a, ENTITY * e, void * P)
+{
+  return P;
+}
+void CALLBACK(ADAPTER * a, ENTITY * e)
+{
+ if ( e && e->callback )
+  e->callback (e) ;
+}
diff --git a/drivers/isdn/hardware/eicon/io.h b/drivers/isdn/hardware/eicon/io.h
new file mode 100644
index 0000000..0c6c650
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/io.h
@@ -0,0 +1,308 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_XDI_COMMON_IO_H_INC__ /* { */
+#define __DIVA_XDI_COMMON_IO_H_INC__
+/*
+ maximum = 16 adapters
+ */
+#define DI_MAX_LINKS    MAX_ADAPTER
+#define ISDN_MAX_NUM_LEN 60
+/* --------------------------------------------------------------------------
+  structure for quadro card management (obsolete for
+  systems that do provide per card load event)
+  -------------------------------------------------------------------------- */
+typedef struct {
+ dword         Num ;
+ DEVICE_NAME   DeviceName[4] ;
+ PISDN_ADAPTER QuadroAdapter[4] ;
+} ADAPTER_LIST_ENTRY, *PADAPTER_LIST_ENTRY ;
+/* --------------------------------------------------------------------------
+  Special OS memory support structures
+  -------------------------------------------------------------------------- */
+#define MAX_MAPPED_ENTRIES 8
+typedef struct {
+ void  * Address;
+ dword    Length;
+} ADAPTER_MEMORY ;
+/* --------------------------------------------------------------------------
+  Configuration of XDI clients carried by XDI
+  -------------------------------------------------------------------------- */
+#define DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON      0x01
+#define DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON 0x02
+typedef struct _diva_xdi_capi_cfg {
+  byte cfg_1;
+} diva_xdi_capi_cfg_t;
+/* --------------------------------------------------------------------------
+  Main data structure kept per adapter
+  -------------------------------------------------------------------------- */
+struct _ISDN_ADAPTER {
+ void             (* DIRequest)(PISDN_ADAPTER, ENTITY *) ;
+ int                 State ; /* from NT4 1.srv, a good idea, but  a poor achievment */
+ int                 Initialized ;
+ int         RegisteredWithDidd ;
+ int                 Unavailable ;  /* callback function possible? */
+ int         ResourcesClaimed ;
+ int         PnpBiosConfigUsed ;
+ dword        Logging ;
+ dword        features ;
+ char        ProtocolIdString[80] ;
+ /*
+  remember mapped memory areas
+ */
+ ADAPTER_MEMORY     MappedMemory[MAX_MAPPED_ENTRIES] ;
+ CARD_PROPERTIES     Properties ;
+ dword               cardType ;
+ dword               protocol_id ;       /* configured protocol identifier */
+ char                protocol_name[8] ;  /* readable name of protocol */
+ dword               BusType ;
+ dword               BusNumber ;
+ dword               slotNumber ;
+ dword               slotId ;
+ dword               ControllerNumber ;  /* for QUADRO cards only */
+ PISDN_ADAPTER       MultiMaster ;       /* for 4-BRI card only - use MultiMaster or QuadroList */
+ PADAPTER_LIST_ENTRY QuadroList ;        /* for QUADRO card  only */
+ PDEVICE_OBJECT      DeviceObject ;
+ dword               DeviceId ;
+ diva_os_adapter_irq_info_t irq_info;
+ dword volatile      IrqCount ;
+ int                 trapped ;
+ dword               DspCodeBaseAddr ;
+ dword               MaxDspCodeSize ;
+ dword               downloadAddr ;
+ dword               DspCodeBaseAddrTable[4] ; /* add. for MultiMaster */
+ dword               MaxDspCodeSizeTable[4] ; /* add. for MultiMaster */
+ dword               downloadAddrTable[4] ; /* add. for MultiMaster */
+ dword               MemoryBase ;
+ dword               MemorySize ;
+ byte                __iomem *Address ;
+ byte                __iomem *Config ;
+ byte                __iomem *Control ;
+ byte                __iomem *reset ;
+ byte                __iomem *port ;
+ byte                __iomem *ram ;
+ byte                __iomem *cfg ;
+ byte                __iomem *prom ;
+ byte                __iomem *ctlReg ;
+ struct pc_maint  *pcm ;
+ diva_os_dependent_devica_name_t os_name;
+ byte                Name[32] ;
+ dword               serialNo ;
+ dword               ANum ;
+ dword               ArchiveType ; /* ARCHIVE_TYPE_NONE ..._SINGLE ..._USGEN ..._MULTI */
+ char               *ProtocolSuffix ; /* internal protocolfile table */
+ char                Archive[32] ;
+ char                Protocol[32] ;
+ char                AddDownload[32] ; /* Dsp- or other additional download files */
+ char                Oad1[ISDN_MAX_NUM_LEN] ;
+ char                Osa1[ISDN_MAX_NUM_LEN] ;
+ char                Oad2[ISDN_MAX_NUM_LEN] ;
+ char                Osa2[ISDN_MAX_NUM_LEN] ;
+ char                Spid1[ISDN_MAX_NUM_LEN] ;
+ char                Spid2[ISDN_MAX_NUM_LEN] ;
+  byte                nosig ;
+  byte                BriLayer2LinkCount ; /* amount of TEI's that adapter will support in P2MP mode */
+ dword               Channels ;
+ dword               tei ;
+ dword               nt2 ;
+ dword               TerminalCount ;
+ dword               WatchDog ;
+ dword               Permanent ;
+ dword               BChMask ; /* B channel mask for unchannelized modes */
+ dword               StableL2 ;
+ dword               DidLen ;
+ dword               NoOrderCheck ;
+ dword               ForceLaw; /* VoiceCoding - default:0, a-law: 1, my-law: 2 */
+ dword               SigFlags ;
+ dword               LowChannel ;
+ dword               NoHscx30 ;
+ dword               ProtVersion ;
+ dword               crc4 ;
+ dword               L1TristateOrQsig ; /* enable Layer 1 Tristate (bit 2)Or Qsig params (bit 0,1)*/
+ dword               InitialDspInfo ;
+ dword               ModemGuardTone ;
+ dword               ModemMinSpeed ;
+ dword               ModemMaxSpeed ;
+ dword               ModemOptions ;
+ dword               ModemOptions2 ;
+ dword               ModemNegotiationMode ;
+ dword               ModemModulationsMask ;
+ dword               ModemTransmitLevel ;
+ dword               FaxOptions ;
+ dword               FaxMaxSpeed ;
+ dword               Part68LevelLimiter ;
+ dword               UsEktsNumCallApp ;
+ byte                UsEktsFeatAddConf ;
+ byte                UsEktsFeatRemoveConf ;
+ byte                UsEktsFeatCallTransfer ;
+ byte                UsEktsFeatMsgWaiting ;
+ byte                QsigDialect;
+ byte                ForceVoiceMailAlert;
+ byte                DisableAutoSpid;
+ byte                ModemCarrierWaitTimeSec;
+ byte                ModemCarrierLossWaitTimeTenthSec;
+ byte                PiafsLinkTurnaroundInFrames;
+ byte                DiscAfterProgress;
+ byte                AniDniLimiter[3];
+ byte                TxAttenuation;  /* PRI/E1 only: attenuate TX signal */
+ word                QsigFeatures;
+ dword               GenerateRingtone ;
+ dword               SupplementaryServicesFeatures;
+ dword               R2Dialect;
+ dword               R2CasOptions;
+ dword               FaxV34Options;
+ dword               DisabledDspMask;
+ dword               AdapterTestMask;
+ dword               DspImageLength;
+ word                AlertToIn20mSecTicks;
+ word                ModemEyeSetup;
+ byte                R2CtryLength;
+ byte                CCBSRelTimer;
+ byte               *PcCfgBufferFile;/* flexible parameter via file */
+ byte               *PcCfgBuffer ; /* flexible parameter via multistring */
+ diva_os_dump_file_t dump_file; /* dump memory to file at lowest irq level */
+ diva_os_board_trace_t board_trace ; /* traces from the board */
+ diva_os_spin_lock_t isr_spin_lock;
+ diva_os_spin_lock_t data_spin_lock;
+ diva_os_soft_isr_t req_soft_isr;
+ diva_os_soft_isr_t isr_soft_isr;
+ diva_os_atomic_t  in_dpc;
+ PBUFFER             RBuffer;        /* Copy of receive lookahead buffer */
+ word                e_max;
+ word                e_count;
+ E_INFO             *e_tbl;
+ word                assign;         /* list of pending ASSIGNs  */
+ word                head;           /* head of request queue    */
+ word                tail;           /* tail of request queue    */
+ ADAPTER             a ;             /* not a separate structure */
+ void        (* out)(ADAPTER * a) ;
+ byte        (* dpc)(ADAPTER * a) ;
+ byte        (* tst_irq)(ADAPTER * a) ;
+ void        (* clr_irq)(ADAPTER * a) ;
+ int         (* load)(PISDN_ADAPTER) ;
+ int         (* mapmem)(PISDN_ADAPTER) ;
+ int         (* chkIrq)(PISDN_ADAPTER) ;
+ void        (* disIrq)(PISDN_ADAPTER) ;
+ void        (* start)(PISDN_ADAPTER) ;
+ void        (* stop)(PISDN_ADAPTER) ;
+ void        (* rstFnc)(PISDN_ADAPTER) ;
+ void        (* trapFnc)(PISDN_ADAPTER) ;
+ dword            (* DetectDsps)(PISDN_ADAPTER) ;
+ void        (* os_trap_nfy_Fnc)(PISDN_ADAPTER, dword) ;
+ diva_os_isr_callback_t diva_isr_handler;
+ dword               sdram_bar;  /* must be 32 bit */
+ dword               fpga_features;
+ volatile int        pcm_pending;
+ volatile void *     pcm_data;
+ diva_xdi_capi_cfg_t capi_cfg;
+ dword               tasks;
+ void               *dma_map;
+ int             (*DivaAdapterTestProc)(PISDN_ADAPTER);
+ void               *AdapterTestMemoryStart;
+ dword               AdapterTestMemoryLength;
+ const byte* cfg_lib_memory_init;
+ dword       cfg_lib_memory_init_length;
+};
+/* ---------------------------------------------------------------------
+  Entity table
+   --------------------------------------------------------------------- */
+struct e_info_s {
+  ENTITY *      e;
+  byte          next;                   /* chaining index           */
+  word          assign_ref;             /* assign reference         */
+};
+/* ---------------------------------------------------------------------
+  S-cards shared ram structure for loading
+   --------------------------------------------------------------------- */
+struct s_load {
+ byte ctrl;
+ byte card;
+ byte msize;
+ byte fill0;
+ word ebit;
+ word elocl;
+ word eloch;
+ byte reserved[20];
+ word signature;
+ byte fill[224];
+ byte b[256];
+};
+#define PR_RAM  ((struct pr_ram *)0)
+#define RAM ((struct dual *)0)
+/* ---------------------------------------------------------------------
+  platform specific conversions
+   --------------------------------------------------------------------- */
+extern void * PTR_P(ADAPTER * a, ENTITY * e, void * P);
+extern void * PTR_X(ADAPTER * a, ENTITY * e);
+extern void * PTR_R(ADAPTER * a, ENTITY * e);
+extern void CALLBACK(ADAPTER * a, ENTITY * e);
+extern void set_ram(void * * adr_ptr);
+/* ---------------------------------------------------------------------
+  ram access functions for io mapped cards
+   --------------------------------------------------------------------- */
+byte io_in(ADAPTER * a, void * adr);
+word io_inw(ADAPTER * a, void * adr);
+void io_in_buffer(ADAPTER * a, void * adr, void * P, word length);
+void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
+void io_out(ADAPTER * a, void * adr, byte data);
+void io_outw(ADAPTER * a, void * adr, word data);
+void io_out_buffer(ADAPTER * a, void * adr, void * P, word length);
+void io_inc(ADAPTER * a, void * adr);
+void bri_in_buffer (PISDN_ADAPTER IoAdapter, dword Pos,
+                    void *Buf, dword Len);
+int bri_out_buffer (PISDN_ADAPTER IoAdapter, dword Pos,
+                    void *Buf, dword Len, int Verify);
+/* ---------------------------------------------------------------------
+  ram access functions for memory mapped cards
+   --------------------------------------------------------------------- */
+byte mem_in(ADAPTER * a, void * adr);
+word mem_inw(ADAPTER * a, void * adr);
+void mem_in_buffer(ADAPTER * a, void * adr, void * P, word length);
+void mem_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
+void mem_out(ADAPTER * a, void * adr, byte data);
+void mem_outw(ADAPTER * a, void * adr, word data);
+void mem_out_buffer(ADAPTER * a, void * adr, void * P, word length);
+void mem_inc(ADAPTER * a, void * adr);
+void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords);
+void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords);
+/* ---------------------------------------------------------------------
+  functions exported by io.c
+   --------------------------------------------------------------------- */
+extern IDI_CALL Requests[MAX_ADAPTER] ;
+extern void     DIDpcRoutine (struct _diva_os_soft_isr* psoft_isr,
+               void* context);
+extern void     request (PISDN_ADAPTER, ENTITY *) ;
+/* ---------------------------------------------------------------------
+  trapFn helpers, used to recover debug trace from dead card
+   --------------------------------------------------------------------- */
+typedef struct {
+ word *buf ;
+ word  cnt ;
+ word  out ;
+} Xdesc ;
+extern void     dump_trap_frame  (PISDN_ADAPTER IoAdapter, byte __iomem *exception) ;
+extern void     dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc) ;
+/* --------------------------------------------------------------------- */
+#endif  /* } __DIVA_XDI_COMMON_IO_H_INC__ */
diff --git a/drivers/isdn/hardware/eicon/istream.c b/drivers/isdn/hardware/eicon/istream.c
new file mode 100644
index 0000000..2313966
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/istream.c
@@ -0,0 +1,226 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#if defined(DIVA_ISTREAM) /* { */
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "di.h"
+#if !defined USE_EXTENDED_DEBUGS
+  #include "dimaint.h"
+#else
+  #define dprintf
+#endif
+#include "dfifo.h"
+int diva_istream_write (void* context,
+             int   Id,
+              void* data,
+             int length,
+             int final,
+            byte usr1,
+            byte usr2);
+int diva_istream_read (void* context,
+            int Id,
+            void* data,
+            int max_length,
+            int* final,
+            byte* usr1,
+            byte* usr2);
+/* -------------------------------------------------------------------
+  Does provide iStream interface to the client
+   ------------------------------------------------------------------- */
+void diva_xdi_provide_istream_info (ADAPTER* a,
+                  diva_xdi_stream_interface_t* pi) {
+  pi->provided_service = 0;
+}
+/* ------------------------------------------------------------------
+  Does write the data from caller's buffer to the card's
+  stream interface.
+  If synchronous service was requested, then function
+  does return amount of data written to stream.
+  'final' does indicate that pice of data to be written is
+  final part of frame (necessary only by structured datatransfer)
+  return  0 if zero lengh packet was written
+  return -1 if stream is full
+  ------------------------------------------------------------------ */
+int diva_istream_write (void* context,
+                int   Id,
+                  void* data,
+                 int length,
+                 int final,
+                byte usr1,
+                byte usr2) {
+ ADAPTER* a = (ADAPTER*)context;
+ int written = 0, to_write = -1;
+ char tmp[4];
+ byte* data_ptr = (byte*)data;
+ for (;;) {
+  a->ram_in_dw (a,
+#ifdef PLATFORM_GT_32BIT
+         ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]),
+#else
+         (void*)(a->tx_stream[Id] + a->tx_pos[Id]),
+#endif
+                  (dword*)&tmp[0],
+         1);
+  if (tmp[0] & DIVA_DFIFO_READY) { /* No free blocks more */
+   if (to_write < 0)
+    return (-1); /* was not able to write       */
+   break;     /* only part of message was written */
+  }
+  to_write = MIN(length, DIVA_DFIFO_DATA_SZ);
+  if (to_write) {
+   a->ram_out_buffer (a,
+#ifdef PLATFORM_GT_32BIT
+            ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]+4),
+#else
+              (void*)(a->tx_stream[Id] + a->tx_pos[Id] + 4),
+#endif
+                         data_ptr,
+             (word)to_write);
+   length  -= to_write;
+   written  += to_write;
+   data_ptr += to_write;
+  }
+  tmp[1] = (char)to_write;
+  tmp[0] = (tmp[0] & DIVA_DFIFO_WRAP) |
+       DIVA_DFIFO_READY |
+       ((!length && final) ? DIVA_DFIFO_LAST : 0);
+  if (tmp[0] & DIVA_DFIFO_LAST) {
+   tmp[2] = usr1;
+   tmp[3] = usr2;
+  }
+    a->ram_out_dw (a,
+#ifdef PLATFORM_GT_32BIT
+         ULongToPtr(a->tx_stream[Id] + a->tx_pos[Id]),
+#else
+           (void*)(a->tx_stream[Id] + a->tx_pos[Id]),
+#endif
+                   (dword*)&tmp[0],
+          1);
+  if (tmp[0] & DIVA_DFIFO_WRAP) {
+   a->tx_pos[Id]  = 0;
+  } else {
+   a->tx_pos[Id] += DIVA_DFIFO_STEP;
+  }
+  if (!length) {
+   break;
+  }
+ }
+ return (written);
+}
+/* -------------------------------------------------------------------
+  In case of SYNCRONOUS service:
+  Does write data from stream in caller's buffer.
+  Does return amount of data written to buffer
+  Final flag is set on return if last part of structured frame
+  was received
+  return 0  if zero packet was received
+  return -1 if stream is empty
+    return -2 if read buffer does not profide sufficient space
+              to accommodate entire segment
+  max_length should be at least 68 bytes
+  ------------------------------------------------------------------- */
+int diva_istream_read (void* context,
+                int Id,
+                void* data,
+                int max_length,
+                int* final,
+               byte* usr1,
+               byte* usr2) {
+ ADAPTER* a = (ADAPTER*)context;
+ int read = 0, to_read = -1;
+ char tmp[4];
+ byte* data_ptr = (byte*)data;
+ *final = 0;
+ for (;;) {
+  a->ram_in_dw (a,
+#ifdef PLATFORM_GT_32BIT
+         ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id]),
+#else
+         (void*)(a->rx_stream[Id] + a->rx_pos[Id]),
+#endif
+                  (dword*)&tmp[0],
+         1);
+  if (tmp[1] > max_length) {
+   if (to_read < 0)
+    return (-2); /* was not able to read */
+   break;
+    }
+  if (!(tmp[0] & DIVA_DFIFO_READY)) {
+   if (to_read < 0)
+    return (-1); /* was not able to read */
+   break;
+  }
+  to_read = MIN(max_length, tmp[1]);
+  if (to_read) {
+   a->ram_in_buffer(a,
+#ifdef PLATFORM_GT_32BIT
+           ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id] + 4),
+#else
+            (void*)(a->rx_stream[Id] + a->rx_pos[Id] + 4),
+#endif
+                       data_ptr,
+            (word)to_read);
+   max_length -= to_read;
+   read     += to_read;
+   data_ptr  += to_read;
+  }
+  if (tmp[0] & DIVA_DFIFO_LAST) {
+   *final = 1;
+  }
+  tmp[0] &= DIVA_DFIFO_WRAP;
+    a->ram_out_dw(a,
+#ifdef PLATFORM_GT_32BIT
+         ULongToPtr(a->rx_stream[Id] + a->rx_pos[Id]),
+#else
+         (void*)(a->rx_stream[Id] + a->rx_pos[Id]),
+#endif
+         (dword*)&tmp[0],
+         1);
+  if (tmp[0] & DIVA_DFIFO_WRAP) {
+   a->rx_pos[Id]  = 0;
+  } else {
+   a->rx_pos[Id] += DIVA_DFIFO_STEP;
+  }
+  if (*final) {
+   if (usr1)
+    *usr1 = tmp[2];
+   if (usr2)
+    *usr2 = tmp[3];
+   break;
+  }
+ }
+ return (read);
+}
+/* ---------------------------------------------------------------------
+  Does check if one of streams had caused interrupt and does
+  wake up corresponding application
+   --------------------------------------------------------------------- */
+void pr_stream (ADAPTER * a) {
+}
+#endif /* } */
diff --git a/drivers/isdn/hardware/eicon/kst_ifc.h b/drivers/isdn/hardware/eicon/kst_ifc.h
new file mode 100644
index 0000000..203189a
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/kst_ifc.h
@@ -0,0 +1,336 @@
+/*
+ *
+  Copyright (c) Eicon Networks, 2000.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    1.9
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_EICON_TRACE_API__
+#define __DIVA_EICON_TRACE_API__
+
+#define DIVA_TRACE_LINE_TYPE_LEN 64
+#define DIVA_TRACE_IE_LEN        64
+#define DIVA_TRACE_FAX_PRMS_LEN  128
+
+typedef struct _diva_trace_ie {
+	byte length;
+	byte data[DIVA_TRACE_IE_LEN];
+} diva_trace_ie_t;
+
+/*
+	Structure used to represent "State\\BX\\Modem" directory
+	to user.
+	*/
+typedef struct _diva_trace_modem_state {
+	dword	ChannelNumber;
+
+	dword	Event;
+
+	dword	Norm;
+
+	dword Options; /* Options received from Application */
+
+	dword	TxSpeed;
+	dword	RxSpeed;
+
+	dword RoundtripMsec;
+
+	dword SymbolRate;
+
+	int		RxLeveldBm;
+	int		EchoLeveldBm;
+
+	dword	SNRdb;
+	dword MAE;
+
+	dword LocalRetrains;
+	dword RemoteRetrains;
+	dword LocalResyncs;
+	dword RemoteResyncs;
+
+	dword DiscReason;
+
+} diva_trace_modem_state_t;
+
+/*
+	Representation of "State\\BX\\FAX" directory
+	*/
+typedef struct _diva_trace_fax_state {
+	dword	ChannelNumber;
+	dword Event;
+	dword Page_Counter;
+	dword Features;
+	char Station_ID[DIVA_TRACE_FAX_PRMS_LEN];
+	char Subaddress[DIVA_TRACE_FAX_PRMS_LEN];
+	char Password[DIVA_TRACE_FAX_PRMS_LEN];
+	dword Speed;
+	dword Resolution;
+	dword Paper_Width;
+	dword Paper_Length;
+	dword Scanline_Time;
+	dword Disc_Reason;
+	dword	dummy;
+} diva_trace_fax_state_t;
+
+/*
+	Structure used to represent Interface State in the abstract
+	and interface/D-channel protocol independent form.
+	*/
+typedef struct _diva_trace_interface_state {
+	char Layer1[DIVA_TRACE_LINE_TYPE_LEN];
+	char Layer2[DIVA_TRACE_LINE_TYPE_LEN];
+} diva_trace_interface_state_t;
+
+typedef struct _diva_incoming_call_statistics {
+	dword Calls;
+	dword Connected;
+	dword User_Busy;
+	dword Call_Rejected;
+	dword Wrong_Number;
+	dword Incompatible_Dst;
+	dword Out_of_Order;
+	dword Ignored;
+} diva_incoming_call_statistics_t;
+
+typedef struct _diva_outgoing_call_statistics {
+	dword Calls;
+	dword Connected;
+	dword User_Busy;
+	dword No_Answer;
+	dword Wrong_Number;
+	dword Call_Rejected;
+	dword Other_Failures;
+} diva_outgoing_call_statistics_t;
+
+typedef struct _diva_modem_call_statistics {
+	dword Disc_Normal;
+	dword Disc_Unspecified;
+	dword Disc_Busy_Tone;
+	dword Disc_Congestion;
+	dword Disc_Carr_Wait;
+	dword Disc_Trn_Timeout;
+	dword Disc_Incompat;
+	dword Disc_Frame_Rej;
+	dword Disc_V42bis;
+} diva_modem_call_statistics_t;
+
+typedef struct _diva_fax_call_statistics {
+	dword Disc_Normal;
+	dword Disc_Not_Ident;
+	dword Disc_No_Response;
+	dword Disc_Retries;
+	dword Disc_Unexp_Msg;
+	dword Disc_No_Polling;
+	dword Disc_Training;
+	dword Disc_Unexpected;
+	dword Disc_Application;
+	dword Disc_Incompat;
+	dword Disc_No_Command;
+	dword Disc_Long_Msg;
+	dword Disc_Supervisor;
+	dword Disc_SUB_SEP_PWD;
+	dword Disc_Invalid_Msg;
+	dword Disc_Page_Coding;
+	dword Disc_App_Timeout;
+	dword Disc_Unspecified;
+} diva_fax_call_statistics_t;
+
+typedef struct _diva_prot_statistics {
+	dword X_Frames;
+	dword X_Bytes;
+	dword X_Errors;
+	dword R_Frames;
+	dword R_Bytes;
+	dword R_Errors;
+} diva_prot_statistics_t;
+
+typedef struct _diva_ifc_statistics {
+	diva_incoming_call_statistics_t	inc;
+	diva_outgoing_call_statistics_t outg;
+	diva_modem_call_statistics_t		mdm;
+	diva_fax_call_statistics_t			fax;
+	diva_prot_statistics_t					b1;
+	diva_prot_statistics_t					b2;
+	diva_prot_statistics_t					d1;
+	diva_prot_statistics_t					d2;
+} diva_ifc_statistics_t;
+
+/*
+	Structure used to represent "State\\BX" directory
+	to user.
+	*/
+typedef struct _diva_trace_line_state {
+	dword	ChannelNumber;
+
+	char Line[DIVA_TRACE_LINE_TYPE_LEN];
+
+	char Framing[DIVA_TRACE_LINE_TYPE_LEN];
+
+	char Layer2[DIVA_TRACE_LINE_TYPE_LEN];
+	char Layer3[DIVA_TRACE_LINE_TYPE_LEN];
+
+	char RemoteAddress[DIVA_TRACE_LINE_TYPE_LEN];
+	char RemoteSubAddress[DIVA_TRACE_LINE_TYPE_LEN];
+
+	char LocalAddress[DIVA_TRACE_LINE_TYPE_LEN];
+	char LocalSubAddress[DIVA_TRACE_LINE_TYPE_LEN];
+
+	diva_trace_ie_t	call_BC;
+	diva_trace_ie_t	call_HLC;
+	diva_trace_ie_t	call_LLC;
+
+	dword Charges;
+
+	dword CallReference;
+
+	dword LastDisconnecCause;
+
+	char UserID[DIVA_TRACE_LINE_TYPE_LEN];
+
+	diva_trace_modem_state_t modem;
+	diva_trace_fax_state_t   fax;
+
+	diva_trace_interface_state_t* pInterface;
+
+	diva_ifc_statistics_t*				pInterfaceStat;
+
+} diva_trace_line_state_t;
+
+#define DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE             ('l')
+#define DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE            ('m')
+#define DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE              ('f')
+#define DIVA_SUPER_TRACE_INTERFACE_CHANGE               ('i')
+#define DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE             ('s')
+#define DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE         ('M')
+#define DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE         ('F')
+
+struct _diva_strace_library_interface;
+typedef void (*diva_trace_channel_state_change_proc_t)(void* user_context,
+							struct _diva_strace_library_interface* hLib,
+							int Adapter,
+							diva_trace_line_state_t* channel, int notify_subject);
+typedef void (*diva_trace_channel_trace_proc_t)(void* user_context,
+							struct _diva_strace_library_interface* hLib,
+							int Adapter, void* xlog_buffer, int length);
+typedef void (*diva_trace_error_proc_t)(void* user_context,
+							struct _diva_strace_library_interface* hLib,
+							int Adapter,
+							int error, const char* file, int line);
+
+/*
+	This structure creates interface from user to library
+	*/
+typedef struct _diva_trace_library_user_interface {
+	void*																		user_context;
+	diva_trace_channel_state_change_proc_t	notify_proc;
+	diva_trace_channel_trace_proc_t					trace_proc;
+	diva_trace_error_proc_t									error_notify_proc;
+} diva_trace_library_user_interface_t;
+
+/*
+	Interface from Library to User
+	*/
+typedef int   (*DivaSTraceLibraryStart_proc_t)(void* hLib);
+typedef int   (*DivaSTraceLibraryFinit_proc_t)(void* hLib);
+typedef int   (*DivaSTraceMessageInput_proc_t)(void* hLib);
+typedef void*	(*DivaSTraceGetHandle_proc_t)(void* hLib);
+
+/*
+	Turn Audio Tap trace on/off
+	Channel should be in the range 1 ... Number of Channels
+	*/
+typedef int (*DivaSTraceSetAudioTap_proc_t)(void* hLib, int Channel, int on);
+
+/*
+	Turn B-channel trace on/off
+	Channel should be in the range 1 ... Number of Channels
+	*/
+typedef int (*DivaSTraceSetBChannel_proc_t)(void* hLib, int Channel, int on);
+
+/*
+	Turn	D-channel (Layer1/Layer2/Layer3) trace on/off
+		Layer1 - All D-channel frames received/sent over the interface
+						 inclusive Layer 2 headers, Layer 2 frames and TEI management frames
+		Layer2 - Events from LAPD protocol instance with SAPI of signalling protocol
+		Layer3 - All D-channel frames addressed to assigned to the card TEI and
+						 SAPI of signalling protocol, and signalling protocol events.
+	*/
+typedef int (*DivaSTraceSetDChannel_proc_t)(void* hLib, int on);
+
+/*
+	Get overall card statistics
+	*/
+typedef int (*DivaSTraceGetOutgoingCallStatistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetIncomingCallStatistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetModemStatistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetFaxStatistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetBLayer1Statistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetBLayer2Statistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetDLayer1Statistics_proc_t)(void* hLib);
+typedef int (*DivaSTraceGetDLayer2Statistics_proc_t)(void* hLib);
+
+/*
+	Call control
+	*/
+typedef int (*DivaSTraceClearCall_proc_t)(void* hLib, int Channel);
+
+typedef struct _diva_strace_library_interface {
+	void* hLib;
+  DivaSTraceLibraryStart_proc_t DivaSTraceLibraryStart;
+  DivaSTraceLibraryStart_proc_t DivaSTraceLibraryStop;
+	DivaSTraceLibraryFinit_proc_t DivaSTraceLibraryFinit;
+	DivaSTraceMessageInput_proc_t DivaSTraceMessageInput;
+	DivaSTraceGetHandle_proc_t    DivaSTraceGetHandle;
+	DivaSTraceSetAudioTap_proc_t  DivaSTraceSetAudioTap;
+	DivaSTraceSetBChannel_proc_t  DivaSTraceSetBChannel;
+	DivaSTraceSetDChannel_proc_t  DivaSTraceSetDChannel;
+	DivaSTraceSetDChannel_proc_t  DivaSTraceSetInfo;
+	DivaSTraceGetOutgoingCallStatistics_proc_t \
+																DivaSTraceGetOutgoingCallStatistics;
+	DivaSTraceGetIncomingCallStatistics_proc_t \
+																DivaSTraceGetIncomingCallStatistics;
+	DivaSTraceGetModemStatistics_proc_t \
+																DivaSTraceGetModemStatistics;
+	DivaSTraceGetFaxStatistics_proc_t \
+																DivaSTraceGetFaxStatistics;
+	DivaSTraceGetBLayer1Statistics_proc_t \
+																DivaSTraceGetBLayer1Statistics;
+	DivaSTraceGetBLayer2Statistics_proc_t \
+																DivaSTraceGetBLayer2Statistics;
+	DivaSTraceGetDLayer1Statistics_proc_t \
+																DivaSTraceGetDLayer1Statistics;
+	DivaSTraceGetDLayer2Statistics_proc_t \
+																DivaSTraceGetDLayer2Statistics;
+	DivaSTraceClearCall_proc_t    DivaSTraceClearCall;
+} diva_strace_library_interface_t;
+
+/*
+	Create and return Library interface
+	*/
+diva_strace_library_interface_t* DivaSTraceLibraryCreateInstance (int Adapter,
+													const diva_trace_library_user_interface_t* user_proc,
+                          byte* pmem);
+dword DivaSTraceGetMemotyRequirement (int channels);
+
+#define DIVA_MAX_ADAPTERS  64
+#define DIVA_MAX_LINES     32
+
+#endif
+
diff --git a/drivers/isdn/hardware/eicon/main_if.h b/drivers/isdn/hardware/eicon/main_if.h
new file mode 100644
index 0000000..0ea339a
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/main_if.h
@@ -0,0 +1,50 @@
+/*
+ *
+  Copyright (c) Eicon Technology Corporation, 2000.
+ *
+  This source file is supplied for the use with Eicon
+  Technology Corporation's range of DIVA Server Adapters.
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*------------------------------------------------------------------*/
+/* file: main_if.h                                                  */
+/*------------------------------------------------------------------*/
+# ifndef MAIN_IF___H
+# define MAIN_IF___H
+
+# include "debug_if.h"
+
+void  DI_lock (void) ;
+void  DI_unlock (void) ;
+
+#ifdef NOT_YET_NEEDED
+void  DI_nttime (LARGE_INTEGER *NTtime) ;
+void  DI_ntlcltime(LARGE_INTEGER *NTtime, LARGE_INTEGER *lclNTtime) ;
+void  DI_nttimefields(LARGE_INTEGER *NTtime, TIME_FIELDS *TimeFields);
+unsigned long  DI_wintime(LARGE_INTEGER *NTtime) ;
+
+unsigned short  DiInsertProcessorNumber (int type) ;
+void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap);
+
+void  StartIoctlTimer (void (*Handler)(void), unsigned long msec) ;
+void  StopIoctlTimer (void) ;
+void  UnpendIoctl (DbgRequest *pDbgReq) ;
+#endif
+
+void add_to_q(int, char* , unsigned int);
+# endif /* MAIN_IF___H */
+
diff --git a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c
new file mode 100644
index 0000000..23960cb
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/maintidi.c
@@ -0,0 +1,2194 @@
+/*
+ *
+  Copyright (c) Eicon Networks, 2000.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    1.9
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "kst_ifc.h"
+#include "di_defs.h"
+#include "maintidi.h"
+#include "pc.h"
+#include "man_defs.h"
+
+
+extern void diva_mnt_internal_dprintf (dword drv_id, dword type, char* p, ...);
+
+#define MODEM_PARSE_ENTRIES  16 /* amount of variables of interest */
+#define FAX_PARSE_ENTRIES    12 /* amount of variables of interest */
+#define LINE_PARSE_ENTRIES   15 /* amount of variables of interest */
+#define STAT_PARSE_ENTRIES   70 /* amount of variables of interest */
+
+/*
+	LOCAL FUNCTIONS
+	*/
+static int DivaSTraceLibraryStart (void* hLib);
+static int DivaSTraceLibraryStop  (void* hLib);
+static int SuperTraceLibraryFinit (void* hLib);
+static void*	SuperTraceGetHandle (void* hLib);
+static int SuperTraceMessageInput (void* hLib);
+static int SuperTraceSetAudioTap  (void* hLib, int Channel, int on);
+static int SuperTraceSetBChannel  (void* hLib, int Channel, int on);
+static int SuperTraceSetDChannel  (void* hLib, int on);
+static int SuperTraceSetInfo      (void* hLib, int on);
+static int SuperTraceClearCall (void* hLib, int Channel);
+static int SuperTraceGetOutgoingCallStatistics (void* hLib);
+static int SuperTraceGetIncomingCallStatistics (void* hLib);
+static int SuperTraceGetModemStatistics (void* hLib);
+static int SuperTraceGetFaxStatistics (void* hLib);
+static int SuperTraceGetBLayer1Statistics (void* hLib);
+static int SuperTraceGetBLayer2Statistics (void* hLib);
+static int SuperTraceGetDLayer1Statistics (void* hLib);
+static int SuperTraceGetDLayer2Statistics (void* hLib);
+
+/*
+	LOCAL FUNCTIONS
+	*/
+static int ScheduleNextTraceRequest (diva_strace_context_t* pLib);
+static int process_idi_event (diva_strace_context_t* pLib,
+															diva_man_var_header_t* pVar);
+static int process_idi_info  (diva_strace_context_t* pLib,
+															diva_man_var_header_t* pVar);
+static int diva_modem_event (diva_strace_context_t* pLib, int Channel);
+static int diva_fax_event   (diva_strace_context_t* pLib, int Channel);
+static int diva_line_event (diva_strace_context_t* pLib, int Channel);
+static int diva_modem_info (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar);
+static int diva_fax_info   (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar);
+static int diva_line_info  (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar);
+static int diva_ifc_statistics (diva_strace_context_t* pLib,
+																diva_man_var_header_t* pVar);
+static diva_man_var_header_t* get_next_var (diva_man_var_header_t* pVar);
+static diva_man_var_header_t* find_var (diva_man_var_header_t* pVar,
+																				const char* name);
+static int diva_strace_read_int  (diva_man_var_header_t* pVar, int* var);
+static int diva_strace_read_uint (diva_man_var_header_t* pVar, dword* var);
+static int diva_strace_read_asz  (diva_man_var_header_t* pVar, char* var);
+static int diva_strace_read_asc  (diva_man_var_header_t* pVar, char* var);
+static int  diva_strace_read_ie  (diva_man_var_header_t* pVar,
+																	diva_trace_ie_t* var);
+static void diva_create_parse_table (diva_strace_context_t* pLib);
+static void diva_trace_error (diva_strace_context_t* pLib,
+															int error, const char* file, int line);
+static void diva_trace_notify_user (diva_strace_context_t* pLib,
+														 int Channel,
+														 int notify_subject);
+static int diva_trace_read_variable (diva_man_var_header_t* pVar,
+																		 void* variable);
+
+/*
+	Initialize the library and return context
+	of the created trace object that will represent
+	the IDI adapter.
+	Return 0 on error.
+	*/
+diva_strace_library_interface_t* DivaSTraceLibraryCreateInstance (int Adapter,
+											const diva_trace_library_user_interface_t* user_proc,
+                      byte* pmem) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)pmem;
+	int i;
+
+	if (!pLib) {
+		return NULL;
+	}
+
+	pmem += sizeof(*pLib);
+	memset(pLib, 0x00, sizeof(*pLib));
+
+	pLib->Adapter  = Adapter;
+
+	/*
+		Set up Library Interface
+		*/
+	pLib->instance.hLib                                = pLib;
+  pLib->instance.DivaSTraceLibraryStart              = DivaSTraceLibraryStart;
+  pLib->instance.DivaSTraceLibraryStop               = DivaSTraceLibraryStop;
+	pLib->instance.DivaSTraceLibraryFinit              = SuperTraceLibraryFinit;
+	pLib->instance.DivaSTraceMessageInput              = SuperTraceMessageInput;
+	pLib->instance.DivaSTraceGetHandle                 = SuperTraceGetHandle;
+	pLib->instance.DivaSTraceSetAudioTap               = SuperTraceSetAudioTap;
+	pLib->instance.DivaSTraceSetBChannel               = SuperTraceSetBChannel;
+	pLib->instance.DivaSTraceSetDChannel               = SuperTraceSetDChannel;
+	pLib->instance.DivaSTraceSetInfo                   = SuperTraceSetInfo;
+	pLib->instance.DivaSTraceGetOutgoingCallStatistics = \
+																			SuperTraceGetOutgoingCallStatistics;
+	pLib->instance.DivaSTraceGetIncomingCallStatistics = \
+																			SuperTraceGetIncomingCallStatistics;
+	pLib->instance.DivaSTraceGetModemStatistics        = \
+																			SuperTraceGetModemStatistics;
+	pLib->instance.DivaSTraceGetFaxStatistics          = \
+																			SuperTraceGetFaxStatistics;
+	pLib->instance.DivaSTraceGetBLayer1Statistics      = \
+																			SuperTraceGetBLayer1Statistics;
+	pLib->instance.DivaSTraceGetBLayer2Statistics      = \
+																			SuperTraceGetBLayer2Statistics;
+	pLib->instance.DivaSTraceGetDLayer1Statistics      = \
+																			SuperTraceGetDLayer1Statistics;
+	pLib->instance.DivaSTraceGetDLayer2Statistics      = \
+																			SuperTraceGetDLayer2Statistics;
+	pLib->instance.DivaSTraceClearCall                 = SuperTraceClearCall;
+
+
+	if (user_proc) {
+		pLib->user_proc_table.user_context      = user_proc->user_context;
+		pLib->user_proc_table.notify_proc       = user_proc->notify_proc;
+		pLib->user_proc_table.trace_proc        = user_proc->trace_proc;
+		pLib->user_proc_table.error_notify_proc = user_proc->error_notify_proc;
+	}
+
+	if (!(pLib->hAdapter = SuperTraceOpenAdapter (Adapter))) {
+    diva_mnt_internal_dprintf (0, DLI_ERR, "Can not open XDI adapter");
+		return NULL;
+	}
+	pLib->Channels = SuperTraceGetNumberOfChannels (pLib->hAdapter);
+
+	/*
+		Calculate amount of parte table entites necessary to translate
+		information from all events of onterest
+		*/
+	pLib->parse_entries = (MODEM_PARSE_ENTRIES + FAX_PARSE_ENTRIES + \
+												 STAT_PARSE_ENTRIES + \
+												 LINE_PARSE_ENTRIES + 1) * pLib->Channels;
+	pLib->parse_table = (diva_strace_path2action_t*)pmem;
+
+	for (i = 0; i < 30; i++) {
+		pLib->lines[i].pInterface     = &pLib->Interface;
+		pLib->lines[i].pInterfaceStat = &pLib->InterfaceStat;
+	}
+
+  pLib->e.R = &pLib->RData;
+
+	pLib->req_busy = 1;
+	pLib->rc_ok    = ASSIGN_OK;
+
+	diva_create_parse_table (pLib);
+
+	return ((diva_strace_library_interface_t*)pLib);
+}
+
+static int DivaSTraceLibraryStart (void* hLib) {
+  diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+  return (SuperTraceASSIGN (pLib->hAdapter, pLib->buffer));
+}
+
+/*
+  Return (-1) on error
+  Return (0) if was initiated or pending
+  Return (1) if removal is complete
+  */
+static int DivaSTraceLibraryStop  (void* hLib) {
+  diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+  if (!pLib->e.Id) { /* Was never started/assigned */
+    return (1);
+  }
+
+  switch (pLib->removal_state) {
+    case 0:
+      pLib->removal_state = 1;
+      ScheduleNextTraceRequest(pLib);
+      break;
+
+    case 3:
+      return (1);
+  }
+
+  return (0);
+}
+
+static int SuperTraceLibraryFinit (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	if (pLib) {
+		if (pLib->hAdapter) {
+			SuperTraceCloseAdapter  (pLib->hAdapter);
+		}
+		return (0);
+	}
+	return (-1);
+}
+
+static void*	SuperTraceGetHandle (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+  return (&pLib->e);
+}
+
+/*
+	After library handle object is gone in signaled state
+	this function should be called and will pick up incoming
+	IDI messages (return codes and indications).
+	*/
+static int SuperTraceMessageInput (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	int ret = 0;
+  byte Rc, Ind;
+
+  if (pLib->e.complete == 255) {
+    /*
+      Process return code
+      */
+    pLib->req_busy = 0;
+    Rc             = pLib->e.Rc;
+    pLib->e.Rc     = 0;
+
+    if (pLib->removal_state == 2) {
+      pLib->removal_state = 3;
+      return (0);
+    }
+
+		if (Rc != pLib->rc_ok) {
+      int ignore = 0;
+      /*
+        Auto-detect amount of events/channels and features
+        */
+      if (pLib->general_b_ch_event == 1) {
+        pLib->general_b_ch_event = 2;
+        ignore = 1;
+      } else if (pLib->general_fax_event == 1) {
+        pLib->general_fax_event = 2;
+        ignore = 1;
+      } else if (pLib->general_mdm_event == 1) {
+        pLib->general_mdm_event = 2;
+        ignore = 1;
+      } else if ((pLib->ChannelsTraceActive < pLib->Channels) && pLib->ChannelsTraceActive) {
+        pLib->ChannelsTraceActive = pLib->Channels;
+        ignore = 1;
+      } else if (pLib->ModemTraceActive < pLib->Channels) {
+        pLib->ModemTraceActive = pLib->Channels;
+        ignore = 1;
+      } else if (pLib->FaxTraceActive < pLib->Channels) {
+        pLib->FaxTraceActive = pLib->Channels;
+        ignore = 1;
+      } else if (pLib->audio_trace_init == 2) {
+        ignore = 1;
+        pLib->audio_trace_init = 1;
+      } else if (pLib->eye_pattern_pending) {
+				pLib->eye_pattern_pending =  0;
+				ignore = 1;
+			} else if (pLib->audio_tap_pending) {
+				pLib->audio_tap_pending = 0;
+				ignore = 1;
+      }
+
+      if (!ignore) {
+        return (-1); /* request failed */
+      }
+    } else {
+      if (pLib->general_b_ch_event == 1) {
+        pLib->ChannelsTraceActive = pLib->Channels;
+        pLib->general_b_ch_event = 2;
+      } else if (pLib->general_fax_event == 1) {
+        pLib->general_fax_event = 2;
+        pLib->FaxTraceActive = pLib->Channels;
+      } else if (pLib->general_mdm_event == 1) {
+        pLib->general_mdm_event = 2;
+        pLib->ModemTraceActive = pLib->Channels;
+      }
+    }
+    if (pLib->audio_trace_init == 2) {
+      pLib->audio_trace_init = 1;
+    }
+    pLib->rc_ok = 0xff; /* default OK after assign was done */
+    if ((ret = ScheduleNextTraceRequest(pLib))) {
+      return (-1);
+    }
+  } else {
+    /*
+      Process indication
+      Always 'RNR' indication if return code is pending
+      */
+    Ind         = pLib->e.Ind;
+    pLib->e.Ind = 0;
+    if (pLib->removal_state) {
+      pLib->e.RNum	= 0;
+      pLib->e.RNR	= 2;
+    } else if (pLib->req_busy) {
+      pLib->e.RNum	= 0;
+      pLib->e.RNR	= 1;
+    } else {
+      if (pLib->e.complete != 0x02) {
+        /*
+          Look-ahead call, set up buffers
+          */
+        pLib->e.RNum       = 1;
+        pLib->e.R->P       = (byte*)&pLib->buffer[0];
+        pLib->e.R->PLength = (word)(sizeof(pLib->buffer) - 1);
+
+      } else {
+        /*
+          Indication reception complete, process it now
+          */
+        byte* p = (byte*)&pLib->buffer[0];
+        pLib->buffer[pLib->e.R->PLength] = 0; /* terminate I.E. with zero */
+
+        switch (Ind) {
+          case MAN_COMBI_IND: {
+            int total_length    = pLib->e.R->PLength;
+            word  this_ind_length;
+
+            while (total_length > 3 && *p) {
+              Ind = *p++;
+              this_ind_length = (word)p[0] | ((word)p[1] << 8);
+              p += 2;
+
+              switch (Ind) {
+                case MAN_INFO_IND:
+                  if (process_idi_info (pLib, (diva_man_var_header_t*)p)) {
+                    return (-1);
+                  }
+                  break;
+      					case MAN_EVENT_IND:
+                  if (process_idi_event (pLib, (diva_man_var_header_t*)p)) {
+                    return (-1);
+                  }
+                  break;
+                case MAN_TRACE_IND:
+                  if (pLib->trace_on == 1) {
+                    /*
+                      Ignore first trace event that is result of
+                      EVENT_ON operation
+                    */
+                    pLib->trace_on++;
+                  } else {
+                    /*
+                      Delivery XLOG buffer to application
+                      */
+                    if (pLib->user_proc_table.trace_proc) {
+                      (*(pLib->user_proc_table.trace_proc))(pLib->user_proc_table.user_context,
+                                                            &pLib->instance, pLib->Adapter,
+                                                            p, this_ind_length);
+                    }
+                  }
+                  break;
+                default:
+                  diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind (DMA mode): %02x", Ind);
+              }
+              p += (this_ind_length+1);
+              total_length -= (4 + this_ind_length);
+            }
+          } break;
+          case MAN_INFO_IND:
+            if (process_idi_info (pLib, (diva_man_var_header_t*)p)) {
+              return (-1);
+            }
+            break;
+					case MAN_EVENT_IND:
+            if (process_idi_event (pLib, (diva_man_var_header_t*)p)) {
+              return (-1);
+            }
+            break;
+          case MAN_TRACE_IND:
+            if (pLib->trace_on == 1) {
+              /*
+                Ignore first trace event that is result of
+                EVENT_ON operation
+              */
+              pLib->trace_on++;
+            } else {
+              /*
+                Delivery XLOG buffer to application
+                */
+              if (pLib->user_proc_table.trace_proc) {
+                (*(pLib->user_proc_table.trace_proc))(pLib->user_proc_table.user_context,
+                                                      &pLib->instance, pLib->Adapter,
+                                                      p, pLib->e.R->PLength);
+              }
+            }
+            break;
+          default:
+            diva_mnt_internal_dprintf (0, DLI_ERR, "Unknon IDI Ind: %02x", Ind);
+        }
+      }
+    }
+  }
+
+	if ((ret = ScheduleNextTraceRequest(pLib))) {
+		return (-1);
+	}
+
+	return (ret);
+}
+
+/*
+	Internal state machine responsible for scheduling of requests
+	*/
+static int ScheduleNextTraceRequest (diva_strace_context_t* pLib) {
+	char name[64];
+	int ret = 0;
+	int i;
+
+	if (pLib->req_busy) {
+		return (0);
+	}
+
+  if (pLib->removal_state == 1) {
+		if (SuperTraceREMOVE (pLib->hAdapter)) {
+      pLib->removal_state = 3;
+    } else {
+      pLib->req_busy = 1;
+      pLib->removal_state = 2;
+    }
+    return (0);
+  }
+
+  if (pLib->removal_state) {
+    return (0);
+  }
+
+  if (!pLib->general_b_ch_event) {
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\B Event", pLib->buffer))) {
+      return (-1);
+    }
+    pLib->general_b_ch_event = 1;
+		pLib->req_busy = 1;
+		return (0);
+  }
+
+  if (!pLib->general_fax_event) {
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\FAX Event", pLib->buffer))) {
+      return (-1);
+    }
+    pLib->general_fax_event = 1;
+		pLib->req_busy = 1;
+		return (0);
+  }
+
+  if (!pLib->general_mdm_event) {
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, "State\\Modem Event", pLib->buffer))) {
+      return (-1);
+    }
+    pLib->general_mdm_event = 1;
+		pLib->req_busy = 1;
+		return (0);
+  }
+
+	if (pLib->ChannelsTraceActive < pLib->Channels) {
+		pLib->ChannelsTraceActive++;
+		sprintf (name, "State\\B%d\\Line", pLib->ChannelsTraceActive);
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->ChannelsTraceActive--;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->ModemTraceActive < pLib->Channels) {
+		pLib->ModemTraceActive++;
+		sprintf (name, "State\\B%d\\Modem\\Event", pLib->ModemTraceActive);
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->ModemTraceActive--;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->FaxTraceActive < pLib->Channels) {
+		pLib->FaxTraceActive++;
+		sprintf (name, "State\\B%d\\FAX\\Event", pLib->FaxTraceActive);
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->FaxTraceActive--;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->trace_mask_init) {
+		word tmp = 0x0000;
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\Event Enable",
+												 		&tmp,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(tmp))) {
+			return (-1);
+		}
+		pLib->trace_mask_init = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->audio_trace_init) {
+		dword tmp = 0x00000000;
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\AudioCh# Enable",
+												 		&tmp,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(tmp))) {
+			return (-1);
+		}
+		pLib->audio_trace_init = 2;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->bchannel_init) {
+		dword tmp = 0x00000000;
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\B-Ch# Enable",
+												 		&tmp,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(tmp))) {
+			return (-1);
+		}
+		pLib->bchannel_init = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->trace_length_init) {
+		word tmp = 30;
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\Max Log Length",
+												 		&tmp,
+														0x82, /* MI_UINT */
+												 		sizeof(tmp))) {
+			return (-1);
+		}
+		pLib->trace_length_init = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->trace_on) {
+		if (SuperTraceTraceOnRequest (pLib->hAdapter,
+																	"Trace\\Log Buffer",
+																	pLib->buffer)) {
+			return (-1);
+		}
+		pLib->trace_on = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->trace_event_mask != pLib->current_trace_event_mask) {
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\Event Enable",
+												 		&pLib->trace_event_mask,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(pLib->trace_event_mask))) {
+			return (-1);
+		}
+		pLib->current_trace_event_mask = pLib->trace_event_mask;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if ((pLib->audio_tap_pending >= 0) && (pLib->audio_tap_mask != pLib->current_audio_tap_mask)) {
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\AudioCh# Enable",
+												 		&pLib->audio_tap_mask,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(pLib->audio_tap_mask))) {
+			return (-1);
+		}
+		pLib->current_audio_tap_mask = pLib->audio_tap_mask;
+		pLib->audio_tap_pending = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if ((pLib->eye_pattern_pending >= 0) && (pLib->audio_tap_mask != pLib->current_eye_pattern_mask)) {
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\EyeCh# Enable",
+												 		&pLib->audio_tap_mask,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(pLib->audio_tap_mask))) {
+			return (-1);
+		}
+		pLib->current_eye_pattern_mask = pLib->audio_tap_mask;
+		pLib->eye_pattern_pending = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->bchannel_trace_mask != pLib->current_bchannel_trace_mask) {
+		if (SuperTraceWriteVar (pLib->hAdapter,
+														pLib->buffer,
+												 		"Trace\\B-Ch# Enable",
+												 		&pLib->bchannel_trace_mask,
+												 		0x87, /* MI_BITFLD */
+												 		sizeof(pLib->bchannel_trace_mask))) {
+			return (-1);
+		}
+		pLib->current_bchannel_trace_mask = pLib->bchannel_trace_mask;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->trace_events_down) {
+		if (SuperTraceTraceOnRequest (pLib->hAdapter,
+																	"Events Down",
+																	pLib->buffer)) {
+			return (-1);
+		}
+		pLib->trace_events_down = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->l1_trace) {
+		if (SuperTraceTraceOnRequest (pLib->hAdapter,
+																	"State\\Layer1",
+																	pLib->buffer)) {
+			return (-1);
+		}
+		pLib->l1_trace = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->l2_trace) {
+		if (SuperTraceTraceOnRequest (pLib->hAdapter,
+																	"State\\Layer2 No1",
+																	pLib->buffer)) {
+			return (-1);
+		}
+		pLib->l2_trace = 1;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	for (i = 0; i < 30; i++) {
+		if (pLib->pending_line_status & (1L << i)) {
+			sprintf (name, "State\\B%d", i+1);
+			if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
+				return (-1);
+			}
+			pLib->pending_line_status &= ~(1L << i);
+			pLib->req_busy = 1;
+			return (0);
+		}
+		if (pLib->pending_modem_status & (1L << i)) {
+			sprintf (name, "State\\B%d\\Modem", i+1);
+			if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
+				return (-1);
+			}
+			pLib->pending_modem_status &= ~(1L << i);
+			pLib->req_busy = 1;
+			return (0);
+		}
+		if (pLib->pending_fax_status & (1L << i)) {
+			sprintf (name, "State\\B%d\\FAX", i+1);
+			if (SuperTraceReadRequest (pLib->hAdapter, name, pLib->buffer)) {
+				return (-1);
+			}
+			pLib->pending_fax_status &= ~(1L << i);
+			pLib->req_busy = 1;
+			return (0);
+		}
+		if (pLib->clear_call_command & (1L << i)) {
+			sprintf (name, "State\\B%d\\Clear Call", i+1);
+			if (SuperTraceExecuteRequest (pLib->hAdapter, name, pLib->buffer)) {
+				return (-1);
+			}
+			pLib->clear_call_command &= ~(1L << i);
+			pLib->req_busy = 1;
+			return (0);
+		}
+	}
+
+	if (pLib->outgoing_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\Outgoing Calls",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->outgoing_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->incoming_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\Incoming Calls",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->incoming_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->modem_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\Modem",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->modem_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->fax_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\FAX",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->fax_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->b1_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\B-Layer1",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->b1_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->b2_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\B-Layer2",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->b2_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->d1_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\D-Layer1",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->d1_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (pLib->d2_ifc_stats) {
+		if (SuperTraceReadRequest (pLib->hAdapter,
+															 "Statistics\\D-Layer2",
+															 pLib->buffer)) {
+			return (-1);
+		}
+		pLib->d2_ifc_stats = 0;
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	if (!pLib->IncomingCallsCallsActive) {
+		pLib->IncomingCallsCallsActive = 1;
+		sprintf (name, "%s", "Statistics\\Incoming Calls\\Calls");
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->IncomingCallsCallsActive = 0;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+	if (!pLib->IncomingCallsConnectedActive) {
+		pLib->IncomingCallsConnectedActive = 1;
+		sprintf (name, "%s", "Statistics\\Incoming Calls\\Connected");
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->IncomingCallsConnectedActive = 0;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+	if (!pLib->OutgoingCallsCallsActive) {
+		pLib->OutgoingCallsCallsActive = 1;
+		sprintf (name, "%s", "Statistics\\Outgoing Calls\\Calls");
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->OutgoingCallsCallsActive = 0;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+	if (!pLib->OutgoingCallsConnectedActive) {
+		pLib->OutgoingCallsConnectedActive = 1;
+		sprintf (name, "%s", "Statistics\\Outgoing Calls\\Connected");
+		if ((ret = SuperTraceTraceOnRequest(pLib->hAdapter, name, pLib->buffer))) {
+			pLib->OutgoingCallsConnectedActive = 0;
+			return (-1);
+		}
+		pLib->req_busy = 1;
+		return (0);
+	}
+
+	return (0);
+}
+
+static int process_idi_event (diva_strace_context_t* pLib,
+				diva_man_var_header_t* pVar) {
+	const char* path = (char*)&pVar->path_length+1;
+	char name[64];
+	int i;
+
+	if (!strncmp("State\\B Event", path, pVar->path_length)) {
+    dword ch_id;
+    if (!diva_trace_read_variable (pVar, &ch_id)) {
+      if (!pLib->line_init_event && !pLib->pending_line_status) {
+        for (i = 1; i <= pLib->Channels; i++) {
+          diva_line_event(pLib, i);
+        }
+        return (0);
+      } else if (ch_id && ch_id <= pLib->Channels) {
+        return (diva_line_event(pLib, (int)ch_id));
+      }
+      return (0);
+    }
+    return (-1);
+  }
+
+	if (!strncmp("State\\FAX Event", path, pVar->path_length)) {
+    dword ch_id;
+    if (!diva_trace_read_variable (pVar, &ch_id)) {
+      if (!pLib->pending_fax_status && !pLib->fax_init_event) {
+        for (i = 1; i <= pLib->Channels; i++) {
+          diva_fax_event(pLib, i);
+        }
+        return (0);
+      } else if (ch_id && ch_id <= pLib->Channels) {
+        return (diva_fax_event(pLib, (int)ch_id));
+      }
+      return (0);
+    }
+    return (-1);
+  }
+
+	if (!strncmp("State\\Modem Event", path, pVar->path_length)) {
+    dword ch_id;
+    if (!diva_trace_read_variable (pVar, &ch_id)) {
+      if (!pLib->pending_modem_status && !pLib->modem_init_event) {
+        for (i = 1; i <= pLib->Channels; i++) {
+          diva_modem_event(pLib, i);
+        }
+        return (0);
+      } else if (ch_id && ch_id <= pLib->Channels) {
+        return (diva_modem_event(pLib, (int)ch_id));
+      }
+      return (0);
+    }
+    return (-1);
+  }
+
+	/*
+		First look for Line Event
+		*/
+	for (i = 1; i <= pLib->Channels; i++) {
+		sprintf (name, "State\\B%d\\Line", i);
+		if (find_var (pVar, name)) {
+			return (diva_line_event(pLib, i));
+		}
+	}
+
+	/*
+		Look for Moden Progress Event
+		*/
+	for (i = 1; i <= pLib->Channels; i++) {
+		sprintf (name, "State\\B%d\\Modem\\Event", i);
+		if (find_var (pVar, name)) {
+			return (diva_modem_event (pLib, i));
+		}
+	}
+
+	/*
+		Look for Fax Event
+		*/
+	for (i = 1; i <= pLib->Channels; i++) {
+		sprintf (name, "State\\B%d\\FAX\\Event", i);
+		if (find_var (pVar, name)) {
+			return (diva_fax_event (pLib, i));
+		}
+	}
+
+	/*
+		Notification about loss of events
+		*/
+	if (!strncmp("Events Down", path, pVar->path_length)) {
+		if (pLib->trace_events_down == 1) {
+			pLib->trace_events_down = 2;
+		} else {
+			diva_trace_error (pLib, 1, "Events Down", 0);
+		}
+		return (0);
+	}
+
+	if (!strncmp("State\\Layer1", path, pVar->path_length)) {
+		diva_strace_read_asz  (pVar, &pLib->lines[0].pInterface->Layer1[0]);
+		if (pLib->l1_trace == 1) {
+			pLib->l1_trace = 2;
+		} else {
+			diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_INTERFACE_CHANGE);
+		}
+		return (0);
+	}
+	if (!strncmp("State\\Layer2 No1", path, pVar->path_length)) {
+		char* tmp = &pLib->lines[0].pInterface->Layer2[0];
+    dword l2_state;
+    diva_strace_read_uint (pVar, &l2_state);
+
+		switch (l2_state) {
+			case 0:
+				strcpy (tmp, "Idle");
+				break;
+			case 1:
+				strcpy (tmp, "Layer2 UP");
+				break;
+			case 2:
+				strcpy (tmp, "Layer2 Disconnecting");
+				break;
+			case 3:
+				strcpy (tmp, "Layer2 Connecting");
+				break;
+			case 4:
+				strcpy (tmp, "SPID Initializing");
+				break;
+			case 5:
+				strcpy (tmp, "SPID Initialised");
+				break;
+			case 6:
+				strcpy (tmp, "Layer2 Connecting");
+				break;
+
+			case  7:
+				strcpy (tmp, "Auto SPID Stopped");
+				break;
+
+			case  8:
+				strcpy (tmp, "Auto SPID Idle");
+				break;
+
+			case  9:
+				strcpy (tmp, "Auto SPID Requested");
+				break;
+
+			case  10:
+				strcpy (tmp, "Auto SPID Delivery");
+				break;
+
+			case 11:
+				strcpy (tmp, "Auto SPID Complete");
+				break;
+
+			default:
+				sprintf (tmp, "U:%d", (int)l2_state);
+		}
+		if (pLib->l2_trace == 1) {
+			pLib->l2_trace = 2;
+		} else {
+			diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_INTERFACE_CHANGE);
+		}
+		return (0);
+	}
+
+	if (!strncmp("Statistics\\Incoming Calls\\Calls", path, pVar->path_length) ||
+			!strncmp("Statistics\\Incoming Calls\\Connected", path, pVar->path_length)) {
+		return (SuperTraceGetIncomingCallStatistics (pLib));
+	}
+
+	if (!strncmp("Statistics\\Outgoing Calls\\Calls", path, pVar->path_length) ||
+			!strncmp("Statistics\\Outgoing Calls\\Connected", path, pVar->path_length)) {
+		return (SuperTraceGetOutgoingCallStatistics (pLib));
+	}
+
+	return (-1);
+}
+
+static int diva_line_event (diva_strace_context_t* pLib, int Channel) {
+	pLib->pending_line_status |= (1L << (Channel-1));
+	return (0);
+}
+
+static int diva_modem_event (diva_strace_context_t* pLib, int Channel) {
+	pLib->pending_modem_status |= (1L << (Channel-1));
+	return (0);
+}
+
+static int diva_fax_event (diva_strace_context_t* pLib, int Channel) {
+	pLib->pending_fax_status |= (1L << (Channel-1));
+	return (0);
+}
+
+/*
+	Process INFO indications that arrive from the card
+	Uses path of first I.E. to detect the source of the
+	infication
+	*/
+static int process_idi_info  (diva_strace_context_t* pLib,
+															diva_man_var_header_t* pVar) {
+	const char* path = (char*)&pVar->path_length+1;
+	char name[64];
+	int i, len;
+
+	/*
+		First look for Modem Status Info
+		*/
+	for (i = pLib->Channels; i > 0; i--) {
+		len = sprintf (name, "State\\B%d\\Modem", i);
+		if (!strncmp(name, path, len)) {
+			return (diva_modem_info (pLib, i, pVar));
+		}
+	}
+
+	/*
+		Look for Fax Status Info
+		*/
+	for (i = pLib->Channels; i > 0; i--) {
+		len = sprintf (name, "State\\B%d\\FAX", i);
+		if (!strncmp(name, path, len)) {
+			return (diva_fax_info (pLib, i, pVar));
+		}
+	}
+
+	/*
+		Look for Line Status Info
+		*/
+	for (i = pLib->Channels; i > 0; i--) {
+		len = sprintf (name, "State\\B%d", i);
+		if (!strncmp(name, path, len)) {
+			return (diva_line_info (pLib, i, pVar));
+		}
+	}
+
+	if (!diva_ifc_statistics (pLib, pVar)) {
+		return (0);
+	}
+
+	return (-1);
+}
+
+/*
+	MODEM INSTANCE STATE UPDATE
+
+	Update Modem Status Information and issue notification to user,
+	that will inform about change in the state of modem instance, that is
+	associuated with this channel
+	*/
+static int diva_modem_info (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar) {
+	diva_man_var_header_t* cur;
+	int i, nr = Channel - 1;
+
+	for (i  = pLib->modem_parse_entry_first[nr];
+			 i <= pLib->modem_parse_entry_last[nr]; i++) {
+		if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
+			if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
+				diva_trace_error (pLib, -3 , __FILE__, __LINE__);
+				return (-1);
+			}
+		} else {
+			diva_trace_error (pLib, -2 , __FILE__, __LINE__);
+			return (-1);
+		}
+	}
+
+	/*
+		We do not use first event to notify user - this is the event that is
+		generated as result of EVENT ON operation and is used only to initialize
+		internal variables of application
+		*/
+	if (pLib->modem_init_event & (1L << nr)) {
+		diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE);
+	} else {
+		pLib->modem_init_event |= (1L << nr);
+	}
+
+	return (0);
+}
+
+static int diva_fax_info (diva_strace_context_t* pLib,
+													int Channel,
+													diva_man_var_header_t* pVar) {
+	diva_man_var_header_t* cur;
+	int i, nr = Channel - 1;
+
+	for (i  = pLib->fax_parse_entry_first[nr];
+			 i <= pLib->fax_parse_entry_last[nr]; i++) {
+		if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
+			if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
+				diva_trace_error (pLib, -3 , __FILE__, __LINE__);
+				return (-1);
+			}
+		} else {
+			diva_trace_error (pLib, -2 , __FILE__, __LINE__);
+			return (-1);
+		}
+	}
+
+	/*
+		We do not use first event to notify user - this is the event that is
+		generated as result of EVENT ON operation and is used only to initialize
+		internal variables of application
+		*/
+	if (pLib->fax_init_event & (1L << nr)) {
+		diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE);
+	} else {
+		pLib->fax_init_event |= (1L << nr);
+	}
+
+	return (0);
+}
+
+/*
+	LINE STATE UPDATE
+	Update Line Status Information and issue notification to user,
+	that will inform about change in the line state.
+	*/
+static int diva_line_info  (diva_strace_context_t* pLib,
+														int Channel,
+														diva_man_var_header_t* pVar) {
+	diva_man_var_header_t* cur;
+	int i, nr = Channel - 1;
+
+	for (i  = pLib->line_parse_entry_first[nr];
+			 i <= pLib->line_parse_entry_last[nr]; i++) {
+		if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
+			if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
+				diva_trace_error (pLib, -3 , __FILE__, __LINE__);
+				return (-1);
+			}
+		} else {
+			diva_trace_error (pLib, -2 , __FILE__, __LINE__);
+			return (-1);
+		}
+	}
+
+	/*
+		We do not use first event to notify user - this is the event that is
+		generated as result of EVENT ON operation and is used only to initialize
+		internal variables of application
+
+		Exception is is if the line is "online". In this case we have to notify
+		user about this confition.
+		*/
+	if (pLib->line_init_event & (1L << nr)) {
+		diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE);
+	} else {
+		pLib->line_init_event |= (1L << nr);
+		if (strcmp (&pLib->lines[nr].Line[0], "Idle")) {
+			diva_trace_notify_user (pLib, nr, DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE);
+		}
+	}
+
+	return (0);
+}
+
+/*
+	Move position to next vatianle in the chain
+	*/
+static diva_man_var_header_t* get_next_var (diva_man_var_header_t* pVar) {
+	byte* msg   = (byte*)pVar;
+	byte* start;
+	int msg_length;
+
+	if (*msg != ESC) return NULL;
+
+	start = msg + 2;
+	msg_length = *(msg+1);
+	msg = (start+msg_length);
+
+	if (*msg != ESC) return NULL;
+
+	return ((diva_man_var_header_t*)msg);
+}
+
+/*
+	Move position to variable with given name
+	*/
+static diva_man_var_header_t* find_var (diva_man_var_header_t* pVar,
+																				const char* name) {
+	const char* path;
+
+	do {
+		path = (char*)&pVar->path_length+1;
+
+		if (!strncmp (name, path, pVar->path_length)) {
+			break;
+		}
+	} while ((pVar = get_next_var (pVar)));
+
+	return (pVar);
+}
+
+static void diva_create_line_parse_table  (diva_strace_context_t* pLib,
+																					 int Channel) {
+	diva_trace_line_state_t* pLine = &pLib->lines[Channel];
+	int nr = Channel+1;
+
+	if ((pLib->cur_parse_entry + LINE_PARSE_ENTRIES) >= pLib->parse_entries) {
+		diva_trace_error (pLib, -1, __FILE__, __LINE__);
+		return;
+	}
+
+	pLine->ChannelNumber = nr;
+
+	pLib->line_parse_entry_first[Channel] = pLib->cur_parse_entry;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Framing", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Framing[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Line", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Line[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Layer2", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Layer2[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Layer3", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Layer3[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Remote Address", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																								&pLine->RemoteAddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Remote SubAddr", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																								&pLine->RemoteSubAddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Local Address", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																								&pLine->LocalAddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Local SubAddr", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																								&pLine->LocalSubAddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\BC", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_BC;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\HLC", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_HLC;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\LLC", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->call_LLC;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Charges", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->Charges;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Call Reference", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->CallReference;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Last Disc Cause", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																										&pLine->LastDisconnecCause;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\User ID", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pLine->UserID[0];
+
+	pLib->line_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
+}
+
+static void diva_create_fax_parse_table (diva_strace_context_t* pLib,
+																				 int Channel) {
+	diva_trace_fax_state_t* pFax = &pLib->lines[Channel].fax;
+	int nr = Channel+1;
+
+	if ((pLib->cur_parse_entry + FAX_PARSE_ENTRIES) >= pLib->parse_entries) {
+		diva_trace_error (pLib, -1, __FILE__, __LINE__);
+		return;
+	}
+	pFax->ChannelNumber = nr;
+
+	pLib->fax_parse_entry_first[Channel] = pLib->cur_parse_entry;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Event", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Event;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Page Counter", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Page_Counter;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Features", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Features;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Station ID", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Station_ID[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Subaddress", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Subaddress[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Password", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Password[0];
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Speed", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Speed;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Resolution", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Resolution;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Paper Width", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Paper_Width;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Paper Length", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Paper_Length;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Scanline Time", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Scanline_Time;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\FAX\\Disc Reason", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pFax->Disc_Reason;
+
+	pLib->fax_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
+}
+
+static void diva_create_modem_parse_table (diva_strace_context_t* pLib,
+																					 int Channel) {
+	diva_trace_modem_state_t* pModem = &pLib->lines[Channel].modem;
+	int nr = Channel+1;
+
+	if ((pLib->cur_parse_entry + MODEM_PARSE_ENTRIES) >= pLib->parse_entries) {
+		diva_trace_error (pLib, -1, __FILE__, __LINE__);
+		return;
+	}
+	pModem->ChannelNumber = nr;
+
+	pLib->modem_parse_entry_first[Channel] = pLib->cur_parse_entry;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Event", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Event;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Norm", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Norm;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Options", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->Options;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\TX Speed", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->TxSpeed;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\RX Speed", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RxSpeed;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Roundtrip ms", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RoundtripMsec;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Symbol Rate", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->SymbolRate;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\RX Level dBm", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RxLeveldBm;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Echo Level dBm", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->EchoLeveldBm;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\SNR dB", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->SNRdb;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\MAE", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->MAE;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Local Retrains", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->LocalRetrains;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Remote Retrains", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RemoteRetrains;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Local Resyncs", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->LocalResyncs;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Remote Resyncs", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->RemoteResyncs;
+
+	sprintf (pLib->parse_table[pLib->cur_parse_entry].path,
+					 "State\\B%d\\Modem\\Disc Reason", nr);
+	pLib->parse_table[pLib->cur_parse_entry++].variable = &pModem->DiscReason;
+
+	pLib->modem_parse_entry_last[Channel] = pLib->cur_parse_entry - 1;
+}
+
+static void diva_create_parse_table (diva_strace_context_t* pLib) {
+	int i;
+
+	for (i = 0; i < pLib->Channels; i++) {
+		diva_create_line_parse_table  (pLib, i);
+		diva_create_modem_parse_table (pLib, i);
+		diva_create_fax_parse_table   (pLib, i);
+	}
+
+	pLib->statistic_parse_first = pLib->cur_parse_entry;
+
+	/*
+		Outgoing Calls
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Calls");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Calls;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Connected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Connected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\User Busy");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.User_Busy;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\No Answer");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.No_Answer;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Wrong Number");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Wrong_Number;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Call Rejected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Call_Rejected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Outgoing Calls\\Other Failures");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.outg.Other_Failures;
+
+	/*
+		Incoming Calls
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Calls");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Calls;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Connected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Connected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\User Busy");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.User_Busy;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Call Rejected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Call_Rejected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Wrong Number");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Wrong_Number;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Incompatible Dst");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Incompatible_Dst;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Out of Order");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Out_of_Order;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Incoming Calls\\Ignored");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.inc.Ignored;
+
+	/*
+		Modem Statistics
+		*/
+	pLib->mdm_statistic_parse_first = pLib->cur_parse_entry;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Normal");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Normal;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Unspecified");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Unspecified;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Busy Tone");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Busy_Tone;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Congestion");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Congestion;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Carr. Wait");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Carr_Wait;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Trn Timeout");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Trn_Timeout;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Incompat.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Incompat;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc Frame Rej.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_Frame_Rej;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\Modem\\Disc V42bis");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.mdm.Disc_V42bis;
+
+	pLib->mdm_statistic_parse_last  = pLib->cur_parse_entry - 1;
+
+	/*
+		Fax Statistics
+		*/
+	pLib->fax_statistic_parse_first = pLib->cur_parse_entry;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Normal");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Normal;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Not Ident.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Not_Ident;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc No Response");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_No_Response;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Retries");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Retries;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Unexp. Msg.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Unexp_Msg;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc No Polling.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_No_Polling;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Training");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Training;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Unexpected");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Unexpected;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Application");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Application;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Incompat.");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Incompat;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc No Command");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_No_Command;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Long Msg");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Long_Msg;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Supervisor");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Supervisor;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc SUB SEP PWD");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_SUB_SEP_PWD;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Invalid Msg");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Invalid_Msg;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Page Coding");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Page_Coding;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc App Timeout");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_App_Timeout;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\FAX\\Disc Unspecified");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.fax.Disc_Unspecified;
+
+	pLib->fax_statistic_parse_last  = pLib->cur_parse_entry - 1;
+
+	/*
+		B-Layer1"
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\X-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.X_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\X-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.X_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\X-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.X_Errors;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\R-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.R_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\R-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.R_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer1\\R-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b1.R_Errors;
+
+	/*
+		B-Layer2
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\X-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.X_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\X-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.X_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\X-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.X_Errors;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\R-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.R_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\R-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.R_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\B-Layer2\\R-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.b2.R_Errors;
+
+	/*
+		D-Layer1
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\X-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.X_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\X-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.X_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\X-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.X_Errors;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\R-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.R_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\R-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.R_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer1\\R-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d1.R_Errors;
+
+	/*
+		D-Layer2
+		*/
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\X-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.X_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\X-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.X_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\X-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.X_Errors;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\R-Frames");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.R_Frames;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\R-Bytes");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.R_Bytes;
+
+	strcpy (pLib->parse_table[pLib->cur_parse_entry].path,
+					"Statistics\\D-Layer2\\R-Errors");
+	pLib->parse_table[pLib->cur_parse_entry++].variable = \
+																		&pLib->InterfaceStat.d2.R_Errors;
+
+
+	pLib->statistic_parse_last  = pLib->cur_parse_entry - 1;
+}
+
+static void diva_trace_error (diva_strace_context_t* pLib,
+															int error, const char* file, int line) {
+	if (pLib->user_proc_table.error_notify_proc) {
+		(*(pLib->user_proc_table.error_notify_proc))(\
+																						pLib->user_proc_table.user_context,
+																						&pLib->instance, pLib->Adapter,
+																						error, file, line);
+	}
+}
+
+/*
+	Delivery notification to user
+	*/
+static void diva_trace_notify_user (diva_strace_context_t* pLib,
+														 int Channel,
+														 int notify_subject) {
+	if (pLib->user_proc_table.notify_proc) {
+		(*(pLib->user_proc_table.notify_proc))(pLib->user_proc_table.user_context,
+																					 &pLib->instance,
+																					 pLib->Adapter,
+																					 &pLib->lines[Channel],
+																					 notify_subject);
+	}
+}
+
+/*
+	Read variable value to they destination based on the variable type
+	*/
+static int diva_trace_read_variable (diva_man_var_header_t* pVar,
+																		 void* variable) {
+	switch (pVar->type) {
+		case 0x03: /* MI_ASCIIZ - syting                               */
+			return (diva_strace_read_asz  (pVar, (char*)variable));
+		case 0x04: /* MI_ASCII  - string                               */
+			return (diva_strace_read_asc  (pVar, (char*)variable));
+		case 0x05: /* MI_NUMBER - counted sequence of bytes            */
+			return (diva_strace_read_ie  (pVar, (diva_trace_ie_t*)variable));
+		case 0x81: /* MI_INT    - signed integer                       */
+			return (diva_strace_read_int (pVar, (int*)variable));
+		case 0x82: /* MI_UINT   - unsigned integer                     */
+			return (diva_strace_read_uint (pVar, (dword*)variable));
+		case 0x83: /* MI_HINT   - unsigned integer, hex representetion */
+			return (diva_strace_read_uint (pVar, (dword*)variable));
+		case 0x87: /* MI_BITFLD - unsigned integer, bit representation */
+			return (diva_strace_read_uint (pVar, (dword*)variable));
+	}
+
+	/*
+		This type of variable is not handled, indicate error
+		Or one problem in management interface, or in application recodeing
+		table, or this application should handle it.
+		*/
+	return (-1);
+}
+
+/*
+	Read signed integer to destination
+	*/
+static int diva_strace_read_int  (diva_man_var_header_t* pVar, int* var) {
+	byte* ptr = (char*)&pVar->path_length;
+	int value;
+
+	ptr += (pVar->path_length + 1);
+
+	switch (pVar->value_length) {
+		case 1:
+			value = *(char*)ptr;
+			break;
+
+		case 2:
+			value = (short)GET_WORD(ptr);
+			break;
+
+		case 4:
+			value = (int)GET_DWORD(ptr);
+			break;
+
+		default:
+			return (-1);
+	}
+
+	*var = value;
+
+	return (0);
+}
+
+static int diva_strace_read_uint (diva_man_var_header_t* pVar, dword* var) {
+	byte* ptr = (char*)&pVar->path_length;
+	dword value;
+
+	ptr += (pVar->path_length + 1);
+
+	switch (pVar->value_length) {
+		case 1:
+			value = (byte)(*ptr);
+			break;
+
+		case 2:
+			value = (word)GET_WORD(ptr);
+			break;
+
+		case 3:
+			value  = (dword)GET_DWORD(ptr);
+			value &= 0x00ffffff;
+			break;
+
+		case 4:
+			value = (dword)GET_DWORD(ptr);
+			break;
+
+		default:
+			return (-1);
+	}
+
+	*var = value;
+
+	return (0);
+}
+
+/*
+	Read zero terminated ASCII string
+	*/
+static int diva_strace_read_asz  (diva_man_var_header_t* pVar, char* var) {
+	char* ptr = (char*)&pVar->path_length;
+	int length;
+
+	ptr += (pVar->path_length + 1);
+
+	if (!(length = pVar->value_length)) {
+		length = strlen (ptr);
+	}
+	memcpy (var, ptr, length);
+	var[length] = 0;
+
+	return (0);
+}
+
+/*
+	Read counted (with leading length byte) ASCII string
+	*/
+static int diva_strace_read_asc  (diva_man_var_header_t* pVar, char* var) {
+	char* ptr = (char*)&pVar->path_length;
+
+	ptr += (pVar->path_length + 1);
+	memcpy (var, ptr+1, *ptr);
+	var[(int)*ptr] = 0;
+
+	return (0);
+}
+
+/*
+		Read one information element - i.e. one string of byte values with
+		one length byte in front
+	*/
+static int  diva_strace_read_ie  (diva_man_var_header_t* pVar,
+																	diva_trace_ie_t* var) {
+	char* ptr = (char*)&pVar->path_length;
+
+	ptr += (pVar->path_length + 1);
+
+	var->length = *ptr;
+	memcpy (&var->data[0], ptr+1, *ptr);
+
+	return (0);
+}
+
+static int SuperTraceSetAudioTap  (void* hLib, int Channel, int on) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if ((Channel < 1) || (Channel > pLib->Channels)) {
+		return (-1);
+	}
+	Channel--;
+
+	if (on) {
+		pLib->audio_tap_mask |=  (1L << Channel);
+	} else {
+		pLib->audio_tap_mask &= ~(1L << Channel);
+	}
+
+  /*
+    EYE patterns have TM_M_DATA set as additional
+    condition
+    */
+  if (pLib->audio_tap_mask) {
+    pLib->trace_event_mask |= TM_M_DATA;
+  } else {
+    pLib->trace_event_mask &= ~TM_M_DATA;
+  }
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceSetBChannel  (void* hLib, int Channel, int on) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if ((Channel < 1) || (Channel > pLib->Channels)) {
+		return (-1);
+	}
+	Channel--;
+
+	if (on) {
+		pLib->bchannel_trace_mask |=  (1L << Channel);
+	} else {
+		pLib->bchannel_trace_mask &= ~(1L << Channel);
+	}
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceSetDChannel  (void* hLib, int on) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if (on) {
+		pLib->trace_event_mask |= (TM_D_CHAN | TM_C_COMM | TM_DL_ERR | TM_LAYER1);
+	} else {
+		pLib->trace_event_mask &= ~(TM_D_CHAN | TM_C_COMM | TM_DL_ERR | TM_LAYER1);
+	}
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceSetInfo (void* hLib, int on) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if (on) {
+		pLib->trace_event_mask |= TM_STRING;
+	} else {
+		pLib->trace_event_mask &= ~TM_STRING;
+	}
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceClearCall (void* hLib, int Channel) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+
+	if ((Channel < 1) || (Channel > pLib->Channels)) {
+		return (-1);
+	}
+	Channel--;
+
+	pLib->clear_call_command |= (1L << Channel);
+
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+/*
+	Parse and update cumulative statistice
+	*/
+static int diva_ifc_statistics (diva_strace_context_t* pLib,
+																diva_man_var_header_t* pVar) {
+	diva_man_var_header_t* cur;
+	int i, one_updated = 0, mdm_updated = 0, fax_updated = 0;
+
+	for (i  = pLib->statistic_parse_first; i <= pLib->statistic_parse_last; i++) {
+		if ((cur = find_var (pVar, pLib->parse_table[i].path))) {
+			if (diva_trace_read_variable (cur, pLib->parse_table[i].variable)) {
+				diva_trace_error (pLib, -3 , __FILE__, __LINE__);
+				return (-1);
+			}
+			one_updated = 1;
+      if ((i >= pLib->mdm_statistic_parse_first) && (i <= pLib->mdm_statistic_parse_last)) {
+        mdm_updated = 1;
+      }
+      if ((i >= pLib->fax_statistic_parse_first) && (i <= pLib->fax_statistic_parse_last)) {
+        fax_updated = 1;
+      }
+		}
+	}
+
+	/*
+		We do not use first event to notify user - this is the event that is
+		generated as result of EVENT ON operation and is used only to initialize
+		internal variables of application
+		*/
+  if (mdm_updated) {
+		diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE);
+  } else if (fax_updated) {
+		diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE);
+  } else if (one_updated) {
+		diva_trace_notify_user (pLib, 0, DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE);
+	}
+
+	return (one_updated ? 0 : -1);
+}
+
+static int SuperTraceGetOutgoingCallStatistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->outgoing_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetIncomingCallStatistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->incoming_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetModemStatistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->modem_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetFaxStatistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->fax_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetBLayer1Statistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->b1_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetBLayer2Statistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->b2_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetDLayer1Statistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->d1_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+static int SuperTraceGetDLayer2Statistics (void* hLib) {
+	diva_strace_context_t* pLib = (diva_strace_context_t*)hLib;
+	pLib->d2_ifc_stats = 1;
+	return (ScheduleNextTraceRequest (pLib));
+}
+
+dword DivaSTraceGetMemotyRequirement (int channels) {
+  dword parse_entries = (MODEM_PARSE_ENTRIES + FAX_PARSE_ENTRIES + \
+												 STAT_PARSE_ENTRIES + \
+												 LINE_PARSE_ENTRIES + 1) * channels;
+  return (sizeof(diva_strace_context_t) + \
+          (parse_entries * sizeof(diva_strace_path2action_t)));
+}
+
diff --git a/drivers/isdn/hardware/eicon/maintidi.h b/drivers/isdn/hardware/eicon/maintidi.h
new file mode 100644
index 0000000..4f06294
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/maintidi.h
@@ -0,0 +1,172 @@
+/*
+ *
+  Copyright (c) Eicon Networks, 2000.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    1.9
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_EICON_TRACE_IDI_IFC_H__
+#define __DIVA_EICON_TRACE_IDI_IFC_H__
+
+void* SuperTraceOpenAdapter   (int AdapterNumber);
+int   SuperTraceCloseAdapter  (void* AdapterHandle);
+int   SuperTraceWrite         (void* AdapterHandle,
+                               const void* data, int length);
+int   SuperTraceReadRequest   (void* AdapterHandle,const char* name,byte* data);
+int   SuperTraceGetNumberOfChannels (void* AdapterHandle);
+int   SuperTraceASSIGN        (void* AdapterHandle, byte* data);
+int   SuperTraceREMOVE        (void* AdapterHandle);
+int   SuperTraceTraceOnRequest(void* hAdapter, const char* name, byte* data);
+int   SuperTraceWriteVar (void* AdapterHandle,
+												byte* data,
+										 		const char* name,
+										 		void* var,
+										 		byte type,
+										 		byte var_length);
+int   SuperTraceExecuteRequest (void* AdapterHandle,
+																const char* name,
+																byte* data);
+
+typedef struct _diva_strace_path2action {
+	char               path[64]; /* Full path to variable            */
+	void*							 variable; /* Variable that will receive value */
+} diva_strace_path2action_t;
+
+#define DIVA_MAX_MANAGEMENT_TRANSFER_SIZE 4096
+
+typedef struct _diva_strace_context {
+	diva_strace_library_interface_t	instance;
+
+	int   Adapter;
+	void* hAdapter;
+
+	int Channels;
+	int	req_busy;
+
+  ENTITY   e;
+  IDI_CALL request;
+  BUFFERS  XData;
+  BUFFERS  RData;
+	byte buffer[DIVA_MAX_MANAGEMENT_TRANSFER_SIZE + 1];
+  int removal_state;
+  int general_b_ch_event;
+  int general_fax_event;
+  int general_mdm_event;
+
+	byte	rc_ok;
+
+	/*
+		Initialization request state machine
+		*/
+	int ChannelsTraceActive;
+	int ModemTraceActive;
+	int FaxTraceActive;
+	int IncomingCallsCallsActive;
+	int IncomingCallsConnectedActive;
+	int OutgoingCallsCallsActive;
+	int OutgoingCallsConnectedActive;
+
+	int trace_mask_init;
+	int audio_trace_init;
+	int bchannel_init;
+	int trace_length_init;
+	int	trace_on;
+	int trace_events_down;
+	int l1_trace;
+	int l2_trace;
+
+	/*
+		Trace\Event Enable
+		*/
+	word trace_event_mask;
+	word current_trace_event_mask;
+
+	dword audio_tap_mask;
+	dword current_audio_tap_mask;
+	dword current_eye_pattern_mask;
+	int   audio_tap_pending;
+	int   eye_pattern_pending;
+
+	dword bchannel_trace_mask;
+	dword current_bchannel_trace_mask;
+
+
+	diva_trace_line_state_t lines[30];
+
+	int	parse_entries;
+	int	cur_parse_entry;
+	diva_strace_path2action_t* parse_table;
+
+	diva_trace_library_user_interface_t user_proc_table;
+
+	int line_parse_entry_first[30];
+	int line_parse_entry_last[30];
+
+	int modem_parse_entry_first[30];
+	int modem_parse_entry_last[30];
+
+	int fax_parse_entry_first[30];
+	int fax_parse_entry_last[30];
+
+	int statistic_parse_first;
+	int statistic_parse_last;
+
+	int mdm_statistic_parse_first;
+	int mdm_statistic_parse_last;
+
+	int fax_statistic_parse_first;
+	int fax_statistic_parse_last;
+
+	dword	line_init_event;
+	dword	modem_init_event;
+	dword	fax_init_event;
+
+	dword	pending_line_status;
+	dword	pending_modem_status;
+	dword	pending_fax_status;
+
+	dword clear_call_command;
+
+	int outgoing_ifc_stats;
+	int incoming_ifc_stats;
+	int modem_ifc_stats;
+	int fax_ifc_stats;
+	int b1_ifc_stats;
+	int b2_ifc_stats;
+	int d1_ifc_stats;
+	int d2_ifc_stats;
+
+	diva_trace_interface_state_t Interface;
+	diva_ifc_statistics_t				 InterfaceStat;
+} diva_strace_context_t;
+
+typedef struct _diva_man_var_header {
+	byte   escape;
+	byte   length;
+	byte   management_id;
+	byte   type;
+	byte   attribute;
+	byte   status;
+	byte   value_length;
+	byte	 path_length;
+} diva_man_var_header_t;
+
+#endif
+
diff --git a/drivers/isdn/hardware/eicon/man_defs.h b/drivers/isdn/hardware/eicon/man_defs.h
new file mode 100644
index 0000000..cb4ef4c
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/man_defs.h
@@ -0,0 +1,133 @@
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    1.9
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/* Definitions for use with the Management Information Element      */
+
+/*------------------------------------------------------------------*/
+/* Management information element                                   */
+/* ----------------------------------------------------------       */
+/* Byte     Coding            Comment                               */
+/* ----------------------------------------------------------       */
+/*    0 | 0 1 1 1 1 1 1 1 | ESC                                     */
+/*    1 | 0 x x x x x x x | Length of information element (m-1)     */
+/*    2 | 1 0 0 0 0 0 0 0 | Management Information Id               */
+/*    3 | x x x x x x x x | Type                                    */
+/*    4 | x x x x x x x x | Attribute                               */
+/*    5 | x x x x x x x x | Status                                  */
+/*    6 | x x x x x x x x | Variable Value Length (m-n)             */
+/*    7 | x x x x x x x x | Path / Variable Name String Length (n-8)*/
+/* 8..n | x x x x x x x x | Path/Node Name String separated by '\'  */
+/* n..m | x x x x x x x x | Variable content                        */
+/*------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------*/
+/* Type Field                                                       */
+/*                                                                  */
+/* MAN_READ:      not used                                          */
+/* MAN_WRITE:     not used                                          */
+/* MAN_EVENT_ON:  not used                                          */
+/* MAN_EVENT_OFF: not used                                          */
+/* MAN_INFO_IND:  type of variable                                  */
+/* MAN_EVENT_IND: type of variable                                  */
+/* MAN_TRACE_IND  not used                                          */
+/*------------------------------------------------------------------*/
+#define MI_DIR          0x01  /* Directory string (zero terminated) */
+#define MI_EXECUTE      0x02  /* Executable function (has no value) */
+#define MI_ASCIIZ       0x03  /* Zero terminated string             */
+#define MI_ASCII        0x04  /* String, first byte is length       */
+#define MI_NUMBER       0x05  /* Number string, first byte is length*/
+#define MI_TRACE        0x06  /* Trace information, format see below*/
+
+#define MI_FIXED_LENGTH 0x80  /* get length from MAN_INFO max_len   */
+#define MI_INT          0x81  /* number to display as signed int    */
+#define MI_UINT         0x82  /* number to display as unsigned int  */
+#define MI_HINT         0x83  /* number to display in hex format    */
+#define MI_HSTR         0x84  /* number to display as a hex string  */
+#define MI_BOOLEAN      0x85  /* number to display as boolean       */
+#define MI_IP_ADDRESS   0x86  /* number to display as IP address    */
+#define MI_BITFLD       0x87  /* number to display as bit field     */
+#define MI_SPID_STATE   0x88  /* state# of SPID initialisation      */
+
+/*------------------------------------------------------------------*/
+/* Attribute Field                                                  */
+/*                                                                  */
+/* MAN_READ:      not used                                          */
+/* MAN_WRITE:     not used                                          */
+/* MAN_EVENT_ON:  not used                                          */
+/* MAN_EVENT_OFF: not used                                          */
+/* MAN_INFO_IND:  set according to capabilities of that variable    */
+/* MAN_EVENT_IND: not used                                          */
+/* MAN_TRACE_IND  not used                                          */
+/*------------------------------------------------------------------*/
+#define MI_WRITE        0x01  /* Variable is writeable              */
+#define MI_EVENT        0x02  /* Variable can indicate changes      */
+
+/*------------------------------------------------------------------*/
+/* Status Field                                                     */
+/*                                                                  */
+/* MAN_READ:      not used                                          */
+/* MAN_WRITE:     not used                                          */
+/* MAN_EVENT_ON:  not used                                          */
+/* MAN_EVENT_OFF: not used                                          */
+/* MAN_INFO_IND:  set according to the actual status                */
+/* MAN_EVENT_IND: set according to the actual statu                 */
+/* MAN_TRACE_IND  not used                                          */
+/*------------------------------------------------------------------*/
+#define MI_LOCKED       0x01  /* write protected by another instance*/
+#define MI_EVENT_ON     0x02  /* Event logging switched on          */
+#define MI_PROTECTED    0x04  /* write protected by this instance   */
+
+/*------------------------------------------------------------------*/
+/* Data Format used for MAN_TRACE_IND (no MI-element used)          */
+/*------------------------------------------------------------------*/
+typedef struct mi_xlog_hdr_s MI_XLOG_HDR;
+struct mi_xlog_hdr_s
+{
+  unsigned long  time;   /* Timestamp in msec units                 */
+  unsigned short size;   /* Size of data that follows               */
+  unsigned short code;   /* code of trace event                     */
+};                       /* unspecified data follows this header    */
+
+/*------------------------------------------------------------------*/
+/* Trace mask definitions for trace events except B channel and     */
+/* debug trace events                                               */
+/*------------------------------------------------------------------*/
+#define TM_D_CHAN   0x0001  /* D-Channel        (D-.) Code 3,4      */
+#define TM_L_LAYER  0x0002  /* Low Layer        (LL)  Code 6,7      */
+#define TM_N_LAYER  0x0004  /* Network Layer    (N)   Code 14,15    */
+#define TM_DL_ERR   0x0008  /* Data Link Error  (MDL) Code 9        */
+#define TM_LAYER1   0x0010  /* Layer 1                Code 20       */
+#define TM_C_COMM   0x0020  /* Call Comment     (SIG) Code 5,21,22  */
+#define TM_M_DATA   0x0040  /* Modulation Data  (EYE) Code 23       */
+#define TM_STRING   0x0080  /* Sting data             Code 24       */
+#define TM_N_USED2  0x0100  /* not used                             */
+#define TM_N_USED3  0x0200  /* not used                             */
+#define TM_N_USED4  0x0400  /* not used                             */
+#define TM_N_USED5  0x0800  /* not used                             */
+#define TM_N_USED6  0x1000  /* not used                             */
+#define TM_N_USED7  0x2000  /* not used                             */
+#define TM_N_USED8  0x4000  /* not used                             */
+#define TM_REST     0x8000  /* Codes 10,11,12,13,16,18,19,128,129   */
+
+/*------ End of file -----------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/mdm_msg.h b/drivers/isdn/hardware/eicon/mdm_msg.h
new file mode 100644
index 0000000..7a737e1
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/mdm_msg.h
@@ -0,0 +1,346 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __EICON_MDM_MSG_H__
+#define __EICON_MDM_MSG_H__
+#define DSP_UDATA_INDICATION_DCD_OFF  0x01
+#define DSP_UDATA_INDICATION_DCD_ON  0x02
+#define DSP_UDATA_INDICATION_CTS_OFF  0x03
+#define DSP_UDATA_INDICATION_CTS_ON  0x04
+/* =====================================================================
+DCD_OFF Message:
+  <word> time of DCD off (sampled from counter at 8kHz)
+DCD_ON Message:
+  <word> time of DCD on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s, max of tx and rx speed)
+  <word> roundtrip delay (ms)
+  <dword> connected speed tx (bit/s)
+  <dword> connected speed rx (bit/s)
+  Size of this message == 19 bytes, but we will receive only 11
+  ===================================================================== */
+#define DSP_CONNECTED_NORM_UNSPECIFIED      0
+#define DSP_CONNECTED_NORM_V21              1
+#define DSP_CONNECTED_NORM_V23              2
+#define DSP_CONNECTED_NORM_V22              3
+#define DSP_CONNECTED_NORM_V22_BIS          4
+#define DSP_CONNECTED_NORM_V32_BIS          5
+#define DSP_CONNECTED_NORM_V34              6
+#define DSP_CONNECTED_NORM_V8               7
+#define DSP_CONNECTED_NORM_BELL_212A        8
+#define DSP_CONNECTED_NORM_BELL_103         9
+#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
+#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
+#define DSP_CONNECTED_NORM_V90              12
+#define DSP_CONNECTED_NORM_V21_CH2          13
+#define DSP_CONNECTED_NORM_V27_TER          14
+#define DSP_CONNECTED_NORM_V29              15
+#define DSP_CONNECTED_NORM_V33              16
+#define DSP_CONNECTED_NORM_V17              17
+#define DSP_CONNECTED_NORM_V32              18
+#define DSP_CONNECTED_NORM_K56_FLEX         19
+#define DSP_CONNECTED_NORM_X2               20
+#define DSP_CONNECTED_NORM_V18              21
+#define DSP_CONNECTED_NORM_V18_LOW_HIGH     22
+#define DSP_CONNECTED_NORM_V18_HIGH_LOW     23
+#define DSP_CONNECTED_NORM_V21_LOW_HIGH     24
+#define DSP_CONNECTED_NORM_V21_HIGH_LOW     25
+#define DSP_CONNECTED_NORM_BELL103_LOW_HIGH 26
+#define DSP_CONNECTED_NORM_BELL103_HIGH_LOW 27
+#define DSP_CONNECTED_NORM_V23_75_1200      28
+#define DSP_CONNECTED_NORM_V23_1200_75      29
+#define DSP_CONNECTED_NORM_EDT_110          30
+#define DSP_CONNECTED_NORM_BAUDOT_45        31
+#define DSP_CONNECTED_NORM_BAUDOT_47        32
+#define DSP_CONNECTED_NORM_BAUDOT_50        33
+#define DSP_CONNECTED_NORM_DTMF             34
+#define DSP_CONNECTED_NORM_V18_RESERVED_13  35
+#define DSP_CONNECTED_NORM_V18_RESERVED_14  36
+#define DSP_CONNECTED_NORM_V18_RESERVED_15  37
+#define DSP_CONNECTED_NORM_VOWN             38
+#define DSP_CONNECTED_NORM_V23_OFF_HOOK     39
+#define DSP_CONNECTED_NORM_V23_ON_HOOK      40
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_3  41
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_4  42
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_5  43
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_6  44
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_7  45
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_8  46
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_9  47
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_10 48
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_11 49
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_12 50
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_13 51
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_14 52
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_15 53
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_16 54
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_17 55
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_18 56
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_19 57
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_20 58
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_21 59
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_22 60
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_23 61
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_24 62
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_25 63
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_26 64
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_27 65
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_28 66
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_29 67
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_30 68
+#define DSP_CONNECTED_NORM_VOWN_RESERVED_31 69
+#define DSP_CONNECTED_OPTION_TRELLIS             0x0001
+#define DSP_CONNECTED_OPTION_V42_TRANS           0x0002
+#define DSP_CONNECTED_OPTION_V42_LAPM            0x0004
+#define DSP_CONNECTED_OPTION_SHORT_TRAIN         0x0008
+#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
+#define DSP_CONNECTED_OPTION_V42BIS              0x0020
+#define DSP_CONNECTED_OPTION_MNP2                0x0040
+#define DSP_CONNECTED_OPTION_MNP3                0x0080
+#define DSP_CONNECTED_OPTION_MNP4                0x00c0
+#define DSP_CONNECTED_OPTION_MNP5                0x0100
+#define DSP_CONNECTED_OPTION_MNP10               0x0200
+#define DSP_CONNECTED_OPTION_MASK_V42            0x0024
+#define DSP_CONNECTED_OPTION_MASK_MNP            0x03c0
+#define DSP_CONNECTED_OPTION_MASK_ERROR_CORRECT  0x03e4
+#define DSP_CONNECTED_OPTION_MASK_COMPRESSION    0x0320
+#define DSP_UDATA_INDICATION_DISCONNECT         5
+/*
+returns:
+  <byte> cause
+*/
+/* ==========================================================
+    DLC: B2 modem configuration
+   ========================================================== */
+/*
+Fields in assign DLC information element for modem protocol V.42/MNP:
+  <byte> length of information element
+  <word> information field length
+  <byte> address A       (not used, default 3)
+  <byte> address B       (not used, default 1)
+  <byte> modulo mode     (not used, default 7)
+  <byte> window size     (not used, default 7)
+  <word> XID length      (not used, default 0)
+  ...    XID information (not used, default empty)
+  <byte> modem protocol negotiation options
+  <byte> modem protocol options
+  <byte> modem protocol break configuration
+  <byte> modem protocol application options
+*/
+#define DLC_MODEMPROT_DISABLE_V42_V42BIS     0x01
+#define DLC_MODEMPROT_DISABLE_MNP_MNP5       0x02
+#define DLC_MODEMPROT_REQUIRE_PROTOCOL       0x04
+#define DLC_MODEMPROT_DISABLE_V42_DETECT     0x08
+#define DLC_MODEMPROT_DISABLE_COMPRESSION    0x10
+#define DLC_MODEMPROT_REQUIRE_PROTOCOL_V34UP 0x20
+#define DLC_MODEMPROT_NO_PROTOCOL_IF_1200    0x01
+#define DLC_MODEMPROT_BUFFER_IN_V42_DETECT   0x02
+#define DLC_MODEMPROT_DISABLE_V42_SREJ       0x04
+#define DLC_MODEMPROT_DISABLE_MNP3           0x08
+#define DLC_MODEMPROT_DISABLE_MNP4           0x10
+#define DLC_MODEMPROT_DISABLE_MNP10          0x20
+#define DLC_MODEMPROT_NO_PROTOCOL_IF_V22BIS  0x40
+#define DLC_MODEMPROT_NO_PROTOCOL_IF_V32BIS  0x80
+#define DLC_MODEMPROT_BREAK_DISABLED         0x00
+#define DLC_MODEMPROT_BREAK_NORMAL           0x01
+#define DLC_MODEMPROT_BREAK_EXPEDITED        0x02
+#define DLC_MODEMPROT_BREAK_DESTRUCTIVE      0x03
+#define DLC_MODEMPROT_BREAK_CONFIG_MASK      0x03
+#define DLC_MODEMPROT_APPL_EARLY_CONNECT     0x01
+#define DLC_MODEMPROT_APPL_PASS_INDICATIONS  0x02
+/* ==========================================================
+    CAI parameters used for the modem L1 configuration
+   ========================================================== */
+/*
+Fields in assign CAI information element:
+  <byte> length of information element
+  <byte> info field and B-channel hardware
+  <byte> rate adaptation bit rate
+  <byte> async framing parameters
+  <byte> reserved
+  <word> packet length
+  <byte> modem line taking options
+  <byte> modem modulation negotiation parameters
+  <byte> modem modulation options
+  <byte> modem disabled modulations mask low
+  <byte> modem disabled modulations mask high
+  <byte> modem enabled modulations mask
+  <word> modem min TX speed
+  <word> modem max TX speed
+  <word> modem min RX speed
+  <word> modem max RX speed
+  <byte> modem disabled symbol rates mask
+  <byte> modem info options mask
+  <byte> modem transmit level adjust
+  <byte> modem speaker parameters
+  <word> modem private debug config
+  <struct> modem reserved
+  <struct> v18 config parameters
+  <struct> v18 probing sequence
+  <struct> v18 probing message
+*/
+#define DSP_CAI_HARDWARE_HDLC_64K          0x05
+#define DSP_CAI_HARDWARE_HDLC_56K          0x08
+#define DSP_CAI_HARDWARE_TRANSP            0x09
+#define DSP_CAI_HARDWARE_V110_SYNC         0x0c
+#define DSP_CAI_HARDWARE_V110_ASYNC        0x0d
+#define DSP_CAI_HARDWARE_HDLC_128K         0x0f
+#define DSP_CAI_HARDWARE_FAX               0x10
+#define DSP_CAI_HARDWARE_MODEM_ASYNC       0x11
+#define DSP_CAI_HARDWARE_MODEM_SYNC        0x12
+#define DSP_CAI_HARDWARE_V110_HDLCA        0x13
+#define DSP_CAI_HARDWARE_ADVANCED_VOICE    0x14
+#define DSP_CAI_HARDWARE_TRANSP_DTMF       0x16
+#define DSP_CAI_HARDWARE_DTMF_VOICE_ISDN   0x17
+#define DSP_CAI_HARDWARE_DTMF_VOICE_LOCAL  0x18
+#define DSP_CAI_HARDWARE_MASK              0x3f
+#define DSP_CAI_ENABLE_INFO_INDICATIONS    0x80
+#define DSP_CAI_RATE_ADAPTATION_300        0x00
+#define DSP_CAI_RATE_ADAPTATION_600        0x01
+#define DSP_CAI_RATE_ADAPTATION_1200       0x02
+#define DSP_CAI_RATE_ADAPTATION_2400       0x03
+#define DSP_CAI_RATE_ADAPTATION_4800       0x04
+#define DSP_CAI_RATE_ADAPTATION_9600       0x05
+#define DSP_CAI_RATE_ADAPTATION_19200      0x06
+#define DSP_CAI_RATE_ADAPTATION_38400      0x07
+#define DSP_CAI_RATE_ADAPTATION_48000      0x08
+#define DSP_CAI_RATE_ADAPTATION_56000      0x09
+#define DSP_CAI_RATE_ADAPTATION_7200       0x0a
+#define DSP_CAI_RATE_ADAPTATION_14400      0x0b
+#define DSP_CAI_RATE_ADAPTATION_28800      0x0c
+#define DSP_CAI_RATE_ADAPTATION_12000      0x0d
+#define DSP_CAI_RATE_ADAPTATION_1200_75    0x0e
+#define DSP_CAI_RATE_ADAPTATION_75_1200    0x0f
+#define DSP_CAI_RATE_ADAPTATION_MASK       0x0f
+#define DSP_CAI_ASYNC_PARITY_ENABLE        0x01
+#define DSP_CAI_ASYNC_PARITY_SPACE         0x00
+#define DSP_CAI_ASYNC_PARITY_ODD           0x02
+#define DSP_CAI_ASYNC_PARITY_EVEN          0x04
+#define DSP_CAI_ASYNC_PARITY_MARK          0x06
+#define DSP_CAI_ASYNC_PARITY_MASK          0x06
+#define DSP_CAI_ASYNC_ONE_STOP_BIT         0x00
+#define DSP_CAI_ASYNC_TWO_STOP_BITS        0x20
+#define DSP_CAI_ASYNC_CHAR_LENGTH_8        0x00
+#define DSP_CAI_ASYNC_CHAR_LENGTH_7        0x40
+#define DSP_CAI_ASYNC_CHAR_LENGTH_6        0x80
+#define DSP_CAI_ASYNC_CHAR_LENGTH_5        0xc0
+#define DSP_CAI_ASYNC_CHAR_LENGTH_MASK     0xc0
+#define DSP_CAI_MODEM_LEASED_LINE_MODE     0x01
+#define DSP_CAI_MODEM_4_WIRE_OPERATION     0x02
+#define DSP_CAI_MODEM_DISABLE_BUSY_DETECT  0x04
+#define DSP_CAI_MODEM_DISABLE_CALLING_TONE 0x08
+#define DSP_CAI_MODEM_DISABLE_ANSWER_TONE  0x10
+#define DSP_CAI_MODEM_ENABLE_DIAL_TONE_DET 0x20
+#define DSP_CAI_MODEM_USE_POTS_INTERFACE   0x40
+#define DSP_CAI_MODEM_FORCE_RAY_TAYLOR_FAX 0x80
+#define DSP_CAI_MODEM_NEGOTIATE_HIGHEST    0x00
+#define DSP_CAI_MODEM_NEGOTIATE_DISABLED   0x01
+#define DSP_CAI_MODEM_NEGOTIATE_IN_CLASS   0x02
+#define DSP_CAI_MODEM_NEGOTIATE_V100       0x03
+#define DSP_CAI_MODEM_NEGOTIATE_V8         0x04
+#define DSP_CAI_MODEM_NEGOTIATE_V8BIS      0x05
+#define DSP_CAI_MODEM_NEGOTIATE_MASK       0x07
+#define DSP_CAI_MODEM_GUARD_TONE_NONE      0x00
+#define DSP_CAI_MODEM_GUARD_TONE_550HZ     0x40
+#define DSP_CAI_MODEM_GUARD_TONE_1800HZ    0x80
+#define DSP_CAI_MODEM_GUARD_TONE_MASK      0xc0
+#define DSP_CAI_MODEM_DISABLE_RETRAIN      0x01
+#define DSP_CAI_MODEM_DISABLE_STEPUPDOWN   0x02
+#define DSP_CAI_MODEM_DISABLE_SPLIT_SPEED  0x04
+#define DSP_CAI_MODEM_DISABLE_TRELLIS      0x08
+#define DSP_CAI_MODEM_ALLOW_RDL_TEST_LOOP  0x10
+#define DSP_CAI_MODEM_DISABLE_FLUSH_TIMER  0x40
+#define DSP_CAI_MODEM_REVERSE_DIRECTION    0x80
+#define DSP_CAI_MODEM_DISABLE_V21          0x01
+#define DSP_CAI_MODEM_DISABLE_V23          0x02
+#define DSP_CAI_MODEM_DISABLE_V22          0x04
+#define DSP_CAI_MODEM_DISABLE_V22BIS       0x08
+#define DSP_CAI_MODEM_DISABLE_V32          0x10
+#define DSP_CAI_MODEM_DISABLE_V32BIS       0x20
+#define DSP_CAI_MODEM_DISABLE_V34          0x40
+#define DSP_CAI_MODEM_DISABLE_V90          0x80
+#define DSP_CAI_MODEM_DISABLE_BELL103      0x01
+#define DSP_CAI_MODEM_DISABLE_BELL212A     0x02
+#define DSP_CAI_MODEM_DISABLE_VFC          0x04
+#define DSP_CAI_MODEM_DISABLE_K56FLEX      0x08
+#define DSP_CAI_MODEM_DISABLE_X2           0x10
+#define DSP_CAI_MODEM_ENABLE_V29FDX        0x01
+#define DSP_CAI_MODEM_ENABLE_V33           0x02
+#define DSP_CAI_MODEM_DISABLE_2400_SYMBOLS 0x01
+#define DSP_CAI_MODEM_DISABLE_2743_SYMBOLS 0x02
+#define DSP_CAI_MODEM_DISABLE_2800_SYMBOLS 0x04
+#define DSP_CAI_MODEM_DISABLE_3000_SYMBOLS 0x08
+#define DSP_CAI_MODEM_DISABLE_3200_SYMBOLS 0x10
+#define DSP_CAI_MODEM_DISABLE_3429_SYMBOLS 0x20
+#define DSP_CAI_MODEM_DISABLE_TX_REDUCTION 0x01
+#define DSP_CAI_MODEM_DISABLE_PRECODING    0x02
+#define DSP_CAI_MODEM_DISABLE_PREEMPHASIS  0x04
+#define DSP_CAI_MODEM_DISABLE_SHAPING      0x08
+#define DSP_CAI_MODEM_DISABLE_NONLINEAR_EN 0x10
+#define DSP_CAI_MODEM_SPEAKER_OFF          0x00
+#define DSP_CAI_MODEM_SPEAKER_DURING_TRAIN 0x01
+#define DSP_CAI_MODEM_SPEAKER_TIL_CONNECT  0x02
+#define DSP_CAI_MODEM_SPEAKER_ALWAYS_ON    0x03
+#define DSP_CAI_MODEM_SPEAKER_CONTROL_MASK 0x03
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_MIN   0x00
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_LOW   0x04
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_HIGH  0x08
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_MAX   0x0c
+#define DSP_CAI_MODEM_SPEAKER_VOLUME_MASK  0x0c
+/* ==========================================================
+    DCD/CTS State
+   ========================================================== */
+#define MDM_WANT_CONNECT_B3_ACTIVE_I  0x01
+#define MDM_NCPI_VALID                0x02
+#define MDM_NCPI_CTS_ON_RECEIVED      0x04
+#define MDM_NCPI_DCD_ON_RECEIVED      0x08
+/* ==========================================================
+    CAPI NCPI Constants
+   ========================================================== */
+#define MDM_NCPI_ECM_V42              0x0001
+#define MDM_NCPI_ECM_MNP              0x0002
+#define MDM_NCPI_TRANSPARENT          0x0004
+#define MDM_NCPI_COMPRESSED           0x0010
+/* ==========================================================
+    CAPI B2 Config Constants
+   ========================================================== */
+#define MDM_B2_DISABLE_V42bis         0x0001
+#define MDM_B2_DISABLE_MNP            0x0002
+#define MDM_B2_DISABLE_TRANS          0x0004
+#define MDM_B2_DISABLE_V42            0x0008
+#define MDM_B2_DISABLE_COMP           0x0010
+/* ==========================================================
+    CAPI B1 Config Constants
+   ========================================================== */
+#define MDM_CAPI_DISABLE_RETRAIN      0x0001
+#define MDM_CAPI_DISABLE_RING_TONE    0x0002
+#define MDM_CAPI_GUARD_1800           0x0004
+#define MDM_CAPI_GUARD_550            0x0008
+#define MDM_CAPI_NEG_V8               0x0003
+#define MDM_CAPI_NEG_V100             0x0002
+#define MDM_CAPI_NEG_MOD_CLASS        0x0001
+#define MDM_CAPI_NEG_DISABLED         0x0000
+#endif
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
new file mode 100644
index 0000000..f9b00f1
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -0,0 +1,15047 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+
+
+
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "capi20.h"
+#include "divacapi.h"
+#include "mdm_msg.h"
+#include "divasync.h"
+
+
+
+#define FILE_ "MESSAGE.C"
+#define dprintf
+
+
+
+
+
+
+
+
+
+/*------------------------------------------------------------------*/
+/* This is options supported for all adapters that are server by    */
+/* XDI driver. Allo it is not necessary to ask it from every adapter*/
+/* and it is not necessary to save it separate for every adapter    */
+/* Macrose defined here have only local meaning                     */
+/*------------------------------------------------------------------*/
+static dword diva_xdi_extended_features = 0;
+
+#define DIVA_CAPI_USE_CMA                 0x00000001
+#define DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR  0x00000002
+#define DIVA_CAPI_XDI_PROVIDES_NO_CANCEL  0x00000004
+#define DIVA_CAPI_XDI_PROVIDES_RX_DMA     0x00000008
+
+/*
+  CAPI can request to process all return codes self only if:
+  protocol code supports this && xdi supports this
+ */
+#define DIVA_CAPI_SUPPORTS_NO_CANCEL(__a__)   (((__a__)->manufacturer_features&MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)&&    ((__a__)->manufacturer_features & MANUFACTURER_FEATURE_OK_FC_LABEL) &&     (diva_xdi_extended_features   & DIVA_CAPI_XDI_PROVIDES_NO_CANCEL))
+
+/*------------------------------------------------------------------*/
+/* local function prototypes                                        */
+/*------------------------------------------------------------------*/
+
+static void group_optimization(DIVA_CAPI_ADAPTER   * a, PLCI   * plci);
+static void set_group_ind_mask (PLCI   *plci);
+static void clear_group_ind_mask_bit (PLCI   *plci, word b);
+static byte test_group_ind_mask_bit (PLCI   *plci, word b);
+void AutomaticLaw(DIVA_CAPI_ADAPTER   *);
+word CapiRelease(word);
+word CapiRegister(word);
+word api_put(APPL   *, CAPI_MSG   *);
+static word api_parse(byte   *, word, byte *, API_PARSE *);
+static void api_save_msg(API_PARSE   *in, byte *format, API_SAVE   *out);
+static void api_load_msg(API_SAVE   *in, API_PARSE   *out);
+
+word api_remove_start(void);
+void api_remove_complete(void);
+
+static void plci_remove(PLCI   *);
+static void diva_get_extended_adapter_features (DIVA_CAPI_ADAPTER  * a);
+static void diva_ask_for_xdi_sdram_bar (DIVA_CAPI_ADAPTER  *, IDI_SYNC_REQ  *);
+
+void   callback(ENTITY   *);
+
+static void control_rc(PLCI   *, byte, byte, byte, byte, byte);
+static void data_rc(PLCI   *, byte);
+static void data_ack(PLCI   *, byte);
+static void sig_ind(PLCI   *);
+static void SendInfo(PLCI   *, dword, byte   * *, byte);
+static void SendSetupInfo(APPL   *, PLCI   *, dword, byte   * *, byte);
+static void SendSSExtInd(APPL   *, PLCI   * plci, dword Id, byte   * * parms);
+
+static void VSwitchReqInd(PLCI   *plci, dword Id, byte   **parms);
+
+static void nl_ind(PLCI   *);
+
+static byte connect_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_a_res(dword,word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte disconnect_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte disconnect_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte listen_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte info_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte info_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte alert_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte facility_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte facility_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_b3_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_b3_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_b3_a_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte disconnect_b3_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte disconnect_b3_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte data_b3_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte data_b3_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte reset_b3_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte reset_b3_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte connect_b3_t90_a_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte select_b_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte manufacturer_req(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+static byte manufacturer_res(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+
+static word get_plci(DIVA_CAPI_ADAPTER   *);
+static void add_p(PLCI   *, byte, byte   *);
+static void add_s(PLCI   * plci, byte code, API_PARSE * p);
+static void add_ss(PLCI   * plci, byte code, API_PARSE * p);
+static void add_ie(PLCI   * plci, byte code, byte   * p, word p_length);
+static void add_d(PLCI   *, word, byte   *);
+static void add_ai(PLCI   *, API_PARSE *);
+static word add_b1(PLCI   *, API_PARSE *, word, word);
+static word add_b23(PLCI   *, API_PARSE *);
+static word add_modem_b23 (PLCI  * plci, API_PARSE* bp_parms);
+static void sig_req(PLCI   *, byte, byte);
+static void nl_req_ncci(PLCI   *, byte, byte);
+static void send_req(PLCI   *);
+static void send_data(PLCI   *);
+static word plci_remove_check(PLCI   *);
+static void listen_check(DIVA_CAPI_ADAPTER   *);
+static byte AddInfo(byte   **, byte   **, byte   *, byte *);
+static byte getChannel(API_PARSE *);
+static void IndParse(PLCI   *, word *, byte   **, byte);
+static byte ie_compare(byte   *, byte *);
+static word find_cip(DIVA_CAPI_ADAPTER   *, byte   *, byte   *);
+static word CPN_filter_ok(byte   *cpn,DIVA_CAPI_ADAPTER   *,word);
+
+/*
+  XON protocol helpers
+  */
+static void channel_flow_control_remove (PLCI   * plci);
+static void channel_x_off (PLCI   * plci, byte ch, byte flag);
+static void channel_x_on (PLCI   * plci, byte ch);
+static void channel_request_xon (PLCI   * plci, byte ch);
+static void channel_xmit_xon (PLCI   * plci);
+static int channel_can_xon (PLCI   * plci, byte ch);
+static void channel_xmit_extended_xon (PLCI   * plci);
+
+static byte SendMultiIE(PLCI   * plci, dword Id, byte   * * parms, byte ie_type, dword info_mask, byte setupParse);
+static word AdvCodecSupport(DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, byte);
+static void CodecIdCheck(DIVA_CAPI_ADAPTER   *, PLCI   *);
+static void SetVoiceChannel(PLCI   *, byte   *, DIVA_CAPI_ADAPTER   * );
+static void VoiceChannelOff(PLCI   *plci);
+static void adv_voice_write_coefs (PLCI   *plci, word write_command);
+static void adv_voice_clear_config (PLCI   *plci);
+
+static word get_b1_facilities (PLCI   * plci, byte b1_resource);
+static byte add_b1_facilities (PLCI   * plci, byte b1_resource, word b1_facilities);
+static void adjust_b1_facilities (PLCI   *plci, byte new_b1_resource, word new_b1_facilities);
+static word adjust_b_process (dword Id, PLCI   *plci, byte Rc);
+static void adjust_b1_resource (dword Id, PLCI   *plci, API_SAVE   *bp_msg, word b1_facilities, word internal_command);
+static void adjust_b_restore (dword Id, PLCI   *plci, byte Rc);
+static void reset_b3_command (dword Id, PLCI   *plci, byte Rc);
+static void select_b_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_connect_ack_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_edata_ack_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_connect_info_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_adjust_b23_command (dword Id, PLCI   *plci, byte Rc);
+static void fax_disconnect_command (dword Id, PLCI   *plci, byte Rc);
+static void hold_save_command (dword Id, PLCI   *plci, byte Rc);
+static void retrieve_restore_command (dword Id, PLCI   *plci, byte Rc);
+static void init_b1_config (PLCI   *plci);
+static void clear_b1_config (PLCI   *plci);
+
+static void dtmf_command (dword Id, PLCI   *plci, byte Rc);
+static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg);
+static void dtmf_confirmation (dword Id, PLCI   *plci);
+static void dtmf_indication (dword Id, PLCI   *plci, byte   *msg, word length);
+static void dtmf_parameter_write (PLCI   *plci);
+
+
+static void mixer_set_bchannel_id_esc (PLCI   *plci, byte bchannel_id);
+static void mixer_set_bchannel_id (PLCI   *plci, byte   *chi);
+static void mixer_clear_config (PLCI   *plci);
+static void mixer_notify_update (PLCI   *plci, byte others);
+static void mixer_command (dword Id, PLCI   *plci, byte Rc);
+static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg);
+static void mixer_indication_coefs_set (dword Id, PLCI   *plci);
+static void mixer_indication_xconnect_from (dword Id, PLCI   *plci, byte   *msg, word length);
+static void mixer_indication_xconnect_to (dword Id, PLCI   *plci, byte   *msg, word length);
+static void mixer_remove (PLCI   *plci);
+
+
+static void ec_command (dword Id, PLCI   *plci, byte Rc);
+static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg);
+static void ec_indication (dword Id, PLCI   *plci, byte   *msg, word length);
+
+
+static void rtp_connect_b3_req_command (dword Id, PLCI   *plci, byte Rc);
+static void rtp_connect_b3_res_command (dword Id, PLCI   *plci, byte Rc);
+
+
+static int  diva_get_dma_descriptor  (PLCI   *plci, dword   *dma_magic);
+static void diva_free_dma_descriptor (PLCI   *plci, int nr);
+
+/*------------------------------------------------------------------*/
+/* external function prototypes                                     */
+/*------------------------------------------------------------------*/
+
+extern byte MapController (byte);
+extern byte UnMapController (byte);
+#define MapId(Id) (((Id) & 0xffffff00L) | MapController ((byte)(Id)))
+#define UnMapId(Id) (((Id) & 0xffffff00L) | UnMapController ((byte)(Id)))
+
+void   sendf(APPL   *, word, dword, word, byte *, ...);
+void   * TransmitBufferSet(APPL   * appl, dword ref);
+void   * TransmitBufferGet(APPL   * appl, void   * p);
+void TransmitBufferFree(APPL   * appl, void   * p);
+void   * ReceiveBufferGet(APPL   * appl, int Num);
+
+int fax_head_line_time (char *buffer);
+
+
+/*------------------------------------------------------------------*/
+/* Global data definitions                                          */
+/*------------------------------------------------------------------*/
+extern byte max_adapter;
+extern byte max_appl;
+extern DIVA_CAPI_ADAPTER   * adapter;
+extern APPL   * application;
+
+
+
+
+
+
+
+static byte remove_started = FALSE;
+static PLCI dummy_plci;
+
+
+static struct _ftable {
+  word command;
+  byte * format;
+  byte (* function)(dword, word, DIVA_CAPI_ADAPTER   *, PLCI   *, APPL   *, API_PARSE *);
+} ftable[] = {
+  {_DATA_B3_R,                          "dwww",         data_b3_req},
+  {_DATA_B3_I|RESPONSE,                 "w",            data_b3_res},
+  {_INFO_R,                             "ss",           info_req},
+  {_INFO_I|RESPONSE,                    "",             info_res},
+  {_CONNECT_R,                          "wsssssssss",   connect_req},
+  {_CONNECT_I|RESPONSE,                 "wsssss",       connect_res},
+  {_CONNECT_ACTIVE_I|RESPONSE,          "",             connect_a_res},
+  {_DISCONNECT_R,                       "s",            disconnect_req},
+  {_DISCONNECT_I|RESPONSE,              "",             disconnect_res},
+  {_LISTEN_R,                           "dddss",        listen_req},
+  {_ALERT_R,                            "s",            alert_req},
+  {_FACILITY_R,                         "ws",           facility_req},
+  {_FACILITY_I|RESPONSE,                "ws",           facility_res},
+  {_CONNECT_B3_R,                       "s",            connect_b3_req},
+  {_CONNECT_B3_I|RESPONSE,              "ws",           connect_b3_res},
+  {_CONNECT_B3_ACTIVE_I|RESPONSE,       "",             connect_b3_a_res},
+  {_DISCONNECT_B3_R,                    "s",            disconnect_b3_req},
+  {_DISCONNECT_B3_I|RESPONSE,           "",             disconnect_b3_res},
+  {_RESET_B3_R,                         "s",            reset_b3_req},
+  {_RESET_B3_I|RESPONSE,                "",             reset_b3_res},
+  {_CONNECT_B3_T90_ACTIVE_I|RESPONSE,   "ws",           connect_b3_t90_a_res},
+  {_CONNECT_B3_T90_ACTIVE_I|RESPONSE,   "",             connect_b3_t90_a_res},
+  {_SELECT_B_REQ,                       "s",            select_b_req},
+  {_MANUFACTURER_R,                     "dws",          manufacturer_req},
+  {_MANUFACTURER_I|RESPONSE,            "dws",          manufacturer_res},
+  {_MANUFACTURER_I|RESPONSE,            "",             manufacturer_res}
+};
+
+static byte * cip_bc[29][2] = {
+  { "",                     ""                     }, /* 0 */
+  { "\x03\x80\x90\xa3",     "\x03\x80\x90\xa2"     }, /* 1 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 2 */
+  { "\x02\x89\x90",         "\x02\x89\x90"         }, /* 3 */
+  { "\x03\x90\x90\xa3",     "\x03\x90\x90\xa2"     }, /* 4 */
+  { "\x03\x91\x90\xa5",     "\x03\x91\x90\xa5"     }, /* 5 */
+  { "\x02\x98\x90",         "\x02\x98\x90"         }, /* 6 */
+  { "\x04\x88\xc0\xc6\xe6", "\x04\x88\xc0\xc6\xe6" }, /* 7 */
+  { "\x04\x88\x90\x21\x8f", "\x04\x88\x90\x21\x8f" }, /* 8 */
+  { "\x03\x91\x90\xa5",     "\x03\x91\x90\xa5"     }, /* 9 */
+  { "",                     ""                     }, /* 10 */
+  { "",                     ""                     }, /* 11 */
+  { "",                     ""                     }, /* 12 */
+  { "",                     ""                     }, /* 13 */
+  { "",                     ""                     }, /* 14 */
+  { "",                     ""                     }, /* 15 */
+
+  { "\x03\x80\x90\xa3",     "\x03\x80\x90\xa2"     }, /* 16 */
+  { "\x03\x90\x90\xa3",     "\x03\x90\x90\xa2"     }, /* 17 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 18 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 19 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 20 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 21 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 22 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 23 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 24 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }, /* 25 */
+  { "\x03\x91\x90\xa5",     "\x03\x91\x90\xa5"     }, /* 26 */
+  { "\x03\x91\x90\xa5",     "\x03\x91\x90\xa5"     }, /* 27 */
+  { "\x02\x88\x90",         "\x02\x88\x90"         }  /* 28 */
+};
+
+static byte * cip_hlc[29] = {
+  "",                           /* 0 */
+  "",                           /* 1 */
+  "",                           /* 2 */
+  "",                           /* 3 */
+  "",                           /* 4 */
+  "",                           /* 5 */
+  "",                           /* 6 */
+  "",                           /* 7 */
+  "",                           /* 8 */
+  "",                           /* 9 */
+  "",                           /* 10 */
+  "",                           /* 11 */
+  "",                           /* 12 */
+  "",                           /* 13 */
+  "",                           /* 14 */
+  "",                           /* 15 */
+
+  "\x02\x91\x81",               /* 16 */
+  "\x02\x91\x84",               /* 17 */
+  "\x02\x91\xa1",               /* 18 */
+  "\x02\x91\xa4",               /* 19 */
+  "\x02\x91\xa8",               /* 20 */
+  "\x02\x91\xb1",               /* 21 */
+  "\x02\x91\xb2",               /* 22 */
+  "\x02\x91\xb5",               /* 23 */
+  "\x02\x91\xb8",               /* 24 */
+  "\x02\x91\xc1",               /* 25 */
+  "\x02\x91\x81",               /* 26 */
+  "\x03\x91\xe0\x01",           /* 27 */
+  "\x03\x91\xe0\x02"            /* 28 */
+};
+
+/*------------------------------------------------------------------*/
+
+#define V120_HEADER_LENGTH 1
+#define V120_HEADER_EXTEND_BIT  0x80
+#define V120_HEADER_BREAK_BIT   0x40
+#define V120_HEADER_C1_BIT      0x04
+#define V120_HEADER_C2_BIT      0x08
+#define V120_HEADER_FLUSH_COND  (V120_HEADER_BREAK_BIT | V120_HEADER_C1_BIT | V120_HEADER_C2_BIT)
+
+static byte v120_default_header[] =
+{
+
+  0x83                          /*  Ext, BR , res, res, C2 , C1 , B  , F   */
+
+};
+
+static byte v120_break_header[] =
+{
+
+  0xc3 | V120_HEADER_BREAK_BIT  /*  Ext, BR , res, res, C2 , C1 , B  , F   */
+
+};
+
+
+/*------------------------------------------------------------------*/
+/* API_PUT function                                                 */
+/*------------------------------------------------------------------*/
+
+word api_put(APPL   * appl, CAPI_MSG   * msg)
+{
+  word i, j, k, l, n;
+  word ret;
+  byte c;
+  byte controller;
+  DIVA_CAPI_ADAPTER   * a;
+  PLCI   * plci;
+  NCCI   * ncci_ptr;
+  word ncci;
+  CAPI_MSG   *m;
+    API_PARSE msg_parms[MAX_MSG_PARMS+1];
+
+  if (msg->header.length < sizeof (msg->header) ||
+      msg->header.length > MAX_MSG_SIZE) {
+    dbug(1,dprintf("bad len"));
+    return _BAD_MSG;
+  }
+
+  controller = (byte)((msg->header.controller &0x7f)-1);
+
+  /* controller starts with 0 up to (max_adapter - 1) */
+  if ( controller >= max_adapter )
+  {
+    dbug(1,dprintf("invalid ctrl"));
+    return _BAD_MSG;
+  }
+  
+  a = &adapter[controller];
+  plci = NULL;
+  if ((msg->header.plci != 0) && (msg->header.plci <= a->max_plci) && !a->adapter_disabled)
+  {
+    dbug(1,dprintf("plci=%x",msg->header.plci));
+    plci = &a->plci[msg->header.plci-1];
+    ncci = GET_WORD(&msg->header.ncci);
+    if (plci->Id
+     && (plci->appl
+      || (plci->State == INC_CON_PENDING)
+      || (plci->State == INC_CON_ALERT)
+      || (msg->header.command == (_DISCONNECT_I|RESPONSE)))
+     && ((ncci == 0)
+      || (msg->header.command == (_DISCONNECT_B3_I|RESPONSE))
+      || ((ncci < MAX_NCCI+1) && (a->ncci_plci[ncci] == plci->Id))))
+    {
+      i = plci->msg_in_read_pos;
+      j = plci->msg_in_write_pos;
+      if (j >= i)
+      {
+        if (j + msg->header.length + MSG_IN_OVERHEAD <= MSG_IN_QUEUE_SIZE)
+          i += MSG_IN_QUEUE_SIZE - j;
+        else
+          j = 0;
+      }
+      else
+      {
+
+        n = (((CAPI_MSG   *)(plci->msg_in_queue))->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc;
+
+        if (i > MSG_IN_QUEUE_SIZE - n)
+          i = MSG_IN_QUEUE_SIZE - n + 1;
+        i -= j;
+      }
+
+      if (i <= ((msg->header.length + MSG_IN_OVERHEAD + 3) & 0xfffc))
+
+      {
+        dbug(0,dprintf("Q-FULL1(msg) - len=%d write=%d read=%d wrap=%d free=%d",
+          msg->header.length, plci->msg_in_write_pos,
+          plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
+
+        return _QUEUE_FULL;
+      }
+      c = FALSE;
+      if ((((byte   *) msg) < ((byte   *)(plci->msg_in_queue)))
+       || (((byte   *) msg) >= ((byte   *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+      {
+        if (plci->msg_in_write_pos != plci->msg_in_read_pos)
+          c = TRUE;
+      }
+      if (msg->header.command == _DATA_B3_R)
+      {
+        if (msg->header.length < 20)
+        {
+          dbug(1,dprintf("DATA_B3 REQ wrong length %d", msg->header.length));
+          return _BAD_MSG;
+        }
+        ncci_ptr = &(a->ncci[ncci]);
+        n = ncci_ptr->data_pending;
+        l = ncci_ptr->data_ack_pending;
+        k = plci->msg_in_read_pos;
+        while (k != plci->msg_in_write_pos)
+        {
+          if (k == plci->msg_in_wrap_pos)
+            k = 0;
+          if ((((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[k]))->header.command == _DATA_B3_R)
+           && (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[k]))->header.ncci == ncci))
+          {
+            n++;
+            if (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[k]))->info.data_b3_req.Flags & 0x0004)
+              l++;
+          }
+
+          k += (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[k]))->header.length +
+            MSG_IN_OVERHEAD + 3) & 0xfffc;
+
+        }
+        if ((n >= MAX_DATA_B3) || (l >= MAX_DATA_ACK))
+        {
+          dbug(0,dprintf("Q-FULL2(data) - pending=%d/%d ack_pending=%d/%d",
+                          ncci_ptr->data_pending, n, ncci_ptr->data_ack_pending, l));
+
+          return _QUEUE_FULL;
+        }
+        if (plci->req_in || plci->internal_command)
+        {
+          if ((((byte   *) msg) >= ((byte   *)(plci->msg_in_queue)))
+           && (((byte   *) msg) < ((byte   *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+          {
+            dbug(0,dprintf("Q-FULL3(requeue)"));
+
+            return _QUEUE_FULL;
+          }
+          c = TRUE;
+        }
+      }
+      else
+      {
+        if (plci->req_in || plci->internal_command)
+          c = TRUE;
+        else
+        {
+          plci->command = msg->header.command;
+          plci->number = msg->header.number;
+        }
+      }
+      if (c)
+      {
+        dbug(1,dprintf("enqueue msg(0x%04x,0x%x,0x%x) - len=%d write=%d read=%d wrap=%d free=%d",
+          msg->header.command, plci->req_in, plci->internal_command,
+          msg->header.length, plci->msg_in_write_pos,
+          plci->msg_in_read_pos, plci->msg_in_wrap_pos, i));
+        if (j == 0)
+          plci->msg_in_wrap_pos = plci->msg_in_write_pos;
+        m = (CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[j]);
+        for (i = 0; i < msg->header.length; i++)
+          ((byte   *)(plci->msg_in_queue))[j++] = ((byte   *) msg)[i];
+        if (m->header.command == _DATA_B3_R)
+        {
+
+          m->info.data_b3_req.Data = (dword)(TransmitBufferSet (appl, m->info.data_b3_req.Data));
+
+        }
+
+        j = (j + 3) & 0xfffc;
+
+        *((APPL   *   *)(&((byte   *)(plci->msg_in_queue))[j])) = appl;
+        plci->msg_in_write_pos = j + MSG_IN_OVERHEAD;
+        return 0;
+      }
+    }
+    else
+    {
+      plci = NULL;
+    }
+  }
+  dbug(1,dprintf("com=%x",msg->header.command));
+
+  for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
+  for(i=0, ret = _BAD_MSG;
+      i<(sizeof(ftable)/sizeof(struct _ftable));
+      i++) {
+
+    if(ftable[i].command==msg->header.command) {
+      /* break loop if the message is correct, otherwise continue scan  */
+      /* (for example: CONNECT_B3_T90_ACT_RES has two specifications)   */
+      if(!api_parse(msg->info.b,(word)(msg->header.length-12),ftable[i].format,msg_parms)) {
+        ret = 0;
+        break;
+      }
+      for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
+    }
+  }
+  if(ret) {
+    dbug(1,dprintf("BAD_MSG"));
+    if(plci) plci->command = 0;
+    return ret;
+  }
+
+
+  c = ftable[i].function(GET_DWORD(&msg->header.controller),
+                         msg->header.number,
+                         a,
+                         plci,
+                         appl,
+                         msg_parms);
+
+  channel_xmit_extended_xon (plci);
+
+  if(c==1) send_req(plci);
+  if(c==2 && plci) plci->req_in = plci->req_in_start = plci->req_out = 0;
+  if(plci && !plci->req_in) plci->command = 0;
+  return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* api_parse function, check the format of api messages             */
+/*------------------------------------------------------------------*/
+
+word api_parse(byte   * msg, word length, byte * format, API_PARSE * parms)
+{
+  word i;
+  word p;
+
+  for(i=0,p=0; format[i]; i++) {
+    if(parms)
+    {
+      parms[i].info = &msg[p];
+    }
+    switch(format[i]) {
+    case 'b':
+      p +=1;
+      break;
+    case 'w':
+      p +=2;
+      break;
+    case 'd':
+      p +=4;
+      break;
+    case 's':
+      if(msg[p]==0xff) {
+        parms[i].info +=2;
+        parms[i].length = msg[p+1] + (msg[p+2]<<8);
+        p +=(parms[i].length +3);
+      }
+      else {
+        parms[i].length = msg[p];
+        p +=(parms[i].length +1);
+      }
+      break;
+    }
+
+    if(p>length) return TRUE;
+  }
+  if(parms) parms[i].info = NULL;
+  return FALSE;
+}
+
+void api_save_msg(API_PARSE   *in, byte *format, API_SAVE   *out)
+{
+  word i, j, n = 0;
+  byte   *p;
+
+  p = out->info;
+  for (i = 0; format[i] != '\0'; i++)
+  {
+    out->parms[i].info = p;
+    out->parms[i].length = in[i].length;
+    switch (format[i])
+    {
+    case 'b':
+      n = 1;
+      break;
+    case 'w':
+      n = 2;
+      break;
+    case 'd':
+      n = 4;
+      break;
+    case 's':
+      n = in[i].length + 1;
+      break;
+    }
+    for (j = 0; j < n; j++)
+      *(p++) = in[i].info[j];
+  }
+  out->parms[i].info = NULL;
+  out->parms[i].length = 0;
+}
+
+void api_load_msg(API_SAVE   *in, API_PARSE   *out)
+{
+  word i;
+
+  i = 0;
+  do
+  {
+    out[i].info = in->parms[i].info;
+    out[i].length = in->parms[i].length;
+  } while (in->parms[i++].info);
+}
+
+
+/*------------------------------------------------------------------*/
+/* CAPI remove function                                             */
+/*------------------------------------------------------------------*/
+
+word api_remove_start(void)
+{
+  word i;
+  word j;
+
+  if(!remove_started) {
+    remove_started = TRUE;
+    for(i=0;i<max_adapter;i++) {
+      if(adapter[i].request) {
+        for(j=0;j<adapter[i].max_plci;j++) {
+          if(adapter[i].plci[j].Sig.Id) plci_remove(&adapter[i].plci[j]);
+        }
+      }
+    }
+    return 1;
+  }
+  else {
+    for(i=0;i<max_adapter;i++) {
+      if(adapter[i].request) {
+        for(j=0;j<adapter[i].max_plci;j++) {
+          if(adapter[i].plci[j].Sig.Id) return 1;
+        }
+      }
+    }
+  }
+  api_remove_complete();
+  return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* internal command queue                                           */
+/*------------------------------------------------------------------*/
+
+static void init_internal_command_queue (PLCI   *plci)
+{
+  word i;
+
+  dbug (1, dprintf ("%s,%d: init_internal_command_queue",
+    (char   *)(FILE_), __LINE__));
+
+  plci->internal_command = 0;
+  for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS; i++)
+    plci->internal_command_queue[i] = NULL;
+}
+
+
+static void start_internal_command (dword Id, PLCI   *plci, t_std_internal_command command_function)
+{
+  word i;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: start_internal_command",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  if (plci->internal_command == 0)
+  {
+    plci->internal_command_queue[0] = command_function;
+    (* command_function)(Id, plci, OK);
+  }
+  else
+  {
+    i = 1;
+    while (plci->internal_command_queue[i] != 0)
+      i++;
+    plci->internal_command_queue[i] = command_function;
+  }
+}
+
+
+static void next_internal_command (dword Id, PLCI   *plci)
+{
+  word i;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: next_internal_command",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  plci->internal_command = 0;
+  plci->internal_command_queue[0] = NULL;
+  while (plci->internal_command_queue[1] != 0)
+  {
+    for (i = 0; i < MAX_INTERNAL_COMMAND_LEVELS - 1; i++)
+      plci->internal_command_queue[i] = plci->internal_command_queue[i+1];
+    plci->internal_command_queue[MAX_INTERNAL_COMMAND_LEVELS - 1] = NULL;
+    (*(plci->internal_command_queue[0]))(Id, plci, OK);
+    if (plci->internal_command != 0)
+      return;
+    plci->internal_command_queue[0] = NULL;
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* NCCI allocate/remove function                                    */
+/*------------------------------------------------------------------*/
+
+static dword ncci_mapping_bug = 0;
+
+static word get_ncci (PLCI   *plci, byte ch, word force_ncci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word ncci, i, j, k;
+
+  a = plci->adapter;
+  if (!ch || a->ch_ncci[ch])
+  {
+    ncci_mapping_bug++;
+    dbug(1,dprintf("NCCI mapping exists %ld %02x %02x %02x-%02x",
+      ncci_mapping_bug, ch, force_ncci, a->ncci_ch[a->ch_ncci[ch]], a->ch_ncci[ch]));
+    ncci = ch;
+  }
+  else
+  {
+    if (force_ncci)
+      ncci = force_ncci;
+    else
+    {
+      if ((ch < MAX_NCCI+1) && !a->ncci_ch[ch])
+        ncci = ch;
+      else
+      {
+        ncci = 1;
+        while ((ncci < MAX_NCCI+1) && a->ncci_ch[ncci])
+          ncci++;
+        if (ncci == MAX_NCCI+1)
+        {
+          ncci_mapping_bug++;
+          i = 1;
+          do
+          {
+            j = 1;
+            while ((j < MAX_NCCI+1) && (a->ncci_ch[j] != i))
+              j++;
+            k = j;
+            if (j < MAX_NCCI+1)
+            {
+              do
+              {
+                j++;
+              } while ((j < MAX_NCCI+1) && (a->ncci_ch[j] != i));
+            }
+          } while ((i < MAX_NL_CHANNEL+1) && (j < MAX_NCCI+1));
+          if (i < MAX_NL_CHANNEL+1)
+          {
+            dbug(1,dprintf("NCCI mapping overflow %ld %02x %02x %02x-%02x-%02x",
+              ncci_mapping_bug, ch, force_ncci, i, k, j));
+          }
+          else
+          {
+            dbug(1,dprintf("NCCI mapping overflow %ld %02x %02x",
+              ncci_mapping_bug, ch, force_ncci));
+          }
+          ncci = ch;
+        }
+      }
+      a->ncci_plci[ncci] = plci->Id;
+      a->ncci_state[ncci] = IDLE;
+      if (!plci->ncci_ring_list)
+        plci->ncci_ring_list = ncci;
+      else
+        a->ncci_next[ncci] = a->ncci_next[plci->ncci_ring_list];
+      a->ncci_next[plci->ncci_ring_list] = (byte) ncci;
+    }
+    a->ncci_ch[ncci] = ch;
+    a->ch_ncci[ch] = (byte) ncci;
+    dbug(1,dprintf("NCCI mapping established %ld %02x %02x %02x-%02x",
+      ncci_mapping_bug, ch, force_ncci, ch, ncci));
+  }
+  return (ncci);
+}
+
+
+static void ncci_free_receive_buffers (PLCI   *plci, word ncci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  APPL   *appl;
+  word i, ncci_code;
+  dword Id;
+
+  a = plci->adapter;
+  Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
+  if (ncci)
+  {
+    if (a->ncci_plci[ncci] == plci->Id)
+    {
+      if (!plci->appl)
+      {
+        ncci_mapping_bug++;
+        dbug(1,dprintf("NCCI mapping appl expected %ld %08lx",
+          ncci_mapping_bug, Id));
+      }
+      else
+      {
+        appl = plci->appl;
+        ncci_code = ncci | (((word) a->Id) << 8);
+        for (i = 0; i < appl->MaxBuffer; i++)
+        {
+          if ((appl->DataNCCI[i] == ncci_code)
+           && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
+          {
+            appl->DataNCCI[i] = 0;
+          }
+        }
+      }
+    }
+  }
+  else
+  {
+    for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
+    {
+      if (a->ncci_plci[ncci] == plci->Id)
+      {
+        if (!plci->appl)
+        {
+          ncci_mapping_bug++;
+          dbug(1,dprintf("NCCI mapping no appl %ld %08lx",
+            ncci_mapping_bug, Id));
+        }
+        else
+        {
+          appl = plci->appl;
+          ncci_code = ncci | (((word) a->Id) << 8);
+          for (i = 0; i < appl->MaxBuffer; i++)
+          {
+            if ((appl->DataNCCI[i] == ncci_code)
+             && (((byte)(appl->DataFlags[i] >> 8)) == plci->Id))
+            {
+              appl->DataNCCI[i] = 0;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+
+static void cleanup_ncci_data (PLCI   *plci, word ncci)
+{
+  NCCI   *ncci_ptr;
+
+  if (ncci && (plci->adapter->ncci_plci[ncci] == plci->Id))
+  {
+    ncci_ptr = &(plci->adapter->ncci[ncci]);
+    if (plci->appl)
+    {
+      while (ncci_ptr->data_pending != 0)
+      {
+        if (!plci->data_sent || (ncci_ptr->DBuffer[ncci_ptr->data_out].P != plci->data_sent_ptr))
+          TransmitBufferFree (plci->appl, ncci_ptr->DBuffer[ncci_ptr->data_out].P);
+        (ncci_ptr->data_out)++;
+        if (ncci_ptr->data_out == MAX_DATA_B3)
+          ncci_ptr->data_out = 0;
+        (ncci_ptr->data_pending)--;
+      }
+    }
+    ncci_ptr->data_out = 0;
+    ncci_ptr->data_pending = 0;
+    ncci_ptr->data_ack_out = 0;
+    ncci_ptr->data_ack_pending = 0;
+  }
+}
+
+
+static void ncci_remove (PLCI   *plci, word ncci, byte preserve_ncci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  dword Id;
+  word i;
+
+  a = plci->adapter;
+  Id = (((dword) ncci) << 16) | (((word)(plci->Id)) << 8) | a->Id;
+  if (!preserve_ncci)
+    ncci_free_receive_buffers (plci, ncci);
+  if (ncci)
+  {
+    if (a->ncci_plci[ncci] != plci->Id)
+    {
+      ncci_mapping_bug++;
+      dbug(1,dprintf("NCCI mapping doesn't exist %ld %08lx %02x",
+        ncci_mapping_bug, Id, preserve_ncci));
+    }
+    else
+    {
+      cleanup_ncci_data (plci, ncci);
+      dbug(1,dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
+        ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
+      a->ch_ncci[a->ncci_ch[ncci]] = 0;
+      if (!preserve_ncci)
+      {
+        a->ncci_ch[ncci] = 0;
+        a->ncci_plci[ncci] = 0;
+        a->ncci_state[ncci] = IDLE;
+        i = plci->ncci_ring_list;
+        while ((i != 0) && (a->ncci_next[i] != plci->ncci_ring_list) && (a->ncci_next[i] != ncci))
+          i = a->ncci_next[i];
+        if ((i != 0) && (a->ncci_next[i] == ncci))
+        {
+          if (i == ncci)
+            plci->ncci_ring_list = 0;
+          else if (plci->ncci_ring_list == ncci)
+            plci->ncci_ring_list = i;
+          a->ncci_next[i] = a->ncci_next[ncci];
+        }
+        a->ncci_next[ncci] = 0;
+      }
+    }
+  }
+  else
+  {
+    for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
+    {
+      if (a->ncci_plci[ncci] == plci->Id)
+      {
+        cleanup_ncci_data (plci, ncci);
+        dbug(1,dprintf("NCCI mapping released %ld %08lx %02x %02x-%02x",
+          ncci_mapping_bug, Id, preserve_ncci, a->ncci_ch[ncci], ncci));
+        a->ch_ncci[a->ncci_ch[ncci]] = 0;
+        if (!preserve_ncci)
+        {
+          a->ncci_ch[ncci] = 0;
+          a->ncci_plci[ncci] = 0;
+          a->ncci_state[ncci] = IDLE;
+          a->ncci_next[ncci] = 0;
+        }
+      }
+    }
+    if (!preserve_ncci)
+      plci->ncci_ring_list = 0;
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* PLCI remove function                                             */
+/*------------------------------------------------------------------*/
+
+static void plci_free_msg_in_queue (PLCI   *plci)
+{
+  word i;
+
+  if (plci->appl)
+  {
+    i = plci->msg_in_read_pos;
+    while (i != plci->msg_in_write_pos)
+    {
+      if (i == plci->msg_in_wrap_pos)
+        i = 0;
+      if (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[i]))->header.command == _DATA_B3_R)
+      {
+
+        TransmitBufferFree (plci->appl,
+          (byte   *)(((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[i]))->info.data_b3_req.Data));
+
+      }
+
+      i += (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[i]))->header.length +
+        MSG_IN_OVERHEAD + 3) & 0xfffc;
+
+    }
+  }
+  plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
+  plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
+  plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
+}
+
+
+static void plci_remove(PLCI   * plci)
+{
+
+  if(!plci) {
+    dbug(1,dprintf("plci_remove(no plci)"));
+    return;
+  }
+  init_internal_command_queue (plci);
+  dbug(1,dprintf("plci_remove(%x,tel=%x)",plci->Id,plci->tel));
+  if(plci_remove_check(plci))
+  {
+    return;
+  }
+  if (plci->Sig.Id == 0xff)
+  {
+    dbug(1,dprintf("D-channel X.25 plci->NL.Id:%0x", plci->NL.Id));
+    if (plci->NL.Id && !plci->nl_remove_id)
+    {
+      nl_req_ncci(plci,REMOVE,0);
+      send_req(plci);
+    }
+  }
+  else
+  {
+    if (!plci->sig_remove_id
+     && (plci->Sig.Id
+      || (plci->req_in!=plci->req_out)
+      || (plci->nl_req || plci->sig_req)))
+    {
+      sig_req(plci,HANGUP,0);
+      send_req(plci);
+    }
+  }
+  ncci_remove (plci, 0, FALSE);
+  plci_free_msg_in_queue (plci);
+
+  plci->channels = 0;
+  plci->appl = NULL;
+  if ((plci->State == INC_CON_PENDING) || (plci->State == INC_CON_ALERT))
+    plci->State = OUTG_DIS_PENDING;
+}
+
+/*------------------------------------------------------------------*/
+/* Application Group function helpers                               */
+/*------------------------------------------------------------------*/
+
+static void set_group_ind_mask (PLCI   *plci)
+{
+  word i;
+
+  for (i = 0; i < C_IND_MASK_DWORDS; i++)
+    plci->group_optimization_mask_table[i] = 0xffffffffL;
+}
+
+static void clear_group_ind_mask_bit (PLCI   *plci, word b)
+{
+  plci->group_optimization_mask_table[b >> 5] &= ~(1L << (b & 0x1f));
+}
+
+static byte test_group_ind_mask_bit (PLCI   *plci, word b)
+{
+  return ((plci->group_optimization_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0);
+}
+
+/*------------------------------------------------------------------*/
+/* c_ind_mask operations for arbitrary MAX_APPL                     */
+/*------------------------------------------------------------------*/
+
+static void clear_c_ind_mask (PLCI   *plci)
+{
+  word i;
+
+  for (i = 0; i < C_IND_MASK_DWORDS; i++)
+    plci->c_ind_mask_table[i] = 0;
+}
+
+static byte c_ind_mask_empty (PLCI   *plci)
+{
+  word i;
+
+  i = 0;
+  while ((i < C_IND_MASK_DWORDS) && (plci->c_ind_mask_table[i] == 0))
+    i++;
+  return (i == C_IND_MASK_DWORDS);
+}
+
+static void set_c_ind_mask_bit (PLCI   *plci, word b)
+{
+  plci->c_ind_mask_table[b >> 5] |= (1L << (b & 0x1f));
+}
+
+static void clear_c_ind_mask_bit (PLCI   *plci, word b)
+{
+  plci->c_ind_mask_table[b >> 5] &= ~(1L << (b & 0x1f));
+}
+
+static byte test_c_ind_mask_bit (PLCI   *plci, word b)
+{
+  return ((plci->c_ind_mask_table[b >> 5] & (1L << (b & 0x1f))) != 0);
+}
+
+static void dump_c_ind_mask (PLCI   *plci)
+{
+static char hex_digit_table[0x10] =
+  {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+  word i, j, k;
+  dword d;
+    char *p;
+    char buf[40];
+
+  for (i = 0; i < C_IND_MASK_DWORDS; i += 4)
+  {
+    p = buf + 36;
+    *p = '\0';
+    for (j = 0; j < 4; j++)
+    {
+      if (i+j < C_IND_MASK_DWORDS)
+      {
+        d = plci->c_ind_mask_table[i+j];
+        for (k = 0; k < 8; k++)
+        {
+          *(--p) = hex_digit_table[d & 0xf];
+          d >>= 4;
+        }
+      }
+      else if (i != 0)
+      {
+        for (k = 0; k < 8; k++)
+          *(--p) = ' ';
+      }
+      *(--p) = ' ';
+    }
+    dbug(1,dprintf ("c_ind_mask =%s", (char   *) p));
+  }
+}
+
+
+
+
+
+#define dump_plcis(a)
+
+
+
+/*------------------------------------------------------------------*/
+/* translation function for each message                            */
+/*------------------------------------------------------------------*/
+
+byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ch;
+  word i;
+  word Info;
+  word CIP;
+  byte LinkLayer;
+  API_PARSE * ai;
+  API_PARSE * bp;
+    API_PARSE ai_parms[5];
+  word channel = 0;
+  dword ch_mask;
+  byte m;
+  static byte esc_chi[35] = {0x02,0x18,0x01};
+  static byte lli[2] = {0x01,0x00};
+  byte noCh = 0;
+  word dir = 0;
+  byte   *p_chi = "";
+
+  for(i=0;i<5;i++) ai_parms[i].length = 0;
+
+  dbug(1,dprintf("connect_req(%d)",parms->length));
+  Info = _WRONG_IDENTIFIER;
+  if(a)
+  {
+    if(a->adapter_disabled)
+    {
+      dbug(1,dprintf("adapter disabled"));
+      Id = ((word)1<<8)|a->Id;
+      sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
+      sendf(appl, _DISCONNECT_I, Id, 0, "w", _L1_ERROR);
+      return FALSE;
+    }
+    Info = _OUT_OF_PLCI;
+    if((i=get_plci(a)))
+    {
+      Info = 0;
+      plci = &a->plci[i-1];
+      plci->appl = appl;
+      plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+      /* check 'external controller' bit for codec support */
+      if(Id & EXT_CONTROLLER)
+      {
+        if(AdvCodecSupport(a, plci, appl, 0) )
+        {
+          plci->Id = 0;
+          sendf(appl, _CONNECT_R|CONFIRM, Id, Number, "w", _WRONG_IDENTIFIER);
+          return 2;
+        }
+      }
+      ai = &parms[9];
+      bp = &parms[5];
+      ch = 0;
+      if(bp->length)LinkLayer = bp->info[3];
+      else LinkLayer = 0;
+      if(ai->length)
+      {
+        ch=0xffff;
+        if(!api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
+        {
+          ch = 0;
+          if(ai_parms[0].length)
+          {
+            ch = GET_WORD(ai_parms[0].info+1);
+            if(ch>4) ch=0; /* safety -> ignore ChannelID */
+            if(ch==4) /* explizit CHI in message */
+            {
+              /* check length of B-CH struct */
+              if((ai_parms[0].info)[3]>=1)
+              {
+                if((ai_parms[0].info)[4]==CHI)
+                {
+                  p_chi = &((ai_parms[0].info)[5]);
+                }
+                else
+                {
+                  p_chi = &((ai_parms[0].info)[3]);
+                }
+                if(p_chi[0]>35) /* check length of channel ID */
+                {
+                  Info = _WRONG_MESSAGE_FORMAT;    
+                }
+              }
+              else Info = _WRONG_MESSAGE_FORMAT;    
+            }
+
+            if(ch==3 && ai_parms[0].length>=7 && ai_parms[0].length<=36)
+            {
+              dir = GET_WORD(ai_parms[0].info+3);
+              ch_mask = 0;
+              m = 0x3f;
+              for(i=0; i+5<=ai_parms[0].length; i++)
+              {
+                if(ai_parms[0].info[i+5]!=0)
+                {
+                  if((ai_parms[0].info[i+5] | m) != 0xff)
+                    Info = _WRONG_MESSAGE_FORMAT;
+                  else
+                  {
+                    if (ch_mask == 0)
+                      channel = i;
+                    ch_mask |= 1L << i;
+                  }
+                }
+                m = 0;
+              }
+              if (ch_mask == 0)
+                Info = _WRONG_MESSAGE_FORMAT;
+              if (!Info)
+              {
+                if ((ai_parms[0].length == 36) || (ch_mask != ((dword)(1L << channel))))
+                {
+                  esc_chi[0] = (byte)(ai_parms[0].length - 2);
+                  for(i=0; i+5<=ai_parms[0].length; i++)
+                    esc_chi[i+3] = ai_parms[0].info[i+5];
+                }
+                else
+                  esc_chi[0] = 2;
+                esc_chi[2] = (byte)channel;
+                plci->b_channel = (byte)channel; /* not correct for ETSI ch 17..31 */
+                add_p(plci,LLI,lli);
+                add_p(plci,ESC,esc_chi);
+                plci->State = LOCAL_CONNECT;
+                if(!dir) plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;     /* dir 0=DTE, 1=DCE */
+              }
+            }
+          }
+        }
+        else  Info = _WRONG_MESSAGE_FORMAT;
+      }
+
+      dbug(1,dprintf("ch=%x,dir=%x,p_ch=%d",ch,dir,channel));
+      plci->command = _CONNECT_R;
+      plci->number = Number;
+      /* x.31 or D-ch free SAPI in LinkLayer? */
+      if(ch==1 && LinkLayer!=3 && LinkLayer!=12) noCh = TRUE;
+      if((ch==0 || ch==2 || noCh || ch==3 || ch==4) && !Info)
+      {
+        /* B-channel used for B3 connections (ch==0), or no B channel    */
+        /* is used (ch==2) or perm. connection (3) is used  do a CALL    */
+        if(noCh) Info = add_b1(plci,&parms[5],2,0);    /* no resource    */
+        else     Info = add_b1(plci,&parms[5],ch,0); 
+        add_s(plci,OAD,&parms[2]);
+        add_s(plci,OSA,&parms[4]);
+        add_s(plci,BC,&parms[6]);
+        add_s(plci,LLC,&parms[7]);
+        add_s(plci,HLC,&parms[8]);
+        CIP = GET_WORD(parms[0].info);
+        if (a->Info_Mask[appl->Id-1] & 0x200)
+        {
+          /* early B3 connect (CIP mask bit 9) no release after a disc */
+          add_p(plci,LLI,"\x01\x01");
+        }
+        if(GET_WORD(parms[0].info)<29) {
+          add_p(plci,BC,cip_bc[GET_WORD(parms[0].info)][a->u_law]);
+          add_p(plci,HLC,cip_hlc[GET_WORD(parms[0].info)]);
+        }
+        add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+        sig_req(plci,ASSIGN,DSIG_ID);
+      }
+      else if(ch==1) {
+
+        /* D-Channel used for B3 connections */
+        plci->Sig.Id = 0xff;
+        Info = 0;
+      }
+
+      if(!Info && ch!=2 && !noCh ) {
+        Info = add_b23(plci,&parms[5]);
+        if(!Info) {
+          if(!(plci->tel && !plci->adv_nl))nl_req_ncci(plci,ASSIGN,0);
+        }
+      }
+
+      if(!Info)
+      {
+        if(ch==0 || ch==2 || ch==3 || noCh || ch==4)
+        {
+          if(plci->spoofed_msg==SPOOFING_REQUIRED)
+          {
+            api_save_msg(parms, "wsssssssss", &plci->saved_msg);
+            plci->spoofed_msg = CALL_REQ;
+            plci->internal_command = BLOCK_PLCI;
+            plci->command = 0;
+            dbug(1,dprintf("Spoof"));
+            send_req(plci);
+            return FALSE;
+          }
+          if(ch==4)add_p(plci,CHI,p_chi);
+          add_s(plci,CPN,&parms[1]);
+          add_s(plci,DSA,&parms[3]);
+          if(noCh) add_p(plci,ESC,"\x02\x18\xfd");  /* D-channel, no B-L3 */
+          add_ai(plci,&parms[9]);
+          if(!dir)sig_req(plci,CALL_REQ,0);
+          else
+          {
+            plci->command = PERM_LIST_REQ;
+            plci->appl = appl;
+            sig_req(plci,LISTEN_REQ,0);
+            send_req(plci);
+            return FALSE;
+          }
+        }
+        send_req(plci);
+        return FALSE;
+      }
+      plci->Id = 0;
+    }
+  }
+  sendf(appl,
+        _CONNECT_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return 2;
+}
+
+byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word i, Info;
+  word Reject;
+  static byte cau_t[] = {0,0,0x90,0x91,0xac,0x9d,0x86,0xd8,0x9b};
+  static byte esc_t[] = {0x03,0x08,0x00,0x00};
+  API_PARSE * ai;
+    API_PARSE ai_parms[5];
+  word ch=0;
+
+  if(!plci) {
+    dbug(1,dprintf("connect_res(no plci)"));
+    return 0;  /* no plci, no send */
+  }
+
+  dbug(1,dprintf("connect_res(State=0x%x)",plci->State));
+  for(i=0;i<5;i++) ai_parms[i].length = 0;
+  ai = &parms[5];
+  dbug(1,dprintf("ai->length=%d",ai->length));
+
+  if(ai->length)
+  {
+    if(!api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
+    {
+      dbug(1,dprintf("ai_parms[0].length=%d/0x%x",ai_parms[0].length,GET_WORD(ai_parms[0].info+1)));
+      ch = 0;
+      if(ai_parms[0].length)
+      {
+        ch = GET_WORD(ai_parms[0].info+1);
+        dbug(1,dprintf("BCH-I=0x%x",ch));
+      }
+    }
+  }
+
+  if(plci->State==INC_CON_CONNECTED_ALERT)
+  {
+    dbug(1,dprintf("Connected Alert Call_Res"));
+    if (a->Info_Mask[appl->Id-1] & 0x200)
+    {
+    /* early B3 connect (CIP mask bit 9) no release after a disc */
+      add_p(plci,LLI,"\x01\x01");
+    }
+    add_s(plci, CONN_NR, &parms[2]);
+    add_s(plci, LLC, &parms[4]);
+    add_ai(plci, &parms[5]);
+    plci->State = INC_CON_ACCEPT;
+    sig_req(plci, CALL_RES,0);
+    return 1;
+  }
+  else if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT) {
+    clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
+    dump_c_ind_mask (plci);
+    Reject = GET_WORD(parms[0].info);
+    dbug(1,dprintf("Reject=0x%x",Reject));
+    if(Reject) 
+    {
+      if(c_ind_mask_empty (plci)) 
+      {
+        if((Reject&0xff00)==0x3400) 
+        {
+          esc_t[2] = ((byte)(Reject&0x00ff)) | 0x80;
+          add_p(plci,ESC,esc_t);
+          add_ai(plci, &parms[5]);
+          sig_req(plci,REJECT,0);
+        }      
+        else if(Reject==1 || Reject>9) 
+        {
+          add_ai(plci, &parms[5]);
+          sig_req(plci,HANGUP,0);
+        }
+        else 
+        {
+          esc_t[2] = cau_t[(Reject&0x000f)];
+          add_p(plci,ESC,esc_t);
+          add_ai(plci, &parms[5]);
+          sig_req(plci,REJECT,0);
+        }
+        plci->appl = appl;
+      }
+      else 
+      {
+        sendf(appl, _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
+      }
+    }
+    else {
+      plci->appl = appl;
+      if(Id & EXT_CONTROLLER){
+        if(AdvCodecSupport(a, plci, appl, 0)){
+          dbug(1,dprintf("connect_res(error from AdvCodecSupport)"));
+          sig_req(plci,HANGUP,0);
+          return 1;
+        }
+        if(plci->tel == ADV_VOICE && a->AdvCodecPLCI)
+        {
+          Info = add_b23(plci, &parms[1]);
+          if (Info)
+          {
+            dbug(1,dprintf("connect_res(error from add_b23)"));
+            sig_req(plci,HANGUP,0);
+            return 1;
+          }
+          if(plci->adv_nl)
+          {
+            nl_req_ncci(plci, ASSIGN, 0);
+          }
+        }
+      }
+      else
+      {
+        plci->tel = 0;
+        if(ch!=2)
+        {
+          Info = add_b23(plci, &parms[1]);
+          if (Info)
+          {
+            dbug(1,dprintf("connect_res(error from add_b23 2)"));
+            sig_req(plci,HANGUP,0);
+            return 1;
+          }
+        }
+        nl_req_ncci(plci, ASSIGN, 0);
+      }
+
+      if(plci->spoofed_msg==SPOOFING_REQUIRED)
+      {
+        api_save_msg(parms, "wsssss", &plci->saved_msg);
+        plci->spoofed_msg = CALL_RES;
+        plci->internal_command = BLOCK_PLCI;
+        plci->command = 0;
+        dbug(1,dprintf("Spoof"));
+      }
+      else
+      {
+        add_b1 (plci, &parms[1], ch, plci->B1_facilities);
+        if (a->Info_Mask[appl->Id-1] & 0x200)
+        {
+          /* early B3 connect (CIP mask bit 9) no release after a disc */
+          add_p(plci,LLI,"\x01\x01");
+        }
+        add_s(plci, CONN_NR, &parms[2]);
+        add_s(plci, LLC, &parms[4]);
+        add_ai(plci, &parms[5]);
+        plci->State = INC_CON_ACCEPT;
+        sig_req(plci, CALL_RES,0);
+      }
+
+      for(i=0; i<max_appl; i++) {
+        if(test_c_ind_mask_bit (plci, i)) {
+          sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
+        }
+      }
+    }
+  }
+  return 1;
+}
+
+byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  dbug(1,dprintf("connect_a_res"));
+  return FALSE;
+}
+
+byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word Info;
+  word i;
+
+  dbug(1,dprintf("disconnect_req"));
+
+  Info = _WRONG_IDENTIFIER;
+
+  if(plci)
+  {
+    if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT)
+    {
+      clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
+      plci->appl = appl;
+      for(i=0; i<max_appl; i++)
+      {
+        if(test_c_ind_mask_bit (plci, i))
+          sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0);
+      }
+      plci->State = OUTG_DIS_PENDING;
+    }
+    if(plci->Sig.Id && plci->appl)
+    {
+      Info = 0;
+        if(plci->Sig.Id!=0xff)
+        {
+          if(plci->State!=INC_DIS_PENDING)
+          {
+            add_ai(plci, &msg[0]);
+            sig_req(plci,HANGUP,0);
+            plci->State = OUTG_DIS_PENDING;
+            return 1;
+          }
+        }
+        else
+        {
+          if (plci->NL.Id && !plci->nl_remove_id)
+          {
+            mixer_remove (plci);
+            nl_req_ncci(plci,REMOVE,0);
+          sendf(appl,_DISCONNECT_R|CONFIRM,Id,Number,"w",0);
+          sendf(appl, _DISCONNECT_I, Id, 0, "w", 0);
+          plci->State = INC_DIS_PENDING;
+          }
+          return 1;
+        }
+      }
+    }
+
+  if(!appl)  return FALSE;
+  sendf(appl, _DISCONNECT_R|CONFIRM, Id, Number, "w",Info);
+  return FALSE;
+}
+
+byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  dbug(1,dprintf("disconnect_res"));
+  if(plci)
+  {
+        /* clear ind mask bit, just in case of collsion of          */
+        /* DISCONNECT_IND and CONNECT_RES                           */
+    clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
+    ncci_free_receive_buffers (plci, 0);
+    if(plci_remove_check(plci))
+    {
+      return 0;
+    }
+    if(plci->State==INC_DIS_PENDING
+    || plci->State==SUSPENDING) {
+      if(c_ind_mask_empty (plci)) {
+        if(plci->State!=SUSPENDING)plci->State = IDLE;
+        dbug(1,dprintf("chs=%d",plci->channels));
+        if(!plci->channels) {
+          plci_remove(plci);
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word Info;
+  byte i;
+
+  dbug(1,dprintf("listen_req(Appl=0x%x)",appl->Id));
+
+  Info = _WRONG_IDENTIFIER;
+  if(a) {
+    Info = 0;
+    a->Info_Mask[appl->Id-1] = GET_DWORD(parms[0].info);
+    a->CIP_Mask[appl->Id-1] = GET_DWORD(parms[1].info);
+    dbug(1,dprintf("CIP_MASK=0x%lx",GET_DWORD(parms[1].info)));
+    if (a->Info_Mask[appl->Id-1] & 0x200){ /* early B3 connect provides */
+      a->Info_Mask[appl->Id-1] |=  0x10;   /* call progression infos    */
+    }
+
+    /* check if external controller listen and switch listen on or off*/
+    if(Id&EXT_CONTROLLER && GET_DWORD(parms[1].info)){
+      if(a->profile.Global_Options & ON_BOARD_CODEC) {
+        dummy_plci.State = IDLE;
+        a->codec_listen[appl->Id-1] = &dummy_plci;
+        a->TelOAD[0] = (byte)(parms[3].length);
+        for(i=1;parms[3].length>=i && i<22;i++) {
+          a->TelOAD[i] = parms[3].info[i];
+        }
+        a->TelOAD[i] = 0;
+        a->TelOSA[0] = (byte)(parms[4].length);
+        for(i=1;parms[4].length>=i && i<22;i++) {
+          a->TelOSA[i] = parms[4].info[i];
+        }
+        a->TelOSA[i] = 0;
+      }
+      else Info = 0x2002; /* wrong controller, codec not supported */
+    }
+    else{               /* clear listen */
+      a->codec_listen[appl->Id-1] = (PLCI   *)0;
+    }
+  }
+  sendf(appl,
+        _LISTEN_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+
+  if (a) listen_check(a);
+  return FALSE;
+}
+
+byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word i;
+  API_PARSE * ai;
+  PLCI   * rc_plci = NULL;
+    API_PARSE ai_parms[5];
+  word Info = 0;
+
+  dbug(1,dprintf("info_req"));
+  for(i=0;i<5;i++) ai_parms[i].length = 0;
+
+  ai = &msg[1];
+
+  if(ai->length)
+  {
+    if(api_parse(&ai->info[1],(word)ai->length,"ssss",ai_parms))
+    {
+      dbug(1,dprintf("AddInfo wrong"));
+      Info = _WRONG_MESSAGE_FORMAT;
+    }
+  }
+  if(!a) Info = _WRONG_STATE;
+
+  if(!Info && plci)
+  {                /* no fac, with CPN, or KEY */
+    rc_plci = plci;
+    if(!ai_parms[3].length && plci->State && (msg[0].length || ai_parms[1].length) )
+    {
+      /* overlap sending option */
+      dbug(1,dprintf("OvlSnd"));
+      add_s(plci,CPN,&msg[0]);
+      add_s(plci,KEY,&ai_parms[1]);
+      sig_req(plci,INFO_REQ,0);
+      send_req(plci);
+      return FALSE;
+    }
+
+    if(plci->State && ai_parms[2].length)
+    {
+      /* User_Info option */
+      dbug(1,dprintf("UUI"));
+      add_s(plci,UUI,&ai_parms[2]);
+      sig_req(plci,USER_DATA,0);
+    }
+    else if(plci->State && ai_parms[3].length)
+    {
+      /* Facility option */
+      dbug(1,dprintf("FAC"));
+      add_s(plci,CPN,&msg[0]);
+      add_ai(plci, &msg[1]);
+      sig_req(plci,FACILITY_REQ,0);
+    }
+    else
+    {
+      Info = _WRONG_STATE;
+    }
+  }
+  else if((ai_parms[1].length || ai_parms[2].length || ai_parms[3].length) && !Info)
+  {
+    /* NCR_Facility option -> send UUI and Keypad too */
+    dbug(1,dprintf("NCR_FAC"));
+    if((i=get_plci(a)))
+    {
+      rc_plci = &a->plci[i-1];
+      appl->NullCREnable  = TRUE;
+      rc_plci->internal_command = C_NCR_FAC_REQ;
+      rc_plci->appl = appl;
+      add_p(rc_plci,CAI,"\x01\x80");
+      add_p(rc_plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+      sig_req(rc_plci,ASSIGN,DSIG_ID);
+      send_req(rc_plci);
+    }
+    else
+    {
+      Info = _OUT_OF_PLCI;
+    }
+
+    if(!Info)
+    {
+      add_s(rc_plci,CPN,&msg[0]);
+      add_ai(rc_plci, &msg[1]);
+      sig_req(rc_plci,NCR_FACILITY,0);
+      send_req(rc_plci);
+      return FALSE;
+     /* for application controlled supplementary services    */
+    }
+  }
+
+  if (!rc_plci)
+  {
+    Info = _WRONG_MESSAGE_FORMAT;
+  }
+
+  if(!Info)
+  {
+    send_req(rc_plci);
+  }
+  else
+  {  /* appl is not assigned to a PLCI or error condition */
+    dbug(1,dprintf("localInfoCon"));
+    sendf(appl,
+          _INFO_R|CONFIRM,
+          Id,
+          Number,
+          "w",Info);
+  }
+  return FALSE;
+}
+
+byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  dbug(1,dprintf("info_res"));
+  return FALSE;
+}
+
+byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word Info;
+  byte ret;
+
+  dbug(1,dprintf("alert_req"));
+
+  Info = _WRONG_IDENTIFIER;
+  ret = FALSE;
+  if(plci) {
+    Info = _ALERT_IGNORED;
+    if(plci->State!=INC_CON_ALERT) {
+      Info = _WRONG_STATE;
+      if(plci->State==INC_CON_PENDING) {
+        Info = 0;
+        plci->State=INC_CON_ALERT;
+        add_ai(plci, &msg[0]);
+        sig_req(plci,CALL_ALERT,0);
+        ret = 1;
+      }
+    }
+  }
+  sendf(appl,
+        _ALERT_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return ret;
+}
+
+byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word Info = 0;
+  word i    = 0;
+
+  word selector;
+  word SSreq;
+  long relatedPLCIvalue;
+  DIVA_CAPI_ADAPTER   * relatedadapter;
+  byte * SSparms  = "";
+    byte RCparms[]  = "\x05\x00\x00\x02\x00\x00";
+    byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00";
+  API_PARSE * parms;
+    API_PARSE ss_parms[11];
+  PLCI   *rplci;
+    byte cai[15];
+  dword d;
+    API_PARSE dummy;
+
+  dbug(1,dprintf("facility_req"));
+  for(i=0;i<9;i++) ss_parms[i].length = 0;
+
+  parms = &msg[1];
+
+  if(!a)
+  {
+    dbug(1,dprintf("wrong Ctrl"));
+    Info = _WRONG_IDENTIFIER;
+  }
+
+  selector = GET_WORD(msg[0].info);
+
+  if(!Info)
+  {
+    switch(selector)
+    {
+      case SELECTOR_HANDSET:
+        Info = AdvCodecSupport(a, plci, appl, HOOK_SUPPORT);
+        break;
+
+      case SELECTOR_SU_SERV:
+        if(!msg[1].length)
+        {
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        SSreq = GET_WORD(&(msg[1].info[1]));
+        PUT_WORD(&RCparms[1],SSreq);
+        SSparms = RCparms;
+        switch(SSreq)
+        {
+          case S_GET_SUPPORTED_SERVICES:
+            if((i=get_plci(a)))
+            {
+              rplci = &a->plci[i-1];
+              rplci->appl = appl;
+              add_p(rplci,CAI,"\x01\x80");
+              add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+              sig_req(rplci,ASSIGN,DSIG_ID);
+              send_req(rplci);
+            }
+            else
+            {
+              PUT_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY);
+              SSparms = (byte *)SSstruct;
+              break;
+            }
+            rplci->internal_command = GETSERV_REQ_PEND;
+            rplci->number = Number;
+            rplci->appl = appl;
+            sig_req(rplci,S_SUPPORTED,0);
+            send_req(rplci);
+            return FALSE;
+            break;
+
+          case S_LISTEN:
+            if(parms->length==7)
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            else
+            {
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            a->Notification_Mask[appl->Id-1] = GET_DWORD(ss_parms[2].info);
+            if(a->Notification_Mask[appl->Id-1] & SMASK_MWI) /* MWI active? */
+            {
+              if((i=get_plci(a)))
+              {
+                rplci = &a->plci[i-1];
+                rplci->appl = appl;
+                add_p(rplci,CAI,"\x01\x80");
+                add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+                sig_req(rplci,ASSIGN,DSIG_ID);
+                send_req(rplci);
+              }
+              else
+              {
+                break;
+              }
+              rplci->internal_command = GET_MWI_STATE;
+              rplci->number = Number;
+              sig_req(rplci,MWI_POLL,0);
+              send_req(rplci);
+            }
+            break;
+
+          case S_HOLD:
+            api_parse(&parms->info[1],(word)parms->length,"ws",ss_parms);
+            if(plci && plci->State && plci->SuppState==IDLE)
+            {
+              plci->SuppState = HOLD_REQUEST;
+              plci->command = C_HOLD_REQ;
+              add_s(plci,CAI,&ss_parms[1]);
+              sig_req(plci,CALL_HOLD,0);
+              send_req(plci);
+              return FALSE;
+            }
+            else Info = 0x3010;                    /* wrong state           */
+            break;
+          case S_RETRIEVE:
+            if(plci && plci->State && plci->SuppState==CALL_HELD)
+            {
+              if(Id & EXT_CONTROLLER)
+              {
+                if(AdvCodecSupport(a, plci, appl, 0))
+                {
+                  Info = 0x3010;                    /* wrong state           */
+                  break;
+                }
+              }
+              else plci->tel = 0;
+
+              plci->SuppState = RETRIEVE_REQUEST;
+              plci->command = C_RETRIEVE_REQ;
+              if(plci->spoofed_msg==SPOOFING_REQUIRED)
+              {
+                plci->spoofed_msg = CALL_RETRIEVE;
+                plci->internal_command = BLOCK_PLCI;
+                plci->command = 0;
+                dbug(1,dprintf("Spoof"));
+                return FALSE;
+              }
+              else
+              {
+                sig_req(plci,CALL_RETRIEVE,0);
+                send_req(plci);
+                return FALSE;
+              }
+            }
+            else Info = 0x3010;                    /* wrong state           */
+            break;
+          case S_SUSPEND:
+            if(parms->length)
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbs",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            if(plci && plci->State)
+            {
+              add_s(plci,CAI,&ss_parms[2]);
+              plci->command = SUSPEND_REQ;
+              sig_req(plci,SUSPEND,0);
+              plci->State = SUSPENDING;
+              send_req(plci);
+            }
+            else Info = 0x3010;                    /* wrong state           */
+            break;
+
+          case S_RESUME:
+            if(!(i=get_plci(a)) )
+            {
+              Info = _OUT_OF_PLCI;
+              break;
+            }
+            rplci = &a->plci[i-1];
+            rplci->appl = appl;
+            rplci->number = Number;
+            rplci->tel = 0;
+            rplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+            /* check 'external controller' bit for codec support */
+            if(Id & EXT_CONTROLLER)
+            {
+              if(AdvCodecSupport(a, rplci, appl, 0) )
+              {
+                rplci->Id = 0;
+                Info = 0x300A;
+                break;
+              }
+            }
+            if(parms->length)
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbs",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                rplci->Id = 0;
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            dummy.length = 0;
+            dummy.info = "\x00";
+            add_b1(rplci, &dummy, 0, 0);
+            if (a->Info_Mask[appl->Id-1] & 0x200)
+            {
+              /* early B3 connect (CIP mask bit 9) no release after a disc */
+              add_p(rplci,LLI,"\x01\x01");
+            }
+            add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+            sig_req(rplci,ASSIGN,DSIG_ID);
+            send_req(rplci);
+            add_s(rplci,CAI,&ss_parms[2]);
+            rplci->command = RESUME_REQ;
+            sig_req(rplci,RESUME,0);
+            rplci->State = RESUMING;
+            send_req(rplci);
+            break;
+
+          case S_CONF_BEGIN: /* Request */
+          case S_CONF_DROP:
+          case S_CONF_ISOLATE:
+          case S_CONF_REATTACH:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if(plci && plci->State && ((plci->SuppState==IDLE)||(plci->SuppState==CALL_HELD)))
+            {
+              d = GET_DWORD(ss_parms[2].info);     
+              if(d>=0x80)
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+              plci->ptyState = (byte)SSreq;
+              plci->command = 0;
+              cai[0] = 2;
+              switch(SSreq)
+              {
+              case S_CONF_BEGIN:
+                  cai[1] = CONF_BEGIN;
+                  plci->internal_command = CONF_BEGIN_REQ_PEND;
+                  break;
+              case S_CONF_DROP:
+                  cai[1] = CONF_DROP;
+                  plci->internal_command = CONF_DROP_REQ_PEND;
+                  break;
+              case S_CONF_ISOLATE:
+                  cai[1] = CONF_ISOLATE;
+                  plci->internal_command = CONF_ISOLATE_REQ_PEND;
+                  break;
+              case S_CONF_REATTACH:
+                  cai[1] = CONF_REATTACH;
+                  plci->internal_command = CONF_REATTACH_REQ_PEND;
+                  break;
+              }
+              cai[2] = (byte)d; /* Conference Size resp. PartyId */
+              add_p(plci,CAI,cai);
+              sig_req(plci,S_SERVICE,0);
+              send_req(plci);
+              return FALSE;
+            }
+            else Info = 0x3010;                    /* wrong state           */
+            break;
+
+          case S_ECT:
+          case S_3PTY_BEGIN:
+          case S_3PTY_END:
+          case S_CONF_ADD:
+            if(parms->length==7)
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            else if(parms->length==8) /* workaround for the T-View-S */
+            {
+              if(api_parse(&parms->info[1],(word)parms->length,"wbdb",ss_parms))
+              {
+                dbug(1,dprintf("format wrong"));
+                Info = _WRONG_MESSAGE_FORMAT;
+                break;
+              }
+            }
+            else
+            {
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if(!msg[1].length)
+            {
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if (!plci)
+            {
+              Info = _WRONG_IDENTIFIER;
+              break;
+            }
+            relatedPLCIvalue = GET_DWORD(ss_parms[2].info);
+            relatedPLCIvalue &= 0x0000FFFF;
+            dbug(1,dprintf("PTY/ECT/addCONF,relPLCI=%lx",relatedPLCIvalue));
+            /* controller starts with 0 up to (max_adapter - 1) */
+            if (((relatedPLCIvalue & 0x7f) == 0)
+             || (MapController ((byte)(relatedPLCIvalue & 0x7f)) == 0)
+             || (MapController ((byte)(relatedPLCIvalue & 0x7f)) > max_adapter))
+            {
+              if(SSreq==S_3PTY_END)
+              {
+                dbug(1, dprintf("wrong Controller use 2nd PLCI=PLCI"));
+                rplci = plci;
+              }
+              else
+              {
+                Info = 0x3010;                    /* wrong state           */
+                break;
+              }
+            }
+            else
+            {  
+              relatedadapter = &adapter[MapController ((byte)(relatedPLCIvalue & 0x7f))-1];
+              relatedPLCIvalue >>=8;
+              /* find PLCI PTR*/
+              for(i=0,rplci=NULL;i<relatedadapter->max_plci;i++)
+              {
+                if(relatedadapter->plci[i].Id == (byte)relatedPLCIvalue)
+                {
+                  rplci = &relatedadapter->plci[i];
+                }
+              }
+              if(!rplci || !relatedPLCIvalue)
+              {
+                if(SSreq==S_3PTY_END)
+                {
+                  dbug(1, dprintf("use 2nd PLCI=PLCI"));
+                  rplci = plci;
+                }
+                else
+                {
+                  Info = 0x3010;                    /* wrong state           */
+                  break;
+                }
+              }
+            }
+/*
+            dbug(1,dprintf("rplci:%x",rplci));
+            dbug(1,dprintf("plci:%x",plci));
+            dbug(1,dprintf("rplci->ptyState:%x",rplci->ptyState));
+            dbug(1,dprintf("plci->ptyState:%x",plci->ptyState));
+            dbug(1,dprintf("SSreq:%x",SSreq));
+            dbug(1,dprintf("rplci->internal_command:%x",rplci->internal_command));
+            dbug(1,dprintf("rplci->appl:%x",rplci->appl));
+            dbug(1,dprintf("rplci->Id:%x",rplci->Id));
+*/
+            /* send PTY/ECT req, cannot check all states because of US stuff */
+            if( !rplci->internal_command && rplci->appl )
+            {
+              plci->command = 0;
+              rplci->relatedPTYPLCI = plci;
+              plci->relatedPTYPLCI = rplci;
+              rplci->ptyState = (byte)SSreq;
+              if(SSreq==S_ECT)
+              {
+                rplci->internal_command = ECT_REQ_PEND;
+                cai[1] = ECT_EXECUTE;
+
+                rplci->vswitchstate=0;
+                rplci->vsprot=0;
+                rplci->vsprotdialect=0;
+                plci->vswitchstate=0;
+                plci->vsprot=0;
+                plci->vsprotdialect=0;
+
+              }
+              else if(SSreq==S_CONF_ADD)
+              {
+                rplci->internal_command = CONF_ADD_REQ_PEND;
+                cai[1] = CONF_ADD;
+              }
+              else
+              {
+                rplci->internal_command = PTY_REQ_PEND;
+                cai[1] = (byte)(SSreq-3);
+              }
+              rplci->number = Number;
+              if(plci!=rplci) /* explicit invocation */
+              {
+                cai[0] = 2;
+                cai[2] = plci->Sig.Id;
+                dbug(1,dprintf("explicit invocation"));
+              }
+              else
+              {
+                dbug(1,dprintf("implicit invocation"));
+                cai[0] = 1;
+              }
+              add_p(rplci,CAI,cai);
+              sig_req(rplci,S_SERVICE,0);
+              send_req(rplci);
+              return FALSE;
+            }
+            else
+            {
+              dbug(0,dprintf("Wrong line"));
+              Info = 0x3010;                    /* wrong state           */
+              break;
+            }
+            break;
+
+          case S_CALL_DEFLECTION:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbwss",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if (!plci)
+            {
+              Info = _WRONG_IDENTIFIER;
+              break;
+            }
+            /* reuse unused screening indicator */
+            ss_parms[3].info[3] = (byte)GET_WORD(&(ss_parms[2].info[0]));
+            plci->command = 0;
+            plci->internal_command = CD_REQ_PEND;
+            appl->CDEnable = TRUE;
+            cai[0] = 1;
+            cai[1] = CALL_DEFLECTION;
+            add_p(plci,CAI,cai);
+            add_p(plci,CPN,ss_parms[3].info);
+            sig_req(plci,S_SERVICE,0);
+            send_req(plci);
+            return FALSE;
+            break;
+
+          case S_CALL_FORWARDING_START:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbdwwsss",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+
+            if((i=get_plci(a)))
+            {
+              rplci = &a->plci[i-1];
+              rplci->appl = appl;
+              add_p(rplci,CAI,"\x01\x80");
+              add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+              sig_req(rplci,ASSIGN,DSIG_ID);
+              send_req(rplci);
+            }
+            else
+            {
+              Info = _OUT_OF_PLCI;
+              break;
+            }
+
+            /* reuse unused screening indicator */
+            rplci->internal_command = CF_START_PEND;
+            rplci->appl = appl;
+            rplci->number = Number;
+            appl->S_Handle = GET_DWORD(&(ss_parms[2].info[0]));
+            cai[0] = 2;
+            cai[1] = 0x70|(byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
+            cai[2] = (byte)GET_WORD(&(ss_parms[4].info[0])); /* Basic Service */
+            add_p(rplci,CAI,cai);
+            add_p(rplci,OAD,ss_parms[5].info);
+            add_p(rplci,CPN,ss_parms[6].info);
+            sig_req(rplci,S_SERVICE,0);
+            send_req(rplci);
+            return FALSE;
+            break;
+
+          case S_INTERROGATE_DIVERSION:
+          case S_INTERROGATE_NUMBERS:
+          case S_CALL_FORWARDING_STOP:
+          case S_CCBS_REQUEST:
+          case S_CCBS_DEACTIVATE:
+          case S_CCBS_INTERROGATE:
+            switch(SSreq)
+            {
+            case S_INTERROGATE_NUMBERS:
+                if(api_parse(&parms->info[1],(word)parms->length,"wbd",ss_parms))
+                {
+                  dbug(0,dprintf("format wrong"));
+                  Info = _WRONG_MESSAGE_FORMAT;
+                }
+                break;
+            case S_CCBS_REQUEST:
+            case S_CCBS_DEACTIVATE:
+                if(api_parse(&parms->info[1],(word)parms->length,"wbdw",ss_parms))
+                {
+                  dbug(0,dprintf("format wrong"));
+                  Info = _WRONG_MESSAGE_FORMAT;
+                }
+                break;
+            case S_CCBS_INTERROGATE:
+                if(api_parse(&parms->info[1],(word)parms->length,"wbdws",ss_parms))
+                {
+                  dbug(0,dprintf("format wrong"));
+                  Info = _WRONG_MESSAGE_FORMAT;
+                }
+                break;
+            default:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbdwws",ss_parms))
+            {
+              dbug(0,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+                break;
+            }
+
+            if(Info) break;
+            if((i=get_plci(a)))
+            {
+              rplci = &a->plci[i-1];
+              switch(SSreq)
+              {
+                case S_INTERROGATE_DIVERSION: /* use cai with S_SERVICE below */
+                  cai[1] = 0x60|(byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
+                  rplci->internal_command = INTERR_DIVERSION_REQ_PEND; /* move to rplci if assigned */
+                  break;
+                case S_INTERROGATE_NUMBERS: /* use cai with S_SERVICE below */
+                  cai[1] = DIVERSION_INTERROGATE_NUM; /* Function */
+                  rplci->internal_command = INTERR_NUMBERS_REQ_PEND; /* move to rplci if assigned */
+                  break;
+                case S_CALL_FORWARDING_STOP:
+                  rplci->internal_command = CF_STOP_PEND;
+                  cai[1] = 0x80|(byte)GET_WORD(&(ss_parms[3].info[0])); /* Function */
+                  break;
+                case S_CCBS_REQUEST:
+                  cai[1] = CCBS_REQUEST;
+                  rplci->internal_command = CCBS_REQUEST_REQ_PEND;
+                  break;
+                case S_CCBS_DEACTIVATE:
+                  cai[1] = CCBS_DEACTIVATE;
+                  rplci->internal_command = CCBS_DEACTIVATE_REQ_PEND;
+                  break;
+                case S_CCBS_INTERROGATE:
+                  cai[1] = CCBS_INTERROGATE;
+                  rplci->internal_command = CCBS_INTERROGATE_REQ_PEND;
+                  break;
+                default:
+                  cai[1] = 0;
+                break;
+              }
+              rplci->appl = appl;
+              rplci->number = Number;
+              add_p(rplci,CAI,"\x01\x80");
+              add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+              sig_req(rplci,ASSIGN,DSIG_ID);
+              send_req(rplci);
+            }
+            else
+            {
+              Info = _OUT_OF_PLCI;
+              break;
+            }
+
+            appl->S_Handle = GET_DWORD(&(ss_parms[2].info[0]));
+            switch(SSreq)
+            {
+            case S_INTERROGATE_NUMBERS:
+                cai[0] = 1;
+                add_p(rplci,CAI,cai);
+                break;
+            case S_CCBS_REQUEST:
+            case S_CCBS_DEACTIVATE:
+                cai[0] = 3;
+                PUT_WORD(&cai[2],GET_WORD(&(ss_parms[3].info[0])));
+                add_p(rplci,CAI,cai);
+                break;
+            case S_CCBS_INTERROGATE:
+                cai[0] = 3;
+                PUT_WORD(&cai[2],GET_WORD(&(ss_parms[3].info[0])));
+                add_p(rplci,CAI,cai);
+                add_p(rplci,OAD,ss_parms[4].info);
+                break;
+            default:
+            cai[0] = 2;
+            cai[2] = (byte)GET_WORD(&(ss_parms[4].info[0])); /* Basic Service */
+            add_p(rplci,CAI,cai);
+            add_p(rplci,OAD,ss_parms[5].info);
+                break;
+            }
+                        
+            sig_req(rplci,S_SERVICE,0);
+            send_req(rplci);
+            return FALSE;
+            break;
+
+          case S_MWI_ACTIVATE:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbwdwwwssss",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if(!plci)
+            {                               
+              if((i=get_plci(a)))
+              {
+                rplci = &a->plci[i-1];
+                rplci->appl = appl;
+                rplci->cr_enquiry=TRUE;
+                add_p(rplci,CAI,"\x01\x80");
+                add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+                sig_req(rplci,ASSIGN,DSIG_ID);
+                send_req(rplci);
+              }
+              else
+              {
+                Info = _OUT_OF_PLCI;
+                break;
+              }
+            }
+            else
+            {
+              rplci = plci;
+              rplci->cr_enquiry=FALSE;
+            }
+
+            rplci->command = 0;
+            rplci->internal_command = MWI_ACTIVATE_REQ_PEND;
+            rplci->appl = appl;
+            rplci->number = Number;
+
+            cai[0] = 13;
+            cai[1] = ACTIVATION_MWI; /* Function */
+            PUT_WORD(&cai[2],GET_WORD(&(ss_parms[2].info[0]))); /* Basic Service */
+            PUT_DWORD(&cai[4],GET_DWORD(&(ss_parms[3].info[0]))); /* Number of Messages */
+            PUT_WORD(&cai[8],GET_WORD(&(ss_parms[4].info[0]))); /* Message Status */
+            PUT_WORD(&cai[10],GET_WORD(&(ss_parms[5].info[0]))); /* Message Reference */
+            PUT_WORD(&cai[12],GET_WORD(&(ss_parms[6].info[0]))); /* Invocation Mode */
+            add_p(rplci,CAI,cai);
+            add_p(rplci,CPN,ss_parms[7].info); /* Receiving User Number */
+            add_p(rplci,OAD,ss_parms[8].info); /* Controlling User Number */
+            add_p(rplci,OSA,ss_parms[9].info); /* Controlling User Provided Number */
+            add_p(rplci,UID,ss_parms[10].info); /* Time */
+            sig_req(rplci,S_SERVICE,0);
+            send_req(rplci);
+            return FALSE;
+
+          case S_MWI_DEACTIVATE:
+            if(api_parse(&parms->info[1],(word)parms->length,"wbwwss",ss_parms))
+            {
+              dbug(1,dprintf("format wrong"));
+              Info = _WRONG_MESSAGE_FORMAT;
+              break;
+            }
+            if(!plci)
+            {                               
+              if((i=get_plci(a)))
+              {
+                rplci = &a->plci[i-1];
+                rplci->appl = appl;
+                rplci->cr_enquiry=TRUE;
+                add_p(rplci,CAI,"\x01\x80");
+                add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+                sig_req(rplci,ASSIGN,DSIG_ID);
+                send_req(rplci);
+              }
+              else
+              {
+                Info = _OUT_OF_PLCI;
+                break;
+              }
+            }
+            else
+            {
+              rplci = plci;
+              rplci->cr_enquiry=FALSE;
+            }
+
+            rplci->command = 0;
+            rplci->internal_command = MWI_DEACTIVATE_REQ_PEND;
+            rplci->appl = appl;
+            rplci->number = Number;
+
+            cai[0] = 5;
+            cai[1] = DEACTIVATION_MWI; /* Function */
+            PUT_WORD(&cai[2],GET_WORD(&(ss_parms[2].info[0]))); /* Basic Service */
+            PUT_WORD(&cai[4],GET_WORD(&(ss_parms[3].info[0]))); /* Invocation Mode */
+            add_p(rplci,CAI,cai);
+            add_p(rplci,CPN,ss_parms[4].info); /* Receiving User Number */
+            add_p(rplci,OAD,ss_parms[5].info); /* Controlling User Number */
+            sig_req(rplci,S_SERVICE,0);
+            send_req(rplci);
+            return FALSE;
+
+          default:
+            Info = 0x300E;  /* not supported */
+            break;
+        }
+        break; /* case SELECTOR_SU_SERV: end */
+
+
+      case SELECTOR_DTMF:
+        return (dtmf_request (Id, Number, a, plci, appl, msg));
+
+
+
+      case SELECTOR_LINE_INTERCONNECT:
+        return (mixer_request (Id, Number, a, plci, appl, msg));
+
+
+
+      case PRIV_SELECTOR_ECHO_CANCELLER:
+        appl->appl_flags |= APPL_FLAG_PRIV_EC_SPEC;
+        return (ec_request (Id, Number, a, plci, appl, msg));
+
+      case SELECTOR_ECHO_CANCELLER:
+        appl->appl_flags &= ~APPL_FLAG_PRIV_EC_SPEC;
+        return (ec_request (Id, Number, a, plci, appl, msg));
+
+
+      case SELECTOR_V42BIS:
+      default:
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+    } /* end of switch(selector) */
+  }
+
+  dbug(1,dprintf("SendFacRc"));
+  sendf(appl,
+        _FACILITY_R|CONFIRM,
+        Id,
+        Number,
+        "wws",Info,selector,SSparms);
+  return FALSE;
+}
+
+byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  dbug(1,dprintf("facility_res"));
+  return FALSE;
+}
+
+byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word Info = 0;
+  byte req;
+  byte len;
+  word w;
+  word fax_control_bits, fax_feature_bits, fax_info_change;
+  API_PARSE * ncpi;
+    byte pvc[2];
+
+    API_PARSE fax_parms[9];
+  word i;
+
+
+  dbug(1,dprintf("connect_b3_req"));
+  if(plci)
+  {
+    if ((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING)
+     || (plci->State == INC_DIS_PENDING) || (plci->SuppState != IDLE))
+    {
+      Info = _WRONG_STATE;
+    }
+    else
+    {
+      /* local reply if assign unsuccessfull
+         or B3 protocol allows only one layer 3 connection
+           and already connected
+             or B2 protocol not any LAPD
+               and connect_b3_req contradicts originate/answer direction */
+      if (!plci->NL.Id
+       || (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))
+        && ((plci->channels != 0)
+         || (((plci->B2_prot != B2_SDLC) && (plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL))
+          && ((plci->call_dir & CALL_DIR_ANSWER) && !(plci->call_dir & CALL_DIR_FORCE_OUTG_NL))))))
+      {
+        dbug(1,dprintf("B3 already connected=%d or no NL.Id=0x%x, dir=%d sstate=0x%x",
+                       plci->channels,plci->NL.Id,plci->call_dir,plci->SuppState));
+        Info = _WRONG_STATE;
+        sendf(appl,                                                        
+              _CONNECT_B3_R|CONFIRM,
+              Id,
+              Number,
+              "w",Info);
+        return FALSE;
+      }
+      plci->requested_options_conn = 0;
+
+      req = N_CONNECT;
+      ncpi = &parms[0];
+      if(plci->B3_prot==2 || plci->B3_prot==3)
+      {
+        if(ncpi->length>2)
+        {
+          /* check for PVC */
+          if(ncpi->info[2] || ncpi->info[3])
+          {
+            pvc[0] = ncpi->info[3];
+            pvc[1] = ncpi->info[2];
+            add_d(plci,2,pvc);
+            req = N_RESET;
+          }
+          else
+          {
+            if(ncpi->info[1] &1) req = N_CONNECT | N_D_BIT;
+            add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
+          }
+        }
+      }
+      else if(plci->B3_prot==5)
+      {
+        if (plci->NL.Id && !plci->nl_remove_id)
+        {
+          fax_control_bits = GET_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low);
+          fax_feature_bits = GET_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->feature_bits_low);
+          if (!(fax_control_bits & T30_CONTROL_BIT_MORE_DOCUMENTS)
+           || (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS))
+          {
+            len = (byte)(&(((T30_INFO *) 0)->universal_6));
+            fax_info_change = FALSE;
+            if (ncpi->length >= 4)
+            {
+              w = GET_WORD(&ncpi->info[3]);
+              if ((w & 0x0001) != ((word)(((T30_INFO   *)(plci->fax_connect_info_buffer))->resolution & 0x0001)))
+              {
+                ((T30_INFO   *)(plci->fax_connect_info_buffer))->resolution =
+                  (byte)((((T30_INFO   *)(plci->fax_connect_info_buffer))->resolution & ~T30_RESOLUTION_R8_0770_OR_200) |
+                  ((w & 0x0001) ? T30_RESOLUTION_R8_0770_OR_200 : 0));
+                fax_info_change = TRUE;
+              }
+              fax_control_bits &= ~(T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
+              if (w & 0x0002)  /* Fax-polling request */
+                fax_control_bits |= T30_CONTROL_BIT_REQUEST_POLLING;
+              if ((w & 0x0004) /* Request to send / poll another document */
+               && (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS))
+              {
+                fax_control_bits |= T30_CONTROL_BIT_MORE_DOCUMENTS;
+              }
+              if (ncpi->length >= 6)
+              {
+                w = GET_WORD(&ncpi->info[5]);
+                if (((byte) w) != ((T30_INFO   *)(plci->fax_connect_info_buffer))->data_format)
+                {
+                  ((T30_INFO   *)(plci->fax_connect_info_buffer))->data_format = (byte) w;
+                  fax_info_change = TRUE;
+                }
+
+                if ((a->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
+                 && (GET_WORD(&ncpi->info[5]) & 0x8000)) /* Private SEP/SUB/PWD enable */
+                {
+                  plci->requested_options_conn |= (1L << PRIVATE_FAX_SUB_SEP_PWD);
+                }
+                if ((a->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD))
+                 && (GET_WORD(&ncpi->info[5]) & 0x4000)) /* Private non-standard facilities enable */
+                {
+                  plci->requested_options_conn |= (1L << PRIVATE_FAX_NONSTANDARD);
+                }
+                fax_control_bits &= ~(T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_SEL_POLLING |
+                  T30_CONTROL_BIT_ACCEPT_PASSWORD);
+                if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
+                  & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
+                {
+                  if (api_parse (&ncpi->info[1], ncpi->length, "wwwwsss", fax_parms))
+                    Info = _WRONG_MESSAGE_FORMAT;
+                  else
+                  {
+                    if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
+                      & (1L << PRIVATE_FAX_SUB_SEP_PWD))
+      {
+                    fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD;
+                    if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING)
+                      fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
+      }
+                    w = fax_parms[4].length;
+                    if (w > 20)
+                      w = 20;
+                    ((T30_INFO   *)(plci->fax_connect_info_buffer))->station_id_len = (byte) w;
+                    for (i = 0; i < w; i++)
+                      ((T30_INFO   *)(plci->fax_connect_info_buffer))->station_id[i] = fax_parms[4].info[1+i];
+                    ((T30_INFO   *)(plci->fax_connect_info_buffer))->head_line_len = 0;
+                    len = (byte)(((T30_INFO *) 0)->station_id + 20);
+                    w = fax_parms[5].length;
+                    if (w > 20)
+                      w = 20;
+                    plci->fax_connect_info_buffer[len++] = (byte) w;
+                    for (i = 0; i < w; i++)
+                      plci->fax_connect_info_buffer[len++] = fax_parms[5].info[1+i];
+                    w = fax_parms[6].length;
+                    if (w > 20)
+                      w = 20;
+                    plci->fax_connect_info_buffer[len++] = (byte) w;
+                    for (i = 0; i < w; i++)
+                      plci->fax_connect_info_buffer[len++] = fax_parms[6].info[1+i];
+                    if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[appl->Id-1])
+                      & (1L << PRIVATE_FAX_NONSTANDARD))
+      {
+                      if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
+        {
+                        dbug(1,dprintf("non-standard facilities info missing or wrong format"));
+                        plci->fax_connect_info_buffer[len++] = 0;
+        }
+                      else
+                      {
+          if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
+            plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
+   plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
+          for (i = 0; i < fax_parms[7].length; i++)
+     plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
+                      }
+                    }
+                  }
+                }
+                else
+                {
+                  len = (byte)(&(((T30_INFO *) 0)->universal_6));
+                }
+                fax_info_change = TRUE;
+
+              }
+              if (fax_control_bits != GET_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low))
+              {
+                PUT_WORD (&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low, fax_control_bits);
+                fax_info_change = TRUE;
+              }
+            }
+            if (Info == GOOD)
+            {
+              plci->fax_connect_info_length = len;
+              if (fax_info_change)
+              {
+                if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
+                {
+                  start_internal_command (Id, plci, fax_connect_info_command);
+                  return FALSE;
+                }
+                else
+                {
+                  start_internal_command (Id, plci, fax_adjust_b23_command);
+                  return FALSE;
+                }
+              }
+            }
+          }
+          else  Info = _WRONG_STATE;
+        }
+        else  Info = _WRONG_STATE;
+      }
+
+      else if (plci->B3_prot == B3_RTP)
+      {
+        plci->internal_req_buffer[0] = ncpi->length + 1;
+        plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE;
+        for (w = 0; w < ncpi->length; w++)
+          plci->internal_req_buffer[2+w] = ncpi->info[1+w];
+        start_internal_command (Id, plci, rtp_connect_b3_req_command);
+        return FALSE;
+      }
+
+      if(!Info)
+      {
+        nl_req_ncci(plci,req,0);
+        return 1;
+      }
+    }
+  }
+  else Info = _WRONG_IDENTIFIER;
+
+  sendf(appl,
+        _CONNECT_B3_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return FALSE;
+}
+
+byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+  API_PARSE * ncpi;
+  byte req;
+
+  word w;
+
+
+    API_PARSE fax_parms[9];
+  word i;
+  byte len;
+
+
+  dbug(1,dprintf("connect_b3_res"));
+
+  ncci = (word)(Id>>16);
+  if(plci && ncci) {
+    if(a->ncci_state[ncci]==INC_CON_PENDING) {
+      if (GET_WORD (&parms[0].info[0]) != 0)
+      {
+        a->ncci_state[ncci] = OUTG_REJ_PENDING;
+        channel_request_xon (plci, a->ncci_ch[ncci]);
+        channel_xmit_xon (plci);
+        cleanup_ncci_data (plci, ncci);
+        nl_req_ncci(plci,N_DISC,(byte)ncci);
+        return 1;
+      }
+      a->ncci_state[ncci] = INC_ACT_PENDING;
+
+      req = N_CONNECT_ACK;
+      ncpi = &parms[1];
+      if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7))
+      {
+
+        if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
+          & (1L << PRIVATE_FAX_NONSTANDARD))
+ {
+   if (((plci->B3_prot == 4) || (plci->B3_prot == 5))
+    && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
+    && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
+   {
+            len = ((byte)(((T30_INFO *) 0)->station_id + 20));
+            if (plci->fax_connect_info_length < len)
+            {
+              ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
+              ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
+            }
+            if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
+            {
+              dbug(1,dprintf("non-standard facilities info missing or wrong format"));
+            }
+            else
+            {
+              if (plci->fax_connect_info_length <= len)
+                plci->fax_connect_info_buffer[len] = 0;
+              len += 1 + plci->fax_connect_info_buffer[len];
+              if (plci->fax_connect_info_length <= len)
+                plci->fax_connect_info_buffer[len] = 0;
+              len += 1 + plci->fax_connect_info_buffer[len];
+              if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
+                plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
+              plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
+              for (i = 0; i < fax_parms[7].length; i++)
+                plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
+            }
+            plci->fax_connect_info_length = len;
+            ((T30_INFO *)(plci->fax_connect_info_buffer))->code = 0;
+            start_internal_command (Id, plci, fax_connect_ack_command);
+     return FALSE;
+          }
+        }
+
+        nl_req_ncci(plci,req,(byte)ncci);
+        if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+         && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+        {
+          if (plci->B3_prot == 4)
+            sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+          else
+            sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+          plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+        }
+      }
+
+      else if (plci->B3_prot == B3_RTP)
+      {
+        plci->internal_req_buffer[0] = ncpi->length + 1;
+        plci->internal_req_buffer[1] = UDATA_REQUEST_RTP_RECONFIGURE;
+        for (w = 0; w < ncpi->length; w++)
+          plci->internal_req_buffer[2+w] = ncpi->info[1+w];
+        start_internal_command (Id, plci, rtp_connect_b3_res_command);
+        return FALSE;
+      }
+
+      else
+      {
+        if(ncpi->length>2) {
+          if(ncpi->info[1] &1) req = N_CONNECT_ACK | N_D_BIT;
+          add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
+        }
+        nl_req_ncci(plci,req,(byte)ncci);
+        sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+        if (plci->adjust_b_restore)
+        {
+          plci->adjust_b_restore = FALSE;
+          start_internal_command (Id, plci, adjust_b_restore);
+        }
+      }
+      return 1;
+    }
+  }
+  return FALSE;
+}
+
+byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+
+  ncci = (word)(Id>>16);
+  dbug(1,dprintf("connect_b3_a_res(ncci=0x%x)",ncci));
+
+  if (plci && ncci && (plci->State != IDLE) && (plci->State != INC_DIS_PENDING)
+   && (plci->State != OUTG_DIS_PENDING))
+  {
+    if(a->ncci_state[ncci]==INC_ACT_PENDING) {
+      a->ncci_state[ncci] = CONNECTED;
+      if(plci->State!=INC_CON_CONNECTED_ALERT) plci->State = CONNECTED;
+      channel_request_xon (plci, a->ncci_ch[ncci]);
+      channel_xmit_xon (plci);
+    }
+  }
+  return FALSE;
+}
+
+byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word Info;
+  word ncci;
+  API_PARSE * ncpi;
+
+  dbug(1,dprintf("disconnect_b3_req"));
+
+  Info = _WRONG_IDENTIFIER;
+  ncci = (word)(Id>>16);
+  if (plci && ncci)
+  {
+    Info = _WRONG_STATE;
+    if ((a->ncci_state[ncci] == CONNECTED)
+     || (a->ncci_state[ncci] == OUTG_CON_PENDING)
+     || (a->ncci_state[ncci] == INC_CON_PENDING)
+     || (a->ncci_state[ncci] == INC_ACT_PENDING))
+    {
+      a->ncci_state[ncci] = OUTG_DIS_PENDING;
+      channel_request_xon (plci, a->ncci_ch[ncci]);
+      channel_xmit_xon (plci);
+
+      if (a->ncci[ncci].data_pending
+       && ((plci->B3_prot == B3_TRANSPARENT)
+        || (plci->B3_prot == B3_T30)
+        || (plci->B3_prot == B3_T30_WITH_EXTENSIONS)))
+      {
+        plci->send_disc = (byte)ncci;
+        plci->command = 0;
+        return FALSE;
+      }
+      else
+      {
+        cleanup_ncci_data (plci, ncci);
+
+        if(plci->B3_prot==2 || plci->B3_prot==3)
+        {
+          ncpi = &parms[0];
+          if(ncpi->length>3)
+          {
+            add_d(plci, (word)(ncpi->length - 3) ,(byte   *)&(ncpi->info[4]));
+          }
+        }
+        nl_req_ncci(plci,N_DISC,(byte)ncci);
+      }
+      return 1;
+    }
+  }
+  sendf(appl,
+        _DISCONNECT_B3_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return FALSE;
+}
+
+byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+  word i;
+
+  ncci = (word)(Id>>16);
+  dbug(1,dprintf("disconnect_b3_res(ncci=0x%x",ncci));
+  if(plci && ncci) {
+    plci->requested_options_conn = 0;
+    plci->fax_connect_info_length = 0;
+    plci->ncpi_state = 0x00;
+    if (((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE))
+      && ((plci->B2_prot != B2_LAPD) && (plci->B2_prot != B2_LAPD_FREE_SAPI_SEL)))
+    {
+      plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
+    }
+    for(i=0; i<MAX_CHANNELS_PER_PLCI && plci->inc_dis_ncci_table[i]!=(byte)ncci; i++);
+    if(i<MAX_CHANNELS_PER_PLCI) {
+      if(plci->channels)plci->channels--;
+      for(; i<MAX_CHANNELS_PER_PLCI-1; i++) plci->inc_dis_ncci_table[i] = plci->inc_dis_ncci_table[i+1];
+      plci->inc_dis_ncci_table[MAX_CHANNELS_PER_PLCI-1] = 0;
+
+      ncci_free_receive_buffers (plci, ncci);
+
+      if((plci->State==IDLE || plci->State==SUSPENDING) && !plci->channels){
+        if(plci->State == SUSPENDING){
+          sendf(plci->appl,
+                _FACILITY_I,
+                Id & 0xffffL,
+                0,
+                "ws", (word)3, "\x03\x04\x00\x00");
+          sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0);
+        }
+        plci_remove(plci);
+        plci->State=IDLE;
+      }
+    }
+    else
+    {
+      if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+       && ((plci->B3_prot == 4) || (plci->B3_prot == 5))
+       && (a->ncci_state[ncci] == INC_DIS_PENDING))
+      {
+        ncci_free_receive_buffers (plci, ncci);
+
+        nl_req_ncci(plci,N_EDATA,(byte)ncci);
+
+        plci->adapter->ncci_state[ncci] = IDLE;
+        start_internal_command (Id, plci, fax_disconnect_command);
+        return 1;
+      }
+    }
+  }
+  return FALSE;
+}
+
+byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  NCCI   *ncci_ptr;
+  DATA_B3_DESC   *data;
+  word Info;
+  word ncci;
+  word i;
+
+  dbug(1,dprintf("data_b3_req"));
+
+  Info = _WRONG_IDENTIFIER;
+  ncci = (word)(Id>>16);
+  dbug(1,dprintf("ncci=0x%x, plci=0x%x",ncci,plci));
+
+  if (plci && ncci)
+  {
+    Info = _WRONG_STATE;
+    if ((a->ncci_state[ncci] == CONNECTED)
+     || (a->ncci_state[ncci] == INC_ACT_PENDING))
+    {
+        /* queue data */
+      ncci_ptr = &(a->ncci[ncci]);
+      i = ncci_ptr->data_out + ncci_ptr->data_pending;
+      if (i >= MAX_DATA_B3)
+        i -= MAX_DATA_B3;
+      data = &(ncci_ptr->DBuffer[i]);
+      data->Number = Number;
+      if ((((byte   *)(parms[0].info)) >= ((byte   *)(plci->msg_in_queue)))
+       && (((byte   *)(parms[0].info)) < ((byte   *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+      {
+
+        data->P = (byte   *)(*((dword   *)(parms[0].info)));
+
+      }
+      else
+        data->P = TransmitBufferSet(appl,*(dword *)parms[0].info);
+      data->Length = GET_WORD(parms[1].info);
+      data->Handle = GET_WORD(parms[2].info);
+      data->Flags = GET_WORD(parms[3].info);
+      (ncci_ptr->data_pending)++;
+
+        /* check for delivery confirmation */
+      if (data->Flags & 0x0004)
+      {
+        i = ncci_ptr->data_ack_out + ncci_ptr->data_ack_pending;
+        if (i >= MAX_DATA_ACK)
+          i -= MAX_DATA_ACK;
+        ncci_ptr->DataAck[i].Number = data->Number;
+        ncci_ptr->DataAck[i].Handle = data->Handle;
+        (ncci_ptr->data_ack_pending)++;
+      }
+
+      send_data(plci);
+      return FALSE;
+    }
+  }
+  if (appl)
+  {
+    if (plci)
+    {
+      if ((((byte   *)(parms[0].info)) >= ((byte   *)(plci->msg_in_queue)))
+       && (((byte   *)(parms[0].info)) < ((byte   *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
+      {
+
+        TransmitBufferFree (appl, (byte   *)(*((dword   *)(parms[0].info))));
+
+      }
+    }
+    sendf(appl,
+          _DATA_B3_R|CONFIRM,
+          Id,
+          Number,
+          "ww",GET_WORD(parms[2].info),Info);
+  }
+  return FALSE;
+}
+
+byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word n;
+  word ncci;
+  word NCCIcode;
+
+  dbug(1,dprintf("data_b3_res"));
+
+  ncci = (word)(Id>>16);
+  if(plci && ncci) {
+    n = GET_WORD(parms[0].info);
+    dbug(1,dprintf("free(%d)",n));
+    NCCIcode = ncci | (((word) a->Id) << 8);
+    if(n<appl->MaxBuffer &&
+       appl->DataNCCI[n]==NCCIcode &&
+       (byte)(appl->DataFlags[n]>>8)==plci->Id) {
+      dbug(1,dprintf("found"));
+      appl->DataNCCI[n] = 0;
+
+      if (channel_can_xon (plci, a->ncci_ch[ncci])) {
+        channel_request_xon (plci, a->ncci_ch[ncci]);
+      }
+      channel_xmit_xon (plci);
+
+      if(appl->DataFlags[n] &4) {
+        nl_req_ncci(plci,N_DATA_ACK,(byte)ncci);
+        return 1;
+      }
+    }
+  }
+  return FALSE;
+}
+
+byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word Info;
+  word ncci;
+
+  dbug(1,dprintf("reset_b3_req"));
+
+  Info = _WRONG_IDENTIFIER;
+  ncci = (word)(Id>>16);
+  if(plci && ncci)
+  {
+    Info = _WRONG_STATE;
+    switch (plci->B3_prot)
+    {
+    case B3_ISO8208:
+    case B3_X25_DCE:
+      if(a->ncci_state[ncci]==CONNECTED)
+      {
+        nl_req_ncci(plci,N_RESET,(byte)ncci);
+        send_req(plci);
+        Info = GOOD;
+      }
+      break;
+    case B3_TRANSPARENT:
+      if(a->ncci_state[ncci]==CONNECTED)
+      {
+        start_internal_command (Id, plci, reset_b3_command);
+        Info = GOOD;
+      }
+      break;
+    }
+  }
+  /* reset_b3 must result in a reset_b3_con & reset_b3_Ind */
+  sendf(appl,
+        _RESET_B3_R|CONFIRM,
+        Id,
+        Number,
+        "w",Info);
+  return FALSE;
+}
+
+byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+
+  dbug(1,dprintf("reset_b3_res"));
+
+  ncci = (word)(Id>>16);
+  if(plci && ncci) {
+    switch (plci->B3_prot)
+    {
+    case B3_ISO8208:
+    case B3_X25_DCE:
+      if(a->ncci_state[ncci]==INC_RES_PENDING)
+      {
+        a->ncci_state[ncci] = CONNECTED;
+        nl_req_ncci(plci,N_RESET_ACK,(byte)ncci);
+        return TRUE;
+      }
+    break;
+    }
+  }
+  return FALSE;
+}
+
+byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word ncci;
+  API_PARSE * ncpi;
+  byte req;
+
+  dbug(1,dprintf("connect_b3_t90_a_res"));
+
+  ncci = (word)(Id>>16);
+  if(plci && ncci) {
+    if(a->ncci_state[ncci]==INC_ACT_PENDING) {
+      a->ncci_state[ncci] = CONNECTED;
+    }
+    else if(a->ncci_state[ncci]==INC_CON_PENDING) {
+      a->ncci_state[ncci] = CONNECTED;
+
+      req = N_CONNECT_ACK;
+
+        /* parms[0]==0 for CAPI original message definition! */
+      if(parms[0].info) {
+        ncpi = &parms[1];
+        if(ncpi->length>2) {
+          if(ncpi->info[1] &1) req = N_CONNECT_ACK | N_D_BIT;
+          add_d(plci,(word)(ncpi->length-3),&ncpi->info[4]);
+        }
+      }
+      nl_req_ncci(plci,req,(byte)ncci);
+      return 1;
+    }
+  }
+  return FALSE;
+}
+
+
+byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word Info=0;
+  word i;
+  byte tel;
+    API_PARSE bp_parms[7];
+
+  if(!plci || !msg)
+  {
+    Info = _WRONG_IDENTIFIER;
+  }
+  else
+  {
+    dbug(1,dprintf("select_b_req[%d],PLCI=0x%x,Tel=0x%x,NL=0x%x,appl=0x%x,sstate=0x%x",
+                   msg->length,plci->Id,plci->tel,plci->NL.Id,plci->appl,plci->SuppState));
+    dbug(1,dprintf("PlciState=0x%x",plci->State));
+    for(i=0;i<7;i++) bp_parms[i].length = 0;
+
+    /* check if no channel is open, no B3 connected only */
+    if((plci->State == IDLE) || (plci->State == OUTG_DIS_PENDING) || (plci->State == INC_DIS_PENDING)
+     || (plci->SuppState != IDLE) || plci->channels || plci->nl_remove_id)
+    {
+      Info = _WRONG_STATE;
+    }
+    /* check message format and fill bp_parms pointer */
+    else if(msg->length && api_parse(&msg->info[1], (word)msg->length, "wwwsss", bp_parms))
+    {
+      Info = _WRONG_MESSAGE_FORMAT;
+    }
+    else
+    {
+      if((plci->State==INC_CON_PENDING) || (plci->State==INC_CON_ALERT)) /* send alert tone inband to the network, */
+      {                                                                  /* e.g. Qsig or RBS or Cornet-N or xess PRI */
+        if(Id & EXT_CONTROLLER)
+        {
+          sendf(appl, _SELECT_B_REQ|CONFIRM, Id, Number, "w", 0x2002); /* wrong controller */
+          return 0;
+        }
+        plci->State=INC_CON_CONNECTED_ALERT;
+        plci->appl = appl;
+        clear_c_ind_mask_bit (plci, (word)(appl->Id-1));
+        dump_c_ind_mask (plci);
+        for(i=0; i<max_appl; i++) /* disconnect the other appls */
+        {                         /* its quasi a connect        */
+          if(test_c_ind_mask_bit (plci, i))
+            sendf(&application[i], _DISCONNECT_I, Id, 0, "w", _OTHER_APPL_CONNECTED);
+        }
+      }
+
+      api_save_msg(msg, "s", &plci->saved_msg);
+      tel = plci->tel;
+      if(Id & EXT_CONTROLLER)
+      {
+        if(tel) /* external controller in use by this PLCI */
+        {
+          if(a->AdvSignalAppl && a->AdvSignalAppl!=appl)
+          {
+            dbug(1,dprintf("Ext_Ctrl in use 1"));
+            Info = _WRONG_STATE;
+          }
+        }
+        else  /* external controller NOT in use by this PLCI ? */
+        {
+          if(a->AdvSignalPLCI)
+          {
+            dbug(1,dprintf("Ext_Ctrl in use 2"));
+            Info = _WRONG_STATE;
+          }
+          else /* activate the codec */
+          {
+            dbug(1,dprintf("Ext_Ctrl start"));
+            if(AdvCodecSupport(a, plci, appl, 0) )
+            {
+              dbug(1,dprintf("Error in codec procedures"));
+              Info = _WRONG_STATE;
+            }
+            else if(plci->spoofed_msg==SPOOFING_REQUIRED) /* wait until codec is active */
+            {
+              plci->spoofed_msg = AWAITING_SELECT_B;
+              plci->internal_command = BLOCK_PLCI; /* lock other commands */
+              plci->command = 0;
+              dbug(1,dprintf("continue if codec loaded"));
+              return FALSE;
+            }
+          }
+        }
+      }
+      else /* external controller bit is OFF */
+      {
+        if(tel) /* external controller in use, need to switch off */
+        {
+          if(a->AdvSignalAppl==appl)
+          {
+            CodecIdCheck(a, plci);
+            plci->tel = 0;
+            plci->adv_nl = 0;
+            dbug(1,dprintf("Ext_Ctrl disable"));
+          }
+          else
+          {
+            dbug(1,dprintf("Ext_Ctrl not requested"));
+          }
+        }
+      }
+      if (!Info)
+      {
+        if (plci->call_dir & CALL_DIR_OUT)
+          plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+        else if (plci->call_dir & CALL_DIR_IN)
+          plci->call_dir = CALL_DIR_IN | CALL_DIR_ANSWER;
+        start_internal_command (Id, plci, select_b_command);
+        return FALSE;
+      }
+    }
+  }
+  sendf(appl, _SELECT_B_REQ|CONFIRM, Id, Number, "w", Info);
+  return FALSE;
+}
+
+byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+{
+  word command;
+  word i;
+  word ncci;
+  API_PARSE * m;
+    API_PARSE m_parms[5];
+  word codec;
+  byte req;
+  byte ch;
+  byte dir;
+  static byte chi[2] = {0x01,0x00};
+  static byte lli[2] = {0x01,0x00};
+  static byte codec_cai[2] = {0x01,0x01};
+  static byte null_msg = {0};
+  static API_PARSE null_parms = { 0, &null_msg };
+  PLCI   * v_plci;
+  word Info=0;
+
+  dbug(1,dprintf("manufacturer_req"));
+  for(i=0;i<5;i++) m_parms[i].length = 0;
+
+  if(GET_DWORD(parms[0].info)!=_DI_MANU_ID) {
+    Info = _WRONG_MESSAGE_FORMAT;
+  }
+  command = GET_WORD(parms[1].info);
+  m = &parms[2];
+  if (!Info)
+  {
+    switch(command) {
+    case _DI_ASSIGN_PLCI:
+      if(api_parse(&m->info[1],(word)m->length,"wbbs",m_parms)) {
+        Info = _WRONG_MESSAGE_FORMAT;
+        break;
+      }
+      codec = GET_WORD(m_parms[0].info);
+      ch = m_parms[1].info[0];
+      dir = m_parms[2].info[0];
+      if((i=get_plci(a))) {
+        plci = &a->plci[i-1];
+        plci->appl = appl;
+        plci->command = _MANUFACTURER_R;
+        plci->m_command = command;
+        plci->number = Number;
+        plci->State = LOCAL_CONNECT;
+        Id = ( ((word)plci->Id<<8)|plci->adapter->Id|0x80);
+        dbug(1,dprintf("ManCMD,plci=0x%x",Id));
+
+        if((ch==1 || ch==2) && (dir<=2)) {
+          chi[1] = (byte)(0x80|ch);
+          lli[1] = 0;
+          plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+          switch(codec)
+          {
+          case 0:
+            Info = add_b1(plci,&m_parms[3],0,0);
+            break;
+          case 1:
+            add_p(plci,CAI,codec_cai);
+            break;
+          /* manual 'swich on' to the codec support without signalling */
+          /* first 'assign plci' with this function, then use */
+          case 2:
+            if(AdvCodecSupport(a, plci, appl, 0) ) {
+              Info = _RESOURCE_ERROR;
+            }
+            else {
+              Info = add_b1(plci,&null_parms,0,B1_FACILITY_LOCAL);
+              lli[1] = 0x10; /* local call codec stream */
+            }
+            break;
+          }
+
+          plci->State = LOCAL_CONNECT;
+          plci->manufacturer = TRUE;
+          plci->command = _MANUFACTURER_R;
+          plci->m_command = command;
+          plci->number = Number;
+
+          if(!Info)
+          {
+            add_p(plci,LLI,lli);
+            add_p(plci,CHI,chi);
+            add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+            sig_req(plci,ASSIGN,DSIG_ID);
+
+            if(!codec)
+            {
+              Info = add_b23(plci,&m_parms[3]);
+              if(!Info)
+              {
+                nl_req_ncci(plci,ASSIGN,0);
+                send_req(plci);
+              }
+            }
+            if(!Info)
+            {
+              dbug(1,dprintf("dir=0x%x,spoof=0x%x",dir,plci->spoofed_msg));
+              if (plci->spoofed_msg==SPOOFING_REQUIRED)
+              {
+                api_save_msg (m_parms, "wbbs", &plci->saved_msg);
+                plci->spoofed_msg = AWAITING_MANUF_CON;
+                plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
+                plci->command = 0;
+                send_req(plci);
+                return FALSE;
+              }
+              if(dir==1) {
+                sig_req(plci,CALL_REQ,0);
+              }
+              else if(!dir){
+                sig_req(plci,LISTEN_REQ,0);
+              }
+              send_req(plci);
+            }
+            else
+            {
+              sendf(appl,
+                    _MANUFACTURER_R|CONFIRM,
+                    Id,
+                    Number,
+                    "dww",_DI_MANU_ID,command,Info);
+              return 2;
+            }
+          }
+        }
+      }
+      else  Info = _OUT_OF_PLCI;
+      break;
+
+    case _DI_IDI_CTRL:
+      if(!plci)
+      {
+        Info = _WRONG_IDENTIFIER;
+        break;
+      }
+      if(api_parse(&m->info[1],(word)m->length,"bs",m_parms)) {
+        Info = _WRONG_MESSAGE_FORMAT;
+        break;
+      }
+      req = m_parms[0].info[0];
+      plci->command = _MANUFACTURER_R;
+      plci->m_command = command;
+      plci->number = Number;
+      if(req==CALL_REQ)
+      {
+        plci->b_channel = getChannel(&m_parms[1]);
+        mixer_set_bchannel_id_esc (plci, plci->b_channel);
+        if(plci->spoofed_msg==SPOOFING_REQUIRED)
+        {
+          plci->spoofed_msg = CALL_REQ | AWAITING_MANUF_CON;
+          plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
+          plci->command = 0;
+          break;
+        }
+      }
+      else if(req==LAW_REQ)
+      {
+        plci->cr_enquiry = TRUE;
+      }
+      add_ss(plci,FTY,&m_parms[1]);
+      sig_req(plci,req,0);
+      send_req(plci);
+      if(req==HANGUP)
+      {      
+        if (plci->NL.Id && !plci->nl_remove_id)
+        {
+          if (plci->channels)
+          {
+            for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
+            {
+              if ((a->ncci_plci[ncci] == plci->Id) && (a->ncci_state[ncci] == CONNECTED))
+              {
+                a->ncci_state[ncci] = OUTG_DIS_PENDING;
+                cleanup_ncci_data (plci, ncci);
+                nl_req_ncci(plci,N_DISC,(byte)ncci);
+              }
+            }
+          }
+          mixer_remove (plci);
+          nl_req_ncci(plci,REMOVE,0);
+          send_req(plci);
+        }  
+      }
+      break;
+
+    case _DI_SIG_CTRL:
+    /* signalling control for loop activation B-channel */
+      if(!plci)
+      {
+        Info = _WRONG_IDENTIFIER;
+        break;
+      }
+      if(m->length){
+        plci->command = _MANUFACTURER_R;
+        plci->number = Number;
+        add_ss(plci,FTY,m);
+        sig_req(plci,SIG_CTRL,0);
+        send_req(plci);
+      }
+      else Info = _WRONG_MESSAGE_FORMAT;
+      break;
+
+    case _DI_RXT_CTRL:
+    /* activation control for receiver/transmitter B-channel */
+      if(!plci)
+      {
+        Info = _WRONG_IDENTIFIER;
+        break;
+      }
+      if(m->length){
+        plci->command = _MANUFACTURER_R;
+        plci->number = Number;
+        add_ss(plci,FTY,m);
+        sig_req(plci,DSP_CTRL,0);
+        send_req(plci);
+      }
+      else Info = _WRONG_MESSAGE_FORMAT;
+      break;
+
+    case _DI_ADV_CODEC:
+    case _DI_DSP_CTRL:
+      /* TEL_CTRL commands to support non standard adjustments: */
+      /* Ring on/off, Handset micro volume, external micro vol. */
+      /* handset+external speaker volume, receiver+transm. gain,*/
+      /* handsfree on (hookinfo off), set mixer command         */
+
+      if(command == _DI_ADV_CODEC)
+      {
+        if(!a->AdvCodecPLCI) {
+          Info = _WRONG_STATE;
+          break;
+        }
+        v_plci = a->AdvCodecPLCI;
+      }
+      else
+      {
+        if (plci
+         && (m->length >= 3)
+         && (m->info[1] == 0x1c)
+         && (m->info[2] >= 1))
+        {
+          if (m->info[3] == DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS)
+          {
+            if ((plci->tel != ADV_VOICE) || (plci != a->AdvSignalPLCI))
+            {
+              Info = _WRONG_STATE;
+              break;
+            }
+            a->adv_voice_coef_length = m->info[2] - 1;
+            if (a->adv_voice_coef_length > m->length - 3)
+              a->adv_voice_coef_length = (byte)(m->length - 3);
+            if (a->adv_voice_coef_length > ADV_VOICE_COEF_BUFFER_SIZE)
+              a->adv_voice_coef_length = ADV_VOICE_COEF_BUFFER_SIZE;
+            for (i = 0; i < a->adv_voice_coef_length; i++)
+              a->adv_voice_coef_buffer[i] = m->info[4 + i];
+            if (plci->B1_facilities & B1_FACILITY_VOICE)
+              adv_voice_write_coefs (plci, ADV_VOICE_WRITE_UPDATE);
+            break;
+          }
+          else if (m->info[3] == DSP_CTRL_SET_DTMF_PARAMETERS)
+          {
+            if (!(a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_PARAMETERS))
+            {
+              Info = _FACILITY_NOT_SUPPORTED;
+              break;
+            }
+
+            plci->dtmf_parameter_length = m->info[2] - 1;
+            if (plci->dtmf_parameter_length > m->length - 3)
+              plci->dtmf_parameter_length = (byte)(m->length - 3);
+            if (plci->dtmf_parameter_length > DTMF_PARAMETER_BUFFER_SIZE)
+              plci->dtmf_parameter_length = DTMF_PARAMETER_BUFFER_SIZE;
+            for (i = 0; i < plci->dtmf_parameter_length; i++)
+              plci->dtmf_parameter_buffer[i] = m->info[4+i];
+            if (plci->B1_facilities & B1_FACILITY_DTMFR)
+              dtmf_parameter_write (plci);
+            break;
+
+          }
+        }
+        v_plci = plci;
+      }
+
+      if(!v_plci)
+      {
+        Info = _WRONG_IDENTIFIER;
+        break;
+      }
+      if(m->length){
+        add_ss(v_plci,FTY,m);
+        sig_req(v_plci,TEL_CTRL,0);
+        send_req(v_plci);
+      }
+      else Info = _WRONG_MESSAGE_FORMAT;
+
+      break;
+
+    case _DI_OPTIONS_REQUEST:
+      if(api_parse(&m->info[1],(word)m->length,"d",m_parms)) {
+        Info = _WRONG_MESSAGE_FORMAT;
+        break;
+      }
+      if (GET_DWORD (m_parms[0].info) & ~a->man_profile.private_options)
+      {
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      a->requested_options_table[appl->Id-1] = GET_DWORD (m_parms[0].info);
+      break;
+
+
+
+    default:
+      Info = _WRONG_MESSAGE_FORMAT;
+      break;
+    }
+  }
+
+  sendf(appl,
+        _MANUFACTURER_R|CONFIRM,
+        Id,
+        Number,
+        "dww",_DI_MANU_ID,command,Info);
+  return FALSE;
+}
+
+
+byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+{
+  word indication;
+
+    API_PARSE m_parms[3];
+  API_PARSE *ncpi;
+    API_PARSE fax_parms[9];
+  word i;
+  byte len;
+
+
+  dbug(1,dprintf("manufacturer_res"));
+
+  if ((msg[0].length == 0)
+   || (msg[1].length == 0)
+   || (GET_DWORD(msg[0].info)!=_DI_MANU_ID))
+  {
+    return FALSE;
+  }
+  indication = GET_WORD(msg[1].info);
+  switch (indication)
+  {
+
+  case _DI_NEGOTIATE_B3:
+    if(!plci)
+      break;
+    if (((plci->B3_prot != 4) && (plci->B3_prot != 5))
+     || !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT))
+    {
+      dbug(1,dprintf("wrong state for NEGOTIATE_B3 parameters"));
+      break;
+    }
+    if (api_parse (&msg[2].info[1], msg[2].length, "ws", m_parms))
+    {
+      dbug(1,dprintf("wrong format in NEGOTIATE_B3 parameters"));
+      break;
+    }
+    ncpi = &m_parms[1];
+    len = ((byte)(((T30_INFO *) 0)->station_id + 20));
+    if (plci->fax_connect_info_length < len)
+    {
+      ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0;
+      ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0;
+    }
+    if (api_parse (&ncpi->info[1], ncpi->length, "wwwwssss", fax_parms))
+    {
+      dbug(1,dprintf("non-standard facilities info missing or wrong format"));
+    }
+    else
+    {
+      if (plci->fax_connect_info_length <= len)
+        plci->fax_connect_info_buffer[len] = 0;
+      len += 1 + plci->fax_connect_info_buffer[len];
+      if (plci->fax_connect_info_length <= len)
+        plci->fax_connect_info_buffer[len] = 0;
+      len += 1 + plci->fax_connect_info_buffer[len];
+      if ((fax_parms[7].length >= 3) && (fax_parms[7].info[1] >= 2))
+        plci->nsf_control_bits = GET_WORD(&fax_parms[7].info[2]);
+      plci->fax_connect_info_buffer[len++] = (byte)(fax_parms[7].length);
+      for (i = 0; i < fax_parms[7].length; i++)
+        plci->fax_connect_info_buffer[len++] = fax_parms[7].info[1+i];
+    }
+    plci->fax_connect_info_length = len;
+    plci->fax_edata_ack_length = plci->fax_connect_info_length;
+    start_internal_command (Id, plci, fax_edata_ack_command);
+    break;
+
+  }
+  return FALSE;
+}
+
+/*------------------------------------------------------------------*/
+/* IDI callback function                                            */
+/*------------------------------------------------------------------*/
+
+void   callback(ENTITY   * e)
+{
+  DIVA_CAPI_ADAPTER   * a;
+  APPL   * appl;
+  PLCI   * plci;
+  CAPI_MSG   *m;
+  word i, j;
+  byte rc;
+  byte ch;
+  byte req;
+  byte global_req;
+  int no_cancel_rc;
+
+  dbug(1,dprintf("%x:CB(%x:Req=%x,Rc=%x,Ind=%x)",
+                 (e->user[0]+1)&0x7fff,e->Id,e->Req,e->Rc,e->Ind));
+
+  a = &(adapter[(byte)e->user[0]]);
+  plci = &(a->plci[e->user[1]]);
+  no_cancel_rc = DIVA_CAPI_SUPPORTS_NO_CANCEL(a);
+
+  /*
+     If new protocol code and new XDI is used then CAPI should work
+     fully in accordance with IDI cpec an look on callback field instead
+     of Rc field for return codes.
+   */
+  if (((e->complete == 0xff) && no_cancel_rc) ||
+      (e->Rc && !no_cancel_rc)) {
+    rc = e->Rc;
+    ch = e->RcCh;
+    req = e->Req;
+    e->Rc = 0;
+
+    if (e->user[0] & 0x8000)
+    {
+      /*
+         If REMOVE request was sent then we have to wait until
+         return code with Id set to zero arrives.
+         All other return codes should be ignored.
+         */
+      if (req == REMOVE)
+      {
+        if (e->Id)
+        {
+          dbug(1,dprintf("cancel RC in REMOVE state"));
+          return;
+        }
+        channel_flow_control_remove (plci);
+        for (i = 0; i < 256; i++)
+        {
+          if (a->FlowControlIdTable[i] == plci->nl_remove_id)
+            a->FlowControlIdTable[i] = 0;
+        }
+        plci->nl_remove_id = 0;
+        if (plci->rx_dma_descriptor > 0) {
+          diva_free_dma_descriptor (plci, plci->rx_dma_descriptor - 1);
+          plci->rx_dma_descriptor = 0;
+        }
+      }
+      if (rc == OK_FC)
+      {
+        a->FlowControlIdTable[ch] = e->Id;
+        a->FlowControlSkipTable[ch] = 0;
+
+        a->ch_flow_control[ch] |= N_OK_FC_PENDING;
+        a->ch_flow_plci[ch] = plci->Id;
+        plci->nl_req = 0;
+      }
+      else
+      {
+        /*
+          Cancel return codes self, if feature was requested
+          */
+        if (no_cancel_rc && (a->FlowControlIdTable[ch] == e->Id) && e->Id) {
+          a->FlowControlIdTable[ch] = 0;
+          if ((rc == OK) && a->FlowControlSkipTable[ch]) {
+            dbug(3,dprintf ("XDI CAPI: RC cancelled Id:0x02, Ch:%02x",                              e->Id, ch));
+            return;
+          }
+        }
+
+        if (a->ch_flow_control[ch] & N_OK_FC_PENDING)
+        {
+          a->ch_flow_control[ch] &= ~N_OK_FC_PENDING;
+          if (ch == e->ReqCh)
+            plci->nl_req = 0;
+        }
+        else
+          plci->nl_req = 0;
+      }
+      if (plci->nl_req)
+        control_rc (plci, 0, rc, ch, 0, TRUE);
+      else
+      {
+        if (req == N_XON)
+        {
+          channel_x_on (plci, ch);
+          if (plci->internal_command)
+            control_rc (plci, req, rc, ch, 0, TRUE);
+        }
+        else
+        {
+          if (plci->nl_global_req)
+          {
+            global_req = plci->nl_global_req;
+            plci->nl_global_req = 0;
+            if (rc != ASSIGN_OK) {
+              e->Id = 0;
+              if (plci->rx_dma_descriptor > 0) {
+                diva_free_dma_descriptor (plci, plci->rx_dma_descriptor - 1);
+                plci->rx_dma_descriptor = 0;
+              }
+            }
+            channel_xmit_xon (plci);
+            control_rc (plci, 0, rc, ch, global_req, TRUE);
+          }
+          else if (plci->data_sent)
+          {
+            channel_xmit_xon (plci);
+            plci->data_sent = FALSE;
+            plci->NL.XNum = 1;
+            data_rc (plci, ch);
+            if (plci->internal_command)
+              control_rc (plci, req, rc, ch, 0, TRUE);
+          }
+          else
+          {
+            channel_xmit_xon (plci);
+            control_rc (plci, req, rc, ch, 0, TRUE);
+          }
+        }
+      }
+    }
+    else
+    {
+      /*
+         If REMOVE request was sent then we have to wait until
+         return code with Id set to zero arrives.
+         All other return codes should be ignored.
+         */
+      if (req == REMOVE)
+      {
+        if (e->Id)
+        {
+          dbug(1,dprintf("cancel RC in REMOVE state"));
+          return;
+        }
+        plci->sig_remove_id = 0;
+      }
+      plci->sig_req = 0;
+      if (plci->sig_global_req)
+      {
+        global_req = plci->sig_global_req;
+        plci->sig_global_req = 0;
+        if (rc != ASSIGN_OK)
+          e->Id = 0;
+        channel_xmit_xon (plci);
+        control_rc (plci, 0, rc, ch, global_req, FALSE);
+      }
+      else
+      {
+        channel_xmit_xon (plci);
+        control_rc (plci, req, rc, ch, 0, FALSE);
+      }
+    }
+    /*
+      Again: in accordance with IDI spec Rc and Ind can't be delivered in the
+      same callback. Also if new XDI and protocol code used then jump
+      direct to finish.
+      */
+    if (no_cancel_rc) {
+      channel_xmit_xon(plci);
+      goto capi_callback_suffix;
+    }
+  }
+
+  channel_xmit_xon(plci);
+
+  if (e->Ind) {
+    if (e->user[0] &0x8000) {
+      byte Ind = e->Ind & 0x0f;
+      byte Ch = e->IndCh;
+      if (((Ind==N_DISC) || (Ind==N_DISC_ACK)) &&
+          (a->ch_flow_plci[Ch] == plci->Id)) {
+        if (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK) {
+          dbug(3,dprintf ("XDI CAPI: I: pending N-XON Ch:%02x", Ch));
+        }
+        a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK;
+      }
+      nl_ind(plci);
+      if ((e->RNR != 1) &&
+          (a->ch_flow_plci[Ch] == plci->Id) &&
+          (a->ch_flow_control[Ch] & N_RX_FLOW_CONTROL_MASK)) {
+        a->ch_flow_control[Ch] &= ~N_RX_FLOW_CONTROL_MASK;
+        dbug(3,dprintf ("XDI CAPI: I: remove faked N-XON Ch:%02x", Ch));
+      }
+    } else {
+      sig_ind(plci);
+    }
+    e->Ind = 0;
+  }
+
+capi_callback_suffix:
+
+  while (!plci->req_in
+   && !plci->internal_command
+   && (plci->msg_in_write_pos != plci->msg_in_read_pos))
+  {
+    j = (plci->msg_in_read_pos == plci->msg_in_wrap_pos) ? 0 : plci->msg_in_read_pos;
+
+    i = (((CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[j]))->header.length + 3) & 0xfffc;
+
+    m = (CAPI_MSG   *)(&((byte   *)(plci->msg_in_queue))[j]);
+    appl = *((APPL   *   *)(&((byte   *)(plci->msg_in_queue))[j+i]));
+    dbug(1,dprintf("dequeue msg(0x%04x) - write=%d read=%d wrap=%d",
+      m->header.command, plci->msg_in_write_pos, plci->msg_in_read_pos, plci->msg_in_wrap_pos));
+    if (plci->msg_in_read_pos == plci->msg_in_wrap_pos)
+    {
+      plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
+      plci->msg_in_read_pos = i + MSG_IN_OVERHEAD;
+    }
+    else
+    {
+      plci->msg_in_read_pos = j + i + MSG_IN_OVERHEAD;
+    }
+    if (plci->msg_in_read_pos == plci->msg_in_write_pos)
+    {
+      plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
+      plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
+    }
+    else if (plci->msg_in_read_pos == plci->msg_in_wrap_pos)
+    {
+      plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
+      plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
+    }
+    i = api_put (appl, m);
+    if (i != 0)
+    {
+      if (m->header.command == _DATA_B3_R)
+
+        TransmitBufferFree (appl, (byte   *)(m->info.data_b3_req.Data));
+
+      dbug(1,dprintf("Error 0x%04x from msg(0x%04x)", i, m->header.command));
+      break;
+    }
+
+    if (plci->li_notify_update)
+    {
+      plci->li_notify_update = FALSE;
+      mixer_notify_update (plci, FALSE);
+    }
+
+  }
+  send_data(plci);
+  send_req(plci);
+}
+
+
+void control_rc(PLCI   * plci, byte req, byte rc, byte ch, byte global_req, byte nl_rc)
+{
+  dword Id;
+  dword rId;
+  word Number;
+  word Info=0;
+  word i;
+  word ncci;
+  DIVA_CAPI_ADAPTER   * a;
+  APPL   * appl;
+  PLCI   * rplci;
+    byte SSparms[]  = "\x05\x00\x00\x02\x00\x00";
+    byte SSstruct[] = "\x09\x00\x00\x06\x00\x00\x00\x00\x00\x00";
+
+  if (!plci) {
+    dbug(0,dprintf("A: control_rc, no plci %02x:%02x:%02x:%02x:%02x", req, rc, ch, global_req, nl_rc));
+    return;
+  }
+  dbug(1,dprintf("req0_in/out=%d/%d",plci->req_in,plci->req_out));
+  if(plci->req_in!=plci->req_out)
+  {
+    if (nl_rc || (global_req != ASSIGN) || (rc == ASSIGN_OK))
+    {
+      dbug(1,dprintf("req_1return"));
+      return;
+    }
+    /* cancel outstanding request on the PLCI after SIG ASSIGN failure */
+  }
+  plci->req_in = plci->req_in_start = plci->req_out = 0;
+  dbug(1,dprintf("control_rc"));
+
+  appl = plci->appl;
+  a = plci->adapter;
+  ncci = a->ch_ncci[ch];
+  if(appl)
+  {
+    Id = (((dword)(ncci ? ncci : ch)) << 16) | ((word)plci->Id << 8) | a->Id;
+    if(plci->tel && plci->SuppState!=CALL_HELD) Id|=EXT_CONTROLLER;
+    Number = plci->number;
+    dbug(1,dprintf("Contr_RC-Id=%08lx,plci=%x,tel=%x, entity=0x%x, command=0x%x, int_command=0x%x",Id,plci->Id,plci->tel,plci->Sig.Id,plci->command,plci->internal_command));
+    dbug(1,dprintf("channels=0x%x",plci->channels));
+    if (plci_remove_check(plci))
+      return;
+    if(req==REMOVE && rc==ASSIGN_OK)
+    {
+      sig_req(plci,HANGUP,0);
+      sig_req(plci,REMOVE,0);
+      send_req(plci);
+    }
+    if(plci->command)
+    {
+      switch(plci->command)
+      {
+      case C_HOLD_REQ:
+        dbug(1,dprintf("HoldRC=0x%x",rc));
+        SSparms[1] = (byte)S_HOLD;
+        if(rc!=OK)
+        {
+          plci->SuppState = IDLE;
+          Info = 0x2001;
+        }
+        sendf(appl,_FACILITY_R|CONFIRM,Id,Number,"wws",Info,3,SSparms);
+        break;
+
+      case C_RETRIEVE_REQ:
+        dbug(1,dprintf("RetrieveRC=0x%x",rc));
+        SSparms[1] = (byte)S_RETRIEVE;
+        if(rc!=OK)
+        {
+          plci->SuppState = CALL_HELD;
+          Info = 0x2001;
+        }
+        sendf(appl,_FACILITY_R|CONFIRM,Id,Number,"wws",Info,3,SSparms);
+        break;
+
+      case _INFO_R:
+        dbug(1,dprintf("InfoRC=0x%x",rc));
+        if(rc!=OK) Info=_WRONG_STATE;
+        sendf(appl,_INFO_R|CONFIRM,Id,Number,"w",Info);
+        break;
+
+      case _CONNECT_R:
+        dbug(1,dprintf("Connect_R=0x%x/0x%x/0x%x/0x%x",req,rc,global_req,nl_rc));
+        if (plci->State == INC_DIS_PENDING)
+          break;
+        if(plci->Sig.Id!=0xff)
+        {
+          if (((global_req == ASSIGN) && (rc != ASSIGN_OK))
+           || (!nl_rc && (req == CALL_REQ) && (rc != OK)))
+          {
+            dbug(1,dprintf("No more IDs/Call_Req failed"));
+            sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
+            plci_remove(plci);
+            plci->State = IDLE;
+            break;
+          }
+          if(plci->State!=LOCAL_CONNECT)plci->State = OUTG_CON_PENDING;
+          sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
+        }
+        else /* D-ch activation */
+        {
+          if (rc != ASSIGN_OK)
+          {
+            dbug(1,dprintf("No more IDs/X.25 Call_Req failed"));
+            sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
+            plci_remove(plci);
+            plci->State = IDLE;
+            break;
+          }
+          sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
+          sendf(plci->appl,_CONNECT_ACTIVE_I,Id,0,"sss","","","");
+          plci->State = INC_ACT_PENDING;
+        }
+        break;
+
+      case _CONNECT_I|RESPONSE:
+        if (plci->State != INC_DIS_PENDING)
+          plci->State = INC_CON_ACCEPT;
+        break;
+
+      case _DISCONNECT_R:
+        if (plci->State == INC_DIS_PENDING)
+          break;
+        if(plci->Sig.Id!=0xff)
+        {
+          plci->State = OUTG_DIS_PENDING;
+          sendf(appl,_DISCONNECT_R|CONFIRM,Id,Number,"w",0);
+        }
+        break;
+
+      case SUSPEND_REQ:
+        break;
+
+      case RESUME_REQ:
+        break;
+
+      case _CONNECT_B3_R:
+        if(rc!=OK)
+        {
+          sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",_WRONG_IDENTIFIER);
+          break;
+        }
+        ncci = get_ncci (plci, ch, 0);
+        Id = (Id & 0xffff) | (((dword) ncci) << 16);
+        plci->channels++;
+        if(req==N_RESET)
+        {
+          a->ncci_state[ncci] = INC_ACT_PENDING;
+          sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",0);
+          sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+        }
+        else
+        {
+          a->ncci_state[ncci] = OUTG_CON_PENDING;
+          sendf(appl,_CONNECT_B3_R|CONFIRM,Id,Number,"w",0);
+        }
+        break;
+
+      case _CONNECT_B3_I|RESPONSE:
+        break;
+
+      case _RESET_B3_R:
+/*        sendf(appl,_RESET_B3_R|CONFIRM,Id,Number,"w",0);*/
+        break;
+
+      case _DISCONNECT_B3_R:
+        sendf(appl,_DISCONNECT_B3_R|CONFIRM,Id,Number,"w",0);
+        break;
+
+      case _MANUFACTURER_R:
+        break;
+
+      case PERM_LIST_REQ:
+        if(rc!=OK)
+        {
+          Info = _WRONG_IDENTIFIER;
+          sendf(plci->appl,_CONNECT_R|CONFIRM,Id,Number,"w",Info);
+          plci_remove(plci);
+        }
+        else
+          sendf(plci->appl,_CONNECT_R|CONFIRM,Id,Number,"w",Info);
+        break;
+
+      default:
+        break;
+      }
+      plci->command = 0;
+    }
+    else if (plci->internal_command)
+    {
+      switch(plci->internal_command)
+      {
+      case BLOCK_PLCI:
+        return;
+
+      case GET_MWI_STATE:
+        if(rc==OK) /* command supported, wait for indication */
+        {
+          return;
+        }
+        plci_remove(plci);
+        break;
+
+        /* Get Supported Services */
+      case GETSERV_REQ_PEND:
+        if(rc==OK) /* command supported, wait for indication */
+        {
+          break;
+        }
+        PUT_DWORD(&SSstruct[6], MASK_TERMINAL_PORTABILITY);
+        sendf(appl, _FACILITY_R|CONFIRM, Id, Number, "wws",0,3,SSstruct);
+        plci_remove(plci);
+        break;
+
+      case INTERR_DIVERSION_REQ_PEND:      /* Interrogate Parameters        */
+      case INTERR_NUMBERS_REQ_PEND:
+      case CF_START_PEND:                  /* Call Forwarding Start pending */
+      case CF_STOP_PEND:                   /* Call Forwarding Stop pending  */
+      case CCBS_REQUEST_REQ_PEND:
+      case CCBS_DEACTIVATE_REQ_PEND:
+      case CCBS_INTERROGATE_REQ_PEND:
+        switch(plci->internal_command)
+        {
+          case INTERR_DIVERSION_REQ_PEND:
+            SSparms[1] = S_INTERROGATE_DIVERSION;
+            break;
+          case INTERR_NUMBERS_REQ_PEND:
+            SSparms[1] = S_INTERROGATE_NUMBERS;
+            break;
+          case CF_START_PEND:
+            SSparms[1] = S_CALL_FORWARDING_START;
+            break;
+          case CF_STOP_PEND:
+            SSparms[1] = S_CALL_FORWARDING_STOP;
+            break;
+          case CCBS_REQUEST_REQ_PEND:
+            SSparms[1] = S_CCBS_REQUEST;
+            break;
+          case CCBS_DEACTIVATE_REQ_PEND:
+            SSparms[1] = S_CCBS_DEACTIVATE;
+            break;
+          case CCBS_INTERROGATE_REQ_PEND:
+            SSparms[1] = S_CCBS_INTERROGATE;
+            break;
+        }
+        if(global_req==ASSIGN)
+        {
+          dbug(1,dprintf("AssignDiversion_RC=0x%x/0x%x",req,rc));
+          return;
+        }
+        if(!plci->appl) break;
+        if(rc==ISDN_GUARD_REJ)
+        {
+          Info = _CAPI_GUARD_ERROR;
+        }
+        else if(rc!=OK)
+        {
+          Info = _SUPPLEMENTARY_SERVICE_NOT_SUPPORTED;
+        }
+        sendf(plci->appl,_FACILITY_R|CONFIRM,Id&0x7,
+              plci->number,"wws",Info,(word)3,SSparms);
+        if(Info) plci_remove(plci);
+        break;
+
+        /* 3pty conference pending */
+      case PTY_REQ_PEND:
+        if(!plci->relatedPTYPLCI) break;
+        rplci = plci->relatedPTYPLCI;
+        SSparms[1] = plci->ptyState;
+        rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
+        if(rplci->tel) rId|=EXT_CONTROLLER;
+        if(rc!=OK)
+        {
+          Info = 0x300E; /* not supported */
+          plci->relatedPTYPLCI = NULL;
+          plci->ptyState = 0;
+        }
+        sendf(rplci->appl,
+              _FACILITY_R|CONFIRM,
+              rId,
+              plci->number,
+              "wws",Info,(word)3,SSparms);
+        break;
+
+        /* Explicit Call Transfer pending */
+      case ECT_REQ_PEND:
+        dbug(1,dprintf("ECT_RC=0x%x/0x%x",req,rc));
+        if(!plci->relatedPTYPLCI) break;
+        rplci = plci->relatedPTYPLCI;
+        SSparms[1] = S_ECT;
+        rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
+        if(rplci->tel) rId|=EXT_CONTROLLER;
+        if(rc!=OK)
+        {
+          Info = 0x300E; /* not supported */
+          plci->relatedPTYPLCI = NULL;
+          plci->ptyState = 0;
+        }
+        sendf(rplci->appl,
+              _FACILITY_R|CONFIRM,
+              rId,
+              plci->number,
+              "wws",Info,(word)3,SSparms);
+        break;
+
+      case _MANUFACTURER_R:
+        dbug(1,dprintf("_Manufacturer_R=0x%x/0x%x",req,rc));
+        if ((global_req == ASSIGN) && (rc != ASSIGN_OK))
+        {
+          dbug(1,dprintf("No more IDs"));
+          sendf(appl,_MANUFACTURER_R|CONFIRM,Id,Number,"dww",_DI_MANU_ID,_MANUFACTURER_R,_OUT_OF_PLCI);
+          plci_remove(plci);  /* after codec init, internal codec commands pending */
+        }
+        break;
+
+      case _CONNECT_R:
+        dbug(1,dprintf("_Connect_R=0x%x/0x%x",req,rc));
+        if ((global_req == ASSIGN) && (rc != ASSIGN_OK))
+        {
+          dbug(1,dprintf("No more IDs"));
+          sendf(appl,_CONNECT_R|CONFIRM,Id&0xffL,Number,"w",_OUT_OF_PLCI);
+          plci_remove(plci);  /* after codec init, internal codec commands pending */
+        }
+        break;
+
+      case PERM_COD_HOOK:                     /* finished with Hook_Ind */
+        return;
+
+      case PERM_COD_CALL:
+        dbug(1,dprintf("***Codec Connect_Pending A, Rc = 0x%x",rc));
+        plci->internal_command = PERM_COD_CONN_PEND;
+        return;
+
+      case PERM_COD_ASSIGN:
+        dbug(1,dprintf("***Codec Assign A, Rc = 0x%x",rc));
+        if(rc!=ASSIGN_OK) break;
+        sig_req(plci,CALL_REQ,0);
+        send_req(plci);
+        plci->internal_command = PERM_COD_CALL;
+        return;
+
+        /* Null Call Reference Request pending */
+      case C_NCR_FAC_REQ:
+        dbug(1,dprintf("NCR_FAC=0x%x/0x%x",req,rc));
+        if(global_req==ASSIGN)
+        {
+          if(rc==ASSIGN_OK)
+          {
+            return;
+          }
+          else
+          {
+            sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE);
+            appl->NullCREnable = FALSE;
+            plci_remove(plci);
+          }
+        }
+        else if(req==NCR_FACILITY)
+        {
+          if(rc==OK)
+          {
+            sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",0);
+          }
+          else
+          {
+            sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE);
+            appl->NullCREnable = FALSE;
+          }
+          plci_remove(plci);
+        }
+        break;
+
+      case HOOK_ON_REQ:
+        if(plci->channels)
+        {
+          if(a->ncci_state[ncci]==CONNECTED)
+          {
+            a->ncci_state[ncci] = OUTG_DIS_PENDING;
+            cleanup_ncci_data (plci, ncci);
+            nl_req_ncci(plci,N_DISC,(byte)ncci);
+          }
+          break;
+        }
+        break;
+
+      case HOOK_OFF_REQ:
+        if (plci->State == INC_DIS_PENDING)
+          break;
+        sig_req(plci,CALL_REQ,0);
+        send_req(plci);
+        plci->State=OUTG_CON_PENDING;
+        break;
+
+
+      case MWI_ACTIVATE_REQ_PEND:
+      case MWI_DEACTIVATE_REQ_PEND:
+        if(global_req == ASSIGN && rc==ASSIGN_OK)
+        {
+          dbug(1,dprintf("MWI_REQ assigned"));
+          return;
+        }
+        else if(rc!=OK)
+        {                 
+          if(rc==WRONG_IE)
+          {
+            Info = 0x2007; /* Illegal message parameter coding */
+            dbug(1,dprintf("MWI_REQ invalid parameter"));
+          }
+          else
+          {
+            Info = 0x300B; /* not supported */                      
+            dbug(1,dprintf("MWI_REQ not supported"));
+          }
+          /* 0x3010: Request not allowed in this state */
+          PUT_WORD(&SSparms[4],0x300E); /* SS not supported */
+                    
+        }
+        if(plci->internal_command==MWI_ACTIVATE_REQ_PEND)
+        {
+          PUT_WORD(&SSparms[1],S_MWI_ACTIVATE);
+        }
+        else PUT_WORD(&SSparms[1],S_MWI_DEACTIVATE);
+
+        if(plci->cr_enquiry)
+        {
+          sendf(plci->appl,
+                _FACILITY_R|CONFIRM,
+                Id&0xf,
+                plci->number,
+                "wws",Info,(word)3,SSparms);
+          if(rc!=OK) plci_remove(plci);
+        }
+        else
+        {
+          sendf(plci->appl,
+                _FACILITY_R|CONFIRM,
+                Id,
+                plci->number,
+                "wws",Info,(word)3,SSparms);
+        }
+        break;
+
+      case CONF_BEGIN_REQ_PEND:
+      case CONF_ADD_REQ_PEND:
+      case CONF_SPLIT_REQ_PEND:
+      case CONF_DROP_REQ_PEND:
+      case CONF_ISOLATE_REQ_PEND:
+      case CONF_REATTACH_REQ_PEND:
+        dbug(1,dprintf("CONF_RC=0x%x/0x%x",req,rc));
+        if((plci->internal_command==CONF_ADD_REQ_PEND)&&(!plci->relatedPTYPLCI)) break;
+        rplci = plci;
+        rId = Id;
+        switch(plci->internal_command)
+        {
+          case CONF_BEGIN_REQ_PEND:
+            SSparms[1] = S_CONF_BEGIN;
+            break;
+          case CONF_ADD_REQ_PEND:
+            SSparms[1] = S_CONF_ADD;
+            rplci = plci->relatedPTYPLCI;
+            rId = ((word)rplci->Id<<8)|rplci->adapter->Id;
+            break;
+          case CONF_SPLIT_REQ_PEND:
+            SSparms[1] = S_CONF_SPLIT;
+            break;
+          case CONF_DROP_REQ_PEND:
+            SSparms[1] = S_CONF_DROP;
+            break;
+          case CONF_ISOLATE_REQ_PEND:
+            SSparms[1] = S_CONF_ISOLATE;
+            break;
+          case CONF_REATTACH_REQ_PEND:
+            SSparms[1] = S_CONF_REATTACH;
+            break;
+        }
+        
+        if(rc!=OK)
+        {
+          Info = 0x300E; /* not supported */
+          plci->relatedPTYPLCI = NULL;
+          plci->ptyState = 0;
+        }
+        sendf(rplci->appl,
+              _FACILITY_R|CONFIRM,
+              rId,
+              plci->number,
+              "wws",Info,(word)3,SSparms);
+        break;
+
+      case VSWITCH_REQ_PEND:
+        if(rc!=OK)
+        {
+          if(plci->relatedPTYPLCI)
+          {
+            plci->relatedPTYPLCI->vswitchstate=0;
+            plci->relatedPTYPLCI->vsprot=0;
+            plci->relatedPTYPLCI->vsprotdialect=0;    
+          }
+          plci->vswitchstate=0;
+          plci->vsprot=0;
+          plci->vsprotdialect=0;
+        }
+        else
+        {
+          if(plci->relatedPTYPLCI &&
+             plci->vswitchstate==1 &&
+             plci->relatedPTYPLCI->vswitchstate==3) /* join complete */
+            plci->vswitchstate=3;
+        }
+        break;
+
+  /* Call Deflection Request pending (SSCT) */
+      case CD_REQ_PEND:
+        SSparms[1] = S_CALL_DEFLECTION;
+        if(rc!=OK)
+        {
+          Info = 0x300E; /* not supported */
+          plci->appl->CDEnable = 0;
+        }  
+        sendf(plci->appl,_FACILITY_R|CONFIRM,Id,
+          plci->number,"wws",Info,(word)3,SSparms);
+        break;
+
+      case RTP_CONNECT_B3_REQ_COMMAND_2:
+        if (rc == OK)
+        {
+          ncci = get_ncci (plci, ch, 0);
+          Id = (Id & 0xffff) | (((dword) ncci) << 16);
+          plci->channels++;
+          a->ncci_state[ncci] = OUTG_CON_PENDING;
+        }
+
+      default:
+        if (plci->internal_command_queue[0])
+        {
+          (*(plci->internal_command_queue[0]))(Id, plci, rc);
+          if (plci->internal_command)
+            return;
+        }
+        break;
+      }
+      next_internal_command (Id, plci);
+    }
+  }
+  else /* appl==0 */
+  {
+    Id = ((word)plci->Id<<8)|plci->adapter->Id;
+    if(plci->tel) Id|=EXT_CONTROLLER;
+
+    switch(plci->internal_command)
+    {
+    case BLOCK_PLCI:
+      return;
+
+    case START_L1_SIG_ASSIGN_PEND:
+    case REM_L1_SIG_ASSIGN_PEND:
+      if(global_req == ASSIGN)
+      {
+        break;
+      }
+      else
+      {
+        dbug(1,dprintf("***L1 Req rem PLCI"));
+        plci->internal_command = 0;
+        sig_req(plci,REMOVE,0);
+        send_req(plci);
+      }
+      break;
+
+      /* Call Deflection Request pending, just no appl ptr assigned */
+    case CD_REQ_PEND:
+      SSparms[1] = S_CALL_DEFLECTION;
+      if(rc!=OK)
+      {
+        Info = 0x300E; /* not supported */
+      }
+      for(i=0; i<max_appl; i++)
+      {
+        if(application[i].CDEnable)
+        {
+          if(!application[i].Id) application[i].CDEnable = 0;
+          else
+          {
+            sendf(&application[i],_FACILITY_R|CONFIRM,Id,
+                  plci->number,"wws",Info,(word)3,SSparms);
+            if(Info) application[i].CDEnable = 0;
+          }
+        }
+      }
+      plci->internal_command = 0;
+      break;
+
+    case PERM_COD_HOOK:                   /* finished with Hook_Ind */
+      return;
+
+    case PERM_COD_CALL:
+      plci->internal_command = PERM_COD_CONN_PEND;
+      dbug(1,dprintf("***Codec Connect_Pending, Rc = 0x%x",rc));
+      return;
+
+    case PERM_COD_ASSIGN:
+      dbug(1,dprintf("***Codec Assign, Rc = 0x%x",rc));
+      plci->internal_command = 0;
+      if(rc!=ASSIGN_OK) break;
+      plci->internal_command = PERM_COD_CALL;
+      sig_req(plci,CALL_REQ,0);
+      send_req(plci);
+      return;
+
+    case LISTEN_SIG_ASSIGN_PEND:
+      if(rc == ASSIGN_OK)
+      {
+        plci->internal_command = 0;
+        dbug(1,dprintf("ListenCheck, new SIG_ID = 0x%x",plci->Sig.Id));
+        add_p(plci,ESC,"\x02\x18\x00");             /* support call waiting */
+        sig_req(plci,INDICATE_REQ,0);
+        send_req(plci);
+      }
+      else
+      {
+        dbug(1,dprintf("ListenCheck failed (assignRc=0x%x)",rc));
+        a->listen_active--;
+        plci_remove(plci);
+        plci->State = IDLE;
+      }
+      break;
+
+    case USELAW_REQ:
+      if(global_req == ASSIGN)
+      {
+        if (rc==ASSIGN_OK)
+      {
+        sig_req(plci,LAW_REQ,0);
+        send_req(plci);
+        dbug(1,dprintf("Auto-Law assigned"));
+        }
+        else
+        {
+          dbug(1,dprintf("Auto-Law assign failed"));
+          a->automatic_law = 3;
+          plci->internal_command = 0;
+          a->automatic_lawPLCI = NULL;
+        }
+        break;
+      }
+      else if(req == LAW_REQ && rc==OK)
+      {
+        dbug(1,dprintf("Auto-Law initiated"));
+        a->automatic_law = 2;
+        plci->internal_command = 0;
+      }
+      else
+      {
+        dbug(1,dprintf("Auto-Law not supported"));
+        a->automatic_law = 3;
+        plci->internal_command = 0;
+        sig_req(plci,REMOVE,0);
+        send_req(plci);
+        a->automatic_lawPLCI = NULL;
+      }
+      break;
+    }
+    plci_remove_check(plci);
+  }
+}
+
+void data_rc(PLCI   * plci, byte ch)
+{
+  dword Id;
+  DIVA_CAPI_ADAPTER   * a;
+  NCCI   *ncci_ptr;
+  DATA_B3_DESC   *data;
+  word ncci;
+
+  if (plci->appl)
+  {
+    TransmitBufferFree (plci->appl, plci->data_sent_ptr);
+    a = plci->adapter;
+    ncci = a->ch_ncci[ch];
+    if (ncci && (a->ncci_plci[ncci] == plci->Id))
+    {
+      ncci_ptr = &(a->ncci[ncci]);
+      dbug(1,dprintf("data_out=%d, data_pending=%d",ncci_ptr->data_out,ncci_ptr->data_pending));
+      if (ncci_ptr->data_pending)
+      {
+        data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]);
+        if (!(data->Flags &4) && a->ncci_state[ncci])
+        {
+          Id = (((dword)ncci)<<16)|((word)plci->Id<<8)|a->Id;
+          if(plci->tel) Id|=EXT_CONTROLLER;
+          sendf(plci->appl,_DATA_B3_R|CONFIRM,Id,data->Number,
+                "ww",data->Handle,0);
+        }
+        (ncci_ptr->data_out)++;
+        if (ncci_ptr->data_out == MAX_DATA_B3)
+          ncci_ptr->data_out = 0;
+        (ncci_ptr->data_pending)--;
+      }
+    }
+  }
+}
+
+void data_ack(PLCI   * plci, byte ch)
+{
+  dword Id;
+  DIVA_CAPI_ADAPTER   * a;
+  NCCI   *ncci_ptr;
+  word ncci;
+
+  a = plci->adapter;
+  ncci = a->ch_ncci[ch];
+  ncci_ptr = &(a->ncci[ncci]);
+  if (ncci_ptr->data_ack_pending)
+  {
+    if (a->ncci_state[ncci] && (a->ncci_plci[ncci] == plci->Id))
+    {
+      Id = (((dword)ncci)<<16)|((word)plci->Id<<8)|a->Id;
+      if(plci->tel) Id|=EXT_CONTROLLER;
+      sendf(plci->appl,_DATA_B3_R|CONFIRM,Id,ncci_ptr->DataAck[ncci_ptr->data_ack_out].Number,
+            "ww",ncci_ptr->DataAck[ncci_ptr->data_ack_out].Handle,0);
+    }
+    (ncci_ptr->data_ack_out)++;
+    if (ncci_ptr->data_ack_out == MAX_DATA_ACK)
+      ncci_ptr->data_ack_out = 0;
+    (ncci_ptr->data_ack_pending)--;
+  }
+}
+
+void sig_ind(PLCI   * plci)
+{
+  dword x_Id;
+  dword Id;
+  dword rId;
+  word Number = 0;
+  word i;
+  word cip;
+  dword cip_mask;
+  byte   *ie;
+  DIVA_CAPI_ADAPTER   * a;
+    API_PARSE saved_parms[MAX_MSG_PARMS+1];
+#define MAXPARMSIDS 31
+    byte   * parms[MAXPARMSIDS];
+    byte   * add_i[4];
+    byte   * multi_fac_parms[MAX_MULTI_IE];
+    byte   * multi_pi_parms [MAX_MULTI_IE];
+    byte   * multi_ssext_parms [MAX_MULTI_IE];
+    byte   * multi_CiPN_parms [MAX_MULTI_IE];
+
+    byte   * multi_vswitch_parms [MAX_MULTI_IE];
+
+  byte ai_len;
+    byte   *esc_chi = "";
+    byte   *esc_law = "";
+    byte   *pty_cai = "";
+    byte   *esc_cr  = "";
+    byte   *esc_profile = "";
+
+    byte facility[256];
+  PLCI   * tplci = NULL;
+  byte chi[] = "\x02\x18\x01";
+  byte voice_cai[]  = "\x06\x14\x00\x00\x00\x00\x08";
+    byte resume_cau[] = "\x05\x05\x00\x02\x00\x00";
+  /* ESC_MSGTYPE must be the last but one message, a new IE has to be */
+  /* included before the ESC_MSGTYPE and MAXPARMSIDS has to be incremented */
+  /* SMSG is situated at the end because its 0 (for compatibility reasons */
+  /* (see Info_Mask Bit 4, first IE. then the message type)           */
+    word parms_id[] =
+         {MAXPARMSIDS, CPN, 0xff, DSA, OSA, BC, LLC, HLC, ESC_CAUSE, DSP, DT, CHA,
+          UUI, CONG_RR, CONG_RNR, ESC_CHI, KEY, CHI, CAU, ESC_LAW,
+          RDN, RDX, CONN_NR, RIN, NI, CAI, ESC_CR,
+          CST, ESC_PROFILE, 0xff, ESC_MSGTYPE, SMSG};
+          /* 14 FTY repl by ESC_CHI */
+          /* 18 PI  repl by ESC_LAW */
+         /* removed OAD changed to 0xff for future use, OAD is multiIE now */
+     word multi_fac_id[] = {1, FTY};
+     word multi_pi_id[]  = {1, PI};
+     word multi_CiPN_id[]  = {1, OAD};
+     word multi_ssext_id[]  = {1, ESC_SSEXT};
+
+     word multi_vswitch_id[]  = {1, ESC_VSWITCH};
+
+  byte   * cau;
+  word ncci;
+    byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
+    byte CF_Ind[] = "\x09\x02\x00\x06\x00\x00\x00\x00\x00\x00";
+    byte Interr_Err_Ind[] = "\x0a\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+    byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\0x00\0x00\0x00\0x00";
+  byte force_mt_info = FALSE;
+  byte dir;
+  dword d;
+  word w;
+
+  a = plci->adapter;
+  Id = ((word)plci->Id<<8)|a->Id;
+  PUT_WORD(&SS_Ind[4],0x0000);
+
+  if (plci->sig_remove_id)
+  {
+    plci->Sig.RNR = 2; /* discard */
+    dbug(1,dprintf("SIG discard while remove pending"));
+    return;
+  }
+  if(plci->tel && plci->SuppState!=CALL_HELD) Id|=EXT_CONTROLLER;
+  dbug(1,dprintf("SigInd-Id=%08lx,plci=%x,tel=%x,state=0x%x,channels=%d,Discflowcl=%d",
+    Id,plci->Id,plci->tel,plci->State,plci->channels,plci->hangup_flow_ctrl_timer));
+  if(plci->Sig.Ind==CALL_HOLD_ACK && plci->channels)
+  {
+    plci->Sig.RNR = 1;
+    return;
+  }
+  if(plci->Sig.Ind==HANGUP && plci->channels)
+  {
+    plci->Sig.RNR = 1;
+    plci->hangup_flow_ctrl_timer++;
+    /* recover the network layer after timeout */
+    if(plci->hangup_flow_ctrl_timer==100)
+    {
+      dbug(1,dprintf("Exceptional disc"));
+      plci->Sig.RNR = 0;
+      plci->hangup_flow_ctrl_timer = 0;
+      for (ncci = 1; ncci < MAX_NCCI+1; ncci++)
+      {
+        if (a->ncci_plci[ncci] == plci->Id)
+        {
+          cleanup_ncci_data (plci, ncci);
+          if(plci->channels)plci->channels--;
+          if (plci->appl)
+            sendf(plci->appl,_DISCONNECT_B3_I, (((dword) ncci) << 16) | Id,0,"ws",0,"");
+        }
+      }
+      if (plci->appl)
+        sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0);
+      plci_remove(plci);
+      plci->State=IDLE;
+    }
+    return;
+  }
+
+  /* do first parse the info with no OAD in, because OAD will be converted */
+  /* first the multiple facility IE, then mult. progress ind.              */
+  /* then the parameters for the info_ind + conn_ind                       */
+  IndParse(plci,multi_fac_id,multi_fac_parms,MAX_MULTI_IE);
+  IndParse(plci,multi_pi_id,multi_pi_parms,MAX_MULTI_IE);
+  IndParse(plci,multi_ssext_id,multi_ssext_parms,MAX_MULTI_IE);
+
+  IndParse(plci,multi_vswitch_id,multi_vswitch_parms,MAX_MULTI_IE);
+
+  IndParse(plci,parms_id,parms,0);
+  IndParse(plci,multi_CiPN_id,multi_CiPN_parms,MAX_MULTI_IE);
+  esc_chi  = parms[14];
+  esc_law  = parms[18];
+  pty_cai  = parms[24];
+  esc_cr   = parms[25];
+  esc_profile = parms[27];
+  if(esc_cr[0] && plci)
+  {
+    if(plci->cr_enquiry && plci->appl)
+    {
+      plci->cr_enquiry = FALSE;
+      /* d = MANU_ID            */
+      /* w = m_command          */
+      /* b = total length       */
+      /* b = indication type    */
+      /* b = length of all IEs  */
+      /* b = IE1                */
+      /* S = IE1 length + cont. */
+      /* b = IE2                */
+      /* S = IE2 lenght + cont. */
+      sendf(plci->appl,
+        _MANUFACTURER_I,
+        Id,
+        0,
+        "dwbbbbSbS",_DI_MANU_ID,plci->m_command,
+        2+1+1+esc_cr[0]+1+1+esc_law[0],plci->Sig.Ind,1+1+esc_cr[0]+1+1+esc_law[0],ESC,esc_cr,ESC,esc_law);
+    }
+  }
+  /* create the additional info structure                                  */
+  add_i[1] = parms[15]; /* KEY of additional info */
+  add_i[2] = parms[11]; /* UUI of additional info */
+  ai_len = AddInfo(add_i,multi_fac_parms, esc_chi, facility);
+
+  /* the ESC_LAW indicates if u-Law or a-Law is actually used by the card  */
+  /* indication returns by the card if requested by the function           */
+  /* AutomaticLaw() after driver init                                      */
+  if (a->automatic_law<4)
+  {
+    if(esc_law[0]){
+      if(esc_law[2]){
+        dbug(0,dprintf("u-Law selected"));
+        a->u_law = 1;
+      }
+      else {
+        dbug(0,dprintf("a-Law selected"));
+        a->u_law = 0;
+      }
+      a->automatic_law = 4;
+      if(plci==a->automatic_lawPLCI) {
+        plci->internal_command = 0;
+        sig_req(plci,REMOVE,0);
+        send_req(plci);
+        a->automatic_lawPLCI = NULL;
+      }
+    }
+    if (esc_profile[0])
+    {
+      dbug (1, dprintf ("[%06x] CardProfile: %lx %lx %lx %lx %lx",
+        UnMapController (a->Id), GET_DWORD (&esc_profile[6]),
+        GET_DWORD (&esc_profile[10]), GET_DWORD (&esc_profile[14]),
+        GET_DWORD (&esc_profile[18]), GET_DWORD (&esc_profile[46])));
+
+      a->profile.Global_Options &= 0x000000ffL;
+      a->profile.B1_Protocols &= 0x000003ffL;
+      a->profile.B2_Protocols &= 0x00001fdfL;
+      a->profile.B3_Protocols &= 0x000000b7L;
+
+      a->profile.Global_Options &= GET_DWORD (&esc_profile[6]) |
+        GL_BCHANNEL_OPERATION_SUPPORTED;
+      a->profile.B1_Protocols &= GET_DWORD (&esc_profile[10]);
+      a->profile.B2_Protocols &= GET_DWORD (&esc_profile[14]);
+      a->profile.B3_Protocols &= GET_DWORD (&esc_profile[18]);
+      a->manufacturer_features = GET_DWORD (&esc_profile[46]);
+      a->man_profile.private_options = 0;
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_ECHO_CANCELLER)
+      {
+        a->man_profile.private_options |= 1L << PRIVATE_ECHO_CANCELLER;
+        a->profile.Global_Options |= GL_ECHO_CANCELLER_SUPPORTED;
+      }
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_RTP)
+        a->man_profile.private_options |= 1L << PRIVATE_RTP;
+      a->man_profile.rtp_primary_payloads = GET_DWORD (&esc_profile[50]);
+      a->man_profile.rtp_additional_payloads = GET_DWORD (&esc_profile[54]);
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_T38)
+        a->man_profile.private_options |= 1L << PRIVATE_T38;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD)
+        a->man_profile.private_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_V18)
+        a->man_profile.private_options |= 1L << PRIVATE_V18;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_DTMF_TONE)
+        a->man_profile.private_options |= 1L << PRIVATE_DTMF_TONE;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_PIAFS)
+        a->man_profile.private_options |= 1L << PRIVATE_PIAFS;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+        a->man_profile.private_options |= 1L << PRIVATE_FAX_PAPER_FORMATS;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_VOWN)
+        a->man_profile.private_options |= 1L << PRIVATE_VOWN;
+
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_NONSTANDARD)
+        a->man_profile.private_options |= 1L << PRIVATE_FAX_NONSTANDARD;
+
+    }
+    else
+    {
+      a->profile.Global_Options &= 0x0000007fL;
+      a->profile.B1_Protocols &= 0x000003dfL;
+      a->profile.B2_Protocols &= 0x00001adfL;
+      a->profile.B3_Protocols &= 0x000000b7L;
+      a->manufacturer_features &= MANUFACTURER_FEATURE_HARDDTMF;
+    }
+    if (a->manufacturer_features & (MANUFACTURER_FEATURE_HARDDTMF |
+      MANUFACTURER_FEATURE_SOFTDTMF_SEND | MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
+    {
+      a->profile.Global_Options |= GL_DTMF_SUPPORTED;
+    }
+    a->manufacturer_features &= ~MANUFACTURER_FEATURE_OOB_CHANNEL;
+    dbug (1, dprintf ("[%06x] Profile: %lx %lx %lx %lx %lx",
+      UnMapController (a->Id), a->profile.Global_Options,
+      a->profile.B1_Protocols, a->profile.B2_Protocols,
+      a->profile.B3_Protocols, a->manufacturer_features));
+  }
+  /* codec plci for the handset/hook state support is just an internal id  */
+  if(plci!=a->AdvCodecPLCI)
+  {
+    force_mt_info =  SendMultiIE(plci,Id,multi_fac_parms, FTY, 0x20, 0);
+    force_mt_info |= SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, 0);
+    SendSSExtInd(NULL,plci,Id,multi_ssext_parms);
+    SendInfo(plci,Id, parms, force_mt_info);
+
+    VSwitchReqInd(plci,Id,multi_vswitch_parms);
+
+  }
+
+  /* switch the codec to the b-channel                                     */
+  if(esc_chi[0] && plci && !plci->SuppState){
+    plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
+    mixer_set_bchannel_id_esc (plci, plci->b_channel);
+    dbug(1,dprintf("storeChannel=0x%x",plci->b_channel));
+    if(plci->tel==ADV_VOICE && plci->appl) {
+      SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a);
+    }
+  }
+
+  if(plci->appl) Number = plci->appl->Number++;
+
+  switch(plci->Sig.Ind) {
+  /* Response to Get_Supported_Services request */
+  case S_SUPPORTED:
+    dbug(1,dprintf("S_Supported"));
+    if(!plci->appl) break;
+    if(pty_cai[0]==4)
+    {
+      PUT_DWORD(&CF_Ind[6],GET_DWORD(&pty_cai[1]) );
+    }
+    else
+    {
+      PUT_DWORD(&CF_Ind[6],MASK_TERMINAL_PORTABILITY | MASK_HOLD_RETRIEVE);
+    }
+    PUT_WORD (&CF_Ind[1], 0);
+    PUT_WORD (&CF_Ind[4], 0);
+    sendf(plci->appl,_FACILITY_R|CONFIRM,Id&0x7,plci->number, "wws",0,3,CF_Ind);
+    plci_remove(plci);
+    break;
+                    
+  /* Supplementary Service rejected */
+  case S_SERVICE_REJ:
+    dbug(1,dprintf("S_Reject=0x%x",pty_cai[5]));
+    if(!pty_cai[0]) break;
+    switch (pty_cai[5])
+    {
+    case ECT_EXECUTE:
+    case THREE_PTY_END:
+    case THREE_PTY_BEGIN:
+      if(!plci->relatedPTYPLCI) break;
+      tplci = plci->relatedPTYPLCI;
+      rId = ( (word)tplci->Id<<8)|tplci->adapter->Id;
+      if(tplci->tel) rId|=EXT_CONTROLLER;
+      if(pty_cai[5]==ECT_EXECUTE)
+      {
+        PUT_WORD(&SS_Ind[1],S_ECT);
+
+        plci->vswitchstate=0;
+        plci->relatedPTYPLCI->vswitchstate=0;
+
+      }
+      else
+      {
+        PUT_WORD(&SS_Ind[1],pty_cai[5]+3);
+      }
+      if(pty_cai[2]!=0xff)
+      {
+        PUT_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        PUT_WORD(&SS_Ind[4],0x300E);
+      }
+      plci->relatedPTYPLCI = NULL;
+      plci->ptyState = 0;
+      sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
+      break;
+
+    case CALL_DEFLECTION:
+      if(pty_cai[2]!=0xff)
+      {
+        PUT_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        PUT_WORD(&SS_Ind[4],0x300E);
+      }
+      PUT_WORD(&SS_Ind[1],pty_cai[5]);
+      for(i=0; i<max_appl; i++)
+      {
+        if(application[i].CDEnable)
+        {
+          if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind);
+          application[i].CDEnable = FALSE;
+        }
+      }
+      break;
+
+    case DEACTIVATION_DIVERSION:
+    case ACTIVATION_DIVERSION:
+    case DIVERSION_INTERROGATE_CFU:
+    case DIVERSION_INTERROGATE_CFB:
+    case DIVERSION_INTERROGATE_CFNR:
+    case DIVERSION_INTERROGATE_NUM:
+    case CCBS_REQUEST:
+    case CCBS_DEACTIVATE:
+    case CCBS_INTERROGATE:
+      if(!plci->appl) break;
+      if(pty_cai[2]!=0xff)
+      {
+        PUT_WORD(&Interr_Err_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        PUT_WORD(&Interr_Err_Ind[4],0x300E);
+      }
+      switch (pty_cai[5])
+      {
+        case DEACTIVATION_DIVERSION:
+          dbug(1,dprintf("Deact_Div"));
+          Interr_Err_Ind[0]=0x9;
+          Interr_Err_Ind[3]=0x6;
+          PUT_WORD(&Interr_Err_Ind[1],S_CALL_FORWARDING_STOP);
+          break;
+        case ACTIVATION_DIVERSION:
+          dbug(1,dprintf("Act_Div"));
+          Interr_Err_Ind[0]=0x9;
+          Interr_Err_Ind[3]=0x6;
+          PUT_WORD(&Interr_Err_Ind[1],S_CALL_FORWARDING_START);
+          break;
+        case DIVERSION_INTERROGATE_CFU:
+        case DIVERSION_INTERROGATE_CFB:
+        case DIVERSION_INTERROGATE_CFNR:
+          dbug(1,dprintf("Interr_Div"));
+          Interr_Err_Ind[0]=0xa;
+          Interr_Err_Ind[3]=0x7;
+          PUT_WORD(&Interr_Err_Ind[1],S_INTERROGATE_DIVERSION);
+          break;
+        case DIVERSION_INTERROGATE_NUM:
+          dbug(1,dprintf("Interr_Num"));
+          Interr_Err_Ind[0]=0xa;
+          Interr_Err_Ind[3]=0x7;
+          PUT_WORD(&Interr_Err_Ind[1],S_INTERROGATE_NUMBERS);
+          break;
+        case CCBS_REQUEST:
+          dbug(1,dprintf("CCBS Request"));
+          Interr_Err_Ind[0]=0xd;
+          Interr_Err_Ind[3]=0xa;
+          PUT_WORD(&Interr_Err_Ind[1],S_CCBS_REQUEST);
+          break;
+        case CCBS_DEACTIVATE:
+          dbug(1,dprintf("CCBS Deactivate"));
+          Interr_Err_Ind[0]=0x9;
+          Interr_Err_Ind[3]=0x6;
+          PUT_WORD(&Interr_Err_Ind[1],S_CCBS_DEACTIVATE);
+          break;
+        case CCBS_INTERROGATE:
+          dbug(1,dprintf("CCBS Interrogate"));
+          Interr_Err_Ind[0]=0xb;
+          Interr_Err_Ind[3]=0x8;
+          PUT_WORD(&Interr_Err_Ind[1],S_CCBS_INTERROGATE);
+          break;
+      }
+      PUT_DWORD(&Interr_Err_Ind[6],plci->appl->S_Handle);
+      sendf(plci->appl,_FACILITY_I,Id&0x7,0,"ws",3, Interr_Err_Ind);
+      plci_remove(plci);
+      break;
+    case ACTIVATION_MWI:      
+    case DEACTIVATION_MWI:
+      if(pty_cai[5]==ACTIVATION_MWI)
+      {
+        PUT_WORD(&SS_Ind[1],S_MWI_ACTIVATE);
+      }
+      else PUT_WORD(&SS_Ind[1],S_MWI_DEACTIVATE);
+      
+      if(pty_cai[2]!=0xff)
+      {
+        PUT_WORD(&SS_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        PUT_WORD(&SS_Ind[4],0x300E);
+      }
+
+      if(plci->cr_enquiry)
+      {
+        sendf(plci->appl,_FACILITY_I,Id&0xf,0,"ws",3, SS_Ind);
+        plci_remove(plci);
+      }
+      else
+      {
+        sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+      }
+      break;
+    case CONF_ADD: /* ERROR */
+    case CONF_BEGIN:
+    case CONF_DROP:
+    case CONF_ISOLATE:
+    case CONF_REATTACH:
+      CONF_Ind[0]=9;
+      CONF_Ind[3]=6;   
+      switch(pty_cai[5])
+      {
+      case CONF_BEGIN:
+          PUT_WORD(&CONF_Ind[1],S_CONF_BEGIN);
+          plci->ptyState = 0;
+          break;
+      case CONF_DROP:
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          PUT_WORD(&CONF_Ind[1],S_CONF_DROP);
+          plci->ptyState = CONNECTED;
+          break;
+      case CONF_ISOLATE:
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          PUT_WORD(&CONF_Ind[1],S_CONF_ISOLATE);
+          plci->ptyState = CONNECTED;
+          break;
+      case CONF_REATTACH:
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          PUT_WORD(&CONF_Ind[1],S_CONF_REATTACH);
+          plci->ptyState = CONNECTED;
+          break;
+      case CONF_ADD:
+          PUT_WORD(&CONF_Ind[1],S_CONF_ADD);
+          plci->relatedPTYPLCI = NULL;
+          tplci=plci->relatedPTYPLCI;
+          if(tplci) tplci->ptyState = CONNECTED;
+          plci->ptyState = CONNECTED;
+          break;
+      }
+          
+      if(pty_cai[2]!=0xff)
+      {
+        PUT_WORD(&CONF_Ind[4],0x3600|(word)pty_cai[2]);
+      }
+      else
+      {
+        PUT_WORD(&CONF_Ind[4],0x3303); /* Time-out: network did not respond
+                                            within the required time */
+      }
+
+      PUT_DWORD(&CONF_Ind[6],0x0);
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
+      break;
+    }
+    break;
+
+  /* Supplementary Service indicates success */
+  case S_SERVICE:
+    dbug(1,dprintf("Service_Ind"));
+    PUT_WORD (&CF_Ind[4], 0);
+    switch (pty_cai[5])
+    {
+    case THREE_PTY_END:
+    case THREE_PTY_BEGIN:
+    case ECT_EXECUTE:
+      if(!plci->relatedPTYPLCI) break;
+      tplci = plci->relatedPTYPLCI;
+      rId = ( (word)tplci->Id<<8)|tplci->adapter->Id;
+      if(tplci->tel) rId|=EXT_CONTROLLER;
+      if(pty_cai[5]==ECT_EXECUTE)
+      {
+        PUT_WORD(&SS_Ind[1],S_ECT);
+
+        if(plci->vswitchstate!=3)
+        {
+
+        plci->ptyState = IDLE;
+        plci->relatedPTYPLCI = NULL;
+        plci->ptyState = 0;
+
+        }
+
+        dbug(1,dprintf("ECT OK"));
+        sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
+
+
+
+      }
+      else
+      {
+        switch (plci->ptyState)
+        {
+        case S_3PTY_BEGIN:
+          plci->ptyState = CONNECTED;
+          dbug(1,dprintf("3PTY ON"));
+          break;
+
+        case S_3PTY_END:
+          plci->ptyState = IDLE;
+          plci->relatedPTYPLCI = NULL;
+          plci->ptyState = 0;
+          dbug(1,dprintf("3PTY OFF"));
+          break;
+        }
+        PUT_WORD(&SS_Ind[1],pty_cai[5]+3);
+        sendf(tplci->appl,_FACILITY_I,rId,0,"ws",3, SS_Ind);
+      }
+      break;
+
+    case CALL_DEFLECTION:
+      PUT_WORD(&SS_Ind[1],pty_cai[5]);
+      for(i=0; i<max_appl; i++)
+      {
+        if(application[i].CDEnable)
+        {
+          if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind);
+          application[i].CDEnable = FALSE;
+        }
+      }
+      break;
+
+    case DEACTIVATION_DIVERSION:
+    case ACTIVATION_DIVERSION:
+      if(!plci->appl) break;
+      PUT_WORD(&CF_Ind[1],pty_cai[5]+2);
+      PUT_DWORD(&CF_Ind[6],plci->appl->S_Handle);
+      sendf(plci->appl,_FACILITY_I,Id&0x7,0,"ws",3, CF_Ind);
+      plci_remove(plci);
+      break;
+
+    case DIVERSION_INTERROGATE_CFU:
+    case DIVERSION_INTERROGATE_CFB:
+    case DIVERSION_INTERROGATE_CFNR:
+    case DIVERSION_INTERROGATE_NUM:
+    case CCBS_REQUEST:
+    case CCBS_DEACTIVATE:
+    case CCBS_INTERROGATE:
+      if(!plci->appl) break;
+      switch (pty_cai[5])
+      {
+        case DIVERSION_INTERROGATE_CFU:
+        case DIVERSION_INTERROGATE_CFB:
+        case DIVERSION_INTERROGATE_CFNR:
+          dbug(1,dprintf("Interr_Div"));
+          PUT_WORD(&pty_cai[1],S_INTERROGATE_DIVERSION);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+        case DIVERSION_INTERROGATE_NUM:
+          dbug(1,dprintf("Interr_Num"));
+          PUT_WORD(&pty_cai[1],S_INTERROGATE_NUMBERS);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+        case CCBS_REQUEST:
+          dbug(1,dprintf("CCBS Request"));
+          PUT_WORD(&pty_cai[1],S_CCBS_REQUEST);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+        case CCBS_DEACTIVATE:
+          dbug(1,dprintf("CCBS Deactivate"));
+          PUT_WORD(&pty_cai[1],S_CCBS_DEACTIVATE);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+        case CCBS_INTERROGATE:
+          dbug(1,dprintf("CCBS Interrogate"));
+          PUT_WORD(&pty_cai[1],S_CCBS_INTERROGATE);
+          pty_cai[3]=pty_cai[0]-3; /* Supplementary Service-specific parameter len */
+          break;
+      }
+      PUT_WORD(&pty_cai[4],0); /* Supplementary Service Reason */
+      PUT_DWORD(&pty_cai[6],plci->appl->S_Handle);
+      sendf(plci->appl,_FACILITY_I,Id&0x7,0,"wS",3, pty_cai);
+      plci_remove(plci);
+      break;
+
+    case ACTIVATION_MWI:
+    case DEACTIVATION_MWI:
+      if(pty_cai[5]==ACTIVATION_MWI)
+      {
+        PUT_WORD(&SS_Ind[1],S_MWI_ACTIVATE);
+      }
+      else PUT_WORD(&SS_Ind[1],S_MWI_DEACTIVATE);
+      if(plci->cr_enquiry)
+      {
+        sendf(plci->appl,_FACILITY_I,Id&0xf,0,"ws",3, SS_Ind);
+        plci_remove(plci);
+      }
+      else
+      {
+        sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+      }
+      break;
+    case MWI_INDICATION:
+      if(pty_cai[0]>=0x12)
+      {
+        PUT_WORD(&pty_cai[3],S_MWI_INDICATE);
+        pty_cai[2]=pty_cai[0]-2; /* len Parameter */
+        pty_cai[5]=pty_cai[0]-5; /* Supplementary Service-specific parameter len */
+        if(plci->appl && (a->Notification_Mask[plci->appl->Id-1]&SMASK_MWI))
+        {
+          if(plci->internal_command==GET_MWI_STATE) /* result on Message Waiting Listen */
+          {
+            sendf(plci->appl,_FACILITY_I,Id&0xf,0,"wS",3, &pty_cai[2]);
+            plci_remove(plci);
+            return;
+          }
+          else  sendf(plci->appl,_FACILITY_I,Id,0,"wS",3, &pty_cai[2]);
+          pty_cai[0]=0;
+        }
+        else
+        {
+          for(i=0; i<max_appl; i++)
+          {                     
+            if(a->Notification_Mask[i]&SMASK_MWI)
+            {
+              sendf(&application[i],_FACILITY_I,Id&0x7,0,"wS",3, &pty_cai[2]);
+              pty_cai[0]=0;
+            }
+          }
+        }
+
+        if(!pty_cai[0])
+        { /* acknowledge */
+          facility[2]= 0; /* returncode */
+        }
+        else facility[2]= 0xff;
+      }
+      else
+      {
+        /* reject */
+        facility[2]= 0xff; /* returncode */
+      }
+      facility[0]= 2;
+      facility[1]= MWI_RESPONSE; /* Function */
+      add_p(plci,CAI,facility);
+      add_p(plci,ESC,multi_ssext_parms[0]); /* remembered parameter -> only one possible */
+      sig_req(plci,S_SERVICE,0);
+      send_req(plci);
+      plci->command = 0;
+      next_internal_command (Id, plci);
+      break;
+    case CONF_ADD: /* OK */
+    case CONF_BEGIN:
+    case CONF_DROP:
+    case CONF_ISOLATE:
+    case CONF_REATTACH:
+    case CONF_PARTYDISC:
+      CONF_Ind[0]=9;
+      CONF_Ind[3]=6;
+      switch(pty_cai[5])
+      {
+      case CONF_BEGIN:
+          PUT_WORD(&CONF_Ind[1],S_CONF_BEGIN);
+          if(pty_cai[0]==6)
+          {
+              d=pty_cai[6];
+              PUT_DWORD(&CONF_Ind[6],d); /* PartyID */
+          }
+          else
+          {
+              PUT_DWORD(&CONF_Ind[6],0x0);
+          }
+          break;
+      case CONF_ISOLATE:
+          PUT_WORD(&CONF_Ind[1],S_CONF_ISOLATE);
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          break;
+      case CONF_REATTACH:
+          PUT_WORD(&CONF_Ind[1],S_CONF_REATTACH);
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          break;
+      case CONF_DROP:
+          PUT_WORD(&CONF_Ind[1],S_CONF_DROP);
+          CONF_Ind[0]=5;
+          CONF_Ind[3]=2;
+          break;
+      case CONF_ADD:
+          PUT_WORD(&CONF_Ind[1],S_CONF_ADD);
+          d=pty_cai[6];
+          PUT_DWORD(&CONF_Ind[6],d); /* PartyID */
+          tplci=plci->relatedPTYPLCI;
+          if(tplci) tplci->ptyState = CONNECTED;
+          break;
+      case CONF_PARTYDISC:
+          CONF_Ind[0]=7;
+          CONF_Ind[3]=4;          
+          PUT_WORD(&CONF_Ind[1],S_CONF_PARTYDISC);
+          d=pty_cai[6];
+          PUT_DWORD(&CONF_Ind[4],d); /* PartyID */
+          break;
+      }
+      plci->ptyState = CONNECTED;
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
+      break;
+    case CCBS_INFO_RETAIN:
+    case CCBS_ERASECALLLINKAGEID:
+    case CCBS_STOP_ALERTING:
+      CONF_Ind[0]=5;
+      CONF_Ind[3]=2;
+      switch(pty_cai[5])
+      {
+      case CCBS_INFO_RETAIN:
+        PUT_WORD(&CONF_Ind[1],S_CCBS_INFO_RETAIN);
+        break;
+      case CCBS_STOP_ALERTING:
+        PUT_WORD(&CONF_Ind[1],S_CCBS_STOP_ALERTING);
+    break;
+      case CCBS_ERASECALLLINKAGEID:
+        PUT_WORD(&CONF_Ind[1],S_CCBS_ERASECALLLINKAGEID);
+        CONF_Ind[0]=7;
+        CONF_Ind[3]=4;
+        CONF_Ind[6]=0;
+        CONF_Ind[7]=0;
+        break;
+      }      
+      w=pty_cai[6];
+      PUT_WORD(&CONF_Ind[4],w); /* PartyID */
+
+      if(plci->appl && (a->Notification_Mask[plci->appl->Id-1]&SMASK_CCBS))
+      {
+        sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, CONF_Ind);
+      }
+      else
+      {
+        for(i=0; i<max_appl; i++)
+            if(a->Notification_Mask[i]&SMASK_CCBS)
+                sendf(&application[i],_FACILITY_I,Id&0x7,0,"ws",3, CONF_Ind);
+      }
+      break;
+    }
+    break;
+  case CALL_HOLD_REJ:
+    cau = parms[7];
+    if(cau)
+    {
+      i = _L3_CAUSE | cau[2];
+      if(cau[2]==0) i = 0x3603;
+    }
+    else
+    {
+      i = 0x3603;
+    }
+    PUT_WORD(&SS_Ind[1],S_HOLD);
+    PUT_WORD(&SS_Ind[4],i);
+    if(plci->SuppState == HOLD_REQUEST)
+    {
+      plci->SuppState = IDLE;
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+    }
+    break;
+
+  case CALL_HOLD_ACK:
+    if(plci->SuppState == HOLD_REQUEST)
+    {
+      plci->SuppState = CALL_HELD;
+      CodecIdCheck(a, plci);
+      start_internal_command (Id, plci, hold_save_command);
+    }
+    break;
+
+  case CALL_RETRIEVE_REJ:
+    cau = parms[7];
+    if(cau)
+    {
+      i = _L3_CAUSE | cau[2];
+      if(cau[2]==0) i = 0x3603;
+    }
+    else
+    {
+      i = 0x3603;
+    }
+    PUT_WORD(&SS_Ind[1],S_RETRIEVE);
+    PUT_WORD(&SS_Ind[4],i);
+    if(plci->SuppState == RETRIEVE_REQUEST)
+    {
+      plci->SuppState = CALL_HELD;
+      CodecIdCheck(a, plci);
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+    }
+    break;
+
+  case CALL_RETRIEVE_ACK:
+    PUT_WORD(&SS_Ind[1],S_RETRIEVE);
+    if(plci->SuppState == RETRIEVE_REQUEST)
+    {
+      plci->SuppState = IDLE;
+      plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
+      plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
+      if(plci->tel)
+      {
+        mixer_set_bchannel_id_esc (plci, plci->b_channel);
+        dbug(1,dprintf("RetrChannel=0x%x",plci->b_channel));
+        SetVoiceChannel(a->AdvCodecPLCI, esc_chi, a);
+        if(plci->B2_prot==B2_TRANSPARENT && plci->B3_prot==B3_TRANSPARENT)
+        {
+          dbug(1,dprintf("Get B-ch"));
+          start_internal_command (Id, plci, retrieve_restore_command);
+        }
+        else
+          sendf(plci->appl,_FACILITY_I,Id,0,"ws",3, SS_Ind);
+      }
+      else
+        start_internal_command (Id, plci, retrieve_restore_command);
+    }
+    break;
+
+  case INDICATE_IND:
+    if(plci->State != LISTENING) {
+      sig_req(plci,HANGUP,0);
+      send_req(plci);
+      break;
+    }
+    cip = find_cip(a,parms[4],parms[6]);
+    cip_mask = 1L<<cip;
+    dbug(1,dprintf("cip=%d,cip_mask=%lx",cip,cip_mask));
+    clear_c_ind_mask (plci);
+    if (!remove_started && !a->adapter_disabled)
+    {
+      set_c_ind_mask_bit (plci, MAX_APPL);
+      group_optimization(a, plci);
+      for(i=0; i<max_appl; i++) {
+        if(application[i].Id
+        && (a->CIP_Mask[i]&1 || a->CIP_Mask[i]&cip_mask)
+        && CPN_filter_ok(parms[0],a,i)
+        && test_group_ind_mask_bit (plci, i) ) {
+          dbug(1,dprintf("storedcip_mask[%d]=0x%lx",i,a->CIP_Mask[i] ));
+          set_c_ind_mask_bit (plci, i);
+          dump_c_ind_mask (plci);
+          plci->State = INC_CON_PENDING;
+          plci->call_dir = (plci->call_dir & ~(CALL_DIR_OUT | CALL_DIR_ORIGINATE)) |
+            CALL_DIR_IN | CALL_DIR_ANSWER;
+          if(esc_chi[0]) {
+            plci->b_channel = esc_chi[esc_chi[0]]&0x1f;
+            mixer_set_bchannel_id_esc (plci, plci->b_channel);
+          }
+          /* if a listen on the ext controller is done, check if hook states */
+          /* are supported or if just a on board codec must be activated     */
+          if(a->codec_listen[i] && !a->AdvSignalPLCI) {
+            if(a->profile.Global_Options & HANDSET)
+              plci->tel = ADV_VOICE;
+            else if(a->profile.Global_Options & ON_BOARD_CODEC)
+              plci->tel = CODEC;
+            if(plci->tel) Id|=EXT_CONTROLLER;
+            a->codec_listen[i] = plci;
+          }
+
+          sendf(&application[i],_CONNECT_I,Id,0,
+                "wSSSSSSSbSSSSS", cip,    /* CIP                 */
+                             parms[0],    /* CalledPartyNumber   */
+                             multi_CiPN_parms[0],    /* CallingPartyNumber  */
+                             parms[2],    /* CalledPartySubad    */
+                             parms[3],    /* CallingPartySubad   */
+                             parms[4],    /* BearerCapability    */
+                             parms[5],    /* LowLC               */
+                             parms[6],    /* HighLC              */
+                             ai_len,      /* nested struct add_i */
+                             add_i[0],    /* B channel info    */
+                             add_i[1],    /* keypad facility   */
+                             add_i[2],    /* user user data    */
+                             add_i[3],    /* nested facility   */
+                             multi_CiPN_parms[1]    /* second CiPN(SCR)   */
+                             );
+          SendSSExtInd(&application[i],
+                        plci,
+                        Id,
+                        multi_ssext_parms);
+          SendSetupInfo(&application[i],
+                        plci,
+                        Id,
+                        parms,
+                        SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, TRUE));
+        }
+      }
+      clear_c_ind_mask_bit (plci, MAX_APPL);
+      dump_c_ind_mask (plci);
+    }
+    if(c_ind_mask_empty (plci)) {
+      sig_req(plci,HANGUP,0);
+      send_req(plci);
+      plci->State = IDLE;
+    }
+    plci->notifiedcall = 0;
+    a->listen_active--;
+    listen_check(a);
+    break;
+
+  case CALL_PEND_NOTIFY:
+    plci->notifiedcall = 1;
+    listen_check(a);
+    break;
+
+  case CALL_IND:
+  case CALL_CON:
+    if(plci->State==ADVANCED_VOICE_SIG || plci->State==ADVANCED_VOICE_NOSIG)
+    {
+      if(plci->internal_command==PERM_COD_CONN_PEND)
+      {
+        if(plci->State==ADVANCED_VOICE_NOSIG)
+        {
+          dbug(1,dprintf("***Codec OK"));
+          if(a->AdvSignalPLCI)
+          {
+            tplci = a->AdvSignalPLCI;
+            if(tplci->spoofed_msg)
+            {
+              dbug(1,dprintf("***Spoofed Msg(0x%x)",tplci->spoofed_msg));
+              tplci->command = 0;
+              tplci->internal_command = 0;
+              x_Id = ((word)tplci->Id<<8)|tplci->adapter->Id | 0x80;
+              switch (tplci->spoofed_msg)
+              {
+              case CALL_RES:
+                tplci->command = _CONNECT_I|RESPONSE;
+                api_load_msg (&tplci->saved_msg, saved_parms);
+                add_b1(tplci,&saved_parms[1],0,tplci->B1_facilities);
+                if (tplci->adapter->Info_Mask[tplci->appl->Id-1] & 0x200)
+                {
+                  /* early B3 connect (CIP mask bit 9) no release after a disc */
+                  add_p(tplci,LLI,"\x01\x01");
+                }
+                add_s(tplci, CONN_NR, &saved_parms[2]);
+                add_s(tplci, LLC, &saved_parms[4]);
+                add_ai(tplci, &saved_parms[5]);
+                tplci->State = INC_CON_ACCEPT;
+                sig_req(tplci, CALL_RES,0);
+                send_req(tplci);
+                break;
+
+              case AWAITING_SELECT_B:
+                dbug(1,dprintf("Select_B continue"));
+                start_internal_command (x_Id, tplci, select_b_command);
+                break;
+
+              case AWAITING_MANUF_CON: /* Get_Plci per Manufacturer_Req to ext controller */
+                if(!tplci->Sig.Id)
+                {
+                  dbug(1,dprintf("No SigID!"));
+                  sendf(tplci->appl, _MANUFACTURER_R|CONFIRM,x_Id,tplci->number, "dww",_DI_MANU_ID,_MANUFACTURER_R,_OUT_OF_PLCI);
+                  plci_remove(tplci);
+                  break;
+                }
+                tplci->command = _MANUFACTURER_R;
+                api_load_msg (&tplci->saved_msg, saved_parms);
+                dir = saved_parms[2].info[0];
+                if(dir==1) {
+                  sig_req(tplci,CALL_REQ,0);
+                }
+                else if(!dir){
+                  sig_req(tplci,LISTEN_REQ,0);
+                }
+                send_req(tplci);
+                sendf(tplci->appl, _MANUFACTURER_R|CONFIRM,x_Id,tplci->number, "dww",_DI_MANU_ID,_MANUFACTURER_R,0);
+                break;
+
+              case (CALL_REQ|AWAITING_MANUF_CON):
+                sig_req(tplci,CALL_REQ,0);
+                send_req(tplci);
+                break;
+
+              case CALL_REQ:
+                if(!tplci->Sig.Id)
+                {
+                  dbug(1,dprintf("No SigID!"));
+                  sendf(tplci->appl,_CONNECT_R|CONFIRM,tplci->adapter->Id,0,"w",_OUT_OF_PLCI);
+                  plci_remove(tplci);
+                  break;
+                }
+                tplci->command = _CONNECT_R;
+                api_load_msg (&tplci->saved_msg, saved_parms);
+                add_s(tplci,CPN,&saved_parms[1]);
+                add_s(tplci,DSA,&saved_parms[3]);
+                add_ai(tplci,&saved_parms[9]);
+                sig_req(tplci,CALL_REQ,0);
+                send_req(tplci);
+                break;
+
+              case CALL_RETRIEVE:
+                tplci->command = C_RETRIEVE_REQ;
+                sig_req(tplci,CALL_RETRIEVE,0);
+                send_req(tplci);
+                break;
+              }
+              tplci->spoofed_msg = 0;
+              if (tplci->internal_command == 0)
+                next_internal_command (x_Id, tplci);
+            }
+          }
+          next_internal_command (Id, plci);
+          break;
+        }
+        dbug(1,dprintf("***Codec Hook Init Req"));
+        plci->internal_command = PERM_COD_HOOK;
+        add_p(plci,FTY,"\x01\x09");             /* Get Hook State*/
+        sig_req(plci,TEL_CTRL,0);
+        send_req(plci);
+      }
+    }
+    else if(plci->command != _MANUFACTURER_R  /* old style permanent connect */
+    && plci->State!=INC_ACT_PENDING)
+    {
+      mixer_set_bchannel_id_esc (plci, plci->b_channel);
+      if(plci->tel == ADV_VOICE && plci->SuppState == IDLE) /* with permanent codec switch on immediately */
+      {
+        chi[2] = plci->b_channel;
+        SetVoiceChannel(a->AdvCodecPLCI, chi, a);
+      }
+      sendf(plci->appl,_CONNECT_ACTIVE_I,Id,0,"Sss",parms[21],"","");
+      plci->State = INC_ACT_PENDING;
+    }
+    break;
+
+  case TEL_CTRL:
+    Number = 0;
+    ie = multi_fac_parms[0]; /* inspect the facility hook indications */
+    if(plci->State==ADVANCED_VOICE_SIG && ie[0]){
+      switch (ie[1]&0x91) {
+        case 0x80:   /* hook off */
+        case 0x81:
+          if(plci->internal_command==PERM_COD_HOOK)
+          {
+            dbug(1,dprintf("init:hook_off"));
+            plci->hook_state = ie[1];
+            next_internal_command (Id, plci);
+            break;
+          }
+          else /* ignore doubled hook indications */
+          {
+            if( ((plci->hook_state)&0xf0)==0x80)
+            {
+              dbug(1,dprintf("ignore hook"));
+              break;
+            }
+            plci->hook_state = ie[1]&0x91;
+          }
+          /* check for incoming call pending */
+          /* and signal '+'.Appl must decide */
+          /* with connect_res if call must   */
+          /* accepted or not                 */
+          for(i=0, tplci=NULL;i<max_appl;i++){
+            if(a->codec_listen[i]
+            && (a->codec_listen[i]->State==INC_CON_PENDING
+              ||a->codec_listen[i]->State==INC_CON_ALERT) ){
+              tplci = a->codec_listen[i];
+              tplci->appl = &application[i];
+            }
+          }
+          /* no incoming call, do outgoing call */
+          /* and signal '+' if outg. setup   */
+          if(!a->AdvSignalPLCI && !tplci){
+            if((i=get_plci(a))) {
+              a->AdvSignalPLCI = &a->plci[i-1];
+              tplci = a->AdvSignalPLCI;
+              tplci->tel  = ADV_VOICE;
+              PUT_WORD(&voice_cai[5],a->AdvSignalAppl->MaxDataLength);
+              if (a->Info_Mask[a->AdvSignalAppl->Id-1] & 0x200){
+                /* early B3 connect (CIP mask bit 9) no release after a disc */
+                add_p(tplci,LLI,"\x01\x01");
+              }
+              add_p(tplci, CAI, voice_cai);
+              add_p(tplci, OAD, a->TelOAD);
+              add_p(tplci, OSA, a->TelOSA);
+              add_p(tplci,SHIFT|6,NULL);
+              add_p(tplci,SIN,"\x02\x01\x00");
+              add_p(tplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+              sig_req(tplci,ASSIGN,DSIG_ID);
+              a->AdvSignalPLCI->internal_command = HOOK_OFF_REQ;
+              a->AdvSignalPLCI->command = 0;
+              tplci->appl = a->AdvSignalAppl;
+              tplci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+              send_req(tplci);
+            }
+
+          }
+
+          if(!tplci) break;
+          Id = ((word)tplci->Id<<8)|a->Id;
+          Id|=EXT_CONTROLLER;
+          sendf(tplci->appl,
+                _FACILITY_I,
+                Id,
+                0,
+                "ws", (word)0, "\x01+");
+          break;
+
+        case 0x90:   /* hook on  */
+        case 0x91:
+          if(plci->internal_command==PERM_COD_HOOK)
+          {
+            dbug(1,dprintf("init:hook_on"));
+            plci->hook_state = ie[1]&0x91;
+            next_internal_command (Id, plci);
+            break;
+          }
+          else /* ignore doubled hook indications */
+          {
+            if( ((plci->hook_state)&0xf0)==0x90) break;
+            plci->hook_state = ie[1]&0x91;
+          }
+          /* hangup the adv. voice call and signal '-' to the appl */
+          if(a->AdvSignalPLCI) {
+            Id = ((word)a->AdvSignalPLCI->Id<<8)|a->Id;
+            if(plci->tel) Id|=EXT_CONTROLLER;
+            sendf(a->AdvSignalAppl,
+                  _FACILITY_I,
+                  Id,
+                  0,
+                  "ws", (word)0, "\x01-");
+            a->AdvSignalPLCI->internal_command = HOOK_ON_REQ;
+            a->AdvSignalPLCI->command = 0;
+            sig_req(a->AdvSignalPLCI,HANGUP,0);
+            send_req(a->AdvSignalPLCI);
+          }
+          break;
+      }
+    }
+    break;
+
+  case RESUME:
+    clear_c_ind_mask_bit (plci, (word)(plci->appl->Id-1));
+    PUT_WORD(&resume_cau[4],GOOD);
+    sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, resume_cau);
+    break;
+
+  case SUSPEND:
+    clear_c_ind_mask (plci);
+
+    if (plci->NL.Id && !plci->nl_remove_id) {
+      mixer_remove (plci);
+      nl_req_ncci(plci,REMOVE,0);
+    }
+    if (!plci->sig_remove_id) {
+      plci->internal_command = 0;
+      sig_req(plci,REMOVE,0);
+    }
+    send_req(plci);
+    if(!plci->channels) {
+      sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, "\x05\x04\x00\x02\x00\x00");
+      sendf(plci->appl, _DISCONNECT_I, Id, 0, "w", 0);
+    }
+    break;
+
+  case SUSPEND_REJ:
+    break;
+
+  case HANGUP:
+    plci->hangup_flow_ctrl_timer=0;
+    if(plci->manufacturer && plci->State==LOCAL_CONNECT) break;
+    cau = parms[7];
+    if(cau) {
+      i = _L3_CAUSE | cau[2];
+      if(cau[2]==0) i = 0;
+      else if(cau[2]==8) i = _L1_ERROR;
+      else if(cau[2]==9 || cau[2]==10) i = _L2_ERROR;
+      else if(cau[2]==5) i = _CAPI_GUARD_ERROR;
+    }
+    else {
+      i = _L3_ERROR;
+    }
+
+    if(plci->State==INC_CON_PENDING || plci->State==INC_CON_ALERT)
+    {
+      for(i=0; i<max_appl; i++)
+      {
+        if(test_c_ind_mask_bit (plci, i))
+          sendf(&application[i], _DISCONNECT_I, Id, 0, "w", 0);
+      }
+    }
+    else
+    {
+      clear_c_ind_mask (plci);
+    }
+    if(!plci->appl)
+    {
+      if (plci->State == LISTENING)
+      {
+        plci->notifiedcall=0;
+        a->listen_active--;
+      }
+      plci->State = INC_DIS_PENDING;
+      if(c_ind_mask_empty (plci))
+      {
+        plci->State = IDLE;
+        if (plci->NL.Id && !plci->nl_remove_id)
+        {
+          mixer_remove (plci);
+          nl_req_ncci(plci,REMOVE,0);
+        }
+        if (!plci->sig_remove_id)
+        {
+          plci->internal_command = 0;
+          sig_req(plci,REMOVE,0);
+        }
+        send_req(plci);
+      }
+    }
+    else
+    {
+        /* collision of DISCONNECT or CONNECT_RES with HANGUP can   */
+        /* result in a second HANGUP! Don't generate another        */
+        /* DISCONNECT                                               */
+      if(plci->State!=IDLE && plci->State!=INC_DIS_PENDING)
+      {
+        if(plci->State==RESUMING)
+        {
+          PUT_WORD(&resume_cau[4],i);
+          sendf(plci->appl,_FACILITY_I,Id,0,"ws", (word)3, resume_cau);
+        }
+        plci->State = INC_DIS_PENDING;
+        sendf(plci->appl,_DISCONNECT_I,Id,0,"w",i);
+      }
+    }
+    break;
+
+  case SSEXT_IND:
+    SendSSExtInd(NULL,plci,Id,multi_ssext_parms);
+    break;
+
+  case VSWITCH_REQ:
+    VSwitchReqInd(plci,Id,multi_vswitch_parms);
+    break;
+  case VSWITCH_IND:
+ if(plci->relatedPTYPLCI &&
+  plci->vswitchstate==3 &&
+  plci->relatedPTYPLCI->vswitchstate==3 &&
+  parms[MAXPARMSIDS-1][0])
+ {
+  add_p(plci->relatedPTYPLCI,SMSG,parms[MAXPARMSIDS-1]);
+  sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
+  send_req(plci->relatedPTYPLCI);
+ }
+    else VSwitchReqInd(plci,Id,multi_vswitch_parms);
+    break;
+
+  }
+}
+
+
+static void SendSetupInfo(APPL   * appl, PLCI   * plci, dword Id, byte   * * parms, byte Info_Sent_Flag)
+{
+  word i;
+  byte   * ie;
+  word Info_Number;
+  byte   * Info_Element;
+  word Info_Mask = 0;
+
+  dbug(1,dprintf("SetupInfo"));
+
+  for(i=0; i<MAXPARMSIDS; i++) {
+    ie = parms[i];
+    Info_Number = 0;
+    Info_Element = ie;
+    if(ie[0]) {
+      switch(i) {
+      case 0:
+        dbug(1,dprintf("CPN "));
+        Info_Number = 0x0070;
+        Info_Mask   = 0x80;
+        Info_Sent_Flag = TRUE;
+        break;
+      case 8:  /* display      */
+        dbug(1,dprintf("display(%d)",i));
+        Info_Number = 0x0028;
+        Info_Mask = 0x04;
+        Info_Sent_Flag = TRUE;
+        break;
+      case 16: /* Channel Id */
+        dbug(1,dprintf("CHI"));
+        Info_Number = 0x0018;
+        Info_Mask = 0x100;
+        Info_Sent_Flag = TRUE;
+        mixer_set_bchannel_id (plci, Info_Element);
+        break;
+      case 19: /* Redirected Number */
+        dbug(1,dprintf("RDN"));
+        Info_Number = 0x0074;
+        Info_Mask = 0x400;
+        Info_Sent_Flag = TRUE;
+        break;
+      case 20: /* Redirected Number extended */
+        dbug(1,dprintf("RDX"));
+        Info_Number = 0x0073;
+        Info_Mask = 0x400;
+        Info_Sent_Flag = TRUE;
+        break;
+      case 22: /* Redirecing Number  */
+        dbug(1,dprintf("RIN"));
+        Info_Number = 0x0076;
+        Info_Mask = 0x400;
+        Info_Sent_Flag = TRUE;
+        break;
+      default:
+        Info_Number = 0;
+        break;
+      }
+    }
+
+    if(i==MAXPARMSIDS-2){ /* to indicate the message type "Setup" */
+      Info_Number = 0x8000 |5;
+      Info_Mask = 0x10;
+      Info_Element = "";
+    }
+
+    if(Info_Sent_Flag && Info_Number){
+      if(plci->adapter->Info_Mask[appl->Id-1] & Info_Mask) {
+        sendf(appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+      }
+    }
+  }
+}
+
+
+void SendInfo(PLCI   * plci, dword Id, byte   * * parms, byte iesent)
+{
+  word i;
+  word j;
+  word k;
+  byte   * ie;
+  word Info_Number;
+  byte   * Info_Element;
+  word Info_Mask = 0;
+  static byte charges[5] = {4,0,0,0,0};
+  static byte cause[] = {0x02,0x80,0x00};
+  APPL   *appl;
+
+  dbug(1,dprintf("InfoParse "));
+
+  if(
+        !plci->appl
+        && !plci->State
+        && plci->Sig.Ind!=NCR_FACILITY
+      )
+  {
+    dbug(1,dprintf("NoParse "));
+    return;
+  }
+  cause[2] = 0;
+  for(i=0; i<MAXPARMSIDS; i++) {
+    ie = parms[i];
+    Info_Number = 0;
+    Info_Element = ie;
+    if(ie[0]) {
+      switch(i) {
+      case 0:
+        dbug(1,dprintf("CPN "));
+        Info_Number = 0x0070;
+        Info_Mask   = 0x80;
+        break;
+      case 7: /* ESC_CAU */
+        dbug(1,dprintf("cau(0x%x)",ie[2]));
+        Info_Number = 0x0008;
+        Info_Mask = 0x00;
+        cause[2] = ie[2];
+        Info_Element = NULL;
+        break;
+      case 8:  /* display      */
+        dbug(1,dprintf("display(%d)",i));
+        Info_Number = 0x0028;
+        Info_Mask = 0x04;
+        break;
+      case 9:  /* Date display */
+        dbug(1,dprintf("date(%d)",i));
+        Info_Number = 0x0029;
+        Info_Mask = 0x02;
+        break;
+      case 10: /* charges */
+        for(j=0;j<4;j++) charges[1+j] = 0;
+        for(j=0; j<ie[0] && !(ie[1+j]&0x80); j++);
+        for(k=1,j++; j<ie[0] && k<=4; j++,k++) charges[k] = ie[1+j];
+        Info_Number = 0x4000;
+        Info_Mask = 0x40;
+        Info_Element = charges;
+        break;
+      case 11: /* user user info */
+        dbug(1,dprintf("uui"));
+        Info_Number = 0x007E;
+        Info_Mask = 0x08;
+        break;
+      case 12: /* congestion receiver ready */
+        dbug(1,dprintf("clRDY"));
+        Info_Number = 0x00B0;
+        Info_Mask = 0x08;
+        Info_Element = "";
+        break;
+      case 13: /* congestion receiver not ready */
+        dbug(1,dprintf("clNRDY"));
+        Info_Number = 0x00BF;
+        Info_Mask = 0x08;
+        Info_Element = "";
+        break;
+      case 15: /* Keypad Facility */
+        dbug(1,dprintf("KEY"));
+        Info_Number = 0x002C;
+        Info_Mask = 0x20;
+        break;
+      case 16: /* Channel Id */
+        dbug(1,dprintf("CHI"));
+        Info_Number = 0x0018;
+        Info_Mask = 0x100;
+        mixer_set_bchannel_id (plci, Info_Element);
+        break;
+      case 17: /* if no 1tr6 cause, send full cause, else esc_cause */
+        dbug(1,dprintf("q9cau(0x%x)",ie[2]));
+        if(!cause[2] || cause[2]<0x80) break;  /* eg. layer 1 error */
+        Info_Number = 0x0008;
+        Info_Mask = 0x01;
+        if(cause[2] != ie[2]) Info_Element = cause;
+        break;
+      case 19: /* Redirected Number */
+        dbug(1,dprintf("RDN"));
+        Info_Number = 0x0074;
+        Info_Mask = 0x400;
+        break;
+      case 22: /* Redirecing Number  */
+        dbug(1,dprintf("RIN"));
+        Info_Number = 0x0076;
+        Info_Mask = 0x400;
+        break;
+      case 23: /* Notification Indicator  */
+        dbug(1,dprintf("NI"));
+        Info_Number = (word)NI;
+        Info_Mask = 0x210;
+        break;
+      case 26: /* Call State  */
+        dbug(1,dprintf("CST"));
+        Info_Number = (word)CST;
+        Info_Mask = 0x01; /* do with cause i.e. for now */
+        break;
+      case MAXPARMSIDS-2:  /* Escape Message Type, must be the last indication */
+        dbug(1,dprintf("ESC/MT[0x%x]",ie[3]));
+        Info_Number = 0x8000 |ie[3];
+        if(iesent) Info_Mask = 0xffff;
+        else  Info_Mask = 0x10;
+        Info_Element = "";
+        break;
+      default:
+        Info_Number  = 0;
+        Info_Mask    = 0;
+        Info_Element = "";
+        break;
+      }
+    }
+
+    if(plci->Sig.Ind==NCR_FACILITY)           /* check controller broadcast */
+    {
+      for(j=0; j<max_appl; j++)
+      {
+        appl = &application[j];
+        if(Info_Number
+        && appl->Id
+        && plci->adapter->Info_Mask[appl->Id-1] &Info_Mask)
+        {
+          dbug(1,dprintf("NCR_Ind"));
+          iesent=TRUE;
+          sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element);
+        }
+      }
+    }
+    else if(!plci->appl)
+    { /* overlap receiving broadcast */
+      if(Info_Number==CPN
+      || Info_Number==KEY
+      || Info_Number==NI
+      || Info_Number==DSP
+      || Info_Number==UUI )
+      {
+        for(j=0; j<max_appl; j++)
+        {
+          if(test_c_ind_mask_bit (plci, j))
+          {
+            dbug(1,dprintf("Ovl_Ind"));
+            iesent=TRUE;
+            sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+          }
+        }
+      }
+    }               /* all other signalling states */
+    else if(Info_Number
+    && plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask)
+    {
+      dbug(1,dprintf("Std_Ind"));
+      iesent=TRUE;
+      sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+    }
+  }
+}
+
+
+byte SendMultiIE(PLCI   * plci, dword Id, byte   * * parms, byte ie_type, dword info_mask, byte setupParse)
+{
+  word i;
+  word j;
+  byte   * ie;
+  word Info_Number;
+  byte   * Info_Element;
+  APPL   *appl;
+  word Info_Mask = 0;
+  byte iesent=0;
+
+  if(
+      !plci->appl
+      && !plci->State
+      && plci->Sig.Ind!=NCR_FACILITY
+      && !setupParse
+      )
+  {
+    dbug(1,dprintf("NoM-IEParse "));
+    return 0;
+  }
+  dbug(1,dprintf("M-IEParse "));
+
+  for(i=0; i<MAX_MULTI_IE; i++)
+  {
+    ie = parms[i];
+    Info_Number = 0;
+    Info_Element = ie;
+    if(ie[0])
+    {
+      dbug(1,dprintf("[Ind0x%x]:IE=0x%x",plci->Sig.Ind,ie_type));
+      Info_Number = (word)ie_type;
+      Info_Mask = (word)info_mask;
+    }
+
+    if(plci->Sig.Ind==NCR_FACILITY)           /* check controller broadcast */
+    {
+      for(j=0; j<max_appl; j++)
+      {
+        appl = &application[j];
+        if(Info_Number
+        && appl->Id
+        && plci->adapter->Info_Mask[appl->Id-1] &Info_Mask)
+        {
+          iesent = TRUE;
+          dbug(1,dprintf("Mlt_NCR_Ind"));
+          sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element);
+        }
+      }
+    }
+    else if(!plci->appl && Info_Number)
+    {                                        /* overlap receiving broadcast */
+      for(j=0; j<max_appl; j++)
+      {
+        if(test_c_ind_mask_bit (plci, j))
+        {
+          iesent = TRUE;
+          dbug(1,dprintf("Mlt_Ovl_Ind"));
+          sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+        }
+      }
+    }                                        /* all other signalling states */
+    else if(Info_Number
+    && plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask)
+    {
+      iesent = TRUE;
+      dbug(1,dprintf("Mlt_Std_Ind"));
+      sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
+    }
+  }
+  return iesent;
+}
+
+static void SendSSExtInd(APPL   * appl, PLCI   * plci, dword Id, byte   * * parms)
+{
+  word i;
+   /* Format of multi_ssext_parms[i][]:
+   0 byte length
+   1 byte SSEXTIE
+   2 byte SSEXT_REQ/SSEXT_IND
+   3 byte length
+   4 word SSExtCommand
+   6... Params
+   */
+  if(
+   plci
+   && plci->State
+   && plci->Sig.Ind!=NCR_FACILITY
+    )
+ for(i=0;i<MAX_MULTI_IE;i++)
+    {
+      if(parms[i][0]<6) continue;
+   if(parms[i][2]==SSEXT_REQ) continue;
+
+   if(appl)
+   {
+    parms[i][0]=0; /* kill it */
+    sendf(appl,_MANUFACTURER_I,
+    Id,
+    0,
+    "dwS",
+    _DI_MANU_ID,
+    _DI_SSEXT_CTRL,
+    &parms[i][3]);
+   }
+   else if(plci->appl)
+   {
+    parms[i][0]=0; /* kill it */
+    sendf(plci->appl,_MANUFACTURER_I,
+    Id,
+    0,
+    "dwS",
+    _DI_MANU_ID,
+    _DI_SSEXT_CTRL,
+    &parms[i][3]);
+   }
+    }
+};
+
+void nl_ind(PLCI   * plci)
+{
+  byte ch;
+  word ncci;
+  dword Id;
+  DIVA_CAPI_ADAPTER   * a;
+  word NCCIcode;
+  APPL   * APPLptr;
+  word count;
+  word Num;
+  word i, ncpi_state;
+  byte len, ncci_state;
+  word msg;
+  word info = 0;
+  word fax_feature_bits;
+  byte fax_send_edata_ack;
+  static byte v120_header_buffer[2 + 3];
+  static word fax_info[] = {
+    0,                     /* T30_SUCCESS                        */
+    _FAX_NO_CONNECTION,    /* T30_ERR_NO_DIS_RECEIVED            */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TIMEOUT_NO_RESPONSE        */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_RESPONSE          */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TOO_MANY_REPEATS           */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_UNEXPECTED_MESSAGE         */
+    _FAX_REMOTE_ABORT,     /* T30_ERR_UNEXPECTED_DCN             */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_DTC_UNSUPPORTED            */
+    _FAX_TRAINING_ERROR,   /* T30_ERR_ALL_RATES_FAILED           */
+    _FAX_TRAINING_ERROR,   /* T30_ERR_TOO_MANY_TRAINS            */
+    _FAX_PARAMETER_ERROR,  /* T30_ERR_RECEIVE_CORRUPTED          */
+    _FAX_REMOTE_ABORT,     /* T30_ERR_UNEXPECTED_DISC            */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_APPLICATION_DISC           */
+    _FAX_REMOTE_REJECT,    /* T30_ERR_INCOMPATIBLE_DIS           */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_INCOMPATIBLE_DCS           */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TIMEOUT_NO_COMMAND         */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_COMMAND           */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TIMEOUT_COMMAND_TOO_LONG   */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_TIMEOUT_RESPONSE_TOO_LONG  */
+    _FAX_NO_CONNECTION,    /* T30_ERR_NOT_IDENTIFIED             */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_SUPERVISORY_TIMEOUT        */
+    _FAX_PARAMETER_ERROR,  /* T30_ERR_TOO_LONG_SCAN_LINE         */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_PAGE_AFTER_MPS    */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_PAGE_AFTER_CFR    */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCS_AFTER_FTT     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCS_AFTER_EOM     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCS_AFTER_MPS     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCN_AFTER_MCF     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_DCN_AFTER_RTN     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_CFR               */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_MCF_AFTER_EOP     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_MCF_AFTER_EOM     */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_RETRY_NO_MCF_AFTER_MPS     */
+    0x331d,                /* T30_ERR_SUB_SEP_UNSUPPORTED        */
+    0x331e,                /* T30_ERR_PWD_UNSUPPORTED            */
+    0x331f,                /* T30_ERR_SUB_SEP_PWD_UNSUPPORTED    */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_INVALID_COMMAND_FRAME      */
+    _FAX_PARAMETER_ERROR,  /* T30_ERR_UNSUPPORTED_PAGE_CODING    */
+    _FAX_PARAMETER_ERROR,  /* T30_ERR_INVALID_PAGE_CODING        */
+    _FAX_REMOTE_REJECT,    /* T30_ERR_INCOMPATIBLE_PAGE_CONFIG   */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_TIMEOUT_FROM_APPLICATION   */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_V34FAX_NO_REACTION_ON_MARK */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_V34FAX_TRAINING_TIMEOUT    */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_V34FAX_UNEXPECTED_V21      */
+    _FAX_PROTOCOL_ERROR,   /* T30_ERR_V34FAX_PRIMARY_CTS_ON      */
+    _FAX_LOCAL_ABORT,      /* T30_ERR_V34FAX_TURNAROUND_POLLING  */
+    _FAX_LOCAL_ABORT       /* T30_ERR_V34FAX_V8_INCOMPATIBILITY  */
+  };
+
+    byte dtmf_code_buffer[CAPIDTMF_RECV_DIGIT_BUFFER_SIZE + 1];
+
+
+  static word rtp_info[] = {
+    GOOD,                  /* RTP_SUCCESS                       */
+    0x3600                 /* RTP_ERR_SSRC_OR_PAYLOAD_CHANGE    */
+  };
+
+  static dword udata_forwarding_table[0x100 / sizeof(dword)] =
+  {
+    0x0020301e, 0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000, 0x00000000
+  };
+
+  ch = plci->NL.IndCh;
+  a = plci->adapter;
+  ncci = a->ch_ncci[ch];
+  Id = (((dword)(ncci ? ncci : ch)) << 16) | (((word) plci->Id) << 8) | a->Id;
+  if(plci->tel) Id|=EXT_CONTROLLER;
+  APPLptr = plci->appl;
+  dbug(1,dprintf("NL_IND-Id(NL:0x%x)=0x%08lx,plci=%x,tel=%x,state=0x%x,ch=0x%x,chs=%d,Ind=%x",
+    plci->NL.Id,Id,plci->Id,plci->tel,plci->State,ch,plci->channels,plci->NL.Ind &0x0f));
+
+  /* in the case if no connect_active_Ind was sent to the appl we wait for */
+
+  if (plci->nl_remove_id)
+  {
+    plci->NL.RNR = 2; /* discard */
+    dbug(1,dprintf("NL discard while remove pending"));
+    return;
+  }
+  if((plci->NL.Ind &0x0f)==N_CONNECT)
+  {
+    if(plci->State==INC_DIS_PENDING
+    || plci->State==OUTG_DIS_PENDING
+    || plci->State==IDLE)
+    {
+      plci->NL.RNR = 2; /* discard */
+      dbug(1,dprintf("discard n_connect"));
+      return;
+    }
+    if(plci->State < INC_ACT_PENDING)
+    {
+      plci->NL.RNR = 1; /* flow control */
+      channel_x_off (plci, ch, N_XON_CONNECT_IND);
+      return;
+    }
+  }
+
+  if(!APPLptr)                         /* no application or invalid data */
+  {                                    /* while reloading the DSP        */
+    dbug(1,dprintf("discard1"));
+    plci->NL.RNR = 2;
+    return;
+  }
+
+  if (((plci->NL.Ind &0x0f) == N_UDATA)
+     && (((plci->B2_prot != B2_SDLC) && ((plci->B1_resource == 17) || (plci->B1_resource == 18)))
+        || (plci->B2_prot == 7)
+        || (plci->B3_prot == 7)) )
+  {
+    plci->ncpi_buffer[0] = 0;
+
+    ncpi_state = plci->ncpi_state;
+    if (plci->NL.complete == 1)
+    {
+      byte  * data = &plci->NL.RBuffer->P[0];
+
+      if ((plci->NL.RBuffer->length >= 12)
+        &&( (*data == DSP_UDATA_INDICATION_DCD_ON)
+          ||(*data == DSP_UDATA_INDICATION_CTS_ON)) )
+      {
+        word conn_opt, ncpi_opt = 0x00;
+/*      HexDump ("MDM N_UDATA:", plci->NL.RBuffer->length, data); */
+
+        if (*data == DSP_UDATA_INDICATION_DCD_ON)
+          plci->ncpi_state |= NCPI_MDM_DCD_ON_RECEIVED;
+        if (*data == DSP_UDATA_INDICATION_CTS_ON)
+          plci->ncpi_state |= NCPI_MDM_CTS_ON_RECEIVED;
+
+        data++;    /* indication code */
+        data += 2; /* timestamp */
+        if ((*data == DSP_CONNECTED_NORM_V18) || (*data == DSP_CONNECTED_NORM_VOWN))
+          ncpi_state &= ~(NCPI_MDM_DCD_ON_RECEIVED | NCPI_MDM_CTS_ON_RECEIVED);
+        data++;    /* connected norm */
+        conn_opt = GET_WORD(data);
+        data += 2; /* connected options */
+
+        PUT_WORD (&(plci->ncpi_buffer[1]), (word)(GET_DWORD(data) & 0x0000FFFF));
+
+        if (conn_opt & DSP_CONNECTED_OPTION_MASK_V42)
+        {
+          ncpi_opt |= MDM_NCPI_ECM_V42;
+        }
+        else if (conn_opt & DSP_CONNECTED_OPTION_MASK_MNP)
+        {
+          ncpi_opt |= MDM_NCPI_ECM_MNP;
+        }
+        else
+        {
+          ncpi_opt |= MDM_NCPI_TRANSPARENT;
+        }
+        if (conn_opt & DSP_CONNECTED_OPTION_MASK_COMPRESSION)
+        {
+          ncpi_opt |= MDM_NCPI_COMPRESSED;
+        }
+        PUT_WORD (&(plci->ncpi_buffer[3]), ncpi_opt);
+        plci->ncpi_buffer[0] = 4;
+
+        plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND | NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND;
+      }
+    }
+    if (plci->B3_prot == 7)
+    {
+      if (((a->ncci_state[ncci] == INC_ACT_PENDING) || (a->ncci_state[ncci] == OUTG_CON_PENDING))
+       && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+       && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+      {
+        a->ncci_state[ncci] = INC_ACT_PENDING;
+        sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+        plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+      }
+    }
+
+    if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+        & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN)))
+     || !(ncpi_state & NCPI_MDM_DCD_ON_RECEIVED)
+     || !(ncpi_state & NCPI_MDM_CTS_ON_RECEIVED))
+
+    {
+      plci->NL.RNR = 2;
+      return;
+    }
+  }
+
+  if(plci->NL.complete == 2)
+    {
+    if (((plci->NL.Ind &0x0f) == N_UDATA)
+     && !(udata_forwarding_table[plci->RData[0].P[0] >> 5] & (1L << (plci->RData[0].P[0] & 0x1f))))
+    {
+      switch(plci->RData[0].P[0])
+      {
+
+      case DTMF_UDATA_INDICATION_FAX_CALLING_TONE:
+        if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG)
+          sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0,"ws", SELECTOR_DTMF, "\x01X");
+        break;
+      case DTMF_UDATA_INDICATION_ANSWER_TONE:
+        if (plci->dtmf_rec_active & DTMF_LISTEN_ACTIVE_FLAG)
+          sendf(plci->appl, _FACILITY_I, Id & 0xffffL, 0,"ws", SELECTOR_DTMF, "\x01Y");
+        break;
+      case DTMF_UDATA_INDICATION_DIGITS_RECEIVED:
+        dtmf_indication (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
+        break;
+      case DTMF_UDATA_INDICATION_DIGITS_SENT:
+        dtmf_confirmation (Id, plci);
+        break;
+
+
+      case UDATA_INDICATION_MIXER_TAP_DATA:
+        capidtmf_recv_process_block (&(plci->capidtmf_state), plci->RData[0].P + 1, (word)(plci->RData[0].PLength - 1));
+ i = capidtmf_indication (&(plci->capidtmf_state), dtmf_code_buffer + 1);
+ if (i != 0)
+ {
+   dtmf_code_buffer[0] = DTMF_UDATA_INDICATION_DIGITS_RECEIVED;
+          dtmf_indication (Id, plci, dtmf_code_buffer, (word)(i + 1));
+ }
+        break;
+
+
+      case UDATA_INDICATION_MIXER_COEFS_SET:
+        mixer_indication_coefs_set (Id, plci);
+        break;
+      case UDATA_INDICATION_XCONNECT_FROM:
+        mixer_indication_xconnect_from (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
+        break;
+      case UDATA_INDICATION_XCONNECT_TO:
+        mixer_indication_xconnect_to (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
+        break;
+
+
+      case LEC_UDATA_INDICATION_DISABLE_DETECT:
+        ec_indication (Id, plci, plci->RData[0].P, plci->RData[0].PLength);
+        break;
+
+
+
+      default:
+        break;
+      }
+    }
+    else
+  {
+      if ((plci->RData[0].PLength != 0)
+     && ((plci->B2_prot == B2_V120_ASYNC)
+      || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
+      || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)))
+    {
+
+      sendf(plci->appl,_DATA_B3_I,Id,0,
+            "dwww",
+            plci->RData[1].P,
+              (plci->NL.RNum < 2) ? 0 : plci->RData[1].PLength,
+            plci->RNum,
+            plci->RFlags);
+
+    }
+    else
+    {
+
+      sendf(plci->appl,_DATA_B3_I,Id,0,
+            "dwww",
+            plci->RData[0].P,
+            plci->RData[0].PLength,
+            plci->RNum,
+            plci->RFlags);
+
+    }
+    }
+    return;
+  }
+
+  fax_feature_bits = 0;
+  if((plci->NL.Ind &0x0f)==N_CONNECT ||
+     (plci->NL.Ind &0x0f)==N_CONNECT_ACK ||
+     (plci->NL.Ind &0x0f)==N_DISC ||
+     (plci->NL.Ind &0x0f)==N_EDATA ||
+     (plci->NL.Ind &0x0f)==N_DISC_ACK)
+  {
+    info = 0;
+    plci->ncpi_buffer[0] = 0;
+    switch (plci->B3_prot) {
+    case  0: /*XPARENT*/
+    case  1: /*T.90 NL*/
+      break;    /* no network control protocol info - jfr */
+    case  2: /*ISO8202*/
+    case  3: /*X25 DCE*/
+      for(i=0; i<plci->NL.RLength; i++) plci->ncpi_buffer[4+i] = plci->NL.RBuffer->P[i];
+      plci->ncpi_buffer[0] = (byte)(i+3);
+      plci->ncpi_buffer[1] = (byte)(plci->NL.Ind &N_D_BIT? 1:0);
+      plci->ncpi_buffer[2] = 0;
+      plci->ncpi_buffer[3] = 0;
+      break;
+    case  4: /*T.30 - FAX*/
+    case  5: /*T.30 - FAX*/
+      if(plci->NL.RLength>=sizeof(T30_INFO))
+      {
+        dbug(1,dprintf("FaxStatus %04x", ((T30_INFO   *)plci->NL.RBuffer->P)->code));
+        len = 9;
+        PUT_WORD(&(plci->ncpi_buffer[1]),((T30_INFO   *)plci->NL.RBuffer->P)->rate_div_2400 * 2400);
+        fax_feature_bits = GET_WORD(&((T30_INFO   *)plci->NL.RBuffer->P)->feature_bits_low);
+        i = (((T30_INFO   *)plci->NL.RBuffer->P)->resolution & T30_RESOLUTION_R8_0770_OR_200) ? 0x0001 : 0x0000;
+        if (plci->B3_prot == 5)
+        {
+          if (!(fax_feature_bits & T30_FEATURE_BIT_ECM))
+            i |= 0x8000; /* This is not an ECM connection */
+          if (fax_feature_bits & T30_FEATURE_BIT_T6_CODING)
+            i |= 0x4000; /* This is a connection with MMR compression */
+          if (fax_feature_bits & T30_FEATURE_BIT_2D_CODING)
+            i |= 0x2000; /* This is a connection with MR compression */
+          if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
+            i |= 0x0004; /* More documents */
+          if (fax_feature_bits & T30_FEATURE_BIT_POLLING)
+            i |= 0x0002; /* Fax-polling indication */
+        }
+        dbug(1,dprintf("FAX Options %04x %04x",fax_feature_bits,i));
+        PUT_WORD(&(plci->ncpi_buffer[3]),i);
+        PUT_WORD(&(plci->ncpi_buffer[5]),((T30_INFO   *)plci->NL.RBuffer->P)->data_format);
+        plci->ncpi_buffer[7] = ((T30_INFO   *)plci->NL.RBuffer->P)->pages_low;
+        plci->ncpi_buffer[8] = ((T30_INFO   *)plci->NL.RBuffer->P)->pages_high;
+        plci->ncpi_buffer[len] = 0;
+        if(((T30_INFO   *)plci->NL.RBuffer->P)->station_id_len)
+        {
+          plci->ncpi_buffer[len] = 20;
+          for (i = 0; i < 20; i++)
+            plci->ncpi_buffer[++len] = ((T30_INFO   *)plci->NL.RBuffer->P)->station_id[i];
+        }
+        if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
+        {
+          if (((T30_INFO   *)plci->NL.RBuffer->P)->code < sizeof(fax_info) / sizeof(fax_info[0]))
+            info = fax_info[((T30_INFO   *)plci->NL.RBuffer->P)->code];
+          else
+            info = _FAX_PROTOCOL_ERROR;
+        }
+
+        if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
+          & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
+        {
+          i = ((word)(((T30_INFO *) 0)->station_id + 20)) + ((T30_INFO   *)plci->NL.RBuffer->P)->head_line_len;
+          while (i < plci->NL.RBuffer->length)
+            plci->ncpi_buffer[++len] = plci->NL.RBuffer->P[i++];
+        }
+
+        plci->ncpi_buffer[0] = len;
+        fax_feature_bits = GET_WORD(&((T30_INFO   *)plci->NL.RBuffer->P)->feature_bits_low);
+        PUT_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->feature_bits_low, fax_feature_bits);
+
+        plci->ncpi_state |= NCPI_VALID_CONNECT_B3_IND;
+ if (((plci->NL.Ind &0x0f) == N_CONNECT_ACK)
+         || (((plci->NL.Ind &0x0f) == N_CONNECT)
+          && (fax_feature_bits & T30_FEATURE_BIT_POLLING))
+         || (((plci->NL.Ind &0x0f) == N_EDATA)
+          && ((((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_TRAIN_OK)
+           || (((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS)
+           || (((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_DTC))))
+ {
+          plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT;
+ }
+ if (((plci->NL.Ind &0x0f) == N_DISC)
+  || ((plci->NL.Ind &0x0f) == N_DISC_ACK)
+  || (((plci->NL.Ind &0x0f) == N_EDATA)
+   && (((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_EOP_CAPI)))
+ {
+          plci->ncpi_state |= NCPI_VALID_CONNECT_B3_ACT | NCPI_VALID_DISC_B3_IND;
+ }
+      }
+      break;
+
+    case B3_RTP:
+      if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
+      {
+        if (plci->NL.RLength != 0)
+        {
+          info = rtp_info[plci->NL.RBuffer->P[0]];
+          plci->ncpi_buffer[0] = plci->NL.RLength - 1;
+          for (i = 1; i < plci->NL.RLength; i++)
+            plci->ncpi_buffer[i] = plci->NL.RBuffer->P[i];
+        }
+      }
+      break;
+
+    }
+    plci->NL.RNR = 2;
+  }
+  switch(plci->NL.Ind &0x0f) {
+  case N_EDATA:
+    if ((plci->B3_prot == 4) || (plci->B3_prot == 5))
+    {
+      dbug(1,dprintf("EDATA ncci=0x%x state=%d code=%02x", ncci, a->ncci_state[ncci],
+        ((T30_INFO   *)plci->NL.RBuffer->P)->code));
+      fax_send_edata_ack = (((T30_INFO   *)(plci->fax_connect_info_buffer))->operating_mode == T30_OPERATING_MODE_CAPI_NEG);
+
+      if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
+       && (plci->nsf_control_bits & (T30_NSF_CONTROL_BIT_NEGOTIATE_IND | T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
+       && (((T30_INFO   *)plci->NL.RBuffer->P)->code == EDATA_T30_DIS)
+       && (a->ncci_state[ncci] == OUTG_CON_PENDING)
+       && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+       && !(plci->ncpi_state & NCPI_NEGOTIATE_B3_SENT))
+      {
+        ((T30_INFO   *)(plci->fax_connect_info_buffer))->code = ((T30_INFO   *)plci->NL.RBuffer->P)->code;
+        sendf(plci->appl,_MANUFACTURER_I,Id,0,"dwbS",_DI_MANU_ID,_DI_NEGOTIATE_B3,
+          (byte)(plci->ncpi_buffer[0] + 1), plci->ncpi_buffer);
+        plci->ncpi_state |= NCPI_NEGOTIATE_B3_SENT;
+ if (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)
+   fax_send_edata_ack = FALSE;
+      }
+
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+      {
+        switch (((T30_INFO   *)plci->NL.RBuffer->P)->code)
+        {
+        case EDATA_T30_DIS:
+          if ((a->ncci_state[ncci] == OUTG_CON_PENDING)
+           && !(GET_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low) & T30_CONTROL_BIT_REQUEST_POLLING)
+           && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+           && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+          {
+            a->ncci_state[ncci] = INC_ACT_PENDING;
+            if (plci->B3_prot == 4)
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+            else
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+            plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+          }
+          break;
+
+        case EDATA_T30_TRAIN_OK:
+          if ((a->ncci_state[ncci] == INC_ACT_PENDING)
+           && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+           && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+          {
+            if (plci->B3_prot == 4)
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+            else
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+            plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+          }
+          break;
+
+        case EDATA_T30_EOP_CAPI:
+          if (a->ncci_state[ncci] == CONNECTED)
+          {
+            sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",GOOD,plci->ncpi_buffer);
+            a->ncci_state[ncci] = INC_DIS_PENDING;
+            plci->ncpi_state = 0;
+     fax_send_edata_ack = FALSE;
+          }
+          break;
+        }
+      }
+      else
+      {
+        switch (((T30_INFO   *)plci->NL.RBuffer->P)->code)
+        {
+        case EDATA_T30_TRAIN_OK:
+          if ((a->ncci_state[ncci] == INC_ACT_PENDING)
+           && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+           && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+          {
+            if (plci->B3_prot == 4)
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+            else
+              sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+            plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+          }
+          break;
+        }
+      }
+      if (fax_send_edata_ack)
+      {
+        ((T30_INFO   *)(plci->fax_connect_info_buffer))->code = ((T30_INFO   *)plci->NL.RBuffer->P)->code;
+ plci->fax_edata_ack_length = 1;
+        start_internal_command (Id, plci, fax_edata_ack_command);
+      }
+    }
+    else
+    {
+      dbug(1,dprintf("EDATA ncci=0x%x state=%d", ncci, a->ncci_state[ncci]));
+    }
+    break;
+  case N_CONNECT:
+    if (!a->ch_ncci[ch])
+    {
+      ncci = get_ncci (plci, ch, 0);
+      Id = (Id & 0xffff) | (((dword) ncci) << 16);
+    }
+    dbug(1,dprintf("N_CONNECT: ch=%d state=%d plci=%lx plci_Id=%lx plci_State=%d",
+      ch, a->ncci_state[ncci], a->ncci_plci[ncci], plci->Id, plci->State));
+
+    msg = _CONNECT_B3_I;
+    if (a->ncci_state[ncci] == IDLE)
+      plci->channels++;
+    else if (plci->B3_prot == 1)
+      msg = _CONNECT_B3_T90_ACTIVE_I;
+
+    a->ncci_state[ncci] = INC_CON_PENDING;
+    if(plci->B3_prot == 4)
+      sendf(plci->appl,msg,Id,0,"s","");
+    else
+      sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
+    break;
+  case N_CONNECT_ACK:
+    dbug(1,dprintf("N_connect_Ack"));
+    if (plci->internal_command_queue[0]
+     && ((plci->adjust_b_state == ADJUST_B_CONNECT_2)
+      || (plci->adjust_b_state == ADJUST_B_CONNECT_3)
+      || (plci->adjust_b_state == ADJUST_B_CONNECT_4)))
+    {
+      (*(plci->internal_command_queue[0]))(Id, plci, 0);
+      if (!plci->internal_command)
+        next_internal_command (Id, plci);
+      break;
+    }
+    msg = _CONNECT_B3_ACTIVE_I;
+    if (plci->B3_prot == 1)
+    {
+      if (a->ncci_state[ncci] != OUTG_CON_PENDING)
+        msg = _CONNECT_B3_T90_ACTIVE_I;
+      a->ncci_state[ncci] = INC_ACT_PENDING;
+      sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
+    }
+    else if ((plci->B3_prot == 4) || (plci->B3_prot == 5) || (plci->B3_prot == 7))
+    {
+      if ((a->ncci_state[ncci] == OUTG_CON_PENDING)
+       && (plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+       && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+      {
+        a->ncci_state[ncci] = INC_ACT_PENDING;
+        if (plci->B3_prot == 4)
+          sendf(plci->appl,msg,Id,0,"s","");
+        else
+          sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
+        plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+      }
+    }
+    else
+    {
+      a->ncci_state[ncci] = INC_ACT_PENDING;
+      sendf(plci->appl,msg,Id,0,"S",plci->ncpi_buffer);
+    }
+    if (plci->adjust_b_restore)
+    {
+      plci->adjust_b_restore = FALSE;
+      start_internal_command (Id, plci, adjust_b_restore);
+    }
+    break;
+  case N_DISC:
+  case N_DISC_ACK:
+    if (plci->internal_command_queue[0]
+     && ((plci->internal_command == FAX_DISCONNECT_COMMAND_1)
+      || (plci->internal_command == FAX_DISCONNECT_COMMAND_2)
+      || (plci->internal_command == FAX_DISCONNECT_COMMAND_3)))
+    {
+      (*(plci->internal_command_queue[0]))(Id, plci, 0);
+      if (!plci->internal_command)
+        next_internal_command (Id, plci);
+    }
+    ncci_state = a->ncci_state[ncci];
+    ncci_remove (plci, ncci, FALSE);
+
+        /* with N_DISC or N_DISC_ACK the IDI frees the respective   */
+        /* channel, so we cannot store the state in ncci_state! The */
+        /* information which channel we received a N_DISC is thus   */
+        /* stored in the inc_dis_ncci_table buffer.                 */
+    for(i=0; plci->inc_dis_ncci_table[i]; i++);
+    plci->inc_dis_ncci_table[i] = (byte) ncci;
+
+      /* need a connect_b3_ind before a disconnect_b3_ind with FAX */
+    if (!plci->channels
+     && (plci->B1_resource == 16)
+     && (plci->State <= CONNECTED))
+    {
+      len = 9;
+      i = ((T30_INFO   *)plci->fax_connect_info_buffer)->rate_div_2400 * 2400;
+      PUT_WORD (&plci->ncpi_buffer[1], i);
+      PUT_WORD (&plci->ncpi_buffer[3], 0);
+      i = ((T30_INFO   *)plci->fax_connect_info_buffer)->data_format;
+      PUT_WORD (&plci->ncpi_buffer[5], i);
+      PUT_WORD (&plci->ncpi_buffer[7], 0);
+      plci->ncpi_buffer[len] = 0;
+      plci->ncpi_buffer[0] = len;
+      if(plci->B3_prot == 4)
+        sendf(plci->appl,_CONNECT_B3_I,Id,0,"s","");
+      else
+      {
+
+        if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1])
+          & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
+        {
+          plci->ncpi_buffer[++len] = 0;
+          plci->ncpi_buffer[++len] = 0;
+          plci->ncpi_buffer[++len] = 0;
+          plci->ncpi_buffer[0] = len;
+        }
+
+        sendf(plci->appl,_CONNECT_B3_I,Id,0,"S",plci->ncpi_buffer);
+      }
+      sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",info,plci->ncpi_buffer);
+      plci->ncpi_state = 0;
+      sig_req(plci,HANGUP,0);
+      send_req(plci);
+      plci->State = OUTG_DIS_PENDING;
+      /* disc here */
+    }
+    else if ((a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+     && ((plci->B3_prot == 4) || (plci->B3_prot == 5))
+     && ((ncci_state == INC_DIS_PENDING) || (ncci_state == IDLE)))
+    {
+      if (ncci_state == IDLE)
+      {
+        if (plci->channels)
+          plci->channels--;
+        if((plci->State==IDLE || plci->State==SUSPENDING) && !plci->channels){
+          if(plci->State == SUSPENDING){
+            sendf(plci->appl,
+                  _FACILITY_I,
+                  Id & 0xffffL,
+                  0,
+                  "ws", (word)3, "\x03\x04\x00\x00");
+            sendf(plci->appl, _DISCONNECT_I, Id & 0xffffL, 0, "w", 0);
+          }
+          plci_remove(plci);
+          plci->State=IDLE;
+        }
+      }
+    }
+    else if (plci->channels)
+    {
+      sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",info,plci->ncpi_buffer);
+      plci->ncpi_state = 0;
+      if ((ncci_state == OUTG_REJ_PENDING)
+       && ((plci->B3_prot != B3_T90NL) && (plci->B3_prot != B3_ISO8208) && (plci->B3_prot != B3_X25_DCE)))
+      {
+        sig_req(plci,HANGUP,0);
+        send_req(plci);
+        plci->State = OUTG_DIS_PENDING;
+      }
+    }
+    break;
+  case N_RESET:
+    a->ncci_state[ncci] = INC_RES_PENDING;
+    sendf(plci->appl,_RESET_B3_I,Id,0,"S",plci->ncpi_buffer);
+    break;
+  case N_RESET_ACK:
+    a->ncci_state[ncci] = CONNECTED;
+    sendf(plci->appl,_RESET_B3_I,Id,0,"S",plci->ncpi_buffer);
+    break;
+
+  case N_UDATA:
+    if (!(udata_forwarding_table[plci->NL.RBuffer->P[0] >> 5] & (1L << (plci->NL.RBuffer->P[0] & 0x1f))))
+    {
+      plci->RData[0].P = plci->internal_ind_buffer + (-((int)(plci->internal_ind_buffer)) & 3);
+      plci->RData[0].PLength = INTERNAL_IND_BUFFER_SIZE;
+      plci->NL.R = plci->RData;
+      plci->NL.RNum = 1;
+      return;
+    }
+  case N_BDATA:
+  case N_DATA:
+    if (((a->ncci_state[ncci] != CONNECTED) && (plci->B2_prot == 1)) /* transparent */
+     || (a->ncci_state[ncci] == IDLE)
+     || (a->ncci_state[ncci] == INC_DIS_PENDING))
+    {
+      plci->NL.RNR = 2;
+      break;
+    }
+    if ((a->ncci_state[ncci] != CONNECTED)
+     && (a->ncci_state[ncci] != OUTG_DIS_PENDING)
+     && (a->ncci_state[ncci] != OUTG_REJ_PENDING))
+    {
+      dbug(1,dprintf("flow control"));
+      plci->NL.RNR = 1; /* flow control  */
+      channel_x_off (plci, ch, 0);
+      break;
+    }
+
+    NCCIcode = ncci | (((word)a->Id) << 8);
+
+                /* count all buffers within the Application pool    */
+                /* belonging to the same NCCI. If this is below the */
+                /* number of buffers available per NCCI we accept   */
+                /* this packet, otherwise we reject it              */
+    count = 0;
+    Num = 0xffff;
+    for(i=0; i<APPLptr->MaxBuffer; i++) {
+      if(NCCIcode==APPLptr->DataNCCI[i]) count++;
+      if(!APPLptr->DataNCCI[i] && Num==0xffff) Num = i;
+    }
+
+    if(count>=APPLptr->MaxNCCIData || Num==0xffff)
+    {
+      dbug(3,dprintf("Flow-Control"));
+      plci->NL.RNR = 1;
+      if( ++(APPLptr->NCCIDataFlowCtrlTimer)>=
+       (word)((a->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL) ? 40 : 2000))
+      {
+        plci->NL.RNR = 2;
+        dbug(3,dprintf("DiscardData"));
+      } else {
+        channel_x_off (plci, ch, 0);
+      }
+      break;
+    }
+    else
+    {
+      APPLptr->NCCIDataFlowCtrlTimer = 0;
+    }
+
+    plci->RData[0].P = ReceiveBufferGet(APPLptr,Num);
+    if(!plci->RData[0].P) {
+      plci->NL.RNR = 1;
+      channel_x_off (plci, ch, 0);
+      break;
+    }
+
+    APPLptr->DataNCCI[Num] = NCCIcode;
+    APPLptr->DataFlags[Num] = (plci->Id<<8) | (plci->NL.Ind>>4);
+    dbug(3,dprintf("Buffer(%d), Max = %d",Num,APPLptr->MaxBuffer));
+
+    plci->RNum = Num;
+    plci->RFlags = plci->NL.Ind>>4;
+    plci->RData[0].PLength = APPLptr->MaxDataLength;
+    plci->NL.R = plci->RData;
+    if ((plci->NL.RLength != 0)
+     && ((plci->B2_prot == B2_V120_ASYNC)
+      || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
+      || (plci->B2_prot == B2_V120_BIT_TRANSPARENT)))
+    {
+      plci->RData[1].P = plci->RData[0].P;
+      plci->RData[1].PLength = plci->RData[0].PLength;
+      plci->RData[0].P = v120_header_buffer + (-((int) v120_header_buffer) & 3);
+      if ((plci->NL.RBuffer->P[0] & V120_HEADER_EXTEND_BIT) || (plci->NL.RLength == 1))
+        plci->RData[0].PLength = 1;
+      else
+        plci->RData[0].PLength = 2;
+      if (plci->NL.RBuffer->P[0] & V120_HEADER_BREAK_BIT)
+        plci->RFlags |= 0x0010;
+      if (plci->NL.RBuffer->P[0] & (V120_HEADER_C1_BIT | V120_HEADER_C2_BIT))
+        plci->RFlags |= 0x8000;
+      plci->NL.RNum = 2;
+    }
+    else
+    {
+      if((plci->NL.Ind &0x0f)==N_UDATA)
+        plci->RFlags |= 0x0010;
+
+      else if ((plci->B3_prot == B3_RTP) && ((plci->NL.Ind & 0x0f) == N_BDATA))
+        plci->RFlags |= 0x0001;
+
+      plci->NL.RNum = 1;
+    }
+    break;
+  case N_DATA_ACK:
+    data_ack (plci, ch);
+    break;
+  default:
+    plci->NL.RNR = 2;
+    break;
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* find a free PLCI                                                 */
+/*------------------------------------------------------------------*/
+
+word get_plci(DIVA_CAPI_ADAPTER   * a)
+{
+  word i,j;
+  PLCI   * plci;
+
+  dump_plcis (a);
+  for(i=0;i<a->max_plci && a->plci[i].Id;i++);
+  if(i==a->max_plci) {
+    dbug(1,dprintf("get_plci: out of PLCIs"));
+    return 0;
+  }
+  plci = &a->plci[i];
+  plci->Id = (byte)(i+1);
+
+  plci->Sig.Id = 0;
+  plci->NL.Id = 0;
+  plci->sig_req = 0;
+  plci->nl_req = 0;
+
+  plci->appl = NULL;
+  plci->relatedPTYPLCI = NULL;
+  plci->State = IDLE;
+  plci->SuppState = IDLE;
+  plci->channels = 0;
+  plci->tel = 0;
+  plci->B1_resource = 0;
+  plci->B2_prot = 0;
+  plci->B3_prot = 0;
+
+  plci->command = 0;
+  plci->m_command = 0;
+  init_internal_command_queue (plci);
+  plci->number = 0;
+  plci->req_in_start = 0;
+  plci->req_in = 0;
+  plci->req_out = 0;
+  plci->msg_in_write_pos = MSG_IN_QUEUE_SIZE;
+  plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
+  plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
+
+  plci->data_sent = FALSE;
+  plci->send_disc = 0;
+  plci->sig_global_req = 0;
+  plci->sig_remove_id = 0;
+  plci->nl_global_req = 0;
+  plci->nl_remove_id = 0;
+  plci->adv_nl = 0;
+  plci->manufacturer = FALSE;
+  plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
+  plci->spoofed_msg = 0;
+  plci->ptyState = 0;
+  plci->cr_enquiry = FALSE;
+  plci->hangup_flow_ctrl_timer = 0;
+
+  plci->ncci_ring_list = 0;
+  for(j=0;j<MAX_CHANNELS_PER_PLCI;j++) plci->inc_dis_ncci_table[j] = 0;
+  clear_c_ind_mask (plci);
+  set_group_ind_mask (plci);
+  plci->fax_connect_info_length = 0;
+  plci->nsf_control_bits = 0;
+  plci->ncpi_state = 0x00;
+  plci->ncpi_buffer[0] = 0;
+
+  plci->requested_options_conn = 0;
+  plci->requested_options = 0;
+  plci->notifiedcall = 0;
+  plci->vswitchstate = 0;
+  plci->vsprot = 0;
+  plci->vsprotdialect = 0;
+  init_b1_config (plci);
+  dbug(1,dprintf("get_plci(%x)",plci->Id));
+  return i+1;
+}
+
+/*------------------------------------------------------------------*/
+/* put a parameter in the parameter buffer                          */
+/*------------------------------------------------------------------*/
+
+static void add_p(PLCI   * plci, byte code, byte   * p)
+{
+  word p_length;
+
+  p_length = 0;
+  if(p) p_length = p[0];
+  add_ie(plci, code, p, p_length);
+}
+
+/*------------------------------------------------------------------*/
+/* put a structure in the parameter buffer                          */
+/*------------------------------------------------------------------*/
+static void add_s(PLCI   * plci, byte code, API_PARSE * p)
+{
+  if(p) add_ie(plci, code, p->info, (word)p->length);
+}
+
+/*------------------------------------------------------------------*/
+/* put multiple structures in the parameter buffer                  */
+/*------------------------------------------------------------------*/
+static void add_ss(PLCI   * plci, byte code, API_PARSE * p)
+{
+  byte i;
+
+  if(p){
+    dbug(1,dprintf("add_ss(%x,len=%d)",code,p->length));
+    for(i=2;i<(byte)p->length;i+=p->info[i]+2){
+      dbug(1,dprintf("add_ss_ie(%x,len=%d)",p->info[i-1],p->info[i]));
+      add_ie(plci, p->info[i-1], (byte   *)&(p->info[i]), (word)p->info[i]);
+    }
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* return the channel number sent by the application in a esc_chi   */
+/*------------------------------------------------------------------*/
+static byte getChannel(API_PARSE * p)
+{
+  byte i;
+
+  if(p){
+    for(i=2;i<(byte)p->length;i+=p->info[i]+2){
+      if(p->info[i]==2){
+        if(p->info[i-1]==ESC && p->info[i+1]==CHI) return (p->info[i+2]);
+      }
+    }
+  }
+  return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/* put an information element in the parameter buffer               */
+/*------------------------------------------------------------------*/
+
+static void add_ie(PLCI   * plci, byte code, byte   * p, word p_length)
+{
+  word i;
+
+  if(!(code &0x80) && !p_length) return;
+
+  if(plci->req_in==plci->req_in_start) {
+    plci->req_in +=2;
+  }
+  else {
+    plci->req_in--;
+  }
+  plci->RBuffer[plci->req_in++] = code;
+
+  if(p) {
+    plci->RBuffer[plci->req_in++] = (byte)p_length;
+    for(i=0;i<p_length;i++) plci->RBuffer[plci->req_in++] = p[1+i];
+  }
+
+  plci->RBuffer[plci->req_in++] = 0;
+}
+
+/*------------------------------------------------------------------*/
+/* put a unstructured data into the buffer                          */
+/*------------------------------------------------------------------*/
+
+void add_d(PLCI   * plci, word length, byte   * p)
+{
+  word i;
+
+  if(plci->req_in==plci->req_in_start) {
+    plci->req_in +=2;
+  }
+  else {
+    plci->req_in--;
+  }
+  for(i=0;i<length;i++) plci->RBuffer[plci->req_in++] = p[i];
+}
+
+/*------------------------------------------------------------------*/
+/* put parameters from the Additional Info parameter in the         */
+/* parameter buffer                                                 */
+/*------------------------------------------------------------------*/
+
+void add_ai(PLCI   * plci, API_PARSE * ai)
+{
+  word i;
+    API_PARSE ai_parms[5];
+
+  for(i=0;i<5;i++) ai_parms[i].length = 0;
+
+  if(!ai->length)
+    return;
+  if(api_parse(&ai->info[1], (word)ai->length, "ssss", ai_parms))
+    return;
+
+  add_s (plci,KEY,&ai_parms[1]);
+  add_s (plci,UUI,&ai_parms[2]);
+  add_ss(plci,FTY,&ai_parms[3]);
+}
+
+/*------------------------------------------------------------------*/
+/* put parameter for b1 protocol in the parameter buffer            */
+/*------------------------------------------------------------------*/
+
+word add_b1(PLCI   * plci, API_PARSE * bp, word b_channel_info, word b1_facilities)
+{
+    API_PARSE bp_parms[8];
+    API_PARSE mdm_cfg[9];
+    API_PARSE global_config[2];
+    byte cai[256];
+  byte resource[] = {5,9,13,12,16,39,9,17,17,18};
+  byte voice_cai[] = "\x06\x14\x00\x00\x00\x00\x08";
+  word i;
+
+    API_PARSE mdm_cfg_v18[4];
+  word j, n, w;
+  dword d;
+
+
+  for(i=0;i<8;i++) bp_parms[i].length = 0;
+  for(i=0;i<2;i++) global_config[i].length = 0;
+
+  dbug(1,dprintf("add_b1"));
+  api_save_msg(bp, "s", &plci->B_protocol);
+
+  if(b_channel_info==2){
+    plci->B1_resource = 0;
+    adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
+    add_p(plci, CAI, "\x01\x00");
+    dbug(1,dprintf("Cai=1,0 (no resource)"));
+    return 0;
+  }
+
+  if(plci->tel == CODEC_PERMANENT) return 0;
+  else if(plci->tel == CODEC){
+    plci->B1_resource = 1;
+    adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
+    add_p(plci, CAI, "\x01\x01");
+    dbug(1,dprintf("Cai=1,1 (Codec)"));
+    return 0;
+  }
+  else if(plci->tel == ADV_VOICE){
+    plci->B1_resource = add_b1_facilities (plci, 9, (word)(b1_facilities | B1_FACILITY_VOICE));
+    adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities | B1_FACILITY_VOICE));
+    voice_cai[1] = plci->B1_resource;
+    PUT_WORD (&voice_cai[5], plci->appl->MaxDataLength);
+    add_p(plci, CAI, voice_cai);
+    dbug(1,dprintf("Cai=1,0x%x (AdvVoice)",voice_cai[1]));
+    return 0;
+  }
+  plci->call_dir &= ~(CALL_DIR_ORIGINATE | CALL_DIR_ANSWER);
+  if (plci->call_dir & CALL_DIR_OUT)
+    plci->call_dir |= CALL_DIR_ORIGINATE;
+  else if (plci->call_dir & CALL_DIR_IN)
+    plci->call_dir |= CALL_DIR_ANSWER;
+
+  if(!bp->length){
+    plci->B1_resource = 0x5;
+    adjust_b1_facilities (plci, plci->B1_resource, b1_facilities);
+    add_p(plci, CAI, "\x01\x05");
+    return 0;
+  }
+
+  dbug(1,dprintf("b_prot_len=%d",(word)bp->length));
+  if(bp->length>256) return _WRONG_MESSAGE_FORMAT;
+  if(api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms))
+  {
+    bp_parms[6].length = 0;
+    if(api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms))
+    {
+      dbug(1,dprintf("b-form.!"));
+      return _WRONG_MESSAGE_FORMAT;
+    }
+  }
+  else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms))
+  {
+    dbug(1,dprintf("b-form.!"));
+    return _WRONG_MESSAGE_FORMAT;
+  }
+
+  if(bp_parms[6].length)
+  {
+    if(api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config))
+    {
+      return _WRONG_MESSAGE_FORMAT;
+    }
+    switch(GET_WORD(global_config[0].info))
+    {
+    case 1:
+      plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE;
+      break;
+    case 2:
+      plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER;
+      break;
+    }
+  }
+  dbug(1,dprintf("call_dir=%04x", plci->call_dir));
+
+
+  if ((GET_WORD(bp_parms[0].info) == B1_RTP)
+   && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP)))
+  {
+    plci->B1_resource = add_b1_facilities (plci, 31, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+    adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+    cai[1] = plci->B1_resource;
+    cai[2] = 0;
+    cai[3] = 0;
+    cai[4] = 0;
+    PUT_WORD(&cai[5],plci->appl->MaxDataLength);
+    for (i = 0; i < bp_parms[3].length; i++)
+      cai[7+i] = bp_parms[3].info[1+i];
+    cai[0] = 6 + bp_parms[3].length;
+    add_p(plci, CAI, cai);
+    return 0;
+  }
+
+
+  if ((GET_WORD(bp_parms[0].info) == B1_PIAFS)
+   && (plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS)))
+  {
+    plci->B1_resource = add_b1_facilities (plci, 35/* PIAFS HARDWARE FACILITY */, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+    adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+    cai[1] = plci->B1_resource;
+    cai[2] = 0;
+    cai[3] = 0;
+    cai[4] = 0;
+    PUT_WORD(&cai[5],plci->appl->MaxDataLength);
+    cai[0] = 6;
+    add_p(plci, CAI, cai);
+    return 0;
+  }
+
+
+  if ((GET_WORD(bp_parms[0].info) >= 32)
+   || (!((1L << GET_WORD(bp_parms[0].info)) & plci->adapter->profile.B1_Protocols)
+    && ((GET_WORD(bp_parms[0].info) != 3)
+     || !((1L << B1_HDLC) & plci->adapter->profile.B1_Protocols)
+     || ((bp_parms[3].length != 0) && (GET_WORD(&bp_parms[3].info[1]) != 0) && (GET_WORD(&bp_parms[3].info[1]) != 56000)))))
+  {
+    return _B1_NOT_SUPPORTED;
+  }
+  plci->B1_resource = add_b1_facilities (plci, resource[GET_WORD(bp_parms[0].info)],
+    (word)(b1_facilities & ~B1_FACILITY_VOICE));
+  adjust_b1_facilities (plci, plci->B1_resource, (word)(b1_facilities & ~B1_FACILITY_VOICE));
+  cai[0] = 6;
+  cai[1] = plci->B1_resource;
+  for (i=2;i<sizeof(cai);i++) cai[i] = 0;
+
+  if ((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
+   || (GET_WORD(bp_parms[0].info) == B1_MODEM_ASYNC)
+   || (GET_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC))
+  { /* B1 - modem */
+    for (i=0;i<7;i++) mdm_cfg[i].length = 0;
+
+    if (bp_parms[3].length)
+    {
+      if(api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwww", mdm_cfg))
+      {
+        return (_WRONG_MESSAGE_FORMAT);
+      }
+        
+      cai[2] = 0; /* Bit rate for adaptation */
+
+      dbug(1,dprintf("MDM Max Bit Rate:<%d>", GET_WORD(mdm_cfg[0].info)));
+
+      PUT_WORD (&cai[13], 0);                          /* Min Tx speed */
+      PUT_WORD (&cai[15], GET_WORD(mdm_cfg[0].info)); /* Max Tx speed */
+      PUT_WORD (&cai[17], 0);                          /* Min Rx speed */
+      PUT_WORD (&cai[19], GET_WORD(mdm_cfg[0].info)); /* Max Rx speed */
+
+      cai[3] = 0; /* Async framing parameters */
+      switch (GET_WORD (mdm_cfg[2].info))
+      {       /* Parity     */
+      case 1: /* odd parity */
+        cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD);
+        dbug(1,dprintf("MDM: odd parity"));
+        break;
+
+      case 2: /* even parity */
+        cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN);
+        dbug(1,dprintf("MDM: even parity"));
+        break;
+
+      default:
+        dbug(1,dprintf("MDM: no parity"));
+        break;
+      }
+
+      switch (GET_WORD (mdm_cfg[3].info))
+      {       /* stop bits   */
+      case 1: /* 2 stop bits */
+        cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS;
+        dbug(1,dprintf("MDM: 2 stop bits"));
+        break;
+
+      default:
+        dbug(1,dprintf("MDM: 1 stop bit"));
+        break;
+      }
+
+      switch (GET_WORD (mdm_cfg[1].info))
+      {     /* char length */
+      case 5:
+        cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5;
+        dbug(1,dprintf("MDM: 5 bits"));
+        break;
+
+      case 6:
+        cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6;
+        dbug(1,dprintf("MDM: 6 bits"));
+        break;
+
+      case 7:
+        cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7;
+        dbug(1,dprintf("MDM: 7 bits"));
+        break;
+
+      default:
+        dbug(1,dprintf("MDM: 8 bits"));
+        break;
+      }
+
+      cai[7] = 0; /* Line taking options */
+      cai[8] = 0; /* Modulation negotiation options */
+      cai[9] = 0; /* Modulation options */
+
+      if (((plci->call_dir & CALL_DIR_ORIGINATE) != 0) ^ ((plci->call_dir & CALL_DIR_OUT) != 0))
+      {
+        cai[9] |= DSP_CAI_MODEM_REVERSE_DIRECTION;
+        dbug(1, dprintf("MDM: Reverse direction"));
+      }
+
+      if (GET_WORD (mdm_cfg[4].info) & MDM_CAPI_DISABLE_RETRAIN)
+      {
+        cai[9] |= DSP_CAI_MODEM_DISABLE_RETRAIN;
+        dbug(1, dprintf("MDM: Disable retrain"));
+      }
+
+      if (GET_WORD (mdm_cfg[4].info) & MDM_CAPI_DISABLE_RING_TONE)
+      {
+        cai[7] |= DSP_CAI_MODEM_DISABLE_CALLING_TONE | DSP_CAI_MODEM_DISABLE_ANSWER_TONE;
+        dbug(1, dprintf("MDM: Disable ring tone"));
+      }
+
+      if (GET_WORD (mdm_cfg[4].info) & MDM_CAPI_GUARD_1800)
+      {
+        cai[8] |= DSP_CAI_MODEM_GUARD_TONE_1800HZ;
+        dbug(1, dprintf("MDM: 1800 guard tone"));
+      }
+      else if (GET_WORD (mdm_cfg[4].info) & MDM_CAPI_GUARD_550 )
+      {
+        cai[8] |= DSP_CAI_MODEM_GUARD_TONE_550HZ;
+        dbug(1, dprintf("MDM: 550 guard tone"));
+      }
+
+      if ((GET_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_V100)
+      {
+        cai[8] |= DSP_CAI_MODEM_NEGOTIATE_V100;
+        dbug(1, dprintf("MDM: V100"));
+      }
+      else if ((GET_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_MOD_CLASS)
+      {
+        cai[8] |= DSP_CAI_MODEM_NEGOTIATE_IN_CLASS;
+        dbug(1, dprintf("MDM: IN CLASS"));
+      }
+      else if ((GET_WORD (mdm_cfg[5].info) & 0x00ff) == MDM_CAPI_NEG_DISABLED)
+      {
+        cai[8] |= DSP_CAI_MODEM_NEGOTIATE_DISABLED;
+        dbug(1, dprintf("MDM: DISABLED"));
+      }
+      cai[0] = 20;
+
+      if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_V18))
+       && (GET_WORD(mdm_cfg[5].info) & 0x8000)) /* Private V.18 enable */
+      {
+        plci->requested_options |= 1L << PRIVATE_V18;
+      }
+      if (GET_WORD(mdm_cfg[5].info) & 0x4000) /* Private VOWN enable */
+        plci->requested_options |= 1L << PRIVATE_VOWN;
+
+      if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+        & ((1L << PRIVATE_V18) | (1L << PRIVATE_VOWN)))
+      {
+        if (!api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwwws", mdm_cfg))
+        {
+          i = 27;
+          if (mdm_cfg[6].length >= 4)
+          {
+            d = GET_DWORD(&mdm_cfg[6].info[1]);
+            cai[7] |= (byte) d;          /* line taking options */
+            cai[9] |= (byte)(d >> 8);    /* modulation options */
+            cai[++i] = (byte)(d >> 16);  /* vown modulation options */
+            cai[++i] = (byte)(d >> 24);
+            if (mdm_cfg[6].length >= 8)
+            {
+              d = GET_DWORD(&mdm_cfg[6].info[5]);
+              cai[10] |= (byte) d;        /* disabled modulations mask */
+              cai[11] |= (byte)(d >> 8);
+              if (mdm_cfg[6].length >= 12)
+              {
+                d = GET_DWORD(&mdm_cfg[6].info[9]);
+                cai[12] = (byte) d;          /* enabled modulations mask */
+                cai[++i] = (byte)(d >> 8);   /* vown enabled modulations */
+                cai[++i] = (byte)(d >> 16);
+                cai[++i] = (byte)(d >> 24);
+                cai[++i] = 0;
+                if (mdm_cfg[6].length >= 14)
+                {
+                  w = GET_WORD(&mdm_cfg[6].info[13]);
+                  if (w != 0)
+                    PUT_WORD(&cai[13], w);  /* min tx speed */
+                  if (mdm_cfg[6].length >= 16)
+                  {
+                    w = GET_WORD(&mdm_cfg[6].info[15]);
+                    if (w != 0)
+                      PUT_WORD(&cai[15], w);  /* max tx speed */
+                    if (mdm_cfg[6].length >= 18)
+                    {
+                      w = GET_WORD(&mdm_cfg[6].info[17]);
+                      if (w != 0)
+                        PUT_WORD(&cai[17], w);  /* min rx speed */
+                      if (mdm_cfg[6].length >= 20)
+                      {
+                        w = GET_WORD(&mdm_cfg[6].info[19]);
+                        if (w != 0)
+                          PUT_WORD(&cai[19], w);  /* max rx speed */
+                        if (mdm_cfg[6].length >= 22)
+                        {
+                          w = GET_WORD(&mdm_cfg[6].info[21]);
+                          cai[23] = (byte)(-((short) w));  /* transmit level */
+                          if (mdm_cfg[6].length >= 24)
+                          {
+                            w = GET_WORD(&mdm_cfg[6].info[23]);
+                            cai[22] |= (byte) w;        /* info options mask */
+                            cai[21] |= (byte)(w >> 8);  /* disabled symbol rates */
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+          cai[27] = i - 27;
+          i++;
+          if (!api_parse(&bp_parms[3].info[1],(word)bp_parms[3].length,"wwwwwwss", mdm_cfg))
+          {
+            if (!api_parse(&mdm_cfg[7].info[1],(word)mdm_cfg[7].length,"sss", mdm_cfg_v18))
+            {
+              for (n = 0; n < 3; n++)
+              {
+                cai[i] = (byte)(mdm_cfg_v18[n].length);
+                for (j = 1; j < ((word)(cai[i] + 1)); j++)
+                  cai[i+j] = mdm_cfg_v18[n].info[j];
+                i += cai[i] + 1;
+              }
+            }
+          }
+          cai[0] = (byte)(i - 1);
+        }
+      }
+
+    }
+  }
+  if(GET_WORD(bp_parms[0].info)==2 ||                         /* V.110 async */
+     GET_WORD(bp_parms[0].info)==3 )                          /* V.110 sync */
+  {
+    if(bp_parms[3].length){
+      dbug(1,dprintf("V.110,%d",GET_WORD(&bp_parms[3].info[1])));
+      switch(GET_WORD(&bp_parms[3].info[1])){                 /* Rate */
+        case 0:
+        case 56000:
+          if(GET_WORD(bp_parms[0].info)==3){                  /* V.110 sync 56k */
+            dbug(1,dprintf("56k sync HSCX"));
+            cai[1] = 8;
+            cai[2] = 0;
+            cai[3] = 0;
+          }
+          else if(GET_WORD(bp_parms[0].info)==2){
+            dbug(1,dprintf("56k async DSP"));
+            cai[2] = 9;
+          }
+          break;
+        case 50:     cai[2] = 1;  break;
+        case 75:     cai[2] = 1;  break;
+        case 110:    cai[2] = 1;  break;
+        case 150:    cai[2] = 1;  break;
+        case 200:    cai[2] = 1;  break;
+        case 300:    cai[2] = 1;  break;
+        case 600:    cai[2] = 1;  break;
+        case 1200:   cai[2] = 2;  break;
+        case 2400:   cai[2] = 3;  break;
+        case 4800:   cai[2] = 4;  break;
+        case 7200:   cai[2] = 10; break;
+        case 9600:   cai[2] = 5;  break;
+        case 12000:  cai[2] = 13; break;
+        case 24000:  cai[2] = 0;  break;
+        case 14400:  cai[2] = 11; break;
+        case 19200:  cai[2] = 6;  break;
+        case 28800:  cai[2] = 12; break;
+        case 38400:  cai[2] = 7;  break;
+        case 48000:  cai[2] = 8;  break;
+        case 76:     cai[2] = 15; break;  /* 75/1200     */
+        case 1201:   cai[2] = 14; break;  /* 1200/75     */
+        case 56001:  cai[2] = 9;  break;  /* V.110 56000 */
+
+        default:
+          return _B1_PARM_NOT_SUPPORTED;
+      }
+      cai[3] = 0;
+      if (cai[1] == 13)                                        /* v.110 async */
+      {
+        if (bp_parms[3].length >= 8)
+        {
+          switch (GET_WORD (&bp_parms[3].info[3]))
+          {       /* char length */
+          case 5:
+            cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_5;
+            break;
+          case 6:
+            cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_6;
+            break;
+          case 7:
+            cai[3] |= DSP_CAI_ASYNC_CHAR_LENGTH_7;
+            break;
+          }
+          switch (GET_WORD (&bp_parms[3].info[5]))
+          {       /* Parity     */
+          case 1: /* odd parity */
+            cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_ODD);
+            break;
+          case 2: /* even parity */
+            cai[3] |= (DSP_CAI_ASYNC_PARITY_ENABLE | DSP_CAI_ASYNC_PARITY_EVEN);
+            break;
+          }
+          switch (GET_WORD (&bp_parms[3].info[7]))
+          {       /* stop bits   */
+          case 1: /* 2 stop bits */
+            cai[3] |= DSP_CAI_ASYNC_TWO_STOP_BITS;
+            break;
+          }
+        }
+      }
+    }
+    else if(cai[1]==8 || GET_WORD(bp_parms[0].info)==3 ){
+      dbug(1,dprintf("V.110 default 56k sync"));
+      cai[1] = 8;
+      cai[2] = 0;
+      cai[3] = 0;
+    }
+    else {
+      dbug(1,dprintf("V.110 default 9600 async"));
+      cai[2] = 5;
+    }
+  }
+  PUT_WORD(&cai[5],plci->appl->MaxDataLength);
+  dbug(1,dprintf("CAI[%d]=%x,%x,%x,%x,%x,%x", cai[0], cai[1], cai[2], cai[3], cai[4], cai[5], cai[6]));
+/* HexDump ("CAI", sizeof(cai), &cai[0]); */
+
+  add_p(plci, CAI, cai);
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/* put parameter for b2 and B3  protocol in the parameter buffer    */
+/*------------------------------------------------------------------*/
+
+word add_b23(PLCI   * plci, API_PARSE * bp)
+{
+  word i, fax_control_bits;
+  byte pos, len;
+  byte SAPI = 0x40;  /* default SAPI 16 for x.31 */
+    API_PARSE bp_parms[8];
+  API_PARSE * b1_config;
+  API_PARSE * b2_config;
+    API_PARSE b2_config_parms[8];
+  API_PARSE * b3_config;
+    API_PARSE b3_config_parms[6];
+    API_PARSE global_config[2];
+
+  static byte llc[3] = {2,0,0};
+  static byte dlc[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+  static byte nlc[256];
+  static byte lli[12] = {1,1};
+
+  const byte llc2_out[] = {1,2,4,6,2,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6};
+  const byte llc2_in[]  = {1,3,4,6,3,0,0,0, X75_V42BIS,V120_L2,V120_V42BIS,V120_L2,6};
+
+  const byte llc3[] = {4,3,2,2,6,6,0};
+  const byte header[] = {0,2,3,3,0,0,0};
+
+  for(i=0;i<8;i++) bp_parms[i].length = 0;
+  for(i=0;i<6;i++) b2_config_parms[i].length = 0;
+  for(i=0;i<5;i++) b3_config_parms[i].length = 0;
+
+  lli[0] = 1;
+  lli[1] = 1;
+  if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)
+    lli[1] |= 2;
+  if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL)
+    lli[1] |= 4;
+
+  if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) {
+    lli[1] |= 0x10;
+    if (plci->rx_dma_descriptor <= 0) {
+      plci->rx_dma_descriptor=diva_get_dma_descriptor(plci,&plci->rx_dma_magic);
+      if (plci->rx_dma_descriptor >= 0)
+        plci->rx_dma_descriptor++;
+    }
+    if (plci->rx_dma_descriptor > 0) {
+      lli[0] = 6;
+      lli[1] |= 0x40;
+      lli[2] = (byte)(plci->rx_dma_descriptor - 1);
+      lli[3] = (byte)plci->rx_dma_magic;
+      lli[4] = (byte)(plci->rx_dma_magic >>  8);
+      lli[5] = (byte)(plci->rx_dma_magic >> 16);
+      lli[6] = (byte)(plci->rx_dma_magic >> 24);
+    }
+  }
+
+  if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) {
+    lli[1] |= 0x20;
+  }
+
+  dbug(1,dprintf("add_b23"));
+  api_save_msg(bp, "s", &plci->B_protocol);
+
+  if(!bp->length && plci->tel)
+  {
+    plci->adv_nl = TRUE;
+    dbug(1,dprintf("Default adv.Nl"));
+    add_p(plci,LLI,lli);
+    plci->B2_prot = 1 /*XPARENT*/;
+    plci->B3_prot = 0 /*XPARENT*/;
+    llc[1] = 2;
+    llc[2] = 4;
+    add_p(plci, LLC, llc);
+    dlc[0] = 2;
+    PUT_WORD(&dlc[1],plci->appl->MaxDataLength);
+    add_p(plci, DLC, dlc);
+    return 0;
+  }
+
+  if(!bp->length) /*default*/
+  {   
+    dbug(1,dprintf("ret default"));
+    add_p(plci,LLI,lli);
+    plci->B2_prot = 0 /*X.75   */;
+    plci->B3_prot = 0 /*XPARENT*/;
+    llc[1] = 1;
+    llc[2] = 4;
+    add_p(plci, LLC, llc);
+    dlc[0] = 2;
+    PUT_WORD(&dlc[1],plci->appl->MaxDataLength);
+    add_p(plci, DLC, dlc);
+    return 0;
+  }
+  dbug(1,dprintf("b_prot_len=%d",(word)bp->length));
+  if((word)bp->length > 256)    return _WRONG_MESSAGE_FORMAT;
+
+  if(api_parse(&bp->info[1], (word)bp->length, "wwwsssb", bp_parms))
+  {
+    bp_parms[6].length = 0;
+    if(api_parse(&bp->info[1], (word)bp->length, "wwwsss", bp_parms))
+    {
+      dbug(1,dprintf("b-form.!"));
+      return _WRONG_MESSAGE_FORMAT;
+    }
+  }
+  else if (api_parse(&bp->info[1], (word)bp->length, "wwwssss", bp_parms))
+  {
+    dbug(1,dprintf("b-form.!"));
+    return _WRONG_MESSAGE_FORMAT;
+  }
+
+  if(plci->tel==ADV_VOICE) /* transparent B on advanced voice */
+  {  
+    if(GET_WORD(bp_parms[1].info)!=1
+    || GET_WORD(bp_parms[2].info)!=0) return _B2_NOT_SUPPORTED;
+    plci->adv_nl = TRUE;
+  }
+  else if(plci->tel) return _B2_NOT_SUPPORTED;
+
+
+  if ((GET_WORD(bp_parms[1].info) == B2_RTP)
+   && (GET_WORD(bp_parms[2].info) == B3_RTP)
+   && (plci->adapter->man_profile.private_options & (1L << PRIVATE_RTP)))
+  {
+    add_p(plci,LLI,lli);
+    plci->B2_prot = (byte) GET_WORD(bp_parms[1].info);
+    plci->B3_prot = (byte) GET_WORD(bp_parms[2].info);
+    llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ? 14 : 13;
+    llc[2] = 4;
+    add_p(plci, LLC, llc);
+    dlc[0] = 2;
+    PUT_WORD(&dlc[1],plci->appl->MaxDataLength);
+    dlc[3] = 3; /* Addr A */
+    dlc[4] = 1; /* Addr B */
+    dlc[5] = 7; /* modulo mode */
+    dlc[6] = 7; /* window size */
+    dlc[7] = 0; /* XID len Lo  */
+    dlc[8] = 0; /* XID len Hi  */
+    for (i = 0; i < bp_parms[4].length; i++)
+      dlc[9+i] = bp_parms[4].info[1+i];
+    dlc[0] = (byte)(8 + bp_parms[4].length);
+    add_p(plci, DLC, dlc);
+    for (i = 0; i < bp_parms[5].length; i++)
+      nlc[1+i] = bp_parms[5].info[1+i];
+    nlc[0] = (byte)(bp_parms[5].length);
+    add_p(plci, NLC, nlc);
+    return 0;
+  }
+
+
+
+  if ((GET_WORD(bp_parms[1].info) >= 32)
+   || (!((1L << GET_WORD(bp_parms[1].info)) & plci->adapter->profile.B2_Protocols)
+    && ((GET_WORD(bp_parms[1].info) != B2_PIAFS)
+     || !(plci->adapter->man_profile.private_options & (1L << PRIVATE_PIAFS)))))
+
+  {
+    return _B2_NOT_SUPPORTED;
+  }
+  if ((GET_WORD(bp_parms[2].info) >= 32)
+   || !((1L << GET_WORD(bp_parms[2].info)) & plci->adapter->profile.B3_Protocols))
+  {
+    return _B3_NOT_SUPPORTED;
+  }
+  if ((GET_WORD(bp_parms[1].info) != B2_SDLC)
+   && ((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
+    || (GET_WORD(bp_parms[0].info) == B1_MODEM_ASYNC)
+    || (GET_WORD(bp_parms[0].info) == B1_MODEM_SYNC_HDLC)))
+  {
+    return (add_modem_b23 (plci, bp_parms));
+  }
+
+  add_p(plci,LLI,lli);
+
+  plci->B2_prot = (byte) GET_WORD(bp_parms[1].info);
+  plci->B3_prot = (byte) GET_WORD(bp_parms[2].info);
+  if(plci->B2_prot==12) SAPI = 0; /* default SAPI D-channel */
+
+  if(bp_parms[6].length)
+  {
+    if(api_parse(&bp_parms[6].info[1], (word)bp_parms[6].length, "w", global_config))
+    {
+      return _WRONG_MESSAGE_FORMAT;
+    }
+    switch(GET_WORD(global_config[0].info))
+    {
+    case 1:
+      plci->call_dir = (plci->call_dir & ~CALL_DIR_ANSWER) | CALL_DIR_ORIGINATE;
+      break;
+    case 2:
+      plci->call_dir = (plci->call_dir & ~CALL_DIR_ORIGINATE) | CALL_DIR_ANSWER;
+      break;
+    }
+  }
+  dbug(1,dprintf("call_dir=%04x", plci->call_dir));
+
+
+  if (plci->B2_prot == B2_PIAFS)
+    llc[1] = PIAFS_CRC;
+  else
+/* IMPLEMENT_PIAFS */
+  {
+    llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ?
+             llc2_out[GET_WORD(bp_parms[1].info)] : llc2_in[GET_WORD(bp_parms[1].info)];
+  }
+  llc[2] = llc3[GET_WORD(bp_parms[2].info)];
+
+  add_p(plci, LLC, llc);
+
+  dlc[0] = 2;
+  PUT_WORD(&dlc[1], plci->appl->MaxDataLength +
+                      header[GET_WORD(bp_parms[2].info)]);
+
+  b1_config = &bp_parms[3];
+  nlc[0] = 0;
+  if(plci->B3_prot == 4
+  || plci->B3_prot == 5)
+  {
+    for (i=0;i<sizeof(T30_INFO);i++) nlc[i] = 0;
+    nlc[0] = sizeof(T30_INFO);
+    if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+      ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI;
+    ((T30_INFO *)&nlc[1])->rate_div_2400 = 0xff;
+    if(b1_config->length>=2)
+    {
+      ((T30_INFO *)&nlc[1])->rate_div_2400 = (byte)(GET_WORD(&b1_config->info[1])/2400);
+    }
+  }
+  b2_config = &bp_parms[4];
+
+
+  if (llc[1] == PIAFS_CRC)
+  {
+    if (plci->B3_prot != B3_TRANSPARENT)
+    {
+      return _B_STACK_NOT_SUPPORTED;
+    }
+    if(b2_config->length && api_parse(&b2_config->info[1], (word)b2_config->length, "bwww", b2_config_parms)) {
+      return _WRONG_MESSAGE_FORMAT;
+    }
+    PUT_WORD(&dlc[1],plci->appl->MaxDataLength);
+    dlc[3] = 0; /* Addr A */
+    dlc[4] = 0; /* Addr B */
+    dlc[5] = 0; /* modulo mode */
+    dlc[6] = 0; /* window size */
+    if (b2_config->length >= 7){
+      dlc[ 7] = 7; 
+      dlc[ 8] = 0; 
+      dlc[ 9] = b2_config_parms[0].info[0]; /* PIAFS protocol Speed configuration */
+      dlc[10] = b2_config_parms[1].info[0]; /* V.42bis P0 */
+      dlc[11] = b2_config_parms[1].info[1]; /* V.42bis P0 */
+      dlc[12] = b2_config_parms[2].info[0]; /* V.42bis P1 */
+      dlc[13] = b2_config_parms[2].info[1]; /* V.42bis P1 */
+      dlc[14] = b2_config_parms[3].info[0]; /* V.42bis P2 */
+      dlc[15] = b2_config_parms[3].info[1]; /* V.42bis P2 */
+      dlc[ 0] = 15;
+      if(b2_config->length >= 8) { /* PIAFS control abilities */
+        dlc[ 7] = 10; 
+        dlc[16] = 2; /* Length of PIAFS extention */
+        dlc[17] = PIAFS_UDATA_ABILITIES; /* control (UDATA) ability */
+        dlc[18] = b2_config_parms[4].info[0]; /* value */
+        dlc[ 0] = 18;
+      }
+    }
+    else /* default values, 64K, variable, no compression */
+    {
+      dlc[ 7] = 7; 
+      dlc[ 8] = 0; 
+      dlc[ 9] = 0x03; /* PIAFS protocol Speed configuration */
+      dlc[10] = 0x03; /* V.42bis P0 */
+      dlc[11] = 0;    /* V.42bis P0 */
+      dlc[12] = 0;    /* V.42bis P1 */
+      dlc[13] = 0;    /* V.42bis P1 */
+      dlc[14] = 0;    /* V.42bis P2 */
+      dlc[15] = 0;    /* V.42bis P2 */
+    dlc[ 0] = 15;
+    }
+    add_p(plci, DLC, dlc);
+  }
+  else
+
+  if ((llc[1] == V120_L2) || (llc[1] == V120_V42BIS))
+  {
+    if (plci->B3_prot != B3_TRANSPARENT)
+      return _B_STACK_NOT_SUPPORTED;
+
+    dlc[0] = 6;
+    PUT_WORD (&dlc[1], GET_WORD (&dlc[1]) + 2);
+    dlc[3] = 0x08;
+    dlc[4] = 0x01;
+    dlc[5] = 127;
+    dlc[6] = 7;
+    if (b2_config->length != 0)
+    {
+      if((llc[1]==V120_V42BIS) && api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms)) {
+        return _WRONG_MESSAGE_FORMAT;
+      }
+      dlc[3] = (byte)((b2_config->info[2] << 3) | ((b2_config->info[1] >> 5) & 0x04));
+      dlc[4] = (byte)((b2_config->info[1] << 1) | 0x01);
+      if (b2_config->info[3] != 128)
+      {
+        dbug(1,dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
+        return _B2_PARM_NOT_SUPPORTED;
+      }
+      dlc[5] = (byte)(b2_config->info[3] - 1);
+      dlc[6] = b2_config->info[4];
+      if(llc[1]==V120_V42BIS){
+        if (b2_config->length >= 10){
+          dlc[ 7] = 6; 
+          dlc[ 8] = 0; 
+          dlc[ 9] = b2_config_parms[4].info[0];
+          dlc[10] = b2_config_parms[4].info[1];
+          dlc[11] = b2_config_parms[5].info[0];
+          dlc[12] = b2_config_parms[5].info[1];
+          dlc[13] = b2_config_parms[6].info[0];
+          dlc[14] = b2_config_parms[6].info[1];
+          dlc[ 0] = 14;
+          dbug(1,dprintf("b2_config_parms[4].info[0] [1]:  %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1]));
+          dbug(1,dprintf("b2_config_parms[5].info[0] [1]:  %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1]));
+          dbug(1,dprintf("b2_config_parms[6].info[0] [1]:  %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1]));
+        }
+        else {
+          dlc[ 6] = 14;
+        }
+      }
+    }
+  }
+  else
+  {
+    if(b2_config->length)
+    {
+      dbug(1,dprintf("B2-Config"));
+      if(llc[1]==X75_V42BIS){
+        if(api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbwww", b2_config_parms))
+        {
+          return _WRONG_MESSAGE_FORMAT;
+        }
+      }
+      else {
+        if(api_parse(&b2_config->info[1], (word)b2_config->length, "bbbbs", b2_config_parms))
+        {
+          return _WRONG_MESSAGE_FORMAT;
+        }
+      }
+          /* if B2 Protocol is LAPD, b2_config structure is different */
+      if(llc[1]==6)
+      {
+        dlc[0] = 4;
+        if(b2_config->length>=1) dlc[2] = b2_config->info[1];      /* TEI */
+        else dlc[2] = 0x01;
+        if( (b2_config->length>=2) && (plci->B2_prot==12) )
+        {
+          SAPI = b2_config->info[2];    /* SAPI */
+        }
+        dlc[1] = SAPI;
+        if( (b2_config->length>=3) && (b2_config->info[3]==128) )
+        {
+          dlc[3] = 127;      /* Mode */
+        }
+        else
+        {
+          dlc[3] = 7;        /* Mode */
+        }
+   
+        if(b2_config->length>=4) dlc[4] = b2_config->info[4];      /* Window */
+        else dlc[4] = 1;
+        dbug(1,dprintf("D-dlc[%d]=%x,%x,%x,%x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
+        if(b2_config->length>5) return _B2_PARM_NOT_SUPPORTED;
+      }
+      else
+      {
+        dlc[0] = (byte)(b2_config_parms[4].length+6);
+        dlc[3] = b2_config->info[1];
+        dlc[4] = b2_config->info[2];
+        if(b2_config->info[3]!=8 && b2_config->info[3]!=128){
+          dbug(1,dprintf("1D-dlc= %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4]));
+          return _B2_PARM_NOT_SUPPORTED;
+        }
+
+        dlc[5] = (byte)(b2_config->info[3]-1);
+        dlc[6] = b2_config->info[4];
+        if(dlc[6]>dlc[5]){
+          dbug(1,dprintf("2D-dlc= %x %x %x %x %x %x %x", dlc[0], dlc[1], dlc[2], dlc[3], dlc[4], dlc[5], dlc[6]));
+          return _B2_PARM_NOT_SUPPORTED;
+        }
+ 
+        if(llc[1]==X75_V42BIS) {
+          if (b2_config->length >= 10){
+            dlc[ 7] = 6; 
+            dlc[ 8] = 0; 
+            dlc[ 9] = b2_config_parms[4].info[0];
+            dlc[10] = b2_config_parms[4].info[1];
+            dlc[11] = b2_config_parms[5].info[0];
+            dlc[12] = b2_config_parms[5].info[1];
+            dlc[13] = b2_config_parms[6].info[0];
+            dlc[14] = b2_config_parms[6].info[1];
+            dlc[ 0] = 14;
+            dbug(1,dprintf("b2_config_parms[4].info[0] [1]:  %x %x", b2_config_parms[4].info[0], b2_config_parms[4].info[1]));
+            dbug(1,dprintf("b2_config_parms[5].info[0] [1]:  %x %x", b2_config_parms[5].info[0], b2_config_parms[5].info[1]));
+            dbug(1,dprintf("b2_config_parms[6].info[0] [1]:  %x %x", b2_config_parms[6].info[0], b2_config_parms[6].info[1]));
+          }
+          else {
+            dlc[ 6] = 14;
+          }
+
+        }
+        else {
+          PUT_WORD(&dlc[7], (word)b2_config_parms[4].length);
+          for(i=0; i<b2_config_parms[4].length; i++)
+            dlc[11+i] = b2_config_parms[4].info[1+i];
+        }
+      }
+    }
+  }
+  add_p(plci, DLC, dlc);
+
+  b3_config = &bp_parms[5];
+  if(b3_config->length)
+  {
+    if(plci->B3_prot == 4 
+    || plci->B3_prot == 5)
+    {
+      if(api_parse(&b3_config->info[1], (word)b3_config->length, "wwss", b3_config_parms))
+      {
+        return _WRONG_MESSAGE_FORMAT;
+      }
+      i = GET_WORD((byte   *)(b3_config_parms[0].info));
+      ((T30_INFO *)&nlc[1])->resolution = (byte)(((i & 0x0001) ||
+        ((plci->B3_prot == 4) && (((byte)(GET_WORD((byte   *)b3_config_parms[1].info))) != 5))) ? T30_RESOLUTION_R8_0770_OR_200 : 0);
+      ((T30_INFO *)&nlc[1])->data_format = (byte)(GET_WORD((byte   *)b3_config_parms[1].info));
+      fax_control_bits = T30_CONTROL_BIT_ALL_FEATURES;
+      if ((((T30_INFO *)&nlc[1])->rate_div_2400 != 0) && (((T30_INFO *)&nlc[1])->rate_div_2400 <= 6))
+        fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_V34FAX;
+      if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
+      {
+
+        if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+          & (1L << PRIVATE_FAX_PAPER_FORMATS))
+        {
+          ((T30_INFO *)&nlc[1])->resolution |= T30_RESOLUTION_R8_1540 |
+            T30_RESOLUTION_R16_1540_OR_400 | T30_RESOLUTION_300_300 |
+            T30_RESOLUTION_INCH_BASED | T30_RESOLUTION_METRIC_BASED;
+        }
+
+ ((T30_INFO *)&nlc[1])->recording_properties =
+   T30_RECORDING_WIDTH_ISO_A3 |
+   (T30_RECORDING_LENGTH_UNLIMITED << 2) |
+   (T30_MIN_SCANLINE_TIME_00_00_00 << 4);
+      }
+      if(plci->B3_prot == 5)
+      {
+        if (i & 0x0002) /* Accept incoming fax-polling requests */
+          fax_control_bits |= T30_CONTROL_BIT_ACCEPT_POLLING;
+        if (i & 0x2000) /* Do not use MR compression */
+          fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_2D_CODING;
+        if (i & 0x4000) /* Do not use MMR compression */
+          fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_T6_CODING;
+        if (i & 0x8000) /* Do not use ECM */
+          fax_control_bits &= ~T30_CONTROL_BIT_ENABLE_ECM;
+        if (plci->fax_connect_info_length != 0)
+        {
+          ((T30_INFO *)&nlc[1])->resolution = ((T30_INFO   *)plci->fax_connect_info_buffer)->resolution;
+          ((T30_INFO *)&nlc[1])->data_format = ((T30_INFO   *)plci->fax_connect_info_buffer)->data_format;
+          ((T30_INFO *)&nlc[1])->recording_properties = ((T30_INFO   *)plci->fax_connect_info_buffer)->recording_properties;
+          fax_control_bits |= GET_WORD(&((T30_INFO   *)plci->fax_connect_info_buffer)->control_bits_low) &
+            (T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
+        }
+      }
+      /* copy station id to NLC */
+      for(i=0; i<20; i++)
+      {
+        if(i<b3_config_parms[2].length)
+        {
+          ((T30_INFO *)&nlc[1])->station_id[i] = ((byte   *)b3_config_parms[2].info)[1+i];
+        }
+        else
+        {
+          ((T30_INFO *)&nlc[1])->station_id[i] = ' ';
+        }
+      }
+      ((T30_INFO *)&nlc[1])->station_id_len = 20;
+      /* copy head line to NLC */
+      if(b3_config_parms[3].length)
+      {
+
+        pos = (byte)(fax_head_line_time (&(((T30_INFO *)&nlc[1])->station_id[20])));
+        if (pos != 0)
+        {
+          if (CAPI_MAX_DATE_TIME_LENGTH + 2 + b3_config_parms[3].length > CAPI_MAX_HEAD_LINE_SPACE)
+            pos = 0;
+          else
+          {
+            ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+            ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+            len = (byte)b3_config_parms[2].length;
+            if (len > 20)
+              len = 20;
+            if (CAPI_MAX_DATE_TIME_LENGTH + 2 + len + 2 + b3_config_parms[3].length <= CAPI_MAX_HEAD_LINE_SPACE)
+            {
+              for (i = 0; i < len; i++)
+                ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ((byte   *)b3_config_parms[2].info)[1+i];
+              ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+              ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ' ';
+            }
+          }
+        }
+
+        len = (byte)b3_config_parms[3].length;
+        if (len > CAPI_MAX_HEAD_LINE_SPACE - pos)
+          len = (byte)(CAPI_MAX_HEAD_LINE_SPACE - pos);
+        ((T30_INFO *)&nlc[1])->head_line_len = (byte)(pos + len);
+        nlc[0] += (byte)(pos + len);
+        for (i = 0; i < len; i++)
+          ((T30_INFO *)&nlc[1])->station_id[20 + pos++] = ((byte   *)b3_config_parms[3].info)[1+i];
+        }
+      else
+        ((T30_INFO *)&nlc[1])->head_line_len = 0;
+
+      plci->nsf_control_bits = 0;
+      if(plci->B3_prot == 5)
+      {
+        if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
+         && (GET_WORD((byte   *)b3_config_parms[1].info) & 0x8000)) /* Private SUB/SEP/PWD enable */
+        {
+          plci->requested_options |= 1L << PRIVATE_FAX_SUB_SEP_PWD;
+        }
+        if ((plci->adapter->man_profile.private_options & (1L << PRIVATE_FAX_NONSTANDARD))
+         && (GET_WORD((byte   *)b3_config_parms[1].info) & 0x4000)) /* Private non-standard facilities enable */
+        {
+          plci->requested_options |= 1L << PRIVATE_FAX_NONSTANDARD;
+        }
+        if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+          & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD)))
+        {
+        if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+          & (1L << PRIVATE_FAX_SUB_SEP_PWD))
+        {
+          fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SUBADDRESS | T30_CONTROL_BIT_ACCEPT_PASSWORD;
+          if (fax_control_bits & T30_CONTROL_BIT_ACCEPT_POLLING)
+            fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING;
+          }
+            len = nlc[0];
+          pos = ((byte)(((T30_INFO *) 0)->station_id + 20));
+   if (pos < plci->fax_connect_info_length)
+   {
+     for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
+              nlc[++len] = plci->fax_connect_info_buffer[pos++];
+          }
+   else
+     nlc[++len] = 0;
+   if (pos < plci->fax_connect_info_length)
+   {
+     for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
+              nlc[++len] = plci->fax_connect_info_buffer[pos++];
+          }
+   else
+     nlc[++len] = 0;
+          if ((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[plci->appl->Id-1])
+            & (1L << PRIVATE_FAX_NONSTANDARD))
+          {
+     if ((pos < plci->fax_connect_info_length) && (plci->fax_connect_info_buffer[pos] != 0))
+     {
+              if ((plci->fax_connect_info_buffer[pos] >= 3) && (plci->fax_connect_info_buffer[pos+1] >= 2))
+                plci->nsf_control_bits = GET_WORD(&plci->fax_connect_info_buffer[pos+2]);
+       for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--)
+                nlc[++len] = plci->fax_connect_info_buffer[pos++];
+            }
+     else
+     {
+              if(api_parse(&b3_config->info[1], (word)b3_config->length, "wwsss", b3_config_parms))
+              {
+                dbug(1,dprintf("non-standard facilities info missing or wrong format"));
+                nlc[++len] = 0;
+              }
+       else
+       {
+                if ((b3_config_parms[4].length >= 3) && (b3_config_parms[4].info[1] >= 2))
+                  plci->nsf_control_bits = GET_WORD(&b3_config_parms[4].info[2]);
+         nlc[++len] = (byte)(b3_config_parms[4].length);
+         for (i = 0; i < b3_config_parms[4].length; i++)
+    nlc[++len] = b3_config_parms[4].info[1+i];
+       }
+            }
+          }
+            nlc[0] = len;
+   if ((plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF)
+    && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP))
+   {
+            ((T30_INFO *)&nlc[1])->operating_mode = T30_OPERATING_MODE_CAPI_NEG;
+          }
+        }
+      }
+
+      PUT_WORD(&(((T30_INFO *)&nlc[1])->control_bits_low), fax_control_bits);
+      len = ((byte)(((T30_INFO *) 0)->station_id + 20));
+      for (i = 0; i < len; i++)
+        plci->fax_connect_info_buffer[i] = nlc[1+i];
+      ((T30_INFO   *) plci->fax_connect_info_buffer)->head_line_len = 0;
+      i += ((T30_INFO *)&nlc[1])->head_line_len;
+      while (i < nlc[0])
+        plci->fax_connect_info_buffer[len++] = nlc[++i];
+      plci->fax_connect_info_length = len;
+    }
+    else
+    {
+      nlc[0] = 14;
+      if(b3_config->length!=16)
+        return _B3_PARM_NOT_SUPPORTED;
+      for(i=0; i<12; i++) nlc[1+i] = b3_config->info[1+i];
+      if(GET_WORD(&b3_config->info[13])!=8 && GET_WORD(&b3_config->info[13])!=128)
+        return _B3_PARM_NOT_SUPPORTED;
+      nlc[13] = b3_config->info[13];
+      if(GET_WORD(&b3_config->info[15])>=nlc[13])
+        return _B3_PARM_NOT_SUPPORTED;
+      nlc[14] = b3_config->info[15];
+    }
+  }
+  else
+  {
+    if (plci->B3_prot == 4 
+     || plci->B3_prot == 5 /*T.30 - FAX*/ ) return _B3_PARM_NOT_SUPPORTED;
+  }
+  add_p(plci, NLC, nlc);
+  return 0;
+}
+
+/*----------------------------------------------------------------*/
+/*      make the same as add_b23, but only for the modem related  */
+/*      L2 and L3 B-Chan protocol.                                */
+/*                                                                */
+/*      Enabled L2 and L3 Configurations:                         */
+/*        If L1 == Modem all negotiation                          */
+/*          only L2 == Modem with full negotiation is allowed     */
+/*        If L1 == Modem async or sync                            */
+/*          only L2 == Transparent is allowed                     */
+/*        L3 == Modem or L3 == Transparent are allowed            */
+/*      B2 Configuration for modem:                               */
+/*          word : enable/disable compression, bitoptions         */
+/*      B3 Configuration for modem:                               */
+/*          empty                                                 */
+/*----------------------------------------------------------------*/
+static word add_modem_b23 (PLCI  * plci, API_PARSE* bp_parms)
+{
+  static byte lli[12] = {1,1};
+  static byte llc[3] = {2,0,0};
+  static byte dlc[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+    API_PARSE mdm_config[2];
+  word i;
+  word b2_config = 0;
+
+  for(i=0;i<2;i++) mdm_config[i].length = 0;
+  for(i=0;i<sizeof(dlc);i++) dlc[i] = 0;
+
+  if (((GET_WORD(bp_parms[0].info) == B1_MODEM_ALL_NEGOTIATE)
+    && (GET_WORD(bp_parms[1].info) != B2_MODEM_EC_COMPRESSION))
+   || ((GET_WORD(bp_parms[0].info) != B1_MODEM_ALL_NEGOTIATE)
+    && (GET_WORD(bp_parms[1].info) != B2_TRANSPARENT)))
+  {
+    return (_B_STACK_NOT_SUPPORTED);
+  }
+  if ((GET_WORD(bp_parms[2].info) != B3_MODEM)
+   && (GET_WORD(bp_parms[2].info) != B3_TRANSPARENT))
+  {
+    return (_B_STACK_NOT_SUPPORTED);
+  }
+
+  plci->B2_prot = (byte) GET_WORD(bp_parms[1].info);
+  plci->B3_prot = (byte) GET_WORD(bp_parms[2].info);
+
+  if ((GET_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION) && bp_parms[4].length)
+  {
+    if (api_parse (&bp_parms[4].info[1],
+                  (word)bp_parms[4].length, "w",
+                  mdm_config))
+    {
+      return (_WRONG_MESSAGE_FORMAT);
+    }
+    b2_config = GET_WORD(mdm_config[0].info);
+  }
+
+  /* OK, L2 is modem */
+
+  lli[0] = 1;
+  lli[1] = 1;
+  if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)
+    lli[1] |= 2;
+  if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_OOB_CHANNEL)
+    lli[1] |= 4;
+
+  if ((lli[1] & 0x02) && (diva_xdi_extended_features & DIVA_CAPI_USE_CMA)) {
+    lli[1] |= 0x10;
+    if (plci->rx_dma_descriptor <= 0) {
+      plci->rx_dma_descriptor=diva_get_dma_descriptor(plci,&plci->rx_dma_magic);
+      if (plci->rx_dma_descriptor >= 0)
+        plci->rx_dma_descriptor++;
+    }
+    if (plci->rx_dma_descriptor > 0) {
+      lli[1] |= 0x40;
+      lli[0] = 6;
+      lli[2] = (byte)(plci->rx_dma_descriptor - 1);
+      lli[3] = (byte)plci->rx_dma_magic;
+      lli[4] = (byte)(plci->rx_dma_magic >>  8);
+      lli[5] = (byte)(plci->rx_dma_magic >> 16);
+      lli[6] = (byte)(plci->rx_dma_magic >> 24);
+    }
+  }
+
+  if (DIVA_CAPI_SUPPORTS_NO_CANCEL(plci->adapter)) {
+    lli[1] |= 0x20;
+  }
+
+  llc[1] = (plci->call_dir & (CALL_DIR_ORIGINATE | CALL_DIR_FORCE_OUTG_NL)) ?
+    /*V42*/ 10 : /*V42_IN*/ 9;
+  llc[2] = 4;                      /* pass L3 always transparent */
+  add_p(plci, LLI, lli);
+  add_p(plci, LLC, llc);
+  i =  1;
+  PUT_WORD (&dlc[i], plci->appl->MaxDataLength);
+  i += 2;
+  if (GET_WORD(bp_parms[1].info) == B2_MODEM_EC_COMPRESSION)
+  {
+    if (bp_parms[4].length)
+  {
+    dbug(1, dprintf("MDM b2_config=%02x", b2_config));
+    dlc[i++] = 3; /* Addr A */
+    dlc[i++] = 1; /* Addr B */
+    dlc[i++] = 7; /* modulo mode */
+    dlc[i++] = 7; /* window size */
+    dlc[i++] = 0; /* XID len Lo  */
+    dlc[i++] = 0; /* XID len Hi  */
+
+    if (b2_config & MDM_B2_DISABLE_V42bis)
+    {
+      dlc[i] |= DLC_MODEMPROT_DISABLE_V42_V42BIS;
+    }
+    if (b2_config & MDM_B2_DISABLE_MNP)
+    {
+      dlc[i] |= DLC_MODEMPROT_DISABLE_MNP_MNP5;
+    }
+    if (b2_config & MDM_B2_DISABLE_TRANS)
+    {
+      dlc[i] |= DLC_MODEMPROT_REQUIRE_PROTOCOL;
+    }
+    if (b2_config & MDM_B2_DISABLE_V42)
+    {
+      dlc[i] |= DLC_MODEMPROT_DISABLE_V42_DETECT;
+    }
+    if (b2_config & MDM_B2_DISABLE_COMP)
+    {
+      dlc[i] |= DLC_MODEMPROT_DISABLE_COMPRESSION;
+    }
+    i++;
+  }
+  }
+  else
+  {
+    dlc[i++] = 3; /* Addr A */
+    dlc[i++] = 1; /* Addr B */
+    dlc[i++] = 7; /* modulo mode */
+    dlc[i++] = 7; /* window size */
+    dlc[i++] = 0; /* XID len Lo  */
+    dlc[i++] = 0; /* XID len Hi  */
+    dlc[i++] = DLC_MODEMPROT_DISABLE_V42_V42BIS |
+               DLC_MODEMPROT_DISABLE_MNP_MNP5 |
+               DLC_MODEMPROT_DISABLE_V42_DETECT |
+               DLC_MODEMPROT_DISABLE_COMPRESSION;
+  }
+  dlc[0] = (byte)(i - 1);
+/* HexDump ("DLC", sizeof(dlc), &dlc[0]); */
+  add_p(plci, DLC, dlc);
+  return (0);
+}
+
+
+/*------------------------------------------------------------------*/
+/* send a request for the signaling entity                          */
+/*------------------------------------------------------------------*/
+
+void sig_req(PLCI   * plci, byte req, byte Id)
+{
+  if(!plci) return;
+  if(plci->adapter->adapter_disabled) return;
+  dbug(1,dprintf("sig_req(%x)",req));
+  if (req == REMOVE)
+    plci->sig_remove_id = plci->Sig.Id;
+  if(plci->req_in==plci->req_in_start) {
+    plci->req_in +=2;
+    plci->RBuffer[plci->req_in++] = 0;
+  }
+  PUT_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start-2);
+  plci->RBuffer[plci->req_in++] = Id;   /* sig/nl flag */
+  plci->RBuffer[plci->req_in++] = req;  /* request */
+  plci->RBuffer[plci->req_in++] = 0;    /* channel */
+  plci->req_in_start = plci->req_in;
+}
+
+/*------------------------------------------------------------------*/
+/* send a request for the network layer entity                      */
+/*------------------------------------------------------------------*/
+
+void nl_req_ncci(PLCI   * plci, byte req, byte ncci)
+{
+  if(!plci) return;
+  if(plci->adapter->adapter_disabled) return;
+  dbug(1,dprintf("nl_req %02x %02x %02x", plci->Id, req, ncci));
+  if (req == REMOVE)
+  {
+    plci->nl_remove_id = plci->NL.Id;
+    ncci_remove (plci, 0, (byte)(ncci != 0));
+    ncci = 0;
+  }
+  if(plci->req_in==plci->req_in_start) {
+    plci->req_in +=2;
+    plci->RBuffer[plci->req_in++] = 0;
+  }
+  PUT_WORD(&plci->RBuffer[plci->req_in_start], plci->req_in-plci->req_in_start-2);
+  plci->RBuffer[plci->req_in++] = 1;    /* sig/nl flag */
+  plci->RBuffer[plci->req_in++] = req;  /* request */
+  plci->RBuffer[plci->req_in++] = plci->adapter->ncci_ch[ncci];   /* channel */
+  plci->req_in_start = plci->req_in;
+}
+
+void send_req(PLCI   * plci)
+{
+  ENTITY   * e;
+  word l;
+/*  word i; */
+
+  if(!plci) return;
+  if(plci->adapter->adapter_disabled) return;
+  channel_xmit_xon (plci);
+
+        /* if nothing to do, return */
+  if(plci->req_in==plci->req_out) return;
+  dbug(1,dprintf("send_req(in=%d,out=%d)",plci->req_in,plci->req_out));
+
+  if(plci->nl_req || plci->sig_req) return;
+
+  l = GET_WORD(&plci->RBuffer[plci->req_out]);
+  plci->req_out += 2;
+  plci->XData[0].P = &plci->RBuffer[plci->req_out];
+  plci->req_out += l;
+  if(plci->RBuffer[plci->req_out]==1)
+  {
+    e = &plci->NL;
+    plci->req_out++;
+    e->Req = plci->nl_req = plci->RBuffer[plci->req_out++];
+    e->ReqCh = plci->RBuffer[plci->req_out++];
+    if(!(e->Id & 0x1f))
+    {
+      e->Id = NL_ID;
+      plci->RBuffer[plci->req_out-4] = CAI;
+      plci->RBuffer[plci->req_out-3] = 1;
+      plci->RBuffer[plci->req_out-2] = (plci->Sig.Id==0xff) ? 0 : plci->Sig.Id;
+      plci->RBuffer[plci->req_out-1] = 0;
+      l+=3;
+      plci->nl_global_req = plci->nl_req;
+    }
+    dbug(1,dprintf("%x:NLREQ(%x:%x:%x)",plci->adapter->Id,e->Id,e->Req,e->ReqCh));
+  }
+  else
+  {
+    e = &plci->Sig;
+    if(plci->RBuffer[plci->req_out])
+      e->Id = plci->RBuffer[plci->req_out];
+    plci->req_out++;
+    e->Req = plci->sig_req = plci->RBuffer[plci->req_out++];
+    e->ReqCh = plci->RBuffer[plci->req_out++];
+    if(!(e->Id & 0x1f))
+      plci->sig_global_req = plci->sig_req;
+    dbug(1,dprintf("%x:SIGREQ(%x:%x:%x)",plci->adapter->Id,e->Id,e->Req,e->ReqCh));
+  }
+  plci->XData[0].PLength = l;
+  e->X = plci->XData;
+  plci->adapter->request(e);
+  dbug(1,dprintf("send_ok"));
+}
+
+void send_data(PLCI   * plci)
+{
+  DIVA_CAPI_ADAPTER   * a;
+  DATA_B3_DESC   * data;
+  NCCI   *ncci_ptr;
+  word ncci;
+
+  if (!plci->nl_req && plci->ncci_ring_list)
+  {
+    a = plci->adapter;
+    ncci = plci->ncci_ring_list;
+    do
+    {
+      ncci = a->ncci_next[ncci];
+      ncci_ptr = &(a->ncci[ncci]);
+      if (!(a->ncci_ch[ncci]
+         && (a->ch_flow_control[a->ncci_ch[ncci]] & N_OK_FC_PENDING)))
+      {
+        if (ncci_ptr->data_pending)
+        {
+          if ((a->ncci_state[ncci] == CONNECTED)
+           || (a->ncci_state[ncci] == INC_ACT_PENDING)
+           || (plci->send_disc == ncci))
+          {
+            data = &(ncci_ptr->DBuffer[ncci_ptr->data_out]);
+            if ((plci->B2_prot == B2_V120_ASYNC)
+             || (plci->B2_prot == B2_V120_ASYNC_V42BIS)
+             || (plci->B2_prot == B2_V120_BIT_TRANSPARENT))
+            {
+              plci->NData[1].P = TransmitBufferGet (plci->appl, data->P);
+              plci->NData[1].PLength = data->Length;
+              if (data->Flags & 0x10)
+                plci->NData[0].P = v120_break_header;
+              else
+                plci->NData[0].P = v120_default_header;
+              plci->NData[0].PLength = 1 ;
+              plci->NL.XNum = 2;
+              plci->NL.Req = plci->nl_req = (byte)((data->Flags&0x07)<<4 |N_DATA);
+            }
+            else
+            {
+              plci->NData[0].P = TransmitBufferGet (plci->appl, data->P);
+              plci->NData[0].PLength = data->Length;
+              if (data->Flags & 0x10)
+                plci->NL.Req = plci->nl_req = (byte)N_UDATA;
+
+              else if ((plci->B3_prot == B3_RTP) && (data->Flags & 0x01))
+                plci->NL.Req = plci->nl_req = (byte)N_BDATA;
+
+              else
+                plci->NL.Req = plci->nl_req = (byte)((data->Flags&0x07)<<4 |N_DATA);
+            }
+            plci->NL.X = plci->NData;
+            plci->NL.ReqCh = a->ncci_ch[ncci];
+            dbug(1,dprintf("%x:DREQ(%x:%x)",a->Id,plci->NL.Id,plci->NL.Req));
+            plci->data_sent = TRUE;
+            plci->data_sent_ptr = data->P;
+            a->request(&plci->NL);
+          }
+          else {
+            cleanup_ncci_data (plci, ncci);
+          }
+        }
+        else if (plci->send_disc == ncci)
+        {
+          /* dprintf("N_DISC"); */
+          plci->NData[0].PLength = 0;
+          plci->NL.ReqCh = a->ncci_ch[ncci];
+          plci->NL.Req = plci->nl_req = N_DISC;
+          a->request(&plci->NL);
+          plci->command = _DISCONNECT_B3_R;
+          plci->send_disc = 0;
+        }
+      }
+    } while (!plci->nl_req && (ncci != plci->ncci_ring_list));
+    plci->ncci_ring_list = ncci;
+  }
+}
+
+void listen_check(DIVA_CAPI_ADAPTER   * a)
+{
+  word i,j;
+  PLCI   * plci;
+  byte activnotifiedcalls = 0;
+
+  dbug(1,dprintf("listen_check(%d,%d)",a->listen_active,a->max_listen));
+  if (!remove_started && !a->adapter_disabled)
+  {
+    for(i=0;i<a->max_plci;i++)
+    {
+      plci = &(a->plci[i]);
+      if(plci->notifiedcall) activnotifiedcalls++;
+    }
+    dbug(1,dprintf("listen_check(%d)",activnotifiedcalls));
+
+    for(i=a->listen_active; i < ((word)(a->max_listen+activnotifiedcalls)); i++) {
+      if((j=get_plci(a))) {
+        a->listen_active++;
+        plci = &a->plci[j-1];
+        plci->State = LISTENING;
+
+        add_p(plci,OAD,"\x01\xfd");
+
+        add_p(plci,KEY,"\x04\x43\x41\x32\x30");
+
+        add_p(plci,CAI,"\x01\xc0");
+        add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+        add_p(plci,LLI,"\x01\xc4");                  /* support Dummy CR FAC + MWI + SpoofNotify */       
+        add_p(plci,SHIFT|6,NULL);
+        add_p(plci,SIN,"\x02\x00\x00");
+        plci->internal_command = LISTEN_SIG_ASSIGN_PEND;     /* do indicate_req if OK  */
+        sig_req(plci,ASSIGN,DSIG_ID);
+        send_req(plci);
+      }
+    }
+  }
+}
+
+/*------------------------------------------------------------------*/
+/* functions for all parameters sent in INDs                        */
+/*------------------------------------------------------------------*/
+
+void IndParse(PLCI   * plci, word * parms_id, byte   ** parms, byte multiIEsize)
+{
+  word ploc;            /* points to current location within packet */
+  byte w;
+  byte wlen;
+  byte codeset,lock;
+  byte   * in;
+  word i;
+  word code;
+  word mIEindex = 0;
+  ploc = 0;
+  codeset = 0;
+  lock = 0;
+
+  in = plci->Sig.RBuffer->P;
+  for(i=0; i<parms_id[0]; i++)   /* multiIE parms_id contains just the 1st */
+  {                            /* element but parms array is larger      */
+    parms[i] = (byte   *)"";
+  }
+  for(i=0; i<multiIEsize; i++)
+  {
+    parms[i] = (byte   *)"";
+  }
+
+  while(ploc<plci->Sig.RBuffer->length-1) {
+
+        /* read information element id and length                   */
+    w = in[ploc];
+
+    if(w & 0x80) {
+/*    w &=0xf0; removed, cannot detect congestion levels */
+/*    upper 4 bit masked with w==SHIFT now               */
+      wlen = 0;
+    }
+    else {
+      wlen = (byte)(in[ploc+1]+1);
+    }
+        /* check if length valid (not exceeding end of packet)      */
+    if((ploc+wlen) > 270) return ;
+    if(lock & 0x80) lock &=0x7f;
+    else codeset = lock;
+
+    if((w&0xf0)==SHIFT) {
+      codeset = in[ploc];
+      if(!(codeset & 0x08)) lock = (byte)(codeset & 7);
+      codeset &=7;
+      lock |=0x80;
+    }
+    else {
+      if(w==ESC && wlen>=3) code = in[ploc+2] |0x800;
+      else code = w;
+      code |= (codeset<<8);
+
+      for(i=1; i<parms_id[0]+1 && parms_id[i]!=code; i++);
+
+      if(i<parms_id[0]+1) {
+        if(!multiIEsize) { /* with multiIEs use next field index,          */
+          mIEindex = i-1;    /* with normal IEs use same index like parms_id */
+        }
+
+        parms[mIEindex] = &in[ploc+1];
+        dbug(1,dprintf("mIE[%d]=0x%x",*parms[mIEindex],in[ploc]));
+        if(parms_id[i]==OAD
+        || parms_id[i]==CONN_NR
+        || parms_id[i]==CAD) {
+          if(in[ploc+2] &0x80) {
+            in[ploc+0] = (byte)(in[ploc+1]+1);
+            in[ploc+1] = (byte)(in[ploc+2] &0x7f);
+            in[ploc+2] = 0x80;
+            parms[mIEindex] = &in[ploc];
+          }
+        }
+        mIEindex++;       /* effects multiIEs only */
+      }
+    }
+
+    ploc +=(wlen+1);
+  }
+  return ;
+}
+
+/*------------------------------------------------------------------*/
+/* try to match a cip from received BC and HLC                      */
+/*------------------------------------------------------------------*/
+
+byte ie_compare(byte   * ie1, byte * ie2)
+{
+  word i;
+  if(!ie1 || ! ie2) return FALSE;
+  if(!ie1[0]) return FALSE;
+  for(i=0;i<(word)(ie1[0]+1);i++) if(ie1[i]!=ie2[i]) return FALSE;
+  return TRUE;
+}
+
+word find_cip(DIVA_CAPI_ADAPTER   * a, byte   * bc, byte   * hlc)
+{
+  word i;
+  word j;
+
+  for(i=9;i && !ie_compare(bc,cip_bc[i][a->u_law]);i--);
+
+  for(j=16;j<29 &&
+           (!ie_compare(bc,cip_bc[j][a->u_law]) || !ie_compare(hlc,cip_hlc[j])); j++);
+  if(j==29) return i;
+  return j;
+}
+
+
+static byte AddInfo(byte   **add_i,
+                    byte   **fty_i,
+                    byte   *esc_chi,
+                    byte *facility)
+{
+  byte i;
+  byte j;
+  byte k;
+  byte flen;
+  byte len=0;
+   /* facility is a nested structure */
+   /* FTY can be more than once      */
+
+  if(esc_chi[0] && !(esc_chi[esc_chi[0]])&0x7f )
+  {
+    add_i[0] = (byte   *)"\x02\x02\x00"; /* use neither b nor d channel */
+  }
+
+  else
+  {
+    add_i[0] = (byte   *)"";
+  }
+  if(!fty_i[0][0])
+  {
+    add_i[3] = (byte   *)"";
+  }
+  else
+  {    /* facility array found  */
+    for(i=0,j=1;i<MAX_MULTI_IE && fty_i[i][0];i++)
+    {
+      dbug(1,dprintf("AddIFac[%d]",fty_i[i][0]));
+      len += fty_i[i][0];
+      len += 2;
+      flen=fty_i[i][0];
+      facility[j++]=0x1c; /* copy fac IE */
+      for(k=0;k<=flen;k++,j++)
+      {
+        facility[j]=fty_i[i][k];
+/*      dbug(1,dprintf("%x ",facility[j])); */
+      }
+    }
+    facility[0] = len;
+    add_i[3] = facility;
+  }
+/*  dbug(1,dprintf("FacArrLen=%d ",len)); */
+  len = add_i[0][0]+add_i[1][0]+add_i[2][0]+add_i[3][0];
+  len += 4;                          /* calculate length of all */
+  return(len);
+}
+
+/*------------------------------------------------------------------*/
+/* voice and codec features                                         */
+/*------------------------------------------------------------------*/
+
+void SetVoiceChannel(PLCI   *plci, byte   *chi, DIVA_CAPI_ADAPTER   * a)
+{
+  byte voice_chi[] = "\x02\x18\x01";
+  byte channel;
+
+  channel = chi[chi[0]]&0x3;
+  dbug(1,dprintf("ExtDevON(Ch=0x%x)",channel));
+  voice_chi[2] = (channel) ? channel : 1;
+  add_p(plci,FTY,"\x02\x01\x07");             /* B On, default on 1 */
+  add_p(plci,ESC,voice_chi);                  /* Channel */
+  sig_req(plci,TEL_CTRL,0);
+  send_req(plci);
+  if(a->AdvSignalPLCI)
+  {
+    adv_voice_write_coefs (a->AdvSignalPLCI, ADV_VOICE_WRITE_ACTIVATION);
+  }
+}
+
+void VoiceChannelOff(PLCI   *plci)
+{
+  dbug(1,dprintf("ExtDevOFF"));
+  add_p(plci,FTY,"\x02\x01\x08");             /* B Off */
+  sig_req(plci,TEL_CTRL,0);
+  send_req(plci);
+  if(plci->adapter->AdvSignalPLCI)
+  {
+    adv_voice_clear_config (plci->adapter->AdvSignalPLCI);
+  }
+}
+
+
+word AdvCodecSupport(DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, byte hook_listen)
+{
+  word j;
+  PLCI   *splci;
+
+  /* check if hardware supports handset with hook states (adv.codec) */
+  /* or if just a on board codec is supported                        */
+  /* the advanced codec plci is just for internal use                */
+
+  /* diva Pro with on-board codec:                                   */
+  if(a->profile.Global_Options & HANDSET)
+  {
+    /* new call, but hook states are already signalled */
+    if(a->AdvCodecFLAG)
+    {
+      if(a->AdvSignalAppl!=appl || a->AdvSignalPLCI)
+      {
+        dbug(1,dprintf("AdvSigPlci=0x%x",a->AdvSignalPLCI));
+        return 0x2001; /* codec in use by another application */
+      }
+      if(plci!=0)
+      {
+        a->AdvSignalPLCI = plci;
+        plci->tel=ADV_VOICE;
+      }
+      return 0;                      /* adv codec still used */
+    }
+    if((j=get_plci(a)))
+    {
+      splci = &a->plci[j-1];
+      splci->tel = CODEC_PERMANENT;
+      /* hook_listen indicates if a facility_req with handset/hook support */
+      /* was sent. Otherwise if just a call on an external device was made */
+      /* the codec will be used but the hook info will be discarded (just  */
+      /* the external controller is in use                                 */
+      if(hook_listen) splci->State = ADVANCED_VOICE_SIG;
+      else
+      {
+        splci->State = ADVANCED_VOICE_NOSIG;
+        if(plci)
+        {
+          plci->spoofed_msg = SPOOFING_REQUIRED;
+        }
+                                               /* indicate D-ch connect if  */
+      }                                        /* codec is connected OK     */
+      if(plci!=0)
+      {
+        a->AdvSignalPLCI = plci;
+        plci->tel=ADV_VOICE;
+      }
+      a->AdvSignalAppl = appl;
+      a->AdvCodecFLAG = TRUE;
+      a->AdvCodecPLCI = splci;
+      add_p(splci,CAI,"\x01\x15");
+      add_p(splci,LLI,"\x01\x00");
+      add_p(splci,ESC,"\x02\x18\x00");
+      add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+      splci->internal_command = PERM_COD_ASSIGN;
+      dbug(1,dprintf("Codec Assign"));
+      sig_req(splci,ASSIGN,DSIG_ID);
+      send_req(splci);
+    }
+    else
+    {
+      return 0x2001; /* wrong state, no more plcis */
+    }
+  }
+  else if(a->profile.Global_Options & ON_BOARD_CODEC)
+  {
+    if(hook_listen) return 0x300B;               /* Facility not supported */
+                                                 /* no hook with SCOM      */
+    if(plci!=0) plci->tel = CODEC;
+    dbug(1,dprintf("S/SCOM codec"));
+    /* first time we use the scom-s codec we must shut down the internal   */
+    /* handset application of the card. This can be done by an assign with */
+    /* a cai with the 0x80 bit set. Assign return code is 'out of resource'*/
+    if(!a->scom_appl_disable){
+      if((j=get_plci(a))) {
+        splci = &a->plci[j-1];
+        add_p(splci,CAI,"\x01\x80");
+        add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+        sig_req(splci,ASSIGN,0xC0);  /* 0xc0 is the TEL_ID */
+        send_req(splci);
+        a->scom_appl_disable = TRUE;
+      }
+      else{
+        return 0x2001; /* wrong state, no more plcis */
+      }
+    }
+  }
+  else return 0x300B;               /* Facility not supported */
+
+  return 0;
+}
+
+
+void CodecIdCheck(DIVA_CAPI_ADAPTER   *a, PLCI   *plci)
+{
+
+  dbug(1,dprintf("CodecIdCheck"));
+
+  if(a->AdvSignalPLCI == plci)
+  {
+    dbug(1,dprintf("PLCI owns codec"));
+    VoiceChannelOff(a->AdvCodecPLCI);
+    if(a->AdvCodecPLCI->State == ADVANCED_VOICE_NOSIG)
+    {
+      dbug(1,dprintf("remove temp codec PLCI"));
+      plci_remove(a->AdvCodecPLCI);
+      a->AdvCodecFLAG  = 0;
+      a->AdvCodecPLCI  = NULL;
+      a->AdvSignalAppl = NULL;
+    }
+    a->AdvSignalPLCI = NULL;
+  }
+}
+
+/* -------------------------------------------------------------------
+    Ask for physical address of card on PCI bus
+   ------------------------------------------------------------------- */
+static void diva_ask_for_xdi_sdram_bar (DIVA_CAPI_ADAPTER  * a,
+                                        IDI_SYNC_REQ  * preq) {
+  a->sdram_bar = 0;
+  if (diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR) {
+    ENTITY   * e = (ENTITY   *)preq;
+
+    e->user[0] = a->Id - 1;
+    preq->xdi_sdram_bar.info.bar    = 0;
+    preq->xdi_sdram_bar.Req         = 0;
+    preq->xdi_sdram_bar.Rc           = IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR;
+
+    (*(a->request))(e);
+
+    a->sdram_bar = preq->xdi_sdram_bar.info.bar;
+    dbug(3,dprintf("A(%d) SDRAM BAR = %08x", a->Id, a->sdram_bar));
+  }
+}
+
+/* -------------------------------------------------------------------
+     Ask XDI about extended features
+   ------------------------------------------------------------------- */
+static void diva_get_extended_adapter_features (DIVA_CAPI_ADAPTER  * a) {
+  IDI_SYNC_REQ   * preq;
+    char buffer[              ((sizeof(preq->xdi_extended_features)+4) > sizeof(ENTITY)) ?                     (sizeof(preq->xdi_extended_features)+4) : sizeof(ENTITY)];
+
+    char features[4];
+  preq = (IDI_SYNC_REQ   *)&buffer[0];
+
+  if (!diva_xdi_extended_features) {
+    ENTITY   * e = (ENTITY   *)preq;
+    diva_xdi_extended_features |= 0x80000000;
+
+    e->user[0] = a->Id - 1;
+    preq->xdi_extended_features.Req = 0;
+    preq->xdi_extended_features.Rc  = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES;
+    preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features);
+    preq->xdi_extended_features.info.features = &features[0];
+
+    (*(a->request))(e);
+
+    if (features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) {
+      /*
+         Check features located in the byte '0'
+         */
+      if (features[0] & DIVA_XDI_EXTENDED_FEATURE_CMA) {
+        diva_xdi_extended_features |= DIVA_CAPI_USE_CMA;
+      }
+      if (features[0] & DIVA_XDI_EXTENDED_FEATURE_RX_DMA) {
+        diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_RX_DMA;
+        dbug(1,dprintf("XDI provides RxDMA"));
+      }
+      if (features[0] & DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR) {
+        diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_SDRAM_BAR;
+      }
+      if (features[0] & DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC) {
+        diva_xdi_extended_features |= DIVA_CAPI_XDI_PROVIDES_NO_CANCEL;
+        dbug(3,dprintf("XDI provides NO_CANCEL_RC feature"));
+      }
+
+    }
+  }
+
+  diva_ask_for_xdi_sdram_bar (a, preq);
+}
+
+/*------------------------------------------------------------------*/
+/* automatic law                                                    */
+/*------------------------------------------------------------------*/
+/* called from OS specific part after init time to get the Law              */
+/* a-law (Euro) and u-law (us,japan) use different BCs in the Setup message */
+void AutomaticLaw(DIVA_CAPI_ADAPTER   *a)
+{
+  word j;
+  PLCI   *splci;
+
+  if(a->automatic_law) {
+    return;
+  }
+  if((j=get_plci(a))) {
+    diva_get_extended_adapter_features (a);
+    splci = &a->plci[j-1];
+    a->automatic_lawPLCI = splci;
+    a->automatic_law = 1;
+    add_p(splci,CAI,"\x01\x80");
+    add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+    splci->internal_command = USELAW_REQ;
+    splci->command = 0;
+    splci->number = 0;
+    sig_req(splci,ASSIGN,DSIG_ID);
+    send_req(splci);
+  }
+}
+
+/* called from OS specific part if an application sends an Capi20Release */
+word CapiRelease(word Id)
+{
+  word i, j, appls_found;
+  PLCI   *plci;
+  APPL   *this;
+  DIVA_CAPI_ADAPTER   *a;
+
+  if (!Id)
+  {
+    dbug(0,dprintf("A: CapiRelease(Id==0)"));
+    return (_WRONG_APPL_ID);
+  }
+
+  this = &application[Id-1];               /* get application pointer */
+
+  for(i=0,appls_found=0; i<max_appl; i++)
+  {
+    if(application[i].Id)       /* an application has been found        */
+    {
+      appls_found++;
+    }
+  }
+
+  for(i=0; i<max_adapter; i++)             /* scan all adapters...    */
+  {
+    a = &adapter[i];
+    if (a->request)
+    {
+      a->Info_Mask[Id-1] = 0;
+      a->CIP_Mask[Id-1] = 0;
+      a->Notification_Mask[Id-1] = 0;
+      a->codec_listen[Id-1] = NULL;
+      a->requested_options_table[Id-1] = 0;
+      for(j=0; j<a->max_plci; j++)           /* and all PLCIs connected */
+      {                                      /* with this application   */
+        plci = &a->plci[j];
+        if(plci->Id)                         /* if plci owns no application */
+        {                                    /* it may be not jet connected */
+          if(plci->State==INC_CON_PENDING
+          || plci->State==INC_CON_ALERT)
+          {
+            if(test_c_ind_mask_bit (plci, (word)(Id-1)))
+            {
+              clear_c_ind_mask_bit (plci, (word)(Id-1));
+              if(c_ind_mask_empty (plci))
+              {
+                sig_req(plci,HANGUP,0);
+                send_req(plci);
+                plci->State = OUTG_DIS_PENDING;
+              }
+            }
+          }
+          if(test_c_ind_mask_bit (plci, (word)(Id-1)))
+          {
+            clear_c_ind_mask_bit (plci, (word)(Id-1));
+            if(c_ind_mask_empty (plci))
+            {
+              if(!plci->appl)
+              {
+                plci_remove(plci);
+                plci->State = IDLE;
+              }
+            }
+          }
+          if(plci->appl==this)
+          {
+            plci->appl = NULL;
+            plci_remove(plci);
+            plci->State = IDLE;
+          }
+        }
+      }
+      listen_check(a);
+
+      if(a->flag_dynamic_l1_down)
+      {
+        if(appls_found==1)            /* last application does a capi release */
+        {
+          if((j=get_plci(a)))
+          {
+            plci = &a->plci[j-1];
+            plci->command = 0;
+            add_p(plci,OAD,"\x01\xfd");
+            add_p(plci,CAI,"\x01\x80");
+            add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+            add_p(plci,SHIFT|6,NULL);
+            add_p(plci,SIN,"\x02\x00\x00");
+            plci->internal_command = REM_L1_SIG_ASSIGN_PEND;
+            sig_req(plci,ASSIGN,DSIG_ID);
+            add_p(plci,FTY,"\x02\xff\x06"); /* l1 down */
+            sig_req(plci,SIG_CTRL,0);
+            send_req(plci);
+          }
+        }
+      }
+      if(a->AdvSignalAppl==this)
+      {
+        this->NullCREnable = FALSE;
+        if (a->AdvCodecPLCI)
+        {
+          plci_remove(a->AdvCodecPLCI);
+          a->AdvCodecPLCI->tel = 0;
+          a->AdvCodecPLCI->adv_nl = 0;
+        }
+        a->AdvSignalAppl = NULL;
+        a->AdvSignalPLCI = NULL;
+        a->AdvCodecFLAG = 0;
+        a->AdvCodecPLCI = NULL;
+      }
+    }
+  }
+
+  this->Id = 0;
+
+  return GOOD;
+}
+
+static word plci_remove_check(PLCI   *plci)
+{
+  if(!plci) return TRUE;
+  if(!plci->NL.Id && c_ind_mask_empty (plci))
+  {
+    if(plci->Sig.Id == 0xff)
+      plci->Sig.Id = 0;
+    if(!plci->Sig.Id)
+    {
+      dbug(1,dprintf("plci_remove_complete(%x)",plci->Id));
+      dbug(1,dprintf("tel=0x%x,Sig=0x%x",plci->tel,plci->Sig.Id));
+      if (plci->Id)
+      {
+        CodecIdCheck(plci->adapter, plci);
+        clear_b1_config (plci);
+        ncci_remove (plci, 0, FALSE);
+        plci_free_msg_in_queue (plci);
+        channel_flow_control_remove (plci);
+        plci->Id = 0;
+        plci->State = IDLE;
+        plci->channels = 0;
+        plci->appl = NULL;
+        plci->notifiedcall = 0;
+      }
+      listen_check(plci->adapter);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+
+/*------------------------------------------------------------------*/
+
+static byte plci_nl_busy (PLCI   *plci)
+{
+  /* only applicable for non-multiplexed protocols */
+  return (plci->nl_req
+    || (plci->ncci_ring_list
+     && plci->adapter->ncci_ch[plci->ncci_ring_list]
+     && (plci->adapter->ch_flow_control[plci->adapter->ncci_ch[plci->ncci_ring_list]] & N_OK_FC_PENDING)));
+}
+
+
+/*------------------------------------------------------------------*/
+/* DTMF facilities                                                  */
+/*------------------------------------------------------------------*/
+
+
+static struct
+{
+  byte send_mask;
+  byte listen_mask;
+  byte character;
+  byte code;
+} dtmf_digit_map[] =
+{
+  { 0x01, 0x01, 0x23, DTMF_DIGIT_TONE_CODE_HASHMARK },
+  { 0x01, 0x01, 0x2a, DTMF_DIGIT_TONE_CODE_STAR },
+  { 0x01, 0x01, 0x30, DTMF_DIGIT_TONE_CODE_0 },
+  { 0x01, 0x01, 0x31, DTMF_DIGIT_TONE_CODE_1 },
+  { 0x01, 0x01, 0x32, DTMF_DIGIT_TONE_CODE_2 },
+  { 0x01, 0x01, 0x33, DTMF_DIGIT_TONE_CODE_3 },
+  { 0x01, 0x01, 0x34, DTMF_DIGIT_TONE_CODE_4 },
+  { 0x01, 0x01, 0x35, DTMF_DIGIT_TONE_CODE_5 },
+  { 0x01, 0x01, 0x36, DTMF_DIGIT_TONE_CODE_6 },
+  { 0x01, 0x01, 0x37, DTMF_DIGIT_TONE_CODE_7 },
+  { 0x01, 0x01, 0x38, DTMF_DIGIT_TONE_CODE_8 },
+  { 0x01, 0x01, 0x39, DTMF_DIGIT_TONE_CODE_9 },
+  { 0x01, 0x01, 0x41, DTMF_DIGIT_TONE_CODE_A },
+  { 0x01, 0x01, 0x42, DTMF_DIGIT_TONE_CODE_B },
+  { 0x01, 0x01, 0x43, DTMF_DIGIT_TONE_CODE_C },
+  { 0x01, 0x01, 0x44, DTMF_DIGIT_TONE_CODE_D },
+  { 0x01, 0x00, 0x61, DTMF_DIGIT_TONE_CODE_A },
+  { 0x01, 0x00, 0x62, DTMF_DIGIT_TONE_CODE_B },
+  { 0x01, 0x00, 0x63, DTMF_DIGIT_TONE_CODE_C },
+  { 0x01, 0x00, 0x64, DTMF_DIGIT_TONE_CODE_D },
+
+  { 0x04, 0x04, 0x80, DTMF_SIGNAL_NO_TONE },
+  { 0x00, 0x04, 0x81, DTMF_SIGNAL_UNIDENTIFIED_TONE },
+  { 0x04, 0x04, 0x82, DTMF_SIGNAL_DIAL_TONE },
+  { 0x04, 0x04, 0x83, DTMF_SIGNAL_PABX_INTERNAL_DIAL_TONE },
+  { 0x04, 0x04, 0x84, DTMF_SIGNAL_SPECIAL_DIAL_TONE },
+  { 0x04, 0x04, 0x85, DTMF_SIGNAL_SECOND_DIAL_TONE },
+  { 0x04, 0x04, 0x86, DTMF_SIGNAL_RINGING_TONE },
+  { 0x04, 0x04, 0x87, DTMF_SIGNAL_SPECIAL_RINGING_TONE },
+  { 0x04, 0x04, 0x88, DTMF_SIGNAL_BUSY_TONE },
+  { 0x04, 0x04, 0x89, DTMF_SIGNAL_CONGESTION_TONE },
+  { 0x04, 0x04, 0x8a, DTMF_SIGNAL_SPECIAL_INFORMATION_TONE },
+  { 0x04, 0x04, 0x8b, DTMF_SIGNAL_COMFORT_TONE },
+  { 0x04, 0x04, 0x8c, DTMF_SIGNAL_HOLD_TONE },
+  { 0x04, 0x04, 0x8d, DTMF_SIGNAL_RECORD_TONE },
+  { 0x04, 0x04, 0x8e, DTMF_SIGNAL_CALLER_WAITING_TONE },
+  { 0x04, 0x04, 0x8f, DTMF_SIGNAL_CALL_WAITING_TONE },
+  { 0x04, 0x04, 0x90, DTMF_SIGNAL_PAY_TONE },
+  { 0x04, 0x04, 0x91, DTMF_SIGNAL_POSITIVE_INDICATION_TONE },
+  { 0x04, 0x04, 0x92, DTMF_SIGNAL_NEGATIVE_INDICATION_TONE },
+  { 0x04, 0x04, 0x93, DTMF_SIGNAL_WARNING_TONE },
+  { 0x04, 0x04, 0x94, DTMF_SIGNAL_INTRUSION_TONE },
+  { 0x04, 0x04, 0x95, DTMF_SIGNAL_CALLING_CARD_SERVICE_TONE },
+  { 0x04, 0x04, 0x96, DTMF_SIGNAL_PAYPHONE_RECOGNITION_TONE },
+  { 0x04, 0x04, 0x97, DTMF_SIGNAL_CPE_ALERTING_SIGNAL },
+  { 0x04, 0x04, 0x98, DTMF_SIGNAL_OFF_HOOK_WARNING_TONE },
+  { 0x04, 0x04, 0xbf, DTMF_SIGNAL_INTERCEPT_TONE },
+  { 0x04, 0x04, 0xc0, DTMF_SIGNAL_MODEM_CALLING_TONE },
+  { 0x04, 0x04, 0xc1, DTMF_SIGNAL_FAX_CALLING_TONE },
+  { 0x04, 0x04, 0xc2, DTMF_SIGNAL_ANSWER_TONE },
+  { 0x04, 0x04, 0xc3, DTMF_SIGNAL_REVERSED_ANSWER_TONE },
+  { 0x04, 0x04, 0xc4, DTMF_SIGNAL_ANSAM_TONE },
+  { 0x04, 0x04, 0xc5, DTMF_SIGNAL_REVERSED_ANSAM_TONE },
+  { 0x04, 0x04, 0xc6, DTMF_SIGNAL_BELL103_ANSWER_TONE },
+  { 0x04, 0x04, 0xc7, DTMF_SIGNAL_FAX_FLAGS },
+  { 0x04, 0x04, 0xc8, DTMF_SIGNAL_G2_FAX_GROUP_ID },
+  { 0x00, 0x04, 0xc9, DTMF_SIGNAL_HUMAN_SPEECH },
+  { 0x04, 0x04, 0xca, DTMF_SIGNAL_ANSWERING_MACHINE_390 },
+  { 0x02, 0x02, 0xf1, DTMF_MF_DIGIT_TONE_CODE_1 },
+  { 0x02, 0x02, 0xf2, DTMF_MF_DIGIT_TONE_CODE_2 },
+  { 0x02, 0x02, 0xf3, DTMF_MF_DIGIT_TONE_CODE_3 },
+  { 0x02, 0x02, 0xf4, DTMF_MF_DIGIT_TONE_CODE_4 },
+  { 0x02, 0x02, 0xf5, DTMF_MF_DIGIT_TONE_CODE_5 },
+  { 0x02, 0x02, 0xf6, DTMF_MF_DIGIT_TONE_CODE_6 },
+  { 0x02, 0x02, 0xf7, DTMF_MF_DIGIT_TONE_CODE_7 },
+  { 0x02, 0x02, 0xf8, DTMF_MF_DIGIT_TONE_CODE_8 },
+  { 0x02, 0x02, 0xf9, DTMF_MF_DIGIT_TONE_CODE_9 },
+  { 0x02, 0x02, 0xfa, DTMF_MF_DIGIT_TONE_CODE_0 },
+  { 0x02, 0x02, 0xfb, DTMF_MF_DIGIT_TONE_CODE_K1 },
+  { 0x02, 0x02, 0xfc, DTMF_MF_DIGIT_TONE_CODE_K2 },
+  { 0x02, 0x02, 0xfd, DTMF_MF_DIGIT_TONE_CODE_KP },
+  { 0x02, 0x02, 0xfe, DTMF_MF_DIGIT_TONE_CODE_S1 },
+  { 0x02, 0x02, 0xff, DTMF_MF_DIGIT_TONE_CODE_ST },
+
+};
+
+#define DTMF_DIGIT_MAP_ENTRIES (sizeof(dtmf_digit_map) / sizeof(dtmf_digit_map[0]))
+
+
+static void dtmf_enable_receiver (PLCI   *plci, byte enable_mask)
+{
+  word min_digit_duration, min_gap_duration;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_enable_receiver %02x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, enable_mask));
+
+  if (enable_mask != 0)
+  {
+    min_digit_duration = (plci->dtmf_rec_pulse_ms == 0) ? 40 : plci->dtmf_rec_pulse_ms;
+    min_gap_duration = (plci->dtmf_rec_pause_ms == 0) ? 40 : plci->dtmf_rec_pause_ms;
+    plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_ENABLE_RECEIVER;
+    PUT_WORD (&plci->internal_req_buffer[1], min_digit_duration);
+    PUT_WORD (&plci->internal_req_buffer[3], min_gap_duration);
+    plci->NData[0].PLength = 5;
+
+    PUT_WORD (&plci->internal_req_buffer[5], INTERNAL_IND_BUFFER_SIZE);
+    plci->NData[0].PLength += 2;
+    capidtmf_recv_enable (&(plci->capidtmf_state), min_digit_duration, min_gap_duration);
+
+  }
+  else
+  {
+    plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_DISABLE_RECEIVER;
+    plci->NData[0].PLength = 1;
+
+    capidtmf_recv_disable (&(plci->capidtmf_state));
+
+  }
+  plci->NData[0].P = plci->internal_req_buffer;
+  plci->NL.X = plci->NData;
+  plci->NL.ReqCh = 0;
+  plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+  plci->adapter->request (&plci->NL);
+}
+
+
+static void dtmf_send_digits (PLCI   *plci, byte   *digit_buffer, word digit_count)
+{
+  word w, i;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_send_digits %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, digit_count));
+
+  plci->internal_req_buffer[0] = DTMF_UDATA_REQUEST_SEND_DIGITS;
+  w = (plci->dtmf_send_pulse_ms == 0) ? 40 : plci->dtmf_send_pulse_ms;
+  PUT_WORD (&plci->internal_req_buffer[1], w);
+  w = (plci->dtmf_send_pause_ms == 0) ? 40 : plci->dtmf_send_pause_ms;
+  PUT_WORD (&plci->internal_req_buffer[3], w);
+  for (i = 0; i < digit_count; i++)
+  {
+    w = 0;
+    while ((w < DTMF_DIGIT_MAP_ENTRIES)
+      && (digit_buffer[i] != dtmf_digit_map[w].character))
+    {
+      w++;
+    }
+    plci->internal_req_buffer[5+i] = (w < DTMF_DIGIT_MAP_ENTRIES) ?
+      dtmf_digit_map[w].code : DTMF_DIGIT_TONE_CODE_STAR;
+  }
+  plci->NData[0].PLength = 5 + digit_count;
+  plci->NData[0].P = plci->internal_req_buffer;
+  plci->NL.X = plci->NData;
+  plci->NL.ReqCh = 0;
+  plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+  plci->adapter->request (&plci->NL);
+}
+
+
+static void dtmf_rec_clear_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_rec_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->dtmf_rec_active = 0;
+  plci->dtmf_rec_pulse_ms = 0;
+  plci->dtmf_rec_pause_ms = 0;
+
+  capidtmf_init (&(plci->capidtmf_state), plci->adapter->u_law);
+
+}
+
+
+static void dtmf_send_clear_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_send_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->dtmf_send_requests = 0;
+  plci->dtmf_send_pulse_ms = 0;
+  plci->dtmf_send_pause_ms = 0;
+}
+
+
+static void dtmf_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  while (plci->dtmf_send_requests != 0)
+    dtmf_confirmation (Id, plci);
+}
+
+
+static word dtmf_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  return (GOOD);
+}
+
+
+static word dtmf_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  if (plci->B1_facilities & B1_FACILITY_DTMFR)
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_DTMF_1:
+      plci->internal_command = plci->adjust_b_command;
+      if (plci_nl_busy (plci))
+      {
+        plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
+        break;
+      }
+      dtmf_enable_receiver (plci, plci->dtmf_rec_active);
+      plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_2;
+      break;
+    case ADJUST_B_RESTORE_DTMF_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Reenable DTMF receiver failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+static void dtmf_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word internal_command, Info;
+  byte mask;
+    byte result[4];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_command %02x %04x %04x %d %d %d %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command,
+    plci->dtmf_cmd, plci->dtmf_rec_pulse_ms, plci->dtmf_rec_pause_ms,
+    plci->dtmf_send_pulse_ms, plci->dtmf_send_pause_ms));
+
+  Info = GOOD;
+  result[0] = 2;
+  PUT_WORD (&result[1], DTMF_SUCCESS);
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  mask = 0x01;
+  switch (plci->dtmf_cmd)
+  {
+
+  case DTMF_LISTEN_TONE_START:
+    mask <<= 1;
+  case DTMF_LISTEN_MF_START:
+    mask <<= 1;
+
+  case DTMF_LISTEN_START:
+    switch (internal_command)
+    {
+    default:
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
+        B1_FACILITY_DTMFR), DTMF_COMMAND_1);
+    case DTMF_COMMAND_1:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Load DTMF failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+    case DTMF_COMMAND_2:
+      if (plci_nl_busy (plci))
+      {
+        plci->internal_command = DTMF_COMMAND_2;
+        return;
+      }
+      plci->internal_command = DTMF_COMMAND_3;
+      dtmf_enable_receiver (plci, (byte)(plci->dtmf_rec_active | mask));
+      return;
+    case DTMF_COMMAND_3:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Enable DTMF receiver failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+
+      plci->tone_last_indication_code = DTMF_SIGNAL_NO_TONE;
+
+      plci->dtmf_rec_active |= mask;
+      break;
+    }
+    break;
+
+
+  case DTMF_LISTEN_TONE_STOP:
+    mask <<= 1;
+  case DTMF_LISTEN_MF_STOP:
+    mask <<= 1;
+
+  case DTMF_LISTEN_STOP:
+    switch (internal_command)
+    {
+    default:
+      plci->dtmf_rec_active &= ~mask;
+      if (plci->dtmf_rec_active)
+        break;
+/*
+    case DTMF_COMMAND_1:
+      if (plci->dtmf_rec_active)
+      {
+        if (plci_nl_busy (plci))
+        {
+          plci->internal_command = DTMF_COMMAND_1;
+          return;
+        }
+        plci->dtmf_rec_active &= ~mask;
+        plci->internal_command = DTMF_COMMAND_2;
+        dtmf_enable_receiver (plci, FALSE);
+        return;
+      }
+      Rc = OK;
+    case DTMF_COMMAND_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Disable DTMF receiver failed %02x",
+          UnMapId (Id), (char far *)(FILE_), __LINE__, Rc));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+*/
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
+        ~(B1_FACILITY_DTMFX | B1_FACILITY_DTMFR)), DTMF_COMMAND_3);
+    case DTMF_COMMAND_3:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Unload DTMF failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+      break;
+    }
+    break;
+
+
+  case DTMF_SEND_TONE:
+    mask <<= 1;
+  case DTMF_SEND_MF:
+    mask <<= 1;
+
+  case DTMF_DIGITS_SEND:
+    switch (internal_command)
+    {
+    default:
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
+        ((plci->dtmf_parameter_length != 0) ? B1_FACILITY_DTMFX | B1_FACILITY_DTMFR : B1_FACILITY_DTMFX)),
+        DTMF_COMMAND_1);
+    case DTMF_COMMAND_1:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Load DTMF failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+    case DTMF_COMMAND_2:
+      if (plci_nl_busy (plci))
+      {
+        plci->internal_command = DTMF_COMMAND_2;
+        return;
+      }
+      plci->dtmf_msg_number_queue[(plci->dtmf_send_requests)++] = plci->number;
+      plci->internal_command = DTMF_COMMAND_3;
+      dtmf_send_digits (plci, &plci->saved_msg.parms[3].info[1], plci->saved_msg.parms[3].length);
+      return;
+    case DTMF_COMMAND_3:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Send DTMF digits failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        if (plci->dtmf_send_requests != 0)
+          (plci->dtmf_send_requests)--;
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      return;
+    }
+    break;
+  }
+  sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number,
+    "wws", Info, SELECTOR_DTMF, result);
+}
+
+
+static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg)
+{
+  word Info;
+  word i, j;
+  byte mask;
+    API_PARSE dtmf_parms[5];
+    byte result[40];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_request",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  Info = GOOD;
+  result[0] = 2;
+  PUT_WORD (&result[1], DTMF_SUCCESS);
+  if (!(a->profile.Global_Options & GL_DTMF_SUPPORTED))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _FACILITY_NOT_SUPPORTED;
+  }
+  else if (api_parse (&msg[1].info[1], msg[1].length, "w", dtmf_parms))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _WRONG_MESSAGE_FORMAT;
+  }
+
+  else if ((GET_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES)
+    || (GET_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_SEND_CODES))
+  {
+    if (!((a->requested_options_table[appl->Id-1])
+        & (1L << PRIVATE_DTMF_TONE)))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, GET_WORD (dtmf_parms[0].info)));
+      PUT_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
+    }
+    else
+    {
+      for (i = 0; i < 32; i++)
+        result[4 + i] = 0;
+      if (GET_WORD (dtmf_parms[0].info) == DTMF_GET_SUPPORTED_DETECT_CODES)
+      {
+        for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++)
+        {
+          if (dtmf_digit_map[i].listen_mask != 0)
+            result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7));
+        }
+      }
+      else
+      {
+        for (i = 0; i < DTMF_DIGIT_MAP_ENTRIES; i++)
+        {
+          if (dtmf_digit_map[i].send_mask != 0)
+            result[4 + (dtmf_digit_map[i].character >> 3)] |= (1 << (dtmf_digit_map[i].character & 0x7));
+        }
+      }
+      result[0] = 3 + 32;
+      result[3] = 32;
+    }
+  }
+
+  else if (plci == NULL)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _WRONG_IDENTIFIER;
+  }
+  else
+  {
+    if (!plci->State
+     || !plci->NL.Id || plci->nl_remove_id)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      Info = _WRONG_STATE;
+    }
+    else
+    {
+      plci->command = 0;
+      plci->dtmf_cmd = GET_WORD (dtmf_parms[0].info);
+      mask = 0x01;
+      switch (plci->dtmf_cmd)
+      {
+
+      case DTMF_LISTEN_TONE_START:
+      case DTMF_LISTEN_TONE_STOP:
+        mask <<= 1;
+      case DTMF_LISTEN_MF_START:
+      case DTMF_LISTEN_MF_STOP:
+        mask <<= 1;
+        if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id-1])
+          & (1L << PRIVATE_DTMF_TONE)))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
+            UnMapId (Id), (char   *)(FILE_), __LINE__, GET_WORD (dtmf_parms[0].info)));
+          PUT_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
+          break;
+        }
+
+      case DTMF_LISTEN_START:
+      case DTMF_LISTEN_STOP:
+        if (!(a->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF)
+         && !(a->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _FACILITY_NOT_SUPPORTED;
+          break;
+        }
+        if (mask & DTMF_LISTEN_ACTIVE_FLAG)
+        {
+          if (api_parse (&msg[1].info[1], msg[1].length, "wwws", dtmf_parms))
+          {
+            plci->dtmf_rec_pulse_ms = 0;
+            plci->dtmf_rec_pause_ms = 0;
+          }
+          else
+          {
+            plci->dtmf_rec_pulse_ms = GET_WORD (dtmf_parms[1].info);
+            plci->dtmf_rec_pause_ms = GET_WORD (dtmf_parms[2].info);
+          }
+        }
+        start_internal_command (Id, plci, dtmf_command);
+        return (FALSE);
+
+
+      case DTMF_SEND_TONE:
+        mask <<= 1;
+      case DTMF_SEND_MF:
+        mask <<= 1;
+        if (!((plci->requested_options_conn | plci->requested_options | plci->adapter->requested_options_table[appl->Id-1])
+          & (1L << PRIVATE_DTMF_TONE)))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
+            UnMapId (Id), (char   *)(FILE_), __LINE__, GET_WORD (dtmf_parms[0].info)));
+          PUT_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
+          break;
+        }
+
+      case DTMF_DIGITS_SEND:
+        if (api_parse (&msg[1].info[1], msg[1].length, "wwws", dtmf_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        if (mask & DTMF_LISTEN_ACTIVE_FLAG)
+        {
+          plci->dtmf_send_pulse_ms = GET_WORD (dtmf_parms[1].info);
+          plci->dtmf_send_pause_ms = GET_WORD (dtmf_parms[2].info);
+        }
+        i = 0;
+        j = 0;
+        while ((i < dtmf_parms[3].length) && (j < DTMF_DIGIT_MAP_ENTRIES))
+        {
+          j = 0;
+          while ((j < DTMF_DIGIT_MAP_ENTRIES)
+            && ((dtmf_parms[3].info[i+1] != dtmf_digit_map[j].character)
+             || ((dtmf_digit_map[j].send_mask & mask) == 0)))
+          {
+            j++;
+          }
+          i++;
+        }
+        if (j == DTMF_DIGIT_MAP_ENTRIES)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Incorrect DTMF digit %02x",
+            UnMapId (Id), (char   *)(FILE_), __LINE__, dtmf_parms[3].info[i]));
+          PUT_WORD (&result[1], DTMF_INCORRECT_DIGIT);
+          break;
+        }
+        if (plci->dtmf_send_requests >=
+          sizeof(plci->dtmf_msg_number_queue) / sizeof(plci->dtmf_msg_number_queue[0]))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: DTMF request overrun",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_STATE;
+          break;
+        }
+        api_save_msg (dtmf_parms, "wwws", &plci->saved_msg);
+        start_internal_command (Id, plci, dtmf_command);
+        return (FALSE);
+
+      default:
+        dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, plci->dtmf_cmd));
+        PUT_WORD (&result[1], DTMF_UNKNOWN_REQUEST);
+      }
+    }
+  }
+  sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+    "wws", Info, SELECTOR_DTMF, result);
+  return (FALSE);
+}
+
+
+static void dtmf_confirmation (dword Id, PLCI   *plci)
+{
+  word Info;
+  word i;
+    byte result[4];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_confirmation",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  Info = GOOD;
+  result[0] = 2;
+  PUT_WORD (&result[1], DTMF_SUCCESS);
+  if (plci->dtmf_send_requests != 0)
+  {
+    sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->dtmf_msg_number_queue[0],
+      "wws", GOOD, SELECTOR_DTMF, result);
+    (plci->dtmf_send_requests)--;
+    for (i = 0; i < plci->dtmf_send_requests; i++)
+      plci->dtmf_msg_number_queue[i] = plci->dtmf_msg_number_queue[i+1];      
+  }
+}
+
+
+static void dtmf_indication (dword Id, PLCI   *plci, byte   *msg, word length)
+{
+  word i, j, n;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_indication",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  n = 0;
+  for (i = 1; i < length; i++)
+  {
+    j = 0;
+    while ((j < DTMF_DIGIT_MAP_ENTRIES)
+      && ((msg[i] != dtmf_digit_map[j].code)
+       || ((dtmf_digit_map[j].listen_mask & plci->dtmf_rec_active) == 0)))
+    {
+      j++;
+    }
+    if (j < DTMF_DIGIT_MAP_ENTRIES)
+    {
+
+      if ((dtmf_digit_map[j].listen_mask & DTMF_TONE_LISTEN_ACTIVE_FLAG)
+       && (plci->tone_last_indication_code == DTMF_SIGNAL_NO_TONE)
+       && (dtmf_digit_map[j].character != DTMF_SIGNAL_UNIDENTIFIED_TONE))
+      {
+        if (n + 1 == i)
+        {
+          for (i = length; i > n + 1; i--)
+            msg[i] = msg[i - 1];
+          length++;
+          i++;
+        }
+        msg[++n] = DTMF_SIGNAL_UNIDENTIFIED_TONE;
+      }
+      plci->tone_last_indication_code = dtmf_digit_map[j].character;
+
+      msg[++n] = dtmf_digit_map[j].character;
+    }
+  }
+  if (n != 0)
+  {
+    msg[0] = (byte) n;
+    sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "wS", SELECTOR_DTMF, msg);
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* DTMF parameters                                                  */
+/*------------------------------------------------------------------*/
+
+static void dtmf_parameter_write (PLCI   *plci)
+{
+  word i;
+    byte parameter_buffer[DTMF_PARAMETER_BUFFER_SIZE + 2];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_write",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  parameter_buffer[0] = plci->dtmf_parameter_length + 1;
+  parameter_buffer[1] = DSP_CTRL_SET_DTMF_PARAMETERS;
+  for (i = 0; i < plci->dtmf_parameter_length; i++)
+    parameter_buffer[2+i] = plci->dtmf_parameter_buffer[i];
+  add_p (plci, FTY, parameter_buffer);
+  sig_req (plci, TEL_CTRL, 0);
+  send_req (plci);
+}
+
+
+static void dtmf_parameter_clear_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->dtmf_parameter_length = 0;
+}
+
+
+static void dtmf_parameter_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+}
+
+
+static word dtmf_parameter_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  return (GOOD);
+}
+
+
+static word dtmf_parameter_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: dtmf_parameter_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  if ((plci->B1_facilities & B1_FACILITY_DTMFR)
+   && (plci->dtmf_parameter_length != 0))
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_DTMF_PARAMETER_1:
+      plci->internal_command = plci->adjust_b_command;
+      if (plci->sig_req)
+      {
+        plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1;
+        break;
+      }
+      dtmf_parameter_write (plci);
+      plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_2;
+      break;
+    case ADJUST_B_RESTORE_DTMF_PARAMETER_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Restore DTMF parameters failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+/*------------------------------------------------------------------*/
+/* Line interconnect facilities                                     */
+/*------------------------------------------------------------------*/
+
+
+LI_CONFIG   *li_config_table;
+word li_total_channels;
+
+
+/*------------------------------------------------------------------*/
+/* translate a CHI information element to a channel number          */
+/* returns 0xff - any channel                                       */
+/*         0xfe - chi wrong coding                                  */
+/*         0xfd - D-channel                                         */
+/*         0x00 - no channel                                        */
+/*         else channel number / PRI: timeslot                      */
+/* if channels is provided we accept more than one channel.         */
+/*------------------------------------------------------------------*/
+
+static byte chi_to_channel (byte   *chi, dword *pchannelmap)
+{
+  int p;
+  int i;
+  dword map;
+  byte excl;
+  byte ofs;
+  byte ch;
+
+  if (pchannelmap) *pchannelmap = 0;
+  if(!chi[0]) return 0xff;
+  excl = 0;
+
+  if(chi[1] & 0x20) {
+    if(chi[0]==1 && chi[1]==0xac) return 0xfd; /* exclusive d-channel */
+    for(i=1; i<chi[0] && !(chi[i] &0x80); i++);
+    if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
+    if((chi[1] |0xc8)!=0xe9) return 0xfe;
+    if(chi[1] &0x08) excl = 0x40;
+
+        /* int. id present */
+    if(chi[1] &0x40) {
+      p=i+1;
+      for(i=p; i<chi[0] && !(chi[i] &0x80); i++);
+      if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
+    }
+
+        /* coding standard, Number/Map, Channel Type */
+    p=i+1;
+    for(i=p; i<chi[0] && !(chi[i] &0x80); i++);
+    if(i==chi[0] || !(chi[i] &0x80)) return 0xfe;
+    if((chi[p]|0xd0)!=0xd3) return 0xfe;
+
+        /* Number/Map */
+    if(chi[p] &0x10) {
+
+        /* map */
+      if((chi[0]-p)==4) ofs = 0;
+      else if((chi[0]-p)==3) ofs = 1;
+      else return 0xfe;
+      ch = 0;
+      map = 0;
+      for(i=0; i<4 && p<chi[0]; i++) {
+        p++;
+        ch += 8;
+        map <<= 8;
+        if(chi[p]) {
+          for (ch=0; !(chi[p] & (1 << ch)); ch++);
+          map |= chi[p];
+        }
+      }
+      ch += ofs;
+      map <<= ofs;
+    }
+    else {
+
+        /* number */
+      p=i+1;
+      ch = chi[p] &0x3f;
+      if(pchannelmap) {
+        if((byte)(chi[0]-p)>30) return 0xfe;
+        map = 0;
+        for(i=p; i<=chi[0]; i++) {
+          if ((chi[i] &0x7f) > 31) return 0xfe;
+          map |= (1L << (chi[i] &0x7f));
+        }
+      }
+      else {
+        if(p!=chi[0]) return 0xfe;
+        if (ch > 31) return 0xfe;
+        map = (1L << ch);
+      }
+      if(chi[p] &0x40) return 0xfe;
+    }
+    if (pchannelmap) *pchannelmap = map;
+    else if (map != ((dword)(1L << ch))) return 0xfe;
+    return (byte)(excl | ch);
+  }
+  else {  /* not PRI */
+    for(i=1; i<chi[0] && !(chi[i] &0x80); i++);
+    if(i!=chi[0] || !(chi[i] &0x80)) return 0xfe;
+    if(chi[1] &0x08) excl = 0x40;
+
+    switch(chi[1] |0x98) {
+    case 0x98: return 0;
+    case 0x99:
+      if (pchannelmap) *pchannelmap = 2;
+      return excl |1;
+    case 0x9a:
+      if (pchannelmap) *pchannelmap = 4;
+      return excl |2;
+    case 0x9b: return 0xff;
+    case 0x9c: return 0xfd; /* d-ch */
+    default: return 0xfe;
+    }
+  }
+}
+
+
+static void mixer_set_bchannel_id_esc (PLCI   *plci, byte bchannel_id)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  PLCI   *splci;
+  byte old_id;
+
+  a = plci->adapter;
+  old_id = plci->li_bchannel_id;
+  if (a->li_pri)
+  {
+    if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
+      li_config_table[a->li_base + (old_id - 1)].plci = NULL;
+    plci->li_bchannel_id = (bchannel_id & 0x1f) + 1;
+    if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
+      li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+  }
+  else
+  {
+    if (((bchannel_id & 0x03) == 1) || ((bchannel_id & 0x03) == 2))
+    {
+      if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
+        li_config_table[a->li_base + (old_id - 1)].plci = NULL;
+      plci->li_bchannel_id = bchannel_id & 0x03;
+      if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE))
+      {
+        splci = a->AdvSignalPLCI;
+        if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL)
+        {
+          if ((splci->li_bchannel_id != 0)
+           && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci))
+          {
+            li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL;
+          }
+          splci->li_bchannel_id = 3 - plci->li_bchannel_id;
+          li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci;
+          dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id_esc %d",
+            (dword)((splci->Id << 8) | UnMapController (splci->adapter->Id)),
+            (char   *)(FILE_), __LINE__, splci->li_bchannel_id));
+        }
+      }
+      if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
+        li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+    }
+  }
+  if ((old_id == 0) && (plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    mixer_clear_config (plci);
+  }
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_set_bchannel_id_esc %d %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, bchannel_id, plci->li_bchannel_id));
+}
+
+
+static void mixer_set_bchannel_id (PLCI   *plci, byte   *chi)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  PLCI   *splci;
+  byte ch, old_id;
+
+  a = plci->adapter;
+  old_id = plci->li_bchannel_id;
+  ch = chi_to_channel (chi, NULL);
+  if (!(ch & 0x80))
+  {
+    if (a->li_pri)
+    {
+      if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
+        li_config_table[a->li_base + (old_id - 1)].plci = NULL;
+      plci->li_bchannel_id = (ch & 0x1f) + 1;
+      if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
+        li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+    }
+    else
+    {
+      if (((ch & 0x1f) == 1) || ((ch & 0x1f) == 2))
+      {
+        if ((old_id != 0) && (li_config_table[a->li_base + (old_id - 1)].plci == plci))
+          li_config_table[a->li_base + (old_id - 1)].plci = NULL;
+        plci->li_bchannel_id = ch & 0x1f;
+        if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI != plci) && (a->AdvSignalPLCI->tel == ADV_VOICE))
+        {
+          splci = a->AdvSignalPLCI;
+          if (li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci == NULL)
+          {
+            if ((splci->li_bchannel_id != 0)
+             && (li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci == splci))
+            {
+              li_config_table[a->li_base + (splci->li_bchannel_id - 1)].plci = NULL;
+            }
+            splci->li_bchannel_id = 3 - plci->li_bchannel_id;
+            li_config_table[a->li_base + (2 - plci->li_bchannel_id)].plci = splci;
+            dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
+              (dword)((splci->Id << 8) | UnMapController (splci->adapter->Id)),
+              (char   *)(FILE_), __LINE__, splci->li_bchannel_id));
+          }
+        }
+        if (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == NULL)
+          li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+      }
+    }
+  }
+  if ((old_id == 0) && (plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    mixer_clear_config (plci);
+  }
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_set_bchannel_id %02x %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, ch, plci->li_bchannel_id));
+}
+
+
+#define MIXER_MAX_DUMP_CHANNELS 34
+
+static void mixer_calculate_coefs (DIVA_CAPI_ADAPTER   *a)
+{
+static char hex_digit_table[0x10] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+  word n, i, j;
+  char *p;
+    char hex_line[2 * MIXER_MAX_DUMP_CHANNELS + MIXER_MAX_DUMP_CHANNELS / 8 + 4];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_calculate_coefs",
+    (dword)(UnMapController (a->Id)), (char   *)(FILE_), __LINE__));
+
+  for (i = 0; i < li_total_channels; i++)
+  {
+    li_config_table[i].channel &= LI_CHANNEL_ADDRESSES_SET;
+    if (li_config_table[i].chflags != 0)
+      li_config_table[i].channel |= LI_CHANNEL_INVOLVED;
+    else
+    {
+      for (j = 0; j < li_total_channels; j++)
+      {
+        if (((li_config_table[i].flag_table[j]) != 0)
+         || ((li_config_table[j].flag_table[i]) != 0))
+        {
+          li_config_table[i].channel |= LI_CHANNEL_INVOLVED;
+        }
+        if (((li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE) != 0)
+         || ((li_config_table[j].flag_table[i] & LI_FLAG_CONFERENCE) != 0))
+        {
+          li_config_table[i].channel |= LI_CHANNEL_CONFERENCE;
+        }
+      }
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    for (j = 0; j < li_total_channels; j++)
+    {
+      li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC);
+      if (li_config_table[i].flag_table[j] & LI_FLAG_CONFERENCE)
+        li_config_table[i].coef_table[j] |= LI_COEF_CH_CH;
+    }
+  }
+  for (n = 0; n < li_total_channels; n++)
+  {
+    if (li_config_table[n].channel & LI_CHANNEL_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (li_config_table[i].channel & LI_CHANNEL_CONFERENCE)
+        {
+          for (j = 0; j < li_total_channels; j++)
+          {
+            li_config_table[i].coef_table[j] |=
+              li_config_table[i].coef_table[n] & li_config_table[n].coef_table[j];
+          }
+        }
+      }
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
+    {
+      li_config_table[i].coef_table[i] &= ~LI_COEF_CH_CH;
+      for (j = 0; j < li_total_channels; j++)
+      {
+        if (li_config_table[i].coef_table[j] & LI_COEF_CH_CH)
+          li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE;
+      }
+      if (li_config_table[i].flag_table[i] & LI_FLAG_CONFERENCE)
+        li_config_table[i].coef_table[i] |= LI_COEF_CH_CH;
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
+    {
+      for (j = 0; j < li_total_channels; j++)
+      {
+        if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
+          li_config_table[i].coef_table[j] |= LI_COEF_CH_CH;
+        if (li_config_table[i].flag_table[j] & LI_FLAG_MONITOR)
+          li_config_table[i].coef_table[j] |= LI_COEF_CH_PC;
+        if (li_config_table[i].flag_table[j] & LI_FLAG_MIX)
+          li_config_table[i].coef_table[j] |= LI_COEF_PC_CH;
+        if (li_config_table[i].flag_table[j] & LI_FLAG_PCCONNECT)
+          li_config_table[i].coef_table[j] |= LI_COEF_PC_PC;
+      }
+      if (li_config_table[i].chflags & LI_CHFLAG_MONITOR)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
+          {
+            li_config_table[i].coef_table[j] |= LI_COEF_CH_PC;
+            if (li_config_table[j].chflags & LI_CHFLAG_MIX)
+              li_config_table[i].coef_table[j] |= LI_COEF_PC_CH | LI_COEF_PC_PC;
+          }
+        }
+      }
+      if (li_config_table[i].chflags & LI_CHFLAG_MIX)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          if (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT)
+            li_config_table[j].coef_table[i] |= LI_COEF_PC_CH;
+        }
+      }
+      if (li_config_table[i].chflags & LI_CHFLAG_LOOP)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          if (li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
+          {
+            for (n = 0; n < li_total_channels; n++)
+            {
+              if (li_config_table[n].flag_table[i] & LI_FLAG_INTERCONNECT)
+              {
+                li_config_table[n].coef_table[j] |= LI_COEF_CH_CH;
+                if (li_config_table[j].chflags & LI_CHFLAG_MIX)
+                {
+                  li_config_table[n].coef_table[j] |= LI_COEF_PC_CH;
+                  if (li_config_table[n].chflags & LI_CHFLAG_MONITOR)
+                    li_config_table[n].coef_table[j] |= LI_COEF_CH_PC | LI_COEF_PC_PC;
+                }
+                else if (li_config_table[n].chflags & LI_CHFLAG_MONITOR)
+                  li_config_table[n].coef_table[j] |= LI_COEF_CH_PC;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
+    {
+      if (li_config_table[i].chflags & (LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP))
+        li_config_table[i].channel |= LI_CHANNEL_ACTIVE;
+      if (li_config_table[i].chflags & LI_CHFLAG_MONITOR)
+        li_config_table[i].channel |= LI_CHANNEL_RX_DATA;
+      if (li_config_table[i].chflags & LI_CHFLAG_MIX)
+        li_config_table[i].channel |= LI_CHANNEL_TX_DATA;
+      for (j = 0; j < li_total_channels; j++)
+      {
+        if ((li_config_table[i].flag_table[j] &
+          (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_MONITOR))
+         || (li_config_table[j].flag_table[i] &
+          (LI_FLAG_INTERCONNECT | LI_FLAG_PCCONNECT | LI_FLAG_CONFERENCE | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX)))
+        {
+          li_config_table[i].channel |= LI_CHANNEL_ACTIVE;
+        }
+        if (li_config_table[i].flag_table[j] & (LI_FLAG_PCCONNECT | LI_FLAG_MONITOR))
+          li_config_table[i].channel |= LI_CHANNEL_RX_DATA;
+        if (li_config_table[j].flag_table[i] & (LI_FLAG_PCCONNECT | LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX))
+          li_config_table[i].channel |= LI_CHANNEL_TX_DATA;
+      }
+      if (!(li_config_table[i].channel & LI_CHANNEL_ACTIVE))
+      {
+        li_config_table[i].coef_table[i] |= LI_COEF_PC_CH | LI_COEF_CH_PC;
+        li_config_table[i].channel |= LI_CHANNEL_TX_DATA | LI_CHANNEL_RX_DATA;
+      }
+    }
+  }
+  for (i = 0; i < li_total_channels; i++)
+  {
+    if (li_config_table[i].channel & LI_CHANNEL_INVOLVED)
+    {
+      j = 0;
+      while ((j < li_total_channels) && !(li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT))
+        j++;
+      if (j < li_total_channels)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          li_config_table[i].coef_table[j] &= ~(LI_COEF_CH_CH | LI_COEF_PC_CH);
+          if (li_config_table[i].flag_table[j] & LI_FLAG_ANNOUNCEMENT)
+            li_config_table[i].coef_table[j] |= LI_COEF_PC_CH;
+        }
+      }
+    }
+  }
+  n = li_total_channels;
+  if (n > MIXER_MAX_DUMP_CHANNELS)
+    n = MIXER_MAX_DUMP_CHANNELS;
+  p = hex_line;
+  for (j = 0; j < n; j++)
+  {
+    if ((j & 0x7) == 0)
+      *(p++) = ' ';
+    *(p++) = hex_digit_table[li_config_table[j].curchnl >> 4];
+    *(p++) = hex_digit_table[li_config_table[j].curchnl & 0xf];
+  }
+  *p = '\0';
+  dbug (1, dprintf ("[%06lx] CURRENT %s",
+    (dword)(UnMapController (a->Id)), (char   *) hex_line));
+  p = hex_line;
+  for (j = 0; j < n; j++)
+  {
+    if ((j & 0x7) == 0)
+      *(p++) = ' ';
+    *(p++) = hex_digit_table[li_config_table[j].channel >> 4];
+    *(p++) = hex_digit_table[li_config_table[j].channel & 0xf];
+  }
+  *p = '\0';
+  dbug (1, dprintf ("[%06lx] CHANNEL %s",
+    (dword)(UnMapController (a->Id)), (char   *) hex_line));
+  p = hex_line;
+  for (j = 0; j < n; j++)
+  {
+    if ((j & 0x7) == 0)
+      *(p++) = ' ';
+    *(p++) = hex_digit_table[li_config_table[j].chflags >> 4];
+    *(p++) = hex_digit_table[li_config_table[j].chflags & 0xf];
+  }
+  *p = '\0';
+  dbug (1, dprintf ("[%06lx] CHFLAG  %s",
+    (dword)(UnMapController (a->Id)), (char   *) hex_line));
+  for (i = 0; i < n; i++)
+  {
+    p = hex_line;
+    for (j = 0; j < n; j++)
+    {
+      if ((j & 0x7) == 0)
+        *(p++) = ' ';
+      *(p++) = hex_digit_table[li_config_table[i].flag_table[j] >> 4];
+      *(p++) = hex_digit_table[li_config_table[i].flag_table[j] & 0xf];
+    }
+    *p = '\0';
+    dbug (1, dprintf ("[%06lx] FLAG[%02x]%s",
+      (dword)(UnMapController (a->Id)), i, (char   *) hex_line));
+  }
+  for (i = 0; i < n; i++)
+  {
+    p = hex_line;
+    for (j = 0; j < n; j++)
+    {
+      if ((j & 0x7) == 0)
+        *(p++) = ' ';
+      *(p++) = hex_digit_table[li_config_table[i].coef_table[j] >> 4];
+      *(p++) = hex_digit_table[li_config_table[i].coef_table[j] & 0xf];
+    }
+    *p = '\0';
+    dbug (1, dprintf ("[%06lx] COEF[%02x]%s",
+      (dword)(UnMapController (a->Id)), i, (char   *) hex_line));
+  }
+}
+
+
+static struct
+{
+  byte mask;
+  byte line_flags;
+} mixer_write_prog_pri[] =
+{
+  { LI_COEF_CH_CH, 0 },
+  { LI_COEF_CH_PC, MIXER_COEF_LINE_TO_PC_FLAG },
+  { LI_COEF_PC_CH, MIXER_COEF_LINE_FROM_PC_FLAG },
+  { LI_COEF_PC_PC, MIXER_COEF_LINE_TO_PC_FLAG | MIXER_COEF_LINE_FROM_PC_FLAG }
+};
+
+static struct
+{
+  byte from_ch;
+  byte to_ch;
+  byte mask;
+  byte xconnect_override;
+} mixer_write_prog_bri[] =
+{
+  { 0, 0, LI_COEF_CH_CH, 0x01 },  /* B      to B      */
+  { 1, 0, LI_COEF_CH_CH, 0x01 },  /* Alt B  to B      */
+  { 0, 0, LI_COEF_PC_CH, 0x80 },  /* PC     to B      */
+  { 1, 0, LI_COEF_PC_CH, 0x01 },  /* Alt PC to B      */
+  { 2, 0, LI_COEF_CH_CH, 0x00 },  /* IC     to B      */
+  { 3, 0, LI_COEF_CH_CH, 0x00 },  /* Alt IC to B      */
+  { 0, 0, LI_COEF_CH_PC, 0x80 },  /* B      to PC     */
+  { 1, 0, LI_COEF_CH_PC, 0x01 },  /* Alt B  to PC     */
+  { 0, 0, LI_COEF_PC_PC, 0x01 },  /* PC     to PC     */
+  { 1, 0, LI_COEF_PC_PC, 0x01 },  /* Alt PC to PC     */
+  { 2, 0, LI_COEF_CH_PC, 0x00 },  /* IC     to PC     */
+  { 3, 0, LI_COEF_CH_PC, 0x00 },  /* Alt IC to PC     */
+  { 0, 2, LI_COEF_CH_CH, 0x00 },  /* B      to IC     */
+  { 1, 2, LI_COEF_CH_CH, 0x00 },  /* Alt B  to IC     */
+  { 0, 2, LI_COEF_PC_CH, 0x00 },  /* PC     to IC     */
+  { 1, 2, LI_COEF_PC_CH, 0x00 },  /* Alt PC to IC     */
+  { 2, 2, LI_COEF_CH_CH, 0x00 },  /* IC     to IC     */
+  { 3, 2, LI_COEF_CH_CH, 0x00 },  /* Alt IC to IC     */
+  { 1, 1, LI_COEF_CH_CH, 0x01 },  /* Alt B  to Alt B  */
+  { 0, 1, LI_COEF_CH_CH, 0x01 },  /* B      to Alt B  */
+  { 1, 1, LI_COEF_PC_CH, 0x80 },  /* Alt PC to Alt B  */
+  { 0, 1, LI_COEF_PC_CH, 0x01 },  /* PC     to Alt B  */
+  { 3, 1, LI_COEF_CH_CH, 0x00 },  /* Alt IC to Alt B  */
+  { 2, 1, LI_COEF_CH_CH, 0x00 },  /* IC     to Alt B  */
+  { 1, 1, LI_COEF_CH_PC, 0x80 },  /* Alt B  to Alt PC */
+  { 0, 1, LI_COEF_CH_PC, 0x01 },  /* B      to Alt PC */
+  { 1, 1, LI_COEF_PC_PC, 0x01 },  /* Alt PC to Alt PC */
+  { 0, 1, LI_COEF_PC_PC, 0x01 },  /* PC     to Alt PC */
+  { 3, 1, LI_COEF_CH_PC, 0x00 },  /* Alt IC to Alt PC */
+  { 2, 1, LI_COEF_CH_PC, 0x00 },  /* IC     to Alt PC */
+  { 1, 3, LI_COEF_CH_CH, 0x00 },  /* Alt B  to Alt IC */
+  { 0, 3, LI_COEF_CH_CH, 0x00 },  /* B      to Alt IC */
+  { 1, 3, LI_COEF_PC_CH, 0x00 },  /* Alt PC to Alt IC */
+  { 0, 3, LI_COEF_PC_CH, 0x00 },  /* PC     to Alt IC */
+  { 3, 3, LI_COEF_CH_CH, 0x00 },  /* Alt IC to Alt IC */
+  { 2, 3, LI_COEF_CH_CH, 0x00 }   /* IC     to Alt IC */
+};
+
+static byte mixer_swapped_index_bri[] =
+{
+  18,  /* B      to B      */
+  19,  /* Alt B  to B      */
+  20,  /* PC     to B      */
+  21,  /* Alt PC to B      */
+  22,  /* IC     to B      */
+  23,  /* Alt IC to B      */
+  24,  /* B      to PC     */
+  25,  /* Alt B  to PC     */
+  26,  /* PC     to PC     */
+  27,  /* Alt PC to PC     */
+  28,  /* IC     to PC     */
+  29,  /* Alt IC to PC     */
+  30,  /* B      to IC     */
+  31,  /* Alt B  to IC     */
+  32,  /* PC     to IC     */
+  33,  /* Alt PC to IC     */
+  34,  /* IC     to IC     */
+  35,  /* Alt IC to IC     */
+  0,   /* Alt B  to Alt B  */
+  1,   /* B      to Alt B  */
+  2,   /* Alt PC to Alt B  */
+  3,   /* PC     to Alt B  */
+  4,   /* Alt IC to Alt B  */
+  5,   /* IC     to Alt B  */
+  6,   /* Alt B  to Alt PC */
+  7,   /* B      to Alt PC */
+  8,   /* Alt PC to Alt PC */
+  9,   /* PC     to Alt PC */
+  10,  /* Alt IC to Alt PC */
+  11,  /* IC     to Alt PC */
+  12,  /* Alt B  to Alt IC */
+  13,  /* B      to Alt IC */
+  14,  /* Alt PC to Alt IC */
+  15,  /* PC     to Alt IC */
+  16,  /* Alt IC to Alt IC */
+  17   /* IC     to Alt IC */
+};
+
+static struct
+{
+  byte mask;
+  byte from_pc;
+  byte to_pc;
+} xconnect_write_prog[] =
+{
+  { LI_COEF_CH_CH, FALSE, FALSE },
+  { LI_COEF_CH_PC, FALSE, TRUE },
+  { LI_COEF_PC_CH, TRUE, FALSE },
+  { LI_COEF_PC_PC, TRUE, TRUE }
+};
+
+
+static void xconnect_query_addresses (PLCI   *plci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word w, ch;
+  byte   *p;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: xconnect_query_addresses",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  a = plci->adapter;
+  if (a->li_pri && ((plci->li_bchannel_id == 0)
+   || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci)))
+  {
+    dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out",
+      (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+      (char   *)(FILE_), __LINE__));
+    return;
+  }
+  p = plci->internal_req_buffer;
+  ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
+  *(p++) = UDATA_REQUEST_XCONNECT_FROM;
+  w = ch;
+  *(p++) = (byte) w;
+  *(p++) = (byte)(w >> 8);
+  w = ch | XCONNECT_CHANNEL_PORT_PC;
+  *(p++) = (byte) w;
+  *(p++) = (byte)(w >> 8);
+  plci->NData[0].P = plci->internal_req_buffer;
+  plci->NData[0].PLength = p - plci->internal_req_buffer;
+  plci->NL.X = plci->NData;
+  plci->NL.ReqCh = 0;
+  plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+  plci->adapter->request (&plci->NL);
+}
+
+
+static void xconnect_write_coefs (PLCI   *plci, word internal_command)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: xconnect_write_coefs %04x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, internal_command));
+
+  plci->li_write_command = internal_command;
+  plci->li_write_channel = 0;
+}
+
+
+static byte xconnect_write_coefs_process (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word w, n, i, j, r, s, to_ch;
+  dword d;
+  byte   *p;
+  struct xconnect_transfer_address_s   *transfer_address;
+  byte ch_map[MIXER_CHANNELS_BRI];
+
+  dbug (1, dprintf ("[%06x] %s,%d: xconnect_write_coefs_process %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->li_write_channel));
+
+  a = plci->adapter;
+  if ((plci->li_bchannel_id == 0)
+   || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))
+  {
+    dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    return (TRUE);
+  }
+  i = a->li_base + (plci->li_bchannel_id - 1);
+  j = plci->li_write_channel;
+  p = plci->internal_req_buffer;
+  if (j != 0)
+  {
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: LI write coefs failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      return (FALSE);
+    }
+  }
+  if (li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+  {
+    r = 0;
+    s = 0;
+    if (j < li_total_channels)
+    {
+      if (li_config_table[i].channel & LI_CHANNEL_ADDRESSES_SET)
+      {
+        s = ((li_config_table[i].send_b.card_address.low | li_config_table[i].send_b.card_address.high) ?
+            (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_PC | LI_COEF_PC_PC)) &
+          ((li_config_table[i].send_pc.card_address.low | li_config_table[i].send_pc.card_address.high) ?
+            (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_PC_CH));
+      }
+      r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+      while ((j < li_total_channels)
+        && ((r == 0)
+         || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET))
+         || (!li_config_table[j].adapter->li_pri
+          && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI))
+         || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low)
+           || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high))
+          && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)
+           || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)))
+         || ((li_config_table[j].adapter->li_base != a->li_base)
+          && !(r & s &
+            ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
+              (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
+            ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
+              (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC))))))
+      {
+        j++;
+        if (j < li_total_channels)
+          r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+      }
+    }
+    if (j < li_total_channels)
+    {
+      plci->internal_command = plci->li_write_command;
+      if (plci_nl_busy (plci))
+        return (TRUE);
+      to_ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
+      *(p++) = UDATA_REQUEST_XCONNECT_TO;
+      do
+      {
+        if (li_config_table[j].adapter->li_base != a->li_base)
+        {
+          r &= s &
+            ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
+              (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
+            ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
+              (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC));
+        }
+        n = 0;
+        do
+        {
+          if (r & xconnect_write_prog[n].mask)
+          {
+            if (xconnect_write_prog[n].from_pc)
+              transfer_address = &(li_config_table[j].send_pc);
+            else
+              transfer_address = &(li_config_table[j].send_b);
+            d = transfer_address->card_address.low;
+            *(p++) = (byte) d;
+            *(p++) = (byte)(d >> 8);
+            *(p++) = (byte)(d >> 16);
+            *(p++) = (byte)(d >> 24);
+            d = transfer_address->card_address.high;
+            *(p++) = (byte) d;
+            *(p++) = (byte)(d >> 8);
+            *(p++) = (byte)(d >> 16);
+            *(p++) = (byte)(d >> 24);
+            d = transfer_address->offset;
+            *(p++) = (byte) d;
+            *(p++) = (byte)(d >> 8);
+            *(p++) = (byte)(d >> 16);
+            *(p++) = (byte)(d >> 24);
+            w = xconnect_write_prog[n].to_pc ? to_ch | XCONNECT_CHANNEL_PORT_PC : to_ch;
+            *(p++) = (byte) w;
+            *(p++) = (byte)(w >> 8);
+            w = ((li_config_table[i].coef_table[j] & xconnect_write_prog[n].mask) == 0) ? 0x01 :
+              (li_config_table[i].adapter->u_law ?
+                 (li_config_table[j].adapter->u_law ? 0x80 : 0x86) :
+                 (li_config_table[j].adapter->u_law ? 0x7a : 0x80));
+            *(p++) = (byte) w;
+            *(p++) = (byte) 0;
+            li_config_table[i].coef_table[j] ^= xconnect_write_prog[n].mask << 4;
+          }
+          n++;
+        } while ((n < sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0]))
+          && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
+        if (n == sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0]))
+        {
+          do
+          {
+            j++;
+            if (j < li_total_channels)
+              r = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+          } while ((j < li_total_channels)
+            && ((r == 0)
+             || (!(li_config_table[j].channel & LI_CHANNEL_ADDRESSES_SET))
+             || (!li_config_table[j].adapter->li_pri
+              && (j >= li_config_table[j].adapter->li_base + MIXER_BCHANNELS_BRI))
+             || (((li_config_table[j].send_b.card_address.low != li_config_table[i].send_b.card_address.low)
+               || (li_config_table[j].send_b.card_address.high != li_config_table[i].send_b.card_address.high))
+              && (!(a->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)
+               || !(li_config_table[j].adapter->manufacturer_features & MANUFACTURER_FEATURE_DMACONNECT)))
+             || ((li_config_table[j].adapter->li_base != a->li_base)
+              && !(r & s &
+                ((li_config_table[j].send_b.card_address.low | li_config_table[j].send_b.card_address.high) ?
+                  (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_PC_CH | LI_COEF_PC_PC)) &
+                ((li_config_table[j].send_pc.card_address.low | li_config_table[j].send_pc.card_address.high) ?
+                  (LI_COEF_CH_CH | LI_COEF_CH_PC | LI_COEF_PC_CH | LI_COEF_PC_PC) : (LI_COEF_CH_CH | LI_COEF_CH_PC))))));
+        }
+      } while ((j < li_total_channels)
+        && ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
+    }
+    else if (j == li_total_channels)
+    {
+      plci->internal_command = plci->li_write_command;
+      if (plci_nl_busy (plci))
+        return (TRUE);
+      if (a->li_pri)
+      {
+        *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
+        w = 0;
+        if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+          w |= MIXER_FEATURE_ENABLE_TX_DATA;
+        if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+          w |= MIXER_FEATURE_ENABLE_RX_DATA;
+        *(p++) = (byte) w;
+        *(p++) = (byte)(w >> 8);
+      }
+      else
+      {
+        *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI;
+        w = 0;
+        if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)
+         && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length))
+        {
+          w = GET_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
+        }
+        if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+          w |= MIXER_FEATURE_ENABLE_TX_DATA;
+        if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+          w |= MIXER_FEATURE_ENABLE_RX_DATA;
+        *(p++) = (byte) w;
+        *(p++) = (byte)(w >> 8);
+        for (j = 0; j < sizeof(ch_map); j += 2)
+        {
+          if (plci->li_bchannel_id == 2)
+          {
+            ch_map[j] = (byte)(j+1);
+            ch_map[j+1] = (byte) j;
+          }
+          else
+          {
+            ch_map[j] = (byte) j;
+            ch_map[j+1] = (byte)(j+1);
+          }
+        }
+        for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+        {
+          i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
+          j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
+          if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
+          {
+            *p = (mixer_write_prog_bri[n].xconnect_override != 0) ?
+              mixer_write_prog_bri[n].xconnect_override :
+              ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
+            if ((i >= a->li_base + MIXER_BCHANNELS_BRI) || (j >= a->li_base + MIXER_BCHANNELS_BRI))
+            {
+              w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+              li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
+            }
+          }
+          else
+          {
+            *p = 0x00;
+            if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE))
+            {
+              w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n];
+              if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length)
+                *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w];
+            }
+          }
+          p++;
+        }
+      }
+      j = li_total_channels + 1;
+    }
+  }
+  else
+  {
+    if (j <= li_total_channels)
+    {
+      plci->internal_command = plci->li_write_command;
+      if (plci_nl_busy (plci))
+        return (TRUE);
+      if (j < a->li_base)
+        j = a->li_base;
+      if (a->li_pri)
+      {
+        *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
+        w = 0;
+        if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+          w |= MIXER_FEATURE_ENABLE_TX_DATA;
+        if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+          w |= MIXER_FEATURE_ENABLE_RX_DATA;
+        *(p++) = (byte) w;
+        *(p++) = (byte)(w >> 8);
+        for (n = 0; n < sizeof(mixer_write_prog_pri) / sizeof(mixer_write_prog_pri[0]); n++)
+        {
+          *(p++) = (byte)((plci->li_bchannel_id - 1) | mixer_write_prog_pri[n].line_flags);
+          for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
+          {
+            w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+            if (w & mixer_write_prog_pri[n].mask)
+            {
+              *(p++) = (li_config_table[i].coef_table[j] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01;
+              li_config_table[i].coef_table[j] ^= mixer_write_prog_pri[n].mask << 4;
+            }
+            else
+              *(p++) = 0x00;
+          }
+          *(p++) = (byte)((plci->li_bchannel_id - 1) | MIXER_COEF_LINE_ROW_FLAG | mixer_write_prog_pri[n].line_flags);
+          for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
+          {
+            w = ((li_config_table[j].coef_table[i] & 0xf) ^ (li_config_table[j].coef_table[i] >> 4));
+            if (w & mixer_write_prog_pri[n].mask)
+            {
+              *(p++) = (li_config_table[j].coef_table[i] & mixer_write_prog_pri[n].mask) ? 0x80 : 0x01;
+              li_config_table[j].coef_table[i] ^= mixer_write_prog_pri[n].mask << 4;
+            }
+            else
+              *(p++) = 0x00;
+          }
+        }
+      }
+      else
+      {
+        *(p++) = UDATA_REQUEST_SET_MIXER_COEFS_BRI;
+        w = 0;
+        if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI)
+         && (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length))
+        {
+          w = GET_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
+        }
+        if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+          w |= MIXER_FEATURE_ENABLE_TX_DATA;
+        if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+          w |= MIXER_FEATURE_ENABLE_RX_DATA;
+        *(p++) = (byte) w;
+        *(p++) = (byte)(w >> 8);
+        for (j = 0; j < sizeof(ch_map); j += 2)
+        {
+          if (plci->li_bchannel_id == 2)
+          {
+            ch_map[j] = (byte)(j+1);
+            ch_map[j+1] = (byte) j;
+          }
+          else
+          {
+            ch_map[j] = (byte) j;
+            ch_map[j+1] = (byte)(j+1);
+          }
+        }
+        for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+        {
+          i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
+          j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
+          if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
+          {
+            *p = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
+            w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+            li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
+          }
+          else
+          {
+            *p = 0x00;
+            if ((a->AdvSignalPLCI != NULL) && (a->AdvSignalPLCI->tel == ADV_VOICE))
+            {
+              w = (plci == a->AdvSignalPLCI) ? n : mixer_swapped_index_bri[n];
+              if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w < a->adv_voice_coef_length)
+                *p = a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + w];
+            }
+          }
+          p++;
+        }
+      }
+      j = li_total_channels + 1;
+    }
+  }
+  plci->li_write_channel = j;
+  if (p != plci->internal_req_buffer)
+  {
+    plci->NData[0].P = plci->internal_req_buffer;
+    plci->NData[0].PLength = p - plci->internal_req_buffer;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+    plci->adapter->request (&plci->NL);
+  }
+  return (TRUE);
+}
+
+
+static void mixer_notify_update (PLCI   *plci, byte others)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i, w;
+  PLCI   *notify_plci;
+    byte msg[sizeof(CAPI_MSG_HEADER) + 6];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_notify_update %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, others));
+
+  a = plci->adapter;
+  if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
+  {
+    if (others)
+      plci->li_notify_update = TRUE;
+    i = 0;
+    do
+    {
+      notify_plci = NULL;
+      if (others)
+      {
+        while ((i < li_total_channels) && (li_config_table[i].plci == NULL))
+          i++;
+        if (i < li_total_channels)
+          notify_plci = li_config_table[i++].plci;
+      }
+      else
+      {
+        if ((plci->li_bchannel_id != 0)
+         && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+        {
+          notify_plci = plci;
+        }
+      }
+      if ((notify_plci != NULL)
+       && !notify_plci->li_notify_update
+       && (notify_plci->appl != NULL)
+       && (notify_plci->State)
+       && notify_plci->NL.Id && !notify_plci->nl_remove_id)
+      {
+        notify_plci->li_notify_update = TRUE;
+        ((CAPI_MSG *) msg)->header.length = 18;
+        ((CAPI_MSG *) msg)->header.appl_id = notify_plci->appl->Id;
+        ((CAPI_MSG *) msg)->header.command = _FACILITY_R;
+        ((CAPI_MSG *) msg)->header.number = 0;
+        ((CAPI_MSG *) msg)->header.controller = notify_plci->adapter->Id;
+        ((CAPI_MSG *) msg)->header.plci = notify_plci->Id;
+        ((CAPI_MSG *) msg)->header.ncci = 0;
+        ((CAPI_MSG *) msg)->info.facility_req.Selector = SELECTOR_LINE_INTERCONNECT;
+        ((CAPI_MSG *) msg)->info.facility_req.structs[0] = 3;
+        PUT_WORD (&(((CAPI_MSG *) msg)->info.facility_req.structs[1]), LI_REQ_SILENT_UPDATE);
+        ((CAPI_MSG *) msg)->info.facility_req.structs[3] = 0;
+        w = api_put (notify_plci->appl, (CAPI_MSG *) msg);
+        if (w != _QUEUE_FULL)
+        {
+          if (w != 0)
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Interconnect notify failed %06x %d",
+              (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+              (char   *)(FILE_), __LINE__,
+              (dword)((notify_plci->Id << 8) | UnMapController (notify_plci->adapter->Id)), w));
+          }
+          notify_plci->li_notify_update = FALSE;
+        }
+      }
+    } while (others && (notify_plci != NULL));
+    if (others)
+      plci->li_notify_update = FALSE;
+  }
+}
+
+
+static void mixer_clear_config (PLCI   *plci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i, j;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->li_notify_update = FALSE;
+  plci->li_plci_b_write_pos = 0;
+  plci->li_plci_b_read_pos = 0;
+  plci->li_plci_b_req_pos = 0;
+  a = plci->adapter;
+  if ((plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    i = a->li_base + (plci->li_bchannel_id - 1);
+    li_config_table[i].curchnl = 0;
+    li_config_table[i].channel = 0;
+    li_config_table[i].chflags = 0;
+    for (j = 0; j < li_total_channels; j++)
+    {
+      li_config_table[j].flag_table[i] = 0;
+      li_config_table[i].flag_table[j] = 0;
+      li_config_table[i].coef_table[j] = 0;
+      li_config_table[j].coef_table[i] = 0;
+    }
+    if (!a->li_pri)
+    {
+      li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
+      if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
+      {
+        i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+        li_config_table[i].curchnl = 0;
+        li_config_table[i].channel = 0;
+        li_config_table[i].chflags = 0;
+        for (j = 0; j < li_total_channels; j++)
+        {
+          li_config_table[i].flag_table[j] = 0;
+          li_config_table[j].flag_table[i] = 0;
+          li_config_table[i].coef_table[j] = 0;
+          li_config_table[j].coef_table[i] = 0;
+        }
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+        {
+          i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+          li_config_table[i].curchnl = 0;
+          li_config_table[i].channel = 0;
+          li_config_table[i].chflags = 0;
+          for (j = 0; j < li_total_channels; j++)
+          {
+            li_config_table[i].flag_table[j] = 0;
+            li_config_table[j].flag_table[i] = 0;
+            li_config_table[i].coef_table[j] = 0;
+            li_config_table[j].coef_table[i] = 0;
+          }
+        }
+      }
+    }
+  }
+}
+
+
+static void mixer_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  do
+  {
+    mixer_indication_coefs_set (Id, plci);
+  } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos);
+}
+
+
+static word mixer_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i, j;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  a = plci->adapter;
+  if ((plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    i = a->li_base + (plci->li_bchannel_id - 1);
+    for (j = 0; j < li_total_channels; j++)
+    {
+      li_config_table[i].coef_table[j] &= 0xf;
+      li_config_table[j].coef_table[i] &= 0xf;
+    }
+    if (!a->li_pri)
+      li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
+  }
+  return (GOOD);
+}
+
+
+static word mixer_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  a = plci->adapter;
+  if ((plci->B1_facilities & B1_FACILITY_MIXER)
+   && (plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_MIXER_1:
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+      {
+        plci->internal_command = plci->adjust_b_command;
+        if (plci_nl_busy (plci))
+        {
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1;
+          break;
+        }
+        xconnect_query_addresses (plci);
+        plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_2;
+        break;
+      }
+      plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
+      Rc = OK;
+    case ADJUST_B_RESTORE_MIXER_2:
+    case ADJUST_B_RESTORE_MIXER_3:
+    case ADJUST_B_RESTORE_MIXER_4:
+      if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Adjust B query addresses failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      if (Rc == OK)
+      {
+        if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_3;
+        else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4)
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
+      }
+      else if (Rc == 0)
+      {
+        if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_4;
+        else if (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3)
+          plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_5;
+      }
+      if (plci->adjust_b_state != ADJUST_B_RESTORE_MIXER_5)
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+    case ADJUST_B_RESTORE_MIXER_5:
+      xconnect_write_coefs (plci, plci->adjust_b_command);
+      plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_6;
+      Rc = OK;
+    case ADJUST_B_RESTORE_MIXER_6:
+      if (!xconnect_write_coefs_process (Id, plci, Rc))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Write mixer coefs failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        break;
+      plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_7;
+    case ADJUST_B_RESTORE_MIXER_7:
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+static void mixer_command (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i, internal_command, Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_command %02x %04x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command,
+    plci->li_cmd));
+
+  Info = GOOD;
+  a = plci->adapter;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (plci->li_cmd)
+  {
+  case LI_REQ_CONNECT:
+  case LI_REQ_DISCONNECT:
+  case LI_REQ_SILENT_UPDATE:
+    switch (internal_command)
+    {
+    default:
+      if (plci->li_channel_bits & LI_CHANNEL_INVOLVED)
+      {
+        adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
+          B1_FACILITY_MIXER), MIXER_COMMAND_1);
+      }
+    case MIXER_COMMAND_1:
+      if (plci->li_channel_bits & LI_CHANNEL_INVOLVED)
+      {
+        if (adjust_b_process (Id, plci, Rc) != GOOD)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Load mixer failed",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _FACILITY_NOT_SUPPORTED;
+          break;
+        }
+        if (plci->internal_command)
+          return;
+      }
+      plci->li_plci_b_req_pos = plci->li_plci_b_write_pos;
+      if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED)
+       || ((get_b1_facilities (plci, plci->B1_resource) & B1_FACILITY_MIXER)
+        && (add_b1_facilities (plci, plci->B1_resource, (word)(plci->B1_facilities &
+         ~B1_FACILITY_MIXER)) == plci->B1_resource)))
+      {
+        xconnect_write_coefs (plci, MIXER_COMMAND_2);
+      }
+      else
+      {
+        do
+        {
+          mixer_indication_coefs_set (Id, plci);
+        } while (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos);
+      }
+    case MIXER_COMMAND_2:
+      if ((plci->li_channel_bits & LI_CHANNEL_INVOLVED)
+       || ((get_b1_facilities (plci, plci->B1_resource) & B1_FACILITY_MIXER)
+        && (add_b1_facilities (plci, plci->B1_resource, (word)(plci->B1_facilities &
+         ~B1_FACILITY_MIXER)) == plci->B1_resource)))
+      {
+        if (!xconnect_write_coefs_process (Id, plci, Rc))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Write mixer coefs failed",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          if (plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
+          {
+            do
+            {
+              plci->li_plci_b_write_pos = (plci->li_plci_b_write_pos == 0) ?
+                LI_PLCI_B_QUEUE_ENTRIES-1 : plci->li_plci_b_write_pos - 1;
+              i = (plci->li_plci_b_write_pos == 0) ?
+                LI_PLCI_B_QUEUE_ENTRIES-1 : plci->li_plci_b_write_pos - 1;
+            } while ((plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
+              && !(plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG));
+          }
+          Info = _FACILITY_NOT_SUPPORTED;
+          break;
+        }
+        if (plci->internal_command)
+          return;
+      }
+      if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED))
+      {
+        adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
+          ~B1_FACILITY_MIXER), MIXER_COMMAND_3);
+      }
+    case MIXER_COMMAND_3:
+      if (!(plci->li_channel_bits & LI_CHANNEL_INVOLVED))
+      {
+        if (adjust_b_process (Id, plci, Rc) != GOOD)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Unload mixer failed",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _FACILITY_NOT_SUPPORTED;
+          break;
+        }
+        if (plci->internal_command)
+          return;
+      }
+      break;
+    }
+    break;
+  }
+  if ((plci->li_bchannel_id == 0)
+   || (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci != plci))
+  {
+    dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out %d",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, (int)(plci->li_bchannel_id)));
+  }
+  else
+  {
+    i = a->li_base + (plci->li_bchannel_id - 1);
+    li_config_table[i].curchnl = plci->li_channel_bits;
+    if (!a->li_pri && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
+    {
+      i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+      li_config_table[i].curchnl = plci->li_channel_bits;
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+      {
+        i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+        li_config_table[i].curchnl = plci->li_channel_bits;
+      }
+    }
+  }
+}
+
+
+static void li_update_connect (dword Id, DIVA_CAPI_ADAPTER   *a, PLCI   *plci,
+  dword plci_b_id, byte connect, dword li_flags)
+{
+  word i, ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s;
+  PLCI   *plci_b;
+  DIVA_CAPI_ADAPTER   *a_b;
+
+  a_b = &(adapter[MapController ((byte)(plci_b_id & 0x7f)) - 1]);
+  plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]);
+  ch_a = a->li_base + (plci->li_bchannel_id - 1);
+  if (!a->li_pri && (plci->tel == ADV_VOICE)
+   && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER))
+  {
+    ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE;
+    ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
+      a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v;
+  }
+  else
+  {
+    ch_a_v = ch_a;
+    ch_a_s = ch_a;
+  }
+  ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1);
+  if (!a_b->li_pri && (plci_b->tel == ADV_VOICE)
+   && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER))
+  {
+    ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE;
+    ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
+      a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v;
+  }
+  else
+  {
+    ch_b_v = ch_b;
+    ch_b_s = ch_b;
+  }
+  if (connect)
+  {
+    li_config_table[ch_a].flag_table[ch_a_v] &= ~LI_FLAG_MONITOR;
+    li_config_table[ch_a].flag_table[ch_a_s] &= ~LI_FLAG_MONITOR;
+    li_config_table[ch_a_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
+    li_config_table[ch_a_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
+  }
+  li_config_table[ch_a].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR;
+  li_config_table[ch_a].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR;
+  li_config_table[ch_b_v].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
+  li_config_table[ch_b_s].flag_table[ch_a] &= ~(LI_FLAG_ANNOUNCEMENT | LI_FLAG_MIX);
+  if (ch_a_v == ch_b_v)
+  {
+    li_config_table[ch_a_v].flag_table[ch_b_v] &= ~LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_b_s] &= ~LI_FLAG_CONFERENCE;
+  }
+  else
+  {
+    if (li_config_table[ch_a_v].flag_table[ch_b_v] & LI_FLAG_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (i != ch_a_v)
+          li_config_table[ch_a_v].flag_table[i] &= ~LI_FLAG_CONFERENCE;
+      }
+    }
+    if (li_config_table[ch_a_s].flag_table[ch_b_v] & LI_FLAG_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (i != ch_a_s)
+          li_config_table[ch_a_s].flag_table[i] &= ~LI_FLAG_CONFERENCE;
+      }
+    }
+    if (li_config_table[ch_b_v].flag_table[ch_a_v] & LI_FLAG_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (i != ch_a_v)
+          li_config_table[i].flag_table[ch_a_v] &= ~LI_FLAG_CONFERENCE;
+      }
+    }
+    if (li_config_table[ch_b_v].flag_table[ch_a_s] & LI_FLAG_CONFERENCE)
+    {
+      for (i = 0; i < li_total_channels; i++)
+      {
+        if (i != ch_a_s)
+          li_config_table[i].flag_table[ch_a_s] &= ~LI_FLAG_CONFERENCE;
+      }
+    }
+  }
+  if (li_flags & LI_FLAG_CONFERENCE_A_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
+  }
+  if (li_flags & LI_FLAG_CONFERENCE_B_A)
+  {
+    li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
+  }
+  if (li_flags & LI_FLAG_MONITOR_A)
+  {
+    li_config_table[ch_a].flag_table[ch_a_v] |= LI_FLAG_MONITOR;
+    li_config_table[ch_a].flag_table[ch_a_s] |= LI_FLAG_MONITOR;
+  }
+  if (li_flags & LI_FLAG_MONITOR_B)
+  {
+    li_config_table[ch_a].flag_table[ch_b_v] |= LI_FLAG_MONITOR;
+    li_config_table[ch_a].flag_table[ch_b_s] |= LI_FLAG_MONITOR;
+  }
+  if (li_flags & LI_FLAG_ANNOUNCEMENT_A)
+  {
+    li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
+    li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
+  }
+  if (li_flags & LI_FLAG_ANNOUNCEMENT_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
+    li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_ANNOUNCEMENT;
+  }
+  if (li_flags & LI_FLAG_MIX_A)
+  {
+    li_config_table[ch_a_v].flag_table[ch_a] |= LI_FLAG_MIX;
+    li_config_table[ch_a_s].flag_table[ch_a] |= LI_FLAG_MIX;
+  }
+  if (li_flags & LI_FLAG_MIX_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_a] |= LI_FLAG_MIX;
+    li_config_table[ch_b_s].flag_table[ch_a] |= LI_FLAG_MIX;
+  }
+  if (ch_a_v != ch_a_s)
+  {
+    li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
+  }
+  if (ch_b_v != ch_b_s)
+  {
+    li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
+  }
+}
+
+
+static void li2_update_connect (dword Id, DIVA_CAPI_ADAPTER   *a, PLCI   *plci,
+  dword plci_b_id, byte connect, dword li_flags)
+{
+  word ch_a, ch_a_v, ch_a_s, ch_b, ch_b_v, ch_b_s;
+  PLCI   *plci_b;
+  DIVA_CAPI_ADAPTER   *a_b;
+
+  a_b = &(adapter[MapController ((byte)(plci_b_id & 0x7f)) - 1]);
+  plci_b = &(a_b->plci[((plci_b_id >> 8) & 0xff) - 1]);
+  ch_a = a->li_base + (plci->li_bchannel_id - 1);
+  if (!a->li_pri && (plci->tel == ADV_VOICE)
+   && (plci == a->AdvSignalPLCI) && (Id & EXT_CONTROLLER))
+  {
+    ch_a_v = ch_a + MIXER_IC_CHANNEL_BASE;
+    ch_a_s = (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
+      a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id) : ch_a_v;
+  }
+  else
+  {
+    ch_a_v = ch_a;
+    ch_a_s = ch_a;
+  }
+  ch_b = a_b->li_base + (plci_b->li_bchannel_id - 1);
+  if (!a_b->li_pri && (plci_b->tel == ADV_VOICE)
+   && (plci_b == a_b->AdvSignalPLCI) && (plci_b_id & EXT_CONTROLLER))
+  {
+    ch_b_v = ch_b + MIXER_IC_CHANNEL_BASE;
+    ch_b_s = (a_b->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC) ?
+      a_b->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci_b->li_bchannel_id) : ch_b_v;
+  }
+  else
+  {
+    ch_b_v = ch_b;
+    ch_b_s = ch_b;
+  }
+  if (connect)
+  {
+    li_config_table[ch_b].flag_table[ch_b_v] &= ~LI_FLAG_MONITOR;
+    li_config_table[ch_b].flag_table[ch_b_s] &= ~LI_FLAG_MONITOR;
+    li_config_table[ch_b_v].flag_table[ch_b] &= ~LI_FLAG_MIX;
+    li_config_table[ch_b_s].flag_table[ch_b] &= ~LI_FLAG_MIX;
+    li_config_table[ch_b].flag_table[ch_b] &= ~LI_FLAG_PCCONNECT;
+    li_config_table[ch_b].chflags &= ~(LI_CHFLAG_MONITOR | LI_CHFLAG_MIX | LI_CHFLAG_LOOP);
+  }
+  li_config_table[ch_b_v].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_b_s].flag_table[ch_a_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_b_v].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_b_s].flag_table[ch_a_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_a_v].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_a_v].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_a_s].flag_table[ch_b_v] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  li_config_table[ch_a_s].flag_table[ch_b_s] &= ~(LI_FLAG_INTERCONNECT | LI_FLAG_CONFERENCE);
+  if (li_flags & LI2_FLAG_INTERCONNECT_A_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_s].flag_table[ch_a_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_v].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_INTERCONNECT;
+  }
+  if (li_flags & LI2_FLAG_INTERCONNECT_B_A)
+  {
+    li_config_table[ch_a_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_a_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_a_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
+  }
+  if (li_flags & LI2_FLAG_MONITOR_B)
+  {
+    li_config_table[ch_b].flag_table[ch_b_v] |= LI_FLAG_MONITOR;
+    li_config_table[ch_b].flag_table[ch_b_s] |= LI_FLAG_MONITOR;
+  }
+  if (li_flags & LI2_FLAG_MIX_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_b] |= LI_FLAG_MIX;
+    li_config_table[ch_b_s].flag_table[ch_b] |= LI_FLAG_MIX;
+  }
+  if (li_flags & LI2_FLAG_MONITOR_X)
+    li_config_table[ch_b].chflags |= LI_CHFLAG_MONITOR;
+  if (li_flags & LI2_FLAG_MIX_X)
+    li_config_table[ch_b].chflags |= LI_CHFLAG_MIX;
+  if (li_flags & LI2_FLAG_LOOP_B)
+  {
+    li_config_table[ch_b_v].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
+    li_config_table[ch_b_s].flag_table[ch_b_s] |= LI_FLAG_INTERCONNECT;
+  }
+  if (li_flags & LI2_FLAG_LOOP_PC)
+    li_config_table[ch_b].flag_table[ch_b] |= LI_FLAG_PCCONNECT;
+  if (li_flags & LI2_FLAG_LOOP_X)
+    li_config_table[ch_b].chflags |= LI_CHFLAG_LOOP;
+  if (li_flags & LI2_FLAG_PCCONNECT_A_B)
+    li_config_table[ch_b_s].flag_table[ch_a_s] |= LI_FLAG_PCCONNECT;
+  if (li_flags & LI2_FLAG_PCCONNECT_B_A)
+    li_config_table[ch_a_s].flag_table[ch_b_s] |= LI_FLAG_PCCONNECT;
+  if (ch_a_v != ch_a_s)
+  {
+    li_config_table[ch_a_v].flag_table[ch_a_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_a_s].flag_table[ch_a_v] |= LI_FLAG_CONFERENCE;
+  }
+  if (ch_b_v != ch_b_s)
+  {
+    li_config_table[ch_b_v].flag_table[ch_b_s] |= LI_FLAG_CONFERENCE;
+    li_config_table[ch_b_s].flag_table[ch_b_v] |= LI_FLAG_CONFERENCE;
+  }
+}
+
+
+static word li_check_main_plci (dword Id, PLCI   *plci)
+{
+  if (plci == NULL)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    return (_WRONG_IDENTIFIER);
+  }
+  if (!plci->State
+   || !plci->NL.Id || plci->nl_remove_id
+   || (plci->li_bchannel_id == 0))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    return (_WRONG_STATE);
+  }
+  li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = plci;
+  return (GOOD);
+}
+
+
+static PLCI   *li_check_plci_b (dword Id, PLCI   *plci,
+  dword plci_b_id, word plci_b_write_pos, byte   *p_result)
+{
+  byte ctlr_b;
+  PLCI   *plci_b;
+
+  if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
+    LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    PUT_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
+    return (NULL);
+  }
+  ctlr_b = 0;
+  if ((plci_b_id & 0x7f) != 0)
+  {
+    ctlr_b = MapController ((byte)(plci_b_id & 0x7f));
+    if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL)))
+      ctlr_b = 0;
+  }
+  if ((ctlr_b == 0)
+   || (((plci_b_id >> 8) & 0xff) == 0)
+   || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI invalid second PLCI %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    PUT_WORD (p_result, _WRONG_IDENTIFIER);
+    return (NULL);
+  }
+  plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]);
+  if (!plci_b->State
+   || !plci_b->NL.Id || plci_b->nl_remove_id
+   || (plci_b->li_bchannel_id == 0))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI peer in wrong state %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    PUT_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
+    return (NULL);
+  }
+  li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci = plci_b;
+  if (((byte)(plci_b_id & ~EXT_CONTROLLER)) !=
+    ((byte)(UnMapController (plci->adapter->Id) & ~EXT_CONTROLLER))
+   && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+    || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI not on same ctrl %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    PUT_WORD (p_result, _WRONG_IDENTIFIER);
+    return (NULL);
+  }
+  if (!(get_b1_facilities (plci_b, add_b1_facilities (plci_b, plci_b->B1_resource,
+    (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Interconnect peer cannot mix %d",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b->B1_resource));
+    PUT_WORD (p_result, _REQUEST_NOT_ALLOWED_IN_THIS_STATE);
+    return (NULL);
+  }
+  return (plci_b);
+}
+
+
+static PLCI   *li2_check_plci_b (dword Id, PLCI   *plci,
+  dword plci_b_id, word plci_b_write_pos, byte   *p_result)
+{
+  byte ctlr_b;
+  PLCI   *plci_b;
+
+  if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
+    LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    PUT_WORD (p_result, _WRONG_STATE);
+    return (NULL);
+  }
+  ctlr_b = 0;
+  if ((plci_b_id & 0x7f) != 0)
+  {
+    ctlr_b = MapController ((byte)(plci_b_id & 0x7f));
+    if ((ctlr_b > max_adapter) || ((ctlr_b != 0) && (adapter[ctlr_b - 1].request == NULL)))
+      ctlr_b = 0;
+  }
+  if ((ctlr_b == 0)
+   || (((plci_b_id >> 8) & 0xff) == 0)
+   || (((plci_b_id >> 8) & 0xff) > adapter[ctlr_b - 1].max_plci))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI invalid second PLCI %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    PUT_WORD (p_result, _WRONG_IDENTIFIER);
+    return (NULL);
+  }
+  plci_b = &(adapter[ctlr_b - 1].plci[((plci_b_id >> 8) & 0xff) - 1]);
+  if (!plci_b->State
+   || !plci_b->NL.Id || plci_b->nl_remove_id
+   || (plci_b->li_bchannel_id == 0)
+   || (li_config_table[plci_b->adapter->li_base + (plci_b->li_bchannel_id - 1)].plci != plci_b))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI peer in wrong state %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    PUT_WORD (p_result, _WRONG_STATE);
+    return (NULL);
+  }
+  if (((byte)(plci_b_id & ~EXT_CONTROLLER)) !=
+    ((byte)(UnMapController (plci->adapter->Id) & ~EXT_CONTROLLER))
+   && (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+    || !(plci_b->adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI not on same ctrl %08lx",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b_id));
+    PUT_WORD (p_result, _WRONG_IDENTIFIER);
+    return (NULL);
+  }
+  if (!(get_b1_facilities (plci_b, add_b1_facilities (plci_b, plci_b->B1_resource,
+    (word)(plci_b->B1_facilities | B1_FACILITY_MIXER))) & B1_FACILITY_MIXER))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Interconnect peer cannot mix %d",
+      UnMapId (Id), (char   *)(FILE_), __LINE__, plci_b->B1_resource));
+    PUT_WORD (p_result, _WRONG_STATE);
+    return (NULL);
+  }
+  return (plci_b);
+}
+
+
+static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg)
+{
+  word Info;
+  word i;
+  dword d, li_flags, plci_b_id;
+  PLCI   *plci_b;
+    API_PARSE li_parms[3];
+    API_PARSE li_req_parms[3];
+    API_PARSE li_participant_struct[2];
+    API_PARSE li_participant_parms[3];
+  word participant_parms_pos;
+  byte result_buffer[32];
+  byte   *result;
+  word result_pos;
+  word plci_b_write_pos;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_request",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  Info = GOOD;
+  result = result_buffer;
+  result_buffer[0] = 0;
+  if (!(a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _FACILITY_NOT_SUPPORTED;
+  }
+  else if (api_parse (&msg[1].info[1], msg[1].length, "ws", li_parms))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _WRONG_MESSAGE_FORMAT;
+  }
+  else
+  {
+    result_buffer[0] = 3;
+    PUT_WORD (&result_buffer[1], GET_WORD (li_parms[0].info));
+    result_buffer[3] = 0;
+    switch (GET_WORD (li_parms[0].info))
+    {
+    case LI_GET_SUPPORTED_SERVICES:
+      if (appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
+      {
+        result_buffer[0] = 17;
+        result_buffer[3] = 14;
+        PUT_WORD (&result_buffer[4], GOOD);
+        d = 0;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_CH)
+          d |= LI_CONFERENCING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC)
+          d |= LI_MONITORING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH)
+          d |= LI_ANNOUNCEMENTS_SUPPORTED | LI_MIXING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+          d |= LI_CROSS_CONTROLLER_SUPPORTED;
+        PUT_DWORD (&result_buffer[6], d);
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+        {
+          d = 0;
+          for (i = 0; i < li_total_channels; i++)
+          {
+            if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+             && (li_config_table[i].adapter->li_pri
+              || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI)))
+            {
+              d++;
+            }
+          }
+        }
+        else
+        {
+          d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI;
+        }
+        PUT_DWORD (&result_buffer[10], d / 2);
+        PUT_DWORD (&result_buffer[14], d);
+      }
+      else
+      {
+        result_buffer[0] = 25;
+        result_buffer[3] = 22;
+        PUT_WORD (&result_buffer[4], GOOD);
+        d = LI2_ASYMMETRIC_SUPPORTED | LI2_B_LOOPING_SUPPORTED | LI2_X_LOOPING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_CH_PC)
+          d |= LI2_MONITORING_SUPPORTED | LI2_REMOTE_MONITORING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_CH)
+          d |= LI2_MIXING_SUPPORTED | LI2_REMOTE_MIXING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_MIXER_PC_PC)
+          d |= LI2_PC_LOOPING_SUPPORTED;
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+          d |= LI2_CROSS_CONTROLLER_SUPPORTED;
+        PUT_DWORD (&result_buffer[6], d);
+        d = a->li_pri ? a->li_channels : MIXER_BCHANNELS_BRI;
+        PUT_DWORD (&result_buffer[10], d / 2);
+        PUT_DWORD (&result_buffer[14], d - 1);
+        if (a->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+        {
+          d = 0;
+          for (i = 0; i < li_total_channels; i++)
+          {
+            if ((li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
+             && (li_config_table[i].adapter->li_pri
+              || (i < li_config_table[i].adapter->li_base + MIXER_BCHANNELS_BRI)))
+            {
+              d++;
+            }
+          }
+        }
+        PUT_DWORD (&result_buffer[18], d / 2);
+        PUT_DWORD (&result_buffer[22], d - 1);
+      }
+      break;
+
+    case LI_REQ_CONNECT:
+      if (li_parms[1].length == 8)
+      {
+        appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC;
+        if (api_parse (&li_parms[1].info[1], li_parms[1].length, "dd", li_req_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        plci_b_id = GET_DWORD (li_req_parms[0].info) & 0xffff;
+        li_flags = GET_DWORD (li_req_parms[1].info);
+        Info = li_check_main_plci (Id, plci);
+        result_buffer[0] = 9;
+        result_buffer[3] = 6;
+        PUT_DWORD (&result_buffer[4], plci_b_id);
+        PUT_WORD (&result_buffer[8], GOOD);
+        if (Info != GOOD)
+          break;
+        result = plci->saved_msg.info;
+        for (i = 0; i <= result_buffer[0]; i++)
+          result[i] = result_buffer[i];
+        plci_b_write_pos = plci->li_plci_b_write_pos;
+        plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
+        if (plci_b == NULL)
+          break;
+        li_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags);
+        plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_LAST_FLAG;
+        plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+        plci->li_plci_b_write_pos = plci_b_write_pos;
+      }
+      else
+      {
+        appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC;
+        if (api_parse (&li_parms[1].info[1], li_parms[1].length, "ds", li_req_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        li_flags = GET_DWORD (li_req_parms[0].info) & ~(LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A);
+        Info = li_check_main_plci (Id, plci);
+        result_buffer[0] = 7;
+        result_buffer[3] = 4;
+        PUT_WORD (&result_buffer[4], Info);
+        result_buffer[6] = 0;
+        if (Info != GOOD)
+          break;
+        result = plci->saved_msg.info;
+        for (i = 0; i <= result_buffer[0]; i++)
+          result[i] = result_buffer[i];
+        plci_b_write_pos = plci->li_plci_b_write_pos;
+        participant_parms_pos = 0;
+        result_pos = 7;
+        li2_update_connect (Id, a, plci, UnMapId (Id), TRUE, li_flags);
+        while (participant_parms_pos < li_req_parms[1].length)
+        {
+          result[result_pos] = 6;
+          result_pos += 7;
+          PUT_DWORD (&result[result_pos - 6], 0);
+          PUT_WORD (&result[result_pos - 2], GOOD);
+          if (api_parse (&li_req_parms[1].info[1 + participant_parms_pos],
+            (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct))
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            PUT_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
+            break;
+          }
+          if (api_parse (&li_participant_struct[0].info[1],
+            li_participant_struct[0].length, "dd", li_participant_parms))
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            PUT_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
+            break;
+          }
+          plci_b_id = GET_DWORD (li_participant_parms[0].info) & 0xffff;
+          li_flags = GET_DWORD (li_participant_parms[1].info);
+          PUT_DWORD (&result[result_pos - 6], plci_b_id);
+          if (sizeof(result) - result_pos < 7)
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: LI result overrun",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            PUT_WORD (&result[result_pos - 2], _WRONG_STATE);
+            break;
+          }
+          plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
+          if (plci_b != NULL)
+          {
+            li2_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags);
+            plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id |
+              ((li_flags & (LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A |
+              LI2_FLAG_PCCONNECT_A_B | LI2_FLAG_PCCONNECT_B_A)) ? 0 : LI_PLCI_B_DISC_FLAG);
+            plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+          }
+          participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) -
+            (&li_req_parms[1].info[1]));
+        }
+        result[0] = (byte)(result_pos - 1);
+        result[3] = (byte)(result_pos - 4);
+        result[6] = (byte)(result_pos - 7);
+        i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
+        if ((plci_b_write_pos == plci->li_plci_b_read_pos)
+         || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
+        {
+          plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
+          plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+        }
+        else
+          plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
+        plci->li_plci_b_write_pos = plci_b_write_pos;
+      }
+      mixer_calculate_coefs (a);
+      plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
+      mixer_notify_update (plci, TRUE);
+      sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+        "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
+      plci->command = 0;
+      plci->li_cmd = GET_WORD (li_parms[0].info);
+      start_internal_command (Id, plci, mixer_command);
+      return (FALSE);
+
+    case LI_REQ_DISCONNECT:
+      if (li_parms[1].length == 4)
+      {
+        appl->appl_flags |= APPL_FLAG_OLD_LI_SPEC;
+        if (api_parse (&li_parms[1].info[1], li_parms[1].length, "d", li_req_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        plci_b_id = GET_DWORD (li_req_parms[0].info) & 0xffff;
+        Info = li_check_main_plci (Id, plci);
+        result_buffer[0] = 9;
+        result_buffer[3] = 6;
+        PUT_DWORD (&result_buffer[4], GET_DWORD (li_req_parms[0].info));
+        PUT_WORD (&result_buffer[8], GOOD);
+        if (Info != GOOD)
+          break;
+        result = plci->saved_msg.info;
+        for (i = 0; i <= result_buffer[0]; i++)
+          result[i] = result_buffer[i];
+        plci_b_write_pos = plci->li_plci_b_write_pos;
+        plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
+        if (plci_b == NULL)
+          break;
+        li_update_connect (Id, a, plci, plci_b_id, FALSE, 0);
+        plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG | LI_PLCI_B_LAST_FLAG;
+        plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+        plci->li_plci_b_write_pos = plci_b_write_pos;
+      }
+      else
+      {
+        appl->appl_flags &= ~APPL_FLAG_OLD_LI_SPEC;
+        if (api_parse (&li_parms[1].info[1], li_parms[1].length, "s", li_req_parms))
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_MESSAGE_FORMAT;
+          break;
+        }
+        Info = li_check_main_plci (Id, plci);
+        result_buffer[0] = 7;
+        result_buffer[3] = 4;
+        PUT_WORD (&result_buffer[4], Info);
+        result_buffer[6] = 0;
+        if (Info != GOOD)
+          break;
+        result = plci->saved_msg.info;
+        for (i = 0; i <= result_buffer[0]; i++)
+          result[i] = result_buffer[i];
+        plci_b_write_pos = plci->li_plci_b_write_pos;
+        participant_parms_pos = 0;
+        result_pos = 7;
+        while (participant_parms_pos < li_req_parms[0].length)
+        {
+          result[result_pos] = 6;
+          result_pos += 7;
+          PUT_DWORD (&result[result_pos - 6], 0);
+          PUT_WORD (&result[result_pos - 2], GOOD);
+          if (api_parse (&li_req_parms[0].info[1 + participant_parms_pos],
+            (word)(li_parms[1].length - participant_parms_pos), "s", li_participant_struct))
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            PUT_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
+            break;
+          }
+          if (api_parse (&li_participant_struct[0].info[1],
+            li_participant_struct[0].length, "d", li_participant_parms))
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            PUT_WORD (&result[result_pos - 2], _WRONG_MESSAGE_FORMAT);
+            break;
+          }
+          plci_b_id = GET_DWORD (li_participant_parms[0].info) & 0xffff;
+          PUT_DWORD (&result[result_pos - 6], plci_b_id);
+          if (sizeof(result) - result_pos < 7)
+          {
+            dbug (1, dprintf ("[%06lx] %s,%d: LI result overrun",
+              UnMapId (Id), (char   *)(FILE_), __LINE__));
+            PUT_WORD (&result[result_pos - 2], _WRONG_STATE);
+            break;
+          }
+          plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
+          if (plci_b != NULL)
+          {
+            li2_update_connect (Id, a, plci, plci_b_id, FALSE, 0);
+            plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
+            plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+          }
+          participant_parms_pos = (word)((&li_participant_struct[0].info[1 + li_participant_struct[0].length]) -
+            (&li_req_parms[0].info[1]));
+        }
+        result[0] = (byte)(result_pos - 1);
+        result[3] = (byte)(result_pos - 4);
+        result[6] = (byte)(result_pos - 7);
+        i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
+        if ((plci_b_write_pos == plci->li_plci_b_read_pos)
+         || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
+        {
+          plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
+          plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+        }
+        else
+          plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
+        plci->li_plci_b_write_pos = plci_b_write_pos;
+      }
+      mixer_calculate_coefs (a);
+      plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
+      mixer_notify_update (plci, TRUE);
+      sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+        "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
+      plci->command = 0;
+      plci->li_cmd = GET_WORD (li_parms[0].info);
+      start_internal_command (Id, plci, mixer_command);
+      return (FALSE);
+
+    case LI_REQ_SILENT_UPDATE:
+      if (!plci || !plci->State
+       || !plci->NL.Id || plci->nl_remove_id
+       || (plci->li_bchannel_id == 0)
+       || (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci != plci))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        return (FALSE);
+      }
+      plci_b_write_pos = plci->li_plci_b_write_pos;
+      if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
+        LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 2)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        return (FALSE);
+      }
+      i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
+      if ((plci_b_write_pos == plci->li_plci_b_read_pos)
+       || (plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG))
+      {
+        plci->li_plci_b_queue[plci_b_write_pos] = LI_PLCI_B_SKIP_FLAG | LI_PLCI_B_LAST_FLAG;
+        plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+      }
+      else
+        plci->li_plci_b_queue[i] |= LI_PLCI_B_LAST_FLAG;
+      plci->li_plci_b_write_pos = plci_b_write_pos;
+      plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
+      plci->command = 0;
+      plci->li_cmd = GET_WORD (li_parms[0].info);
+      start_internal_command (Id, plci, mixer_command);
+      return (FALSE);
+
+    default:
+      dbug (1, dprintf ("[%06lx] %s,%d: LI unknown request %04x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, GET_WORD (li_parms[0].info)));
+      Info = _FACILITY_NOT_SUPPORTED;
+    }
+  }
+  sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+    "wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
+  return (FALSE);
+}
+
+
+static void mixer_indication_coefs_set (dword Id, PLCI   *plci)
+{
+  dword d;
+  DIVA_CAPI_ADAPTER   *a;
+    byte result[12];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_coefs_set",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  a = plci->adapter;
+  if (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos)
+  {
+    do
+    {
+      d = plci->li_plci_b_queue[plci->li_plci_b_read_pos];
+      if (!(d & LI_PLCI_B_SKIP_FLAG))
+      {
+        if (plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
+        {
+          if (d & LI_PLCI_B_DISC_FLAG)
+          {
+            result[0] = 5;
+            PUT_WORD (&result[1], LI_IND_DISCONNECT);
+            result[3] = 2;
+            PUT_WORD (&result[4], _LI_USER_INITIATED);
+          }
+          else
+          {
+            result[0] = 7;
+            PUT_WORD (&result[1], LI_IND_CONNECT_ACTIVE);
+            result[3] = 4;
+            PUT_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
+          }
+        }
+        else
+        {
+          if (d & LI_PLCI_B_DISC_FLAG)
+          {
+            result[0] = 9;
+            PUT_WORD (&result[1], LI_IND_DISCONNECT);
+            result[3] = 6;
+            PUT_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
+            PUT_WORD (&result[8], _LI_USER_INITIATED);
+          }
+          else
+          {
+            result[0] = 7;
+            PUT_WORD (&result[1], LI_IND_CONNECT_ACTIVE);
+            result[3] = 4;
+            PUT_DWORD (&result[4], d & ~LI_PLCI_B_FLAG_MASK);
+          }
+        }
+        sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0,
+          "ws", SELECTOR_LINE_INTERCONNECT, result);
+      }
+      plci->li_plci_b_read_pos = (plci->li_plci_b_read_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ?
+        0 : plci->li_plci_b_read_pos + 1;
+    } while (!(d & LI_PLCI_B_LAST_FLAG) && (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos));
+  }
+}
+
+
+static void mixer_indication_xconnect_from (dword Id, PLCI   *plci, byte   *msg, word length)
+{
+  word i, j, ch;
+  struct xconnect_transfer_address_s s,   *p;
+  DIVA_CAPI_ADAPTER   *a;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_xconnect_from %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, (int) length));
+
+  a = plci->adapter;
+  i = 1;
+  for (i = 1; i < length; i += 16)
+  {
+    s.card_address.low = msg[i] | (msg[i+1] << 8) | (((dword)(msg[i+2])) << 16) | (((dword)(msg[i+3])) << 24);
+    s.card_address.high = msg[i+4] | (msg[i+5] << 8) | (((dword)(msg[i+6])) << 16) | (((dword)(msg[i+7])) << 24);
+    s.offset = msg[i+8] | (msg[i+9] << 8) | (((dword)(msg[i+10])) << 16) | (((dword)(msg[i+11])) << 24);
+    ch = msg[i+12] | (msg[i+13] << 8);
+    j = ch & XCONNECT_CHANNEL_NUMBER_MASK;
+    if (!a->li_pri && (plci->li_bchannel_id == 2))
+      j = 1 - j;
+    j += a->li_base;
+    if (ch & XCONNECT_CHANNEL_PORT_PC)
+      p = &(li_config_table[j].send_pc);
+    else
+      p = &(li_config_table[j].send_b);
+    p->card_address.low = s.card_address.low;
+    p->card_address.high = s.card_address.high;
+    p->offset = s.offset;
+    li_config_table[j].channel |= LI_CHANNEL_ADDRESSES_SET;
+  }
+  if (plci->internal_command_queue[0]
+   && ((plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_2)
+    || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_3)
+    || (plci->adjust_b_state == ADJUST_B_RESTORE_MIXER_4)))
+  {
+    (*(plci->internal_command_queue[0]))(Id, plci, 0);
+    if (!plci->internal_command)
+      next_internal_command (Id, plci);
+  }
+  mixer_notify_update (plci, TRUE);
+}
+
+
+static void mixer_indication_xconnect_to (dword Id, PLCI   *plci, byte   *msg, word length)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_xconnect_to %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, (int) length));
+
+}
+
+
+static byte mixer_notify_source_removed (PLCI   *plci, dword plci_b_id)
+{
+  word plci_b_write_pos;
+
+  plci_b_write_pos = plci->li_plci_b_write_pos;
+  if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
+    LI_PLCI_B_QUEUE_ENTRIES + plci->li_plci_b_read_pos) - plci_b_write_pos - 1 < 1)
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
+      (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+      (char   *)(FILE_), __LINE__));
+    return (FALSE);
+  }
+  plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
+  plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
+  plci->li_plci_b_write_pos = plci_b_write_pos;
+  return (TRUE);
+}
+
+
+static void mixer_remove (PLCI   *plci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  PLCI   *notify_plci;
+  dword plci_b_id;
+  word i, j;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: mixer_remove",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  a = plci->adapter;
+  plci_b_id = (plci->Id << 8) | UnMapController (plci->adapter->Id);
+  if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
+  {
+    if ((plci->li_bchannel_id != 0)
+     && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+    {
+      i = a->li_base + (plci->li_bchannel_id - 1);
+      if ((li_config_table[i].curchnl | li_config_table[i].channel) & LI_CHANNEL_INVOLVED)
+      {
+        for (j = 0; j < li_total_channels; j++)
+        {
+          if ((li_config_table[i].flag_table[j] & LI_FLAG_INTERCONNECT)
+           || (li_config_table[j].flag_table[i] & LI_FLAG_INTERCONNECT))
+          {
+            notify_plci = li_config_table[j].plci;
+            if ((notify_plci != NULL)
+             && (notify_plci != plci)
+             && (notify_plci->appl != NULL)
+             && !(notify_plci->appl->appl_flags & APPL_FLAG_OLD_LI_SPEC)
+             && (notify_plci->State)
+             && notify_plci->NL.Id && !notify_plci->nl_remove_id)
+            {
+              mixer_notify_source_removed (notify_plci, plci_b_id);
+            }
+          }
+        }
+        mixer_clear_config (plci);
+        mixer_calculate_coefs (a);
+        mixer_notify_update (plci, TRUE);
+      }
+      li_config_table[i].plci = NULL;
+      plci->li_bchannel_id = 0;
+    }
+  }
+}
+
+
+/*------------------------------------------------------------------*/
+/* Echo canceller facilities                                        */
+/*------------------------------------------------------------------*/
+
+
+static void ec_write_parameters (PLCI   *plci)
+{
+  word w;
+    byte parameter_buffer[6];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_write_parameters",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  parameter_buffer[0] = 5;
+  parameter_buffer[1] = DSP_CTRL_SET_LEC_PARAMETERS;
+  PUT_WORD (&parameter_buffer[2], plci->ec_idi_options);
+  plci->ec_idi_options &= ~LEC_RESET_COEFFICIENTS;
+  w = (plci->ec_tail_length == 0) ? 128 : plci->ec_tail_length;
+  PUT_WORD (&parameter_buffer[4], w);
+  add_p (plci, FTY, parameter_buffer);
+  sig_req (plci, TEL_CTRL, 0);
+  send_req (plci);
+}
+
+
+static void ec_clear_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
+    LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING;
+  plci->ec_tail_length = 0;
+}
+
+
+static void ec_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+}
+
+
+static word ec_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  return (GOOD);
+}
+
+
+static word ec_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  if (plci->B1_facilities & B1_FACILITY_EC)
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_EC_1:
+      plci->internal_command = plci->adjust_b_command;
+      if (plci->sig_req)
+      {
+        plci->adjust_b_state = ADJUST_B_RESTORE_EC_1;
+        break;
+      }
+      ec_write_parameters (plci);
+      plci->adjust_b_state = ADJUST_B_RESTORE_EC_2;
+      break;
+    case ADJUST_B_RESTORE_EC_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Restore EC failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+static void ec_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word internal_command, Info;
+    byte result[8];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_command %02x %04x %04x %04x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command,
+    plci->ec_cmd, plci->ec_idi_options, plci->ec_tail_length));
+
+  Info = GOOD;
+  if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
+  {
+    result[0] = 2;
+    PUT_WORD (&result[1], EC_SUCCESS);
+  }
+  else
+  {
+    result[0] = 5;
+    PUT_WORD (&result[1], plci->ec_cmd);
+    result[3] = 2;
+    PUT_WORD (&result[4], GOOD);
+  }
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (plci->ec_cmd)
+  {
+  case EC_ENABLE_OPERATION:
+  case EC_FREEZE_COEFFICIENTS:
+  case EC_RESUME_COEFFICIENT_UPDATE:
+  case EC_RESET_COEFFICIENTS:
+    switch (internal_command)
+    {
+    default:
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities |
+        B1_FACILITY_EC), EC_COMMAND_1);
+    case EC_COMMAND_1:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Load EC failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+    case EC_COMMAND_2:
+      if (plci->sig_req)
+      {
+        plci->internal_command = EC_COMMAND_2;
+        return;
+      }
+      plci->internal_command = EC_COMMAND_3;
+      ec_write_parameters (plci);
+      return;
+    case EC_COMMAND_3:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Enable EC failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      break;
+    }
+    break;
+
+  case EC_DISABLE_OPERATION:
+    switch (internal_command)
+    {
+    default:
+    case EC_COMMAND_1:
+      if (plci->B1_facilities & B1_FACILITY_EC)
+      {
+        if (plci->sig_req)
+        {
+          plci->internal_command = EC_COMMAND_1;
+          return;
+        }
+        plci->internal_command = EC_COMMAND_2;
+        ec_write_parameters (plci);
+        return;
+      }
+      Rc = OK;
+    case EC_COMMAND_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Disable EC failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      adjust_b1_resource (Id, plci, NULL, (word)(plci->B1_facilities &
+        ~B1_FACILITY_EC), EC_COMMAND_3);
+    case EC_COMMAND_3:
+      if (adjust_b_process (Id, plci, Rc) != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Unload EC failed",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _FACILITY_NOT_SUPPORTED;
+        break;
+      }
+      if (plci->internal_command)
+        return;
+      break;
+    }
+    break;
+  }
+  sendf (plci->appl, _FACILITY_R | CONFIRM, Id & 0xffffL, plci->number,
+    "wws", Info, (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
+    PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
+}
+
+
+static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER   *a, PLCI   *plci, APPL   *appl, API_PARSE *msg)
+{
+  word Info;
+  word opt;
+    API_PARSE ec_parms[3];
+    byte result[16];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_request",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  Info = GOOD;
+  result[0] = 0;
+  if (!(a->man_profile.private_options & (1L << PRIVATE_ECHO_CANCELLER)))
+  {
+    dbug (1, dprintf ("[%06lx] %s,%d: Facility not supported",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+    Info = _FACILITY_NOT_SUPPORTED;
+  }
+  else
+  {
+    if (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
+    {
+      if (api_parse (&msg[1].info[1], msg[1].length, "w", ec_parms))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _WRONG_MESSAGE_FORMAT;
+      }
+      else
+      {
+        if (plci == NULL)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_IDENTIFIER;
+        }
+        else if (!plci->State || !plci->NL.Id || plci->nl_remove_id)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_STATE;
+        }
+        else
+        {
+          plci->command = 0;
+          plci->ec_cmd = GET_WORD (ec_parms[0].info);
+          plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS);
+          result[0] = 2;
+          PUT_WORD (&result[1], EC_SUCCESS);
+          if (msg[1].length >= 4)
+          {
+            opt = GET_WORD (&ec_parms[0].info[2]);
+            plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING |
+              LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS);
+            if (!(opt & EC_DISABLE_NON_LINEAR_PROCESSING))
+              plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING;
+            if (opt & EC_DETECT_DISABLE_TONE)
+              plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR;
+            if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS))
+              plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS;
+            if (msg[1].length >= 6)
+            {
+              plci->ec_tail_length = GET_WORD (&ec_parms[0].info[4]);
+            }
+          }
+          switch (plci->ec_cmd)
+          {
+          case EC_ENABLE_OPERATION:
+            plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_DISABLE_OPERATION:
+            plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
+              LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
+              LEC_RESET_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_FREEZE_COEFFICIENTS:
+            plci->ec_idi_options |= LEC_FREEZE_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_RESUME_COEFFICIENT_UPDATE:
+            plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_RESET_COEFFICIENTS:
+            plci->ec_idi_options |= LEC_RESET_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          default:
+            dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x",
+              UnMapId (Id), (char   *)(FILE_), __LINE__, plci->ec_cmd));
+            PUT_WORD (&result[1], EC_UNSUPPORTED_OPERATION);
+          }
+        }
+      }
+    }
+    else
+    {
+      if (api_parse (&msg[1].info[1], msg[1].length, "ws", ec_parms))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Wrong message format",
+          UnMapId (Id), (char   *)(FILE_), __LINE__));
+        Info = _WRONG_MESSAGE_FORMAT;
+      }
+      else
+      {
+        if (GET_WORD (ec_parms[0].info) == EC_GET_SUPPORTED_SERVICES)
+        {
+          result[0] = 11;
+          PUT_WORD (&result[1], EC_GET_SUPPORTED_SERVICES);
+          result[3] = 8;
+          PUT_WORD (&result[4], GOOD);
+          PUT_WORD (&result[6], 0x0007);
+          PUT_WORD (&result[8], LEC_MAX_SUPPORTED_TAIL_LENGTH);
+          PUT_WORD (&result[10], 0);
+        }
+        else if (plci == NULL)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong PLCI",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_IDENTIFIER;
+        }
+        else if (!plci->State || !plci->NL.Id || plci->nl_remove_id)
+        {
+          dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
+            UnMapId (Id), (char   *)(FILE_), __LINE__));
+          Info = _WRONG_STATE;
+        }
+        else
+        {
+          plci->command = 0;
+          plci->ec_cmd = GET_WORD (ec_parms[0].info);
+          plci->ec_idi_options &= ~(LEC_MANUAL_DISABLE | LEC_RESET_COEFFICIENTS);
+          result[0] = 5;
+          PUT_WORD (&result[1], plci->ec_cmd);
+          result[3] = 2;
+          PUT_WORD (&result[4], GOOD);
+          plci->ec_idi_options &= ~(LEC_ENABLE_NONLINEAR_PROCESSING |
+            LEC_ENABLE_2100HZ_DETECTOR | LEC_REQUIRE_2100HZ_REVERSALS);
+          plci->ec_tail_length = 0;
+          if (ec_parms[1].length >= 2)
+          {
+            opt = GET_WORD (&ec_parms[1].info[1]);
+            if (opt & EC_ENABLE_NON_LINEAR_PROCESSING)
+              plci->ec_idi_options |= LEC_ENABLE_NONLINEAR_PROCESSING;
+            if (opt & EC_DETECT_DISABLE_TONE)
+              plci->ec_idi_options |= LEC_ENABLE_2100HZ_DETECTOR;
+            if (!(opt & EC_DO_NOT_REQUIRE_REVERSALS))
+              plci->ec_idi_options |= LEC_REQUIRE_2100HZ_REVERSALS;
+            if (ec_parms[1].length >= 4)
+            {
+              plci->ec_tail_length = GET_WORD (&ec_parms[1].info[3]);
+            }
+          }
+          switch (plci->ec_cmd)
+          {
+          case EC_ENABLE_OPERATION:
+            plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          case EC_DISABLE_OPERATION:
+            plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
+              LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
+              LEC_RESET_COEFFICIENTS;
+            start_internal_command (Id, plci, ec_command);
+            return (FALSE);
+
+          default:
+            dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x",
+              UnMapId (Id), (char   *)(FILE_), __LINE__, plci->ec_cmd));
+            PUT_WORD (&result[4], _FACILITY_SPECIFIC_FUNCTION_NOT_SUPP);
+          }
+        }
+      }
+    }
+  }
+  sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
+    "wws", Info, (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
+    PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
+  return (FALSE);
+}
+
+
+static void ec_indication (dword Id, PLCI   *plci, byte   *msg, word length)
+{
+    byte result[8];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: ec_indication",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+  if (!(plci->ec_idi_options & LEC_MANUAL_DISABLE))
+  {
+    if (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC)
+    {
+      result[0] = 2;
+      PUT_WORD (&result[1], 0);
+      switch (msg[1])
+      {
+      case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ:
+        PUT_WORD (&result[1], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ);
+        break;
+      case LEC_DISABLE_TYPE_REVERSED_2100HZ:
+        PUT_WORD (&result[1], EC_BYPASS_DUE_TO_REVERSED_2100HZ);
+        break;
+      case LEC_DISABLE_RELEASED:
+        PUT_WORD (&result[1], EC_BYPASS_RELEASED);
+        break;
+      }
+    }
+    else
+    {
+      result[0] = 5;
+      PUT_WORD (&result[1], EC_BYPASS_INDICATION);
+      result[3] = 2;
+      PUT_WORD (&result[4], 0);
+      switch (msg[1])
+      {
+      case LEC_DISABLE_TYPE_CONTIGNUOUS_2100HZ:
+        PUT_WORD (&result[4], EC_BYPASS_DUE_TO_CONTINUOUS_2100HZ);
+        break;
+      case LEC_DISABLE_TYPE_REVERSED_2100HZ:
+        PUT_WORD (&result[4], EC_BYPASS_DUE_TO_REVERSED_2100HZ);
+        break;
+      case LEC_DISABLE_RELEASED:
+        PUT_WORD (&result[4], EC_BYPASS_RELEASED);
+        break;
+      }
+    }
+    sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", (plci->appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
+      PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
+  }
+}
+
+
+
+/*------------------------------------------------------------------*/
+/* Advanced voice                                                   */
+/*------------------------------------------------------------------*/
+
+static void adv_voice_write_coefs (PLCI   *plci, word write_command)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word i;
+  byte *p;
+
+  word w, n, j, k;
+  byte ch_map[MIXER_CHANNELS_BRI];
+
+    byte coef_buffer[ADV_VOICE_COEF_BUFFER_SIZE + 2];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_write_coefs %d",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, write_command));
+
+  a = plci->adapter;
+  p = coef_buffer + 1;
+  *(p++) = DSP_CTRL_OLD_SET_MIXER_COEFFICIENTS;
+  i = 0;
+  while (i + sizeof(word) <= a->adv_voice_coef_length)
+  {
+    PUT_WORD (p, GET_WORD (a->adv_voice_coef_buffer + i));
+    p += 2;
+    i += 2;
+  }
+  while (i < ADV_VOICE_OLD_COEF_COUNT * sizeof(word))
+  {
+    PUT_WORD (p, 0x8000);
+    p += 2;
+    i += 2;
+  }
+
+  if (!a->li_pri && (plci->li_bchannel_id == 0))
+  {
+    if ((li_config_table[a->li_base].plci == NULL) && (li_config_table[a->li_base + 1].plci != NULL))
+    {
+      plci->li_bchannel_id = 1;
+      li_config_table[a->li_base].plci = plci;
+      dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
+        (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+        (char   *)(FILE_), __LINE__, plci->li_bchannel_id));
+    }
+    else if ((li_config_table[a->li_base].plci != NULL) && (li_config_table[a->li_base + 1].plci == NULL))
+    {
+      plci->li_bchannel_id = 2;
+      li_config_table[a->li_base + 1].plci = plci;
+      dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_set_bchannel_id %d",
+        (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+        (char   *)(FILE_), __LINE__, plci->li_bchannel_id));
+    }
+  }
+  if (!a->li_pri && (plci->li_bchannel_id != 0)
+   && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    i = a->li_base + (plci->li_bchannel_id - 1);
+    switch (write_command)
+    {
+    case ADV_VOICE_WRITE_ACTIVATION:
+      j = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+      k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+      if (!(plci->B1_facilities & B1_FACILITY_MIXER))
+      {
+        li_config_table[j].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX;
+        li_config_table[i].flag_table[j] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR;
+      }
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+      {
+        li_config_table[k].flag_table[i] |= LI_FLAG_CONFERENCE | LI_FLAG_MIX;
+        li_config_table[i].flag_table[k] |= LI_FLAG_CONFERENCE | LI_FLAG_MONITOR;
+        li_config_table[k].flag_table[j] |= LI_FLAG_CONFERENCE;
+        li_config_table[j].flag_table[k] |= LI_FLAG_CONFERENCE;
+      }
+      mixer_calculate_coefs (a);
+      li_config_table[i].curchnl = li_config_table[i].channel;
+      li_config_table[j].curchnl = li_config_table[j].channel;
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+        li_config_table[k].curchnl = li_config_table[k].channel;
+      break;
+
+    case ADV_VOICE_WRITE_DEACTIVATION:
+      for (j = 0; j < li_total_channels; j++)
+      {
+        li_config_table[i].flag_table[j] = 0;
+        li_config_table[j].flag_table[i] = 0;
+      }
+      k = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+      for (j = 0; j < li_total_channels; j++)
+      {
+        li_config_table[k].flag_table[j] = 0;
+        li_config_table[j].flag_table[k] = 0;
+      }
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+      {
+        k = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+        for (j = 0; j < li_total_channels; j++)
+        {
+          li_config_table[k].flag_table[j] = 0;
+          li_config_table[j].flag_table[k] = 0;
+        }
+      }
+      mixer_calculate_coefs (a);
+      break;
+    }
+    if (plci->B1_facilities & B1_FACILITY_MIXER)
+    {
+      w = 0;
+      if (ADV_VOICE_NEW_COEF_BASE + sizeof(word) <= a->adv_voice_coef_length)
+        w = GET_WORD (a->adv_voice_coef_buffer + ADV_VOICE_NEW_COEF_BASE);
+      if (li_config_table[i].channel & LI_CHANNEL_TX_DATA)
+        w |= MIXER_FEATURE_ENABLE_TX_DATA;
+      if (li_config_table[i].channel & LI_CHANNEL_RX_DATA)
+        w |= MIXER_FEATURE_ENABLE_RX_DATA;
+      *(p++) = (byte) w;
+      *(p++) = (byte)(w >> 8);
+      for (j = 0; j < sizeof(ch_map); j += 2)
+      {
+        ch_map[j] = (byte)(j + (plci->li_bchannel_id - 1));
+        ch_map[j+1] = (byte)(j + (2 - plci->li_bchannel_id));
+      }
+      for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+      {
+        i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
+        j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
+        if (li_config_table[i].channel & li_config_table[j].channel & LI_CHANNEL_INVOLVED)
+        {
+          *(p++) = ((li_config_table[i].coef_table[j] & mixer_write_prog_bri[n].mask) ? 0x80 : 0x01);
+          w = ((li_config_table[i].coef_table[j] & 0xf) ^ (li_config_table[i].coef_table[j] >> 4));
+          li_config_table[i].coef_table[j] ^= (w & mixer_write_prog_bri[n].mask) << 4;
+        }
+        else
+        {
+          *(p++) = (ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n < a->adv_voice_coef_length) ?
+            a->adv_voice_coef_buffer[ADV_VOICE_NEW_COEF_BASE + sizeof(word) + n] : 0x00;
+        }
+      }
+    }
+    else
+    {
+      for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++)
+        *(p++) = a->adv_voice_coef_buffer[i];
+    }
+  }
+  else
+
+  {
+    for (i = ADV_VOICE_NEW_COEF_BASE; i < a->adv_voice_coef_length; i++)
+      *(p++) = a->adv_voice_coef_buffer[i];
+  }
+  coef_buffer[0] = (p - coef_buffer) - 1;
+  add_p (plci, FTY, coef_buffer);
+  sig_req (plci, TEL_CTRL, 0);
+  send_req (plci);
+}
+
+
+static void adv_voice_clear_config (PLCI   *plci)
+{
+  DIVA_CAPI_ADAPTER   *a;
+
+  word i, j;
+
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_clear_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  a = plci->adapter;
+  if ((plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
+  {
+    a->adv_voice_coef_length = 0;
+
+    if (!a->li_pri && (plci->li_bchannel_id != 0)
+     && (li_config_table[a->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+    {
+      i = a->li_base + (plci->li_bchannel_id - 1);
+      li_config_table[i].curchnl = 0;
+      li_config_table[i].channel = 0;
+      li_config_table[i].chflags = 0;
+      for (j = 0; j < li_total_channels; j++)
+      {
+        li_config_table[i].flag_table[j] = 0;
+        li_config_table[j].flag_table[i] = 0;
+        li_config_table[i].coef_table[j] = 0;
+        li_config_table[j].coef_table[i] = 0;
+      }
+      li_config_table[i].coef_table[i] |= LI_COEF_CH_PC_SET | LI_COEF_PC_CH_SET;
+      i = a->li_base + MIXER_IC_CHANNEL_BASE + (plci->li_bchannel_id - 1);
+      li_config_table[i].curchnl = 0;
+      li_config_table[i].channel = 0;
+      li_config_table[i].chflags = 0;
+      for (j = 0; j < li_total_channels; j++)
+      {
+        li_config_table[i].flag_table[j] = 0;
+        li_config_table[j].flag_table[i] = 0;
+        li_config_table[i].coef_table[j] = 0;
+        li_config_table[j].coef_table[i] = 0;
+      }
+      if (a->manufacturer_features & MANUFACTURER_FEATURE_SLAVE_CODEC)
+      {
+        i = a->li_base + MIXER_IC_CHANNEL_BASE + (2 - plci->li_bchannel_id);
+        li_config_table[i].curchnl = 0;
+        li_config_table[i].channel = 0;
+        li_config_table[i].chflags = 0;
+        for (j = 0; j < li_total_channels; j++)
+        {
+          li_config_table[i].flag_table[j] = 0;
+          li_config_table[j].flag_table[i] = 0;
+          li_config_table[i].coef_table[j] = 0;
+          li_config_table[j].coef_table[i] = 0;
+        }
+      }
+    }
+
+  }
+}
+
+
+static void adv_voice_prepare_switch (dword Id, PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_prepare_switch",
+    UnMapId (Id), (char   *)(FILE_), __LINE__));
+
+}
+
+
+static word adv_voice_save_config (dword Id, PLCI   *plci, byte Rc)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_save_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  return (GOOD);
+}
+
+
+static word adv_voice_restore_config (dword Id, PLCI   *plci, byte Rc)
+{
+  DIVA_CAPI_ADAPTER   *a;
+  word Info;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adv_voice_restore_config %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  a = plci->adapter;
+  if ((plci->B1_facilities & B1_FACILITY_VOICE)
+   && (plci->tel == ADV_VOICE) && (plci == a->AdvSignalPLCI))
+  {
+    switch (plci->adjust_b_state)
+    {
+    case ADJUST_B_RESTORE_VOICE_1:
+      plci->internal_command = plci->adjust_b_command;
+      if (plci->sig_req)
+      {
+        plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1;
+        break;
+      }
+      adv_voice_write_coefs (plci, ADV_VOICE_WRITE_UPDATE);
+      plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_2;
+      break;
+    case ADJUST_B_RESTORE_VOICE_2:
+      if ((Rc != OK) && (Rc != OK_FC))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Restore voice config failed %02x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+        Info = _WRONG_STATE;
+        break;
+      }
+      break;
+    }
+  }
+  return (Info);
+}
+
+
+
+
+/*------------------------------------------------------------------*/
+/* B1 resource switching                                            */
+/*------------------------------------------------------------------*/
+
+static byte b1_facilities_table[] =
+{
+  0x00,  /* 0  No bchannel resources      */
+  0x00,  /* 1  Codec (automatic law)      */
+  0x00,  /* 2  Codec (A-law)              */
+  0x00,  /* 3  Codec (y-law)              */
+  0x00,  /* 4  HDLC for X.21              */
+  0x00,  /* 5  HDLC                       */
+  0x00,  /* 6  External Device 0          */
+  0x00,  /* 7  External Device 1          */
+  0x00,  /* 8  HDLC 56k                   */
+  0x00,  /* 9  Transparent                */
+  0x00,  /* 10 Loopback to network        */
+  0x00,  /* 11 Test pattern to net        */
+  0x00,  /* 12 Rate adaptation sync       */
+  0x00,  /* 13 Rate adaptation async      */
+  0x00,  /* 14 R-Interface                */
+  0x00,  /* 15 HDLC 128k leased line      */
+  0x00,  /* 16 FAX                        */
+  0x00,  /* 17 Modem async                */
+  0x00,  /* 18 Modem sync HDLC            */
+  0x00,  /* 19 V.110 async HDLC           */
+  0x12,  /* 20 Adv voice (Trans,mixer)    */
+  0x00,  /* 21 Codec connected to IC      */
+  0x0c,  /* 22 Trans,DTMF                 */
+  0x1e,  /* 23 Trans,DTMF+mixer           */
+  0x1f,  /* 24 Trans,DTMF+mixer+local     */
+  0x13,  /* 25 Trans,mixer+local          */
+  0x12,  /* 26 HDLC,mixer                 */
+  0x12,  /* 27 HDLC 56k,mixer             */
+  0x2c,  /* 28 Trans,LEC+DTMF             */
+  0x3e,  /* 29 Trans,LEC+DTMF+mixer       */
+  0x3f,  /* 30 Trans,LEC+DTMF+mixer+local */
+  0x2c,  /* 31 RTP,LEC+DTMF               */
+  0x3e,  /* 32 RTP,LEC+DTMF+mixer         */
+  0x3f,  /* 33 RTP,LEC+DTMF+mixer+local   */
+  0x00,  /* 34 Signaling task             */
+  0x00,  /* 35 PIAFS                      */
+  0x0c,  /* 36 Trans,DTMF+TONE            */
+  0x1e,  /* 37 Trans,DTMF+TONE+mixer      */
+  0x1f   /* 38 Trans,DTMF+TONE+mixer+local*/
+};
+
+
+static word get_b1_facilities (PLCI   * plci, byte b1_resource)
+{
+  word b1_facilities;
+
+  b1_facilities = b1_facilities_table[b1_resource];
+  if ((b1_resource == 9) || (b1_resource == 20) || (b1_resource == 25))
+  {
+
+    if (!(((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE))
+       || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id-1] & (1L << PRIVATE_DTMF_TONE)))))
+
+    {
+      if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND)
+        b1_facilities |= B1_FACILITY_DTMFX;
+      if (plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)
+        b1_facilities |= B1_FACILITY_DTMFR;
+    }
+  }
+  if ((b1_resource == 17) || (b1_resource == 18))
+  {
+    if (plci->adapter->manufacturer_features & (MANUFACTURER_FEATURE_V18 | MANUFACTURER_FEATURE_VOWN))
+      b1_facilities |= B1_FACILITY_DTMFX | B1_FACILITY_DTMFR;
+  }
+/*
+  dbug (1, dprintf ("[%06lx] %s,%d: get_b1_facilities %d %04x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char far *)(FILE_), __LINE__, b1_resource, b1_facilites));
+*/
+  return (b1_facilities);
+}
+
+
+static byte add_b1_facilities (PLCI   * plci, byte b1_resource, word b1_facilities)
+{
+  byte b;
+
+  switch (b1_resource)
+  {
+  case 5:
+  case 26:
+    if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+      b = 26;
+    else
+      b = 5;
+    break;
+
+  case 8:
+  case 27:
+    if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+      b = 27;
+    else
+      b = 8;
+    break;
+
+  case 9:
+  case 20:
+  case 22:
+  case 23:
+  case 24:
+  case 25:
+  case 28:
+  case 29:
+  case 30:
+  case 36:
+  case 37:
+  case 38:
+    if (b1_facilities & B1_FACILITY_EC)
+    {
+      if (b1_facilities & B1_FACILITY_LOCAL)
+        b = 30;
+      else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+        b = 29;
+      else
+        b = 28;
+    }
+
+    else if ((b1_facilities & (B1_FACILITY_DTMFX | B1_FACILITY_DTMFR | B1_FACILITY_MIXER))
+      && (((plci->requested_options_conn | plci->requested_options) & (1L << PRIVATE_DTMF_TONE))
+       || (plci->appl && (plci->adapter->requested_options_table[plci->appl->Id-1] & (1L << PRIVATE_DTMF_TONE)))))
+    {
+      if (b1_facilities & B1_FACILITY_LOCAL)
+        b = 38;
+      else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+        b = 37;
+      else
+        b = 36;
+    }
+
+    else if (((plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_HARDDTMF)
+      && !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE))
+     || ((b1_facilities & B1_FACILITY_DTMFR)
+      && ((b1_facilities & B1_FACILITY_MIXER)
+       || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE)))
+     || ((b1_facilities & B1_FACILITY_DTMFX)
+      && ((b1_facilities & B1_FACILITY_MIXER)
+       || !(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_SOFTDTMF_SEND))))
+    {
+      if (b1_facilities & B1_FACILITY_LOCAL)
+        b = 24;
+      else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+        b = 23;
+      else
+        b = 22;
+    }
+    else
+    {
+      if (b1_facilities & B1_FACILITY_LOCAL)
+        b = 25;
+      else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+        b = 20;
+      else
+        b = 9;
+    }
+    break;
+
+  case 31:
+  case 32:
+  case 33:
+    if (b1_facilities & B1_FACILITY_LOCAL)
+      b = 33;
+    else if (b1_facilities & (B1_FACILITY_MIXER | B1_FACILITY_VOICE))
+      b = 32;
+    else
+      b = 31;
+    break;
+
+  default:
+    b = b1_resource;
+  }
+  dbug (1, dprintf ("[%06lx] %s,%d: add_b1_facilities %d %04x %d %04x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__,
+    b1_resource, b1_facilities, b, get_b1_facilities (plci, b)));
+  return (b);
+}
+
+
+static void adjust_b1_facilities (PLCI   *plci, byte new_b1_resource, word new_b1_facilities)
+{
+  word removed_facilities;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b1_facilities %d %04x %04x",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__, new_b1_resource, new_b1_facilities,
+    new_b1_facilities & get_b1_facilities (plci, new_b1_resource)));
+
+  new_b1_facilities &= get_b1_facilities (plci, new_b1_resource);
+  removed_facilities = plci->B1_facilities & ~new_b1_facilities;
+
+  if (removed_facilities & B1_FACILITY_EC)
+    ec_clear_config (plci);
+
+
+  if (removed_facilities & B1_FACILITY_DTMFR)
+  {
+    dtmf_rec_clear_config (plci);
+    dtmf_parameter_clear_config (plci);
+  }
+  if (removed_facilities & B1_FACILITY_DTMFX)
+    dtmf_send_clear_config (plci);
+
+
+  if (removed_facilities & B1_FACILITY_MIXER)
+    mixer_clear_config (plci);
+
+  if (removed_facilities & B1_FACILITY_VOICE)
+    adv_voice_clear_config (plci);
+  plci->B1_facilities = new_b1_facilities;
+}
+
+
+static void adjust_b_clear (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_clear",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->adjust_b_restore = FALSE;
+}
+
+
+static word adjust_b_process (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  byte b1_resource;
+  NCCI   * ncci_ptr;
+    API_PARSE bp[2];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_process %02x %d",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->adjust_b_state));
+
+  Info = GOOD;
+  switch (plci->adjust_b_state)
+  {
+  case ADJUST_B_START:
+    if ((plci->adjust_b_parms_msg == NULL)
+     && (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1)
+     && ((plci->adjust_b_mode & ~(ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 |
+      ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_RESTORE)) == 0))
+    {
+      b1_resource = (plci->adjust_b_mode == ADJUST_B_MODE_NO_RESOURCE) ?
+        0 : add_b1_facilities (plci, plci->B1_resource, plci->adjust_b_facilities);
+      if (b1_resource == plci->B1_resource)
+      {
+        adjust_b1_facilities (plci, b1_resource, plci->adjust_b_facilities);
+        break;
+      }
+      if (plci->adjust_b_facilities & ~get_b1_facilities (plci, b1_resource))
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Adjust B nonsupported facilities %d %d %04x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__,
+          plci->B1_resource, b1_resource, plci->adjust_b_facilities));
+        Info = _WRONG_STATE;
+        break;
+      }
+    }
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      mixer_prepare_switch (Id, plci);
+
+
+      dtmf_prepare_switch (Id, plci);
+      dtmf_parameter_prepare_switch (Id, plci);
+
+
+      ec_prepare_switch (Id, plci);
+
+      adv_voice_prepare_switch (Id, plci);
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_MIXER_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_MIXER_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      Info = mixer_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_DTMF_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_DTMF_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      Info = dtmf_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_REMOVE_L23_1;
+  case ADJUST_B_REMOVE_L23_1:
+    if ((plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23)
+     && plci->NL.Id && !plci->nl_remove_id)
+    {
+      plci->internal_command = plci->adjust_b_command;
+      if (plci->adjust_b_ncci != 0)
+      {
+        ncci_ptr = &(plci->adapter->ncci[plci->adjust_b_ncci]);
+        while (ncci_ptr->data_pending)
+        {
+          plci->data_sent_ptr = ncci_ptr->DBuffer[ncci_ptr->data_out].P;
+          data_rc (plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]);
+        }
+        while (ncci_ptr->data_ack_pending)
+          data_ack (plci, plci->adapter->ncci_ch[plci->adjust_b_ncci]);
+      }
+      nl_req_ncci (plci, REMOVE,
+        (byte)((plci->adjust_b_mode & ADJUST_B_MODE_CONNECT) ? plci->adjust_b_ncci : 0));
+      send_req (plci);
+      plci->adjust_b_state = ADJUST_B_REMOVE_L23_2;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_REMOVE_L23_2;
+    Rc = OK;
+  case ADJUST_B_REMOVE_L23_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B remove failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci->adjust_b_mode & ADJUST_B_MODE_REMOVE_L23)
+    {
+      if (plci_nl_busy (plci))
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_EC_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_EC_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      Info = ec_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_DTMF_PARAMETER_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_DTMF_PARAMETER_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+
+      Info = dtmf_parameter_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_SAVE_VOICE_1;
+    Rc = OK;
+  case ADJUST_B_SAVE_VOICE_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SAVE)
+    {
+      Info = adv_voice_save_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+    }
+    plci->adjust_b_state = ADJUST_B_SWITCH_L1_1;
+  case ADJUST_B_SWITCH_L1_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_SWITCH_L1)
+    {
+      if (plci->sig_req)
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+      if (plci->adjust_b_parms_msg != NULL)
+        api_load_msg (plci->adjust_b_parms_msg, bp);
+      else
+        api_load_msg (&plci->B_protocol, bp);
+      Info = add_b1 (plci, bp,
+        (word)((plci->adjust_b_mode & ADJUST_B_MODE_NO_RESOURCE) ? 2 : 0),
+        plci->adjust_b_facilities);
+      if (Info != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Adjust B invalid L1 parameters %d %04x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__,
+          plci->B1_resource, plci->adjust_b_facilities));
+        break;
+      }
+      plci->internal_command = plci->adjust_b_command;
+      sig_req (plci, RESOURCES, 0);
+      send_req (plci);
+      plci->adjust_b_state = ADJUST_B_SWITCH_L1_2;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_SWITCH_L1_2;
+    Rc = OK;
+  case ADJUST_B_SWITCH_L1_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B switch failed %02x %d %04x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__,
+        Rc, plci->B1_resource, plci->adjust_b_facilities));
+      Info = _WRONG_STATE;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_VOICE_1;
+    Rc = OK;
+  case ADJUST_B_RESTORE_VOICE_1:
+  case ADJUST_B_RESTORE_VOICE_2:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+      Info = adv_voice_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_PARAMETER_1;
+    Rc = OK;
+  case ADJUST_B_RESTORE_DTMF_PARAMETER_1:
+  case ADJUST_B_RESTORE_DTMF_PARAMETER_2:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+
+      Info = dtmf_parameter_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_EC_1;
+    Rc = OK;
+  case ADJUST_B_RESTORE_EC_1:
+  case ADJUST_B_RESTORE_EC_2:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+
+      Info = ec_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_ASSIGN_L23_1;
+  case ADJUST_B_ASSIGN_L23_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23)
+    {
+      if (plci_nl_busy (plci))
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+      if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
+        plci->call_dir |= CALL_DIR_FORCE_OUTG_NL;
+      if (plci->adjust_b_parms_msg != NULL)
+        api_load_msg (plci->adjust_b_parms_msg, bp);
+      else
+        api_load_msg (&plci->B_protocol, bp);
+      Info = add_b23 (plci, bp);
+      if (Info != GOOD)
+      {
+        dbug (1, dprintf ("[%06lx] %s,%d: Adjust B invalid L23 parameters %04x",
+          UnMapId (Id), (char   *)(FILE_), __LINE__, Info));
+        break;
+      }
+      plci->internal_command = plci->adjust_b_command;
+      nl_req_ncci (plci, ASSIGN, 0);
+      send_req (plci);
+      plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_ASSIGN_L23_2;
+    Rc = ASSIGN_OK;
+  case ADJUST_B_ASSIGN_L23_2:
+    if ((Rc != OK) && (Rc != OK_FC) && (Rc != ASSIGN_OK))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B assign failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci->adjust_b_mode & ADJUST_B_MODE_ASSIGN_L23)
+    {
+      if (Rc != ASSIGN_OK)
+      {
+        plci->internal_command = plci->adjust_b_command;
+        break;
+      }
+    }
+    if (plci->adjust_b_mode & ADJUST_B_MODE_USER_CONNECT)
+    {
+      plci->adjust_b_restore = TRUE;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_CONNECT_1;
+  case ADJUST_B_CONNECT_1:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
+    {
+      plci->internal_command = plci->adjust_b_command;
+      if (plci_nl_busy (plci))
+        break;
+      nl_req_ncci (plci, N_CONNECT, 0);
+      send_req (plci);
+      plci->adjust_b_state = ADJUST_B_CONNECT_2;
+      break;
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
+    Rc = OK;
+  case ADJUST_B_CONNECT_2:
+  case ADJUST_B_CONNECT_3:
+  case ADJUST_B_CONNECT_4:
+    if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B connect failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (Rc == OK)
+    {
+      if (plci->adjust_b_mode & ADJUST_B_MODE_CONNECT)
+      {
+        get_ncci (plci, (byte)(Id >> 16), plci->adjust_b_ncci);
+        Id = (Id & 0xffff) | (((dword)(plci->adjust_b_ncci)) << 16);
+      }
+      if (plci->adjust_b_state == ADJUST_B_CONNECT_2)
+        plci->adjust_b_state = ADJUST_B_CONNECT_3;
+      else if (plci->adjust_b_state == ADJUST_B_CONNECT_4)
+        plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
+    }
+    else if (Rc == 0)
+    {
+      if (plci->adjust_b_state == ADJUST_B_CONNECT_2)
+        plci->adjust_b_state = ADJUST_B_CONNECT_4;
+      else if (plci->adjust_b_state == ADJUST_B_CONNECT_3)
+        plci->adjust_b_state = ADJUST_B_RESTORE_DTMF_1;
+    }
+    if (plci->adjust_b_state != ADJUST_B_RESTORE_DTMF_1)
+    {
+      plci->internal_command = plci->adjust_b_command;
+      break;
+    }
+    Rc = OK;
+  case ADJUST_B_RESTORE_DTMF_1:
+  case ADJUST_B_RESTORE_DTMF_2:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+
+      Info = dtmf_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_RESTORE_MIXER_1;
+    Rc = OK;
+  case ADJUST_B_RESTORE_MIXER_1:
+  case ADJUST_B_RESTORE_MIXER_2:
+  case ADJUST_B_RESTORE_MIXER_3:
+  case ADJUST_B_RESTORE_MIXER_4:
+  case ADJUST_B_RESTORE_MIXER_5:
+  case ADJUST_B_RESTORE_MIXER_6:
+  case ADJUST_B_RESTORE_MIXER_7:
+    if (plci->adjust_b_mode & ADJUST_B_MODE_RESTORE)
+    {
+
+      Info = mixer_restore_config (Id, plci, Rc);
+      if ((Info != GOOD) || plci->internal_command)
+        break;
+
+    }
+    plci->adjust_b_state = ADJUST_B_END;
+  case ADJUST_B_END:
+    break;
+  }
+  return (Info);
+}
+
+
+static void adjust_b1_resource (dword Id, PLCI   *plci, API_SAVE   *bp_msg, word b1_facilities, word internal_command)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b1_resource %d %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__,
+    plci->B1_resource, b1_facilities));
+
+  plci->adjust_b_parms_msg = bp_msg;
+  plci->adjust_b_facilities = b1_facilities;
+  plci->adjust_b_command = internal_command;
+  plci->adjust_b_ncci = (word)(Id >> 16);
+  if ((bp_msg == NULL) && (plci->B1_resource == 0))
+    plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_NO_RESOURCE | ADJUST_B_MODE_SWITCH_L1;
+  else
+    plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_SWITCH_L1 | ADJUST_B_MODE_RESTORE;
+  plci->adjust_b_state = ADJUST_B_START;
+  dbug (1, dprintf ("[%06lx] %s,%d: Adjust B1 resource %d %04x...",
+    UnMapId (Id), (char   *)(FILE_), __LINE__,
+    plci->B1_resource, b1_facilities));
+}
+
+
+static void adjust_b_restore (dword Id, PLCI   *plci, byte Rc)
+{
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: adjust_b_restore %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    if (plci->req_in != 0)
+    {
+      plci->internal_command = ADJUST_B_RESTORE_1;
+      break;
+    }
+    Rc = OK;
+  case ADJUST_B_RESTORE_1:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B enqueued failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+    }
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = ADJUST_B_RESTORE_2;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_RESTORE;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: Adjust B restore...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case ADJUST_B_RESTORE_2:
+    if (adjust_b_process (Id, plci, Rc) != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Adjust B restore failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+    }
+    if (plci->internal_command)
+      break;
+    break;
+  }
+}
+
+
+static void reset_b3_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: reset_b3_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = RESET_B3_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_CONNECT;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: Reset B3...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case RESET_B3_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Reset failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+    break;
+  }
+/*  sendf (plci->appl, _RESET_B3_R | CONFIRM, Id, plci->number, "w", Info);*/
+  sendf(plci->appl,_RESET_B3_I,Id,0,"s","");
+}
+
+
+static void select_b_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+  byte esc_chi[3];
+
+  dbug (1, dprintf ("[%06lx] %s,%d: select_b_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->adjust_b_parms_msg = &plci->saved_msg;
+    if ((plci->tel == ADV_VOICE) && (plci == plci->adapter->AdvSignalPLCI))
+      plci->adjust_b_facilities = plci->B1_facilities | B1_FACILITY_VOICE;
+    else
+      plci->adjust_b_facilities = plci->B1_facilities & ~B1_FACILITY_VOICE;
+    plci->adjust_b_command = SELECT_B_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    if (plci->saved_msg.parms[0].length == 0)
+    {
+      plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 |
+        ADJUST_B_MODE_NO_RESOURCE;
+    }
+    else
+    {
+      plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_SWITCH_L1 |
+        ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE;
+    }
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: Select B protocol...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case SELECT_B_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: Select B protocol failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+    if (plci->tel == ADV_VOICE)
+    {
+      esc_chi[0] = 0x02;
+      esc_chi[1] = 0x18;
+      esc_chi[2] = plci->b_channel;
+      SetVoiceChannel (plci->adapter->AdvCodecPLCI, esc_chi, plci->adapter);
+    }
+    break;
+  }
+  sendf (plci->appl, _SELECT_B_REQ | CONFIRM, Id, plci->number, "w", Info);
+}
+
+
+static void fax_connect_ack_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_ack_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case FAX_CONNECT_ACK_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_CONNECT_ACK_COMMAND_1;
+      return;
+    }
+    plci->internal_command = FAX_CONNECT_ACK_COMMAND_2;
+    plci->NData[0].P = plci->fax_connect_info_buffer;
+    plci->NData[0].PLength = plci->fax_connect_info_length;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_CONNECT_ACK;
+    plci->adapter->request (&plci->NL);
+    return;
+  case FAX_CONNECT_ACK_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX issue CONNECT ACK failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      break;
+    }
+  }
+  if ((plci->ncpi_state & NCPI_VALID_CONNECT_B3_ACT)
+   && !(plci->ncpi_state & NCPI_CONNECT_B3_ACT_SENT))
+  {
+    if (plci->B3_prot == 4)
+      sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
+    else
+      sendf(plci->appl,_CONNECT_B3_ACTIVE_I,Id,0,"S",plci->ncpi_buffer);
+    plci->ncpi_state |= NCPI_CONNECT_B3_ACT_SENT;
+  }
+}
+
+
+static void fax_edata_ack_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_edata_ack_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case FAX_EDATA_ACK_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_EDATA_ACK_COMMAND_1;
+      return;
+    }
+    plci->internal_command = FAX_EDATA_ACK_COMMAND_2;
+    plci->NData[0].P = plci->fax_connect_info_buffer;
+    plci->NData[0].PLength = plci->fax_edata_ack_length;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_EDATA;
+    plci->adapter->request (&plci->NL);
+    return;
+  case FAX_EDATA_ACK_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX issue EDATA ACK failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      break;
+    }
+  }
+}
+
+
+static void fax_connect_info_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_info_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case FAX_CONNECT_INFO_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_CONNECT_INFO_COMMAND_1;
+      return;
+    }
+    plci->internal_command = FAX_CONNECT_INFO_COMMAND_2;
+    plci->NData[0].P = plci->fax_connect_info_buffer;
+    plci->NData[0].PLength = plci->fax_connect_info_length;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_EDATA;
+    plci->adapter->request (&plci->NL);
+    return;
+  case FAX_CONNECT_INFO_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX setting connect info failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_CONNECT_INFO_COMMAND_2;
+      return;
+    }
+    plci->command = _CONNECT_B3_R;
+    nl_req_ncci (plci, N_CONNECT, 0);
+    send_req (plci);
+    return;
+  }
+  sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
+}
+
+
+static void fax_adjust_b23_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_adjust_b23_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = FAX_ADJUST_B23_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_REMOVE_L23 | ADJUST_B_MODE_ASSIGN_L23;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: FAX adjust B23...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case FAX_ADJUST_B23_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX adjust failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+  case FAX_ADJUST_B23_COMMAND_2:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = FAX_ADJUST_B23_COMMAND_2;
+      return;
+    }
+    plci->command = _CONNECT_B3_R;
+    nl_req_ncci (plci, N_CONNECT, 0);
+    send_req (plci);
+    return;
+  }
+  sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
+}
+
+
+static void fax_disconnect_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: fax_disconnect_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->internal_command = FAX_DISCONNECT_COMMAND_1;
+    return;
+  case FAX_DISCONNECT_COMMAND_1:
+  case FAX_DISCONNECT_COMMAND_2:
+  case FAX_DISCONNECT_COMMAND_3:
+    if ((Rc != OK) && (Rc != OK_FC) && (Rc != 0))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: FAX disconnect EDATA failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      break;
+    }
+    if (Rc == OK)
+    {
+      if ((internal_command == FAX_DISCONNECT_COMMAND_1)
+       || (internal_command == FAX_DISCONNECT_COMMAND_2))
+      {
+        plci->internal_command = FAX_DISCONNECT_COMMAND_2;
+      }
+    }
+    else if (Rc == 0)
+    {
+      if (internal_command == FAX_DISCONNECT_COMMAND_1)
+        plci->internal_command = FAX_DISCONNECT_COMMAND_3;
+    }
+    return;
+  }
+}
+
+
+
+static void rtp_connect_b3_req_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_req_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case RTP_CONNECT_B3_REQ_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_1;
+      return;
+    }
+    plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2;
+    nl_req_ncci (plci, N_CONNECT, 0);
+    send_req (plci);
+    return;
+  case RTP_CONNECT_B3_REQ_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect info failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_2;
+      return;
+    }
+    plci->internal_command = RTP_CONNECT_B3_REQ_COMMAND_3;
+    plci->NData[0].PLength = plci->internal_req_buffer[0];
+    plci->NData[0].P = plci->internal_req_buffer + 1;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+    plci->adapter->request (&plci->NL);
+    break;
+  case RTP_CONNECT_B3_REQ_COMMAND_3:
+    return;
+  }
+  sendf (plci->appl, _CONNECT_B3_R | CONFIRM, Id, plci->number, "w", Info);
+}
+
+
+static void rtp_connect_b3_res_command (dword Id, PLCI   *plci, byte Rc)
+{
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_res_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+  case RTP_CONNECT_B3_RES_COMMAND_1:
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_1;
+      return;
+    }
+    plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2;
+    nl_req_ncci (plci, N_CONNECT_ACK, (byte)(Id >> 16));
+    send_req (plci);
+    return;
+  case RTP_CONNECT_B3_RES_COMMAND_2:
+    if ((Rc != OK) && (Rc != OK_FC))
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect resp info failed %02x",
+        UnMapId (Id), (char   *)(FILE_), __LINE__, Rc));
+      Info = _WRONG_STATE;
+      break;
+    }
+    if (plci_nl_busy (plci))
+    {
+      plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_2;
+      return;
+    }
+    sendf (plci->appl, _CONNECT_B3_ACTIVE_I, Id, 0, "s", "");
+    plci->internal_command = RTP_CONNECT_B3_RES_COMMAND_3;
+    plci->NData[0].PLength = plci->internal_req_buffer[0];
+    plci->NData[0].P = plci->internal_req_buffer + 1;
+    plci->NL.X = plci->NData;
+    plci->NL.ReqCh = 0;
+    plci->NL.Req = plci->nl_req = (byte) N_UDATA;
+    plci->adapter->request (&plci->NL);
+    return;
+  case RTP_CONNECT_B3_RES_COMMAND_3:
+    return;
+  }
+}
+
+
+
+static void hold_save_command (dword Id, PLCI   *plci, byte Rc)
+{
+    byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: hold_save_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    if (!plci->NL.Id)
+      break;
+    plci->command = 0;
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = HOLD_SAVE_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_SAVE | ADJUST_B_MODE_REMOVE_L23;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: HOLD save...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case HOLD_SAVE_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: HOLD save failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+  }
+  sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind);
+}
+
+
+static void retrieve_restore_command (dword Id, PLCI   *plci, byte Rc)
+{
+    byte SS_Ind[] = "\x05\x03\x00\x02\x00\x00"; /* Retrieve_Ind struct*/
+  word Info;
+  word internal_command;
+
+  dbug (1, dprintf ("[%06lx] %s,%d: retrieve_restore_command %02x %04x",
+    UnMapId (Id), (char   *)(FILE_), __LINE__, Rc, plci->internal_command));
+
+  Info = GOOD;
+  internal_command = plci->internal_command;
+  plci->internal_command = 0;
+  switch (internal_command)
+  {
+  default:
+    plci->command = 0;
+    plci->adjust_b_parms_msg = NULL;
+    plci->adjust_b_facilities = plci->B1_facilities;
+    plci->adjust_b_command = RETRIEVE_RESTORE_COMMAND_1;
+    plci->adjust_b_ncci = (word)(Id >> 16);
+    plci->adjust_b_mode = ADJUST_B_MODE_ASSIGN_L23 | ADJUST_B_MODE_USER_CONNECT | ADJUST_B_MODE_RESTORE;
+    plci->adjust_b_state = ADJUST_B_START;
+    dbug (1, dprintf ("[%06lx] %s,%d: RETRIEVE restore...",
+      UnMapId (Id), (char   *)(FILE_), __LINE__));
+  case RETRIEVE_RESTORE_COMMAND_1:
+    Info = adjust_b_process (Id, plci, Rc);
+    if (Info != GOOD)
+    {
+      dbug (1, dprintf ("[%06lx] %s,%d: RETRIEVE restore failed",
+        UnMapId (Id), (char   *)(FILE_), __LINE__));
+      break;
+    }
+    if (plci->internal_command)
+      return;
+  }
+  sendf (plci->appl, _FACILITY_I, Id & 0xffffL, 0, "ws", 3, SS_Ind);
+}
+
+
+static void init_b1_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: init_b1_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  plci->B1_resource = 0;
+  plci->B1_facilities = 0;
+
+  plci->li_bchannel_id = 0;
+  mixer_clear_config (plci);
+
+
+  ec_clear_config (plci);
+
+
+  dtmf_rec_clear_config (plci);
+  dtmf_send_clear_config (plci);
+  dtmf_parameter_clear_config (plci);
+
+  adv_voice_clear_config (plci);
+  adjust_b_clear (plci);
+}
+
+
+static void clear_b1_config (PLCI   *plci)
+{
+
+  dbug (1, dprintf ("[%06lx] %s,%d: clear_b1_config",
+    (dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
+    (char   *)(FILE_), __LINE__));
+
+  adv_voice_clear_config (plci);
+  adjust_b_clear (plci);
+
+  ec_clear_config (plci);
+
+
+  dtmf_rec_clear_config (plci);
+  dtmf_send_clear_config (plci);
+  dtmf_parameter_clear_config (plci);
+
+
+  if ((plci->li_bchannel_id != 0)
+   && (li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci == plci))
+  {
+    mixer_clear_config (plci);
+    li_config_table[plci->adapter->li_base + (plci->li_bchannel_id - 1)].plci = NULL;
+    plci->li_bchannel_id = 0;
+  }
+
+  plci->B1_resource = 0;
+  plci->B1_facilities = 0;
+}
+
+
+/* -----------------------------------------------------------------
+                XON protocol local helpers
+   ----------------------------------------------------------------- */
+static void channel_flow_control_remove (PLCI   * plci) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+  word i;
+  for(i=1;i<MAX_NL_CHANNEL+1;i++) {
+    if (a->ch_flow_plci[i] == plci->Id) {
+      a->ch_flow_plci[i] = 0;
+      a->ch_flow_control[i] = 0;
+    }
+  }
+}
+
+static void channel_x_on (PLCI   * plci, byte ch) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+  if (a->ch_flow_control[ch] & N_XON_SENT) {
+    a->ch_flow_control[ch] &= ~N_XON_SENT;
+  }
+}
+
+static void channel_x_off (PLCI   * plci, byte ch, byte flag) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+  if ((a->ch_flow_control[ch] & N_RX_FLOW_CONTROL_MASK) == 0) {
+    a->ch_flow_control[ch] |= (N_CH_XOFF | flag);
+    a->ch_flow_plci[ch] = plci->Id;
+    a->ch_flow_control_pending++;
+  }
+}
+
+static void channel_request_xon (PLCI   * plci, byte ch) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+
+  if (a->ch_flow_control[ch] & N_CH_XOFF) {
+    a->ch_flow_control[ch] |= N_XON_REQ;
+    a->ch_flow_control[ch] &= ~N_CH_XOFF;
+    a->ch_flow_control[ch] &= ~N_XON_CONNECT_IND;
+  }
+}
+
+static void channel_xmit_extended_xon (PLCI   * plci) {
+  DIVA_CAPI_ADAPTER   * a;
+  int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]);
+  int i, one_requested = 0;
+
+  if ((!plci) || (!plci->Id) || ((a = plci->adapter) == 0)) {
+    return;
+  }
+
+  for (i = 0; i < max_ch; i++) {
+    if ((a->ch_flow_control[i] & N_CH_XOFF) &&
+        (a->ch_flow_control[i] & N_XON_CONNECT_IND) &&
+        (plci->Id == a->ch_flow_plci[i])) {
+      channel_request_xon (plci, (byte)i);
+      one_requested = 1;
+    }
+  }
+
+  if (one_requested) {
+    channel_xmit_xon (plci);
+  }
+}
+
+/*
+  Try to xmit next X_ON
+  */
+static int find_channel_with_pending_x_on (DIVA_CAPI_ADAPTER   * a, PLCI   * plci) {
+  int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]);
+  int i;
+
+  if (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)) {
+    return (0);
+  }
+
+  if (a->last_flow_control_ch >= max_ch) {
+    a->last_flow_control_ch = 1;
+  }
+  for (i=a->last_flow_control_ch; i < max_ch; i++) {
+    if ((a->ch_flow_control[i] & N_XON_REQ) &&
+        (plci->Id == a->ch_flow_plci[i])) {
+      a->last_flow_control_ch = i+1;
+      return (i);
+    }
+  }
+
+  for (i = 1; i < a->last_flow_control_ch; i++) {
+    if ((a->ch_flow_control[i] & N_XON_REQ) &&
+        (plci->Id == a->ch_flow_plci[i])) {
+      a->last_flow_control_ch = i+1;
+      return (i);
+    }
+  }
+
+  return (0);
+}
+
+static void channel_xmit_xon (PLCI   * plci) {
+  DIVA_CAPI_ADAPTER   * a = plci->adapter;
+  byte ch;
+
+  if (plci->nl_req || !plci->NL.Id || plci->nl_remove_id) {
+    return;
+  }
+  if ((ch = (byte)find_channel_with_pending_x_on (a, plci)) == 0) {
+    return;
+  }
+  a->ch_flow_control[ch] &= ~N_XON_REQ;
+  a->ch_flow_control[ch] |= N_XON_SENT;
+
+  plci->NL.Req = plci->nl_req = (byte)N_XON;
+  plci->NL.ReqCh         = ch;
+  plci->NL.X             = plci->NData;
+  plci->NL.XNum          = 1;
+  plci->NData[0].P       = &plci->RBuffer[0];
+  plci->NData[0].PLength = 0;
+
+  plci->adapter->request(&plci->NL);
+}
+
+static int channel_can_xon (PLCI   * plci, byte ch) {
+  APPL   * APPLptr;
+  DIVA_CAPI_ADAPTER   * a;
+  word NCCIcode;
+  dword count;
+  word Num;
+  word i;
+
+  APPLptr = plci->appl;
+  a = plci->adapter;
+
+  if (!APPLptr)
+    return (0);
+
+  NCCIcode = a->ch_ncci[ch] | (((word) a->Id) << 8);
+
+                /* count all buffers within the Application pool    */
+                /* belonging to the same NCCI. XON if a first is    */
+                /* used.                                            */
+  count = 0;
+  Num = 0xffff;
+  for(i=0; i<APPLptr->MaxBuffer; i++) {
+    if(NCCIcode==APPLptr->DataNCCI[i]) count++;
+    if(!APPLptr->DataNCCI[i] && Num==0xffff) Num = i;
+  }
+  if ((count > 2) || (Num == 0xffff)) {
+    return (0);
+  }
+  return (1);
+}
+
+
+/*------------------------------------------------------------------*/
+
+static word CPN_filter_ok(byte   *cpn,DIVA_CAPI_ADAPTER   * a,word offset)
+{
+  return 1;
+}
+
+
+
+/**********************************************************************************/
+/* function groups the listening applications according to the CIP mask and the   */
+/* Info_Mask. Each group gets just one Connect_Ind. Some application manufacturer */
+/* are not multi-instance capable, so they start e.g. 30 applications what causes */
+/* big problems on application level (one call, 30 Connect_Ind, ect). The         */
+/* function must be enabled by setting "a->group_optimization_enabled" from the   */
+/* OS specific part (per adapter).                                                */
+/**********************************************************************************/
+static void group_optimization(DIVA_CAPI_ADAPTER   * a, PLCI   * plci)
+{
+  word i,j,k,busy,group_found;
+  dword info_mask_group[MAX_CIP_TYPES];
+  dword cip_mask_group[MAX_CIP_TYPES];
+  word appl_number_group_type[MAX_APPL];
+  PLCI   *auxplci;
+
+  set_group_ind_mask (plci); /* all APPLs within this inc. call are allowed to dial in */
+
+  if(!a->group_optimization_enabled)
+  {
+    dbug(1,dprintf("No group optimization"));
+    return;
+  }
+
+  dbug(1,dprintf("Group optimization = 0x%x...", a->group_optimization_enabled));
+
+  for(i=0;i<MAX_CIP_TYPES;i++)
+  {
+    info_mask_group[i] = 0;
+    cip_mask_group [i] = 0;
+  }
+  for(i=0;i<MAX_APPL;i++)
+  {
+    appl_number_group_type[i] = 0;
+  }
+  for(i=0; i<max_appl; i++) /* check if any multi instance capable application is present */
+  {  /* group_optimization set to 1 means not to optimize multi-instance capable applications (default) */
+    if(application[i].Id && (application[i].MaxNCCI) > 1 && (a->CIP_Mask[i])  && (a->group_optimization_enabled ==1) )
+    {
+      dbug(1,dprintf("Multi-Instance capable, no optimization required"));
+      return; /* allow good application unfiltered access */
+    }
+  }
+  for(i=0; i<max_appl; i++) /* Build CIP Groups */
+  {
+    if(application[i].Id && a->CIP_Mask[i] )
+    {
+      for(k=0,busy=FALSE; k<a->max_plci; k++)
+      {
+        if(a->plci[k].Id) 
+        {
+          auxplci = &a->plci[k];
+          if(auxplci->appl == &application[i]) /* application has a busy PLCI */
+          {
+            busy = TRUE;
+            dbug(1,dprintf("Appl 0x%x is busy",i+1));
+          }
+          else if(test_c_ind_mask_bit (auxplci, i)) /* application has an incoming call pending */
+          {
+            busy = TRUE;
+            dbug(1,dprintf("Appl 0x%x has inc. call pending",i+1));
+          }
+        }
+      }
+
+      for(j=0,group_found=0; j<=(MAX_CIP_TYPES) && !busy &&!group_found; j++)     /* build groups with free applications only */
+      {
+        if(j==MAX_CIP_TYPES)       /* all groups are in use but group still not found */
+        {                           /* the MAX_CIP_TYPES group enables all calls because of field overflow */
+          appl_number_group_type[i] = MAX_CIP_TYPES;
+          group_found=TRUE;
+          dbug(1,dprintf("Field overflow appl 0x%x",i+1));
+        }
+        else if( (info_mask_group[j]==a->CIP_Mask[i]) && (cip_mask_group[j]==a->Info_Mask[i]) )  
+        {                                      /* is group already present ?                  */
+          appl_number_group_type[i] = j|0x80;  /* store the group number for each application */
+          group_found=TRUE;
+          dbug(1,dprintf("Group 0x%x found with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j]));
+        }
+        else if(!info_mask_group[j])
+        {                                      /* establish a new group                       */
+          appl_number_group_type[i] = j|0x80;  /* store the group number for each application */
+          info_mask_group[j] = a->CIP_Mask[i]; /* store the new CIP mask for the new group    */
+          cip_mask_group[j] = a->Info_Mask[i]; /* store the new Info_Mask for this new group  */
+          group_found=TRUE;
+          dbug(1,dprintf("New Group 0x%x established with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j]));
+        }
+      }
+    }
+  }
+        
+  for(i=0; i<max_appl; i++) /* Build group_optimization_mask_table */
+  {
+    if(appl_number_group_type[i]) /* application is free, has listens and is member of a group */
+    {
+      if(appl_number_group_type[i] == MAX_CIP_TYPES)
+      {
+        dbug(1,dprintf("OverflowGroup 0x%x, valid appl = 0x%x, call enabled",appl_number_group_type[i],i+1));
+      }
+      else
+      {
+        dbug(1,dprintf("Group 0x%x, valid appl = 0x%x",appl_number_group_type[i],i+1));
+        for(j=i+1; j<max_appl; j++)   /* search other group members and mark them as busy        */
+        {
+          if(appl_number_group_type[i] == appl_number_group_type[j]) 
+          {
+            dbug(1,dprintf("Appl 0x%x is member of group 0x%x, no call",j+1,appl_number_group_type[j]));
+            clear_group_ind_mask_bit (plci, j);           /* disable call on other group members */
+            appl_number_group_type[j] = 0;       /* remove disabled group member from group list */
+          }
+        }
+      }
+    }
+    else                                                 /* application should not get a call */
+    {
+      clear_group_ind_mask_bit (plci, i);
+    }
+  }
+
+}
+
+
+
+/* OS notifies the driver about a application Capi_Register */
+word CapiRegister(word id)
+{
+  word i,j,appls_found;
+
+  PLCI   *plci;
+  DIVA_CAPI_ADAPTER   *a;
+
+  for(i=0,appls_found=0; i<max_appl; i++)
+  {
+    if( application[i].Id && (application[i].Id!=id) )
+    {
+      appls_found++;                       /* an application has been found */
+    }
+  }
+
+  if(appls_found) return TRUE;
+  for(i=0; i<max_adapter; i++)                   /* scan all adapters...    */
+  {
+    a = &adapter[i];
+    if(a->request)
+    {
+      if(a->flag_dynamic_l1_down)  /* remove adapter from L1 tristate (Huntgroup) */
+      {
+        if(!appls_found)           /* first application does a capi register   */
+        {
+          if((j=get_plci(a)))                    /* activate L1 of all adapters */
+          {
+            plci = &a->plci[j-1];
+            plci->command = 0;
+            add_p(plci,OAD,"\x01\xfd");
+            add_p(plci,CAI,"\x01\x80");
+            add_p(plci,UID,"\x06\x43\x61\x70\x69\x32\x30");
+            add_p(plci,SHIFT|6,NULL);
+            add_p(plci,SIN,"\x02\x00\x00");
+            plci->internal_command = START_L1_SIG_ASSIGN_PEND;
+            sig_req(plci,ASSIGN,DSIG_ID);
+            add_p(plci,FTY,"\x02\xff\x07"); /* l1 start */
+            sig_req(plci,SIG_CTRL,0);
+            send_req(plci);
+          }
+        }
+      }
+    }
+  }
+  return FALSE;
+}
+
+/*------------------------------------------------------------------*/
+
+/* Functions for virtual Switching e.g. Transfer by join, Conference */
+
+static void VSwitchReqInd(PLCI   *plci, dword Id, byte   **parms)
+{
+ word i;
+ /* Format of vswitch_t:
+ 0 byte length
+ 1 byte VSWITCHIE
+ 2 byte VSWITCH_REQ/VSWITCH_IND
+ 3 byte reserved
+ 4 word VSwitchcommand
+ 6 word returnerror
+ 8... Params
+ */
+ if(!plci ||
+  !plci->appl ||
+  !plci->State ||
+  plci->Sig.Ind==NCR_FACILITY
+  )
+  return;
+ 
+ for(i=0;i<MAX_MULTI_IE;i++)
+ {
+        if(!parms[i][0]) continue;
+  if(parms[i][0]<7)
+  {
+   parms[i][0]=0; /* kill it */
+   continue;
+  }
+  dbug(1,dprintf("VSwitchReqInd(%d)",parms[i][4]));
+  switch(parms[i][4])
+  {
+  case VSJOIN:
+   if(!plci->relatedPTYPLCI ||
+    (plci->ptyState!=S_ECT && plci->relatedPTYPLCI->ptyState!=S_ECT))
+   { /* Error */
+    break;
+   }
+   /* remember all necessary informations */
+   if(parms[i][0]!=11 || parms[i][8]!=3) /* Length Test */
+   {
+    break;
+   }
+   if(parms[i][2]==VSWITCH_IND && parms[i][9]==1)
+   {   /* first indication after ECT-Request on Consultation Call */
+    plci->vswitchstate=parms[i][9];
+    parms[i][9]=2; /* State */
+    /* now ask first Call to join */
+   }
+   else if(parms[i][2]==VSWITCH_REQ && parms[i][9]==3)
+   { /* Answer of VSWITCH_REQ from first Call */
+    plci->vswitchstate=parms[i][9];
+    /* tell consultation call to join
+    and the protocol capabilities of the first call */
+   }
+   else
+   { /* Error */
+    break;
+   }    
+   plci->vsprot=parms[i][10]; /* protocol */
+   plci->vsprotdialect=parms[i][11]; /* protocoldialect */
+   /* send join request to related PLCI */
+   parms[i][1]=VSWITCHIE;
+   parms[i][2]=VSWITCH_REQ;
+   
+   plci->relatedPTYPLCI->command = 0;
+   plci->relatedPTYPLCI->internal_command = VSWITCH_REQ_PEND;
+   add_p(plci->relatedPTYPLCI,ESC,&parms[i][0]);
+   sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
+   send_req(plci->relatedPTYPLCI);
+   break;
+  case VSTRANSPORT:
+  default:
+   if(plci->relatedPTYPLCI &&
+    plci->vswitchstate==3 &&
+    plci->relatedPTYPLCI->vswitchstate==3)
+   {
+    add_p(plci->relatedPTYPLCI,ESC,&parms[i][0]);
+    sig_req(plci->relatedPTYPLCI,VSWITCH_REQ,0);
+    send_req(plci->relatedPTYPLCI);
+   }
+   break;
+  }  
+  parms[i][0]=0; /* kill it */
+ }
+}
+
+
+/*------------------------------------------------------------------*/
+
+static int diva_get_dma_descriptor (PLCI   *plci, dword   *dma_magic) {
+  ENTITY e;
+  IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
+
+  if (!(diva_xdi_extended_features & DIVA_CAPI_XDI_PROVIDES_RX_DMA)) {
+    return (-1);
+  }
+
+  pReq->xdi_dma_descriptor_operation.Req = 0;
+  pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
+
+  pReq->xdi_dma_descriptor_operation.info.operation =     IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_number  = -1;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
+
+  e.user[0] = plci->adapter->Id - 1;
+  plci->adapter->request((ENTITY*)pReq);
+
+  if (!pReq->xdi_dma_descriptor_operation.info.operation &&
+      (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) &&
+      pReq->xdi_dma_descriptor_operation.info.descriptor_magic) {
+    *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic;
+    dbug(3,dprintf("dma_alloc, a:%d (%d-%08x)",
+         plci->adapter->Id,
+         pReq->xdi_dma_descriptor_operation.info.descriptor_number,
+         *dma_magic));
+    return (pReq->xdi_dma_descriptor_operation.info.descriptor_number);
+  } else {
+    dbug(1,dprintf("dma_alloc failed"));
+    return (-1);
+  }
+}
+
+static void diva_free_dma_descriptor (PLCI   *plci, int nr) {
+  ENTITY e;
+  IDI_SYNC_REQ* pReq = (IDI_SYNC_REQ*)&e;
+
+  if (nr < 0) {
+    return;
+  }
+
+  pReq->xdi_dma_descriptor_operation.Req = 0;
+  pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
+
+  pReq->xdi_dma_descriptor_operation.info.operation =                                                IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_number  = nr;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
+  pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
+
+  e.user[0] = plci->adapter->Id - 1;
+  plci->adapter->request((ENTITY*)pReq);
+
+  if (!pReq->xdi_dma_descriptor_operation.info.operation) {
+    dbug(1,dprintf("dma_free(%d)", nr));
+  } else {
+    dbug(1,dprintf("dma_free failed (%d)", nr));
+  }
+}
+
+/*------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/mi_pc.h b/drivers/isdn/hardware/eicon/mi_pc.h
new file mode 100644
index 0000000..a861dac
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/mi_pc.h
@@ -0,0 +1,204 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+/*----------------------------------------------------------------------------
+// MAESTRA ISA PnP */
+#define BRI_MEMORY_BASE                 0x1f700000
+#define BRI_MEMORY_SIZE                 0x00100000  /* 1MB on the BRI                         */
+#define BRI_SHARED_RAM_SIZE             0x00010000  /* 64k shared RAM                         */
+#define BRI_RAY_TAYLOR_DSP_CODE_SIZE    0x00020000  /* max 128k DSP-Code (Ray Taylor's code)  */
+#define BRI_ORG_MAX_DSP_CODE_SIZE       0x00050000  /* max 320k DSP-Code (Telindus)           */
+#define BRI_V90D_MAX_DSP_CODE_SIZE      0x00060000  /* max 384k DSP-Code if V.90D included    */
+#define BRI_CACHED_ADDR(x)              (((x) & 0x1fffffffL) | 0x80000000L)
+#define BRI_UNCACHED_ADDR(x)            (((x) & 0x1fffffffL) | 0xa0000000L)
+#define ADDR  4
+#define ADDRH 6
+#define DATA  0
+#define RESET 7
+#define DEFAULT_ADDRESS 0x240
+#define DEFAULT_IRQ     3
+#define M_PCI_ADDR   0x04  /* MAESTRA BRI PCI */
+#define M_PCI_ADDRH  0x0c  /* MAESTRA BRI PCI */
+#define M_PCI_DATA   0x00  /* MAESTRA BRI PCI */
+#define M_PCI_RESET  0x10  /* MAESTRA BRI PCI */
+/*----------------------------------------------------------------------------
+// MAESTRA PRI PCI */
+#define MP_IRQ_RESET                    0xc18       /* offset of isr in the CONFIG memory bar */
+#define MP_IRQ_RESET_VAL                0xfe        /* value to clear an interrupt            */
+#define MP_MEMORY_SIZE                  0x00400000  /* 4MB on standard PRI                    */
+#define MP2_MEMORY_SIZE                 0x00800000  /* 8MB on PRI Rev. 2                      */
+#define MP_SHARED_RAM_OFFSET            0x00001000  /* offset of shared RAM base in the DRAM memory bar */
+#define MP_SHARED_RAM_SIZE              0x00010000  /* 64k shared RAM                         */
+#define MP_PROTOCOL_OFFSET              (MP_SHARED_RAM_OFFSET + MP_SHARED_RAM_SIZE)
+#define MP_RAY_TAYLOR_DSP_CODE_SIZE     0x00040000  /* max 256k DSP-Code (Ray Taylor's code)  */
+#define MP_ORG_MAX_DSP_CODE_SIZE        0x00060000  /* max 384k DSP-Code (Telindus)           */
+#define MP_V90D_MAX_DSP_CODE_SIZE       0x00070000  /* max 448k DSP-Code if V.90D included)   */
+#define MP_VOIP_MAX_DSP_CODE_SIZE       0x00090000  /* max 576k DSP-Code if voice over IP included */
+#define MP_CACHED_ADDR(x)               (((x) & 0x1fffffffL) | 0x80000000L)
+#define MP_UNCACHED_ADDR(x)             (((x) & 0x1fffffffL) | 0xa0000000L)
+#define MP_RESET         0x20        /* offset of RESET register in the DEVICES memory bar */
+/* RESET register bits */
+#define _MP_S2M_RESET    0x10        /* active lo   */
+#define _MP_LED2         0x08        /* 1 = on      */
+#define _MP_LED1         0x04        /* 1 = on      */
+#define _MP_DSP_RESET    0x02        /* active lo   */
+#define _MP_RISC_RESET   0x81        /* active hi, bit 7 for compatibility with old boards */
+/* CPU exception context structure in MP shared ram after trap */
+typedef struct mp_xcptcontext_s MP_XCPTC;
+struct mp_xcptcontext_s {
+    dword       sr;
+    dword       cr;
+    dword       epc;
+    dword       vaddr;
+    dword       regs[32];
+    dword       mdlo;
+    dword       mdhi;
+    dword       reseverd;
+    dword       xclass;
+};
+/* boot interface structure for PRI */
+struct mp_load {
+  dword     volatile cmd;
+  dword     volatile addr;
+  dword     volatile len;
+  dword     volatile err;
+  dword     volatile live;
+  dword     volatile res1[0x1b];
+  dword     volatile TrapId;    /* has value 0x999999XX on a CPU trap */
+  dword     volatile res2[0x03];
+  MP_XCPTC  volatile xcpt;      /* contains register dump */
+  dword     volatile rest[((0x1020>>2)-6) - 0x1b - 1 - 0x03 - (sizeof(MP_XCPTC)>>2)];
+  dword     volatile signature;
+  dword data[60000]; /* real interface description */
+};
+/*----------------------------------------------------------------------------*/
+/* SERVER 4BRI (Quattro PCI)                                                  */
+#define MQ_BOARD_REG_OFFSET             0x800000    /* PC relative On board registers offset  */
+#define MQ_BREG_RISC                    0x1200      /* RISC Reset ect                         */
+#define MQ_RISC_COLD_RESET_MASK         0x0001      /* RISC Cold reset                        */
+#define MQ_RISC_WARM_RESET_MASK         0x0002      /* RISC Warm reset                        */
+#define MQ_BREG_IRQ_TEST                0x0608      /* Interrupt request, no CPU interaction  */
+#define MQ_IRQ_REQ_ON                   0x1
+#define MQ_IRQ_REQ_OFF                  0x0
+#define MQ_BOARD_DSP_OFFSET             0xa00000    /* PC relative On board DSP regs offset   */
+#define MQ_DSP1_ADDR_OFFSET             0x0008      /* Addr register offset DSP 1 subboard 1  */
+#define MQ_DSP2_ADDR_OFFSET             0x0208      /* Addr register offset DSP 2 subboard 1  */
+#define MQ_DSP1_DATA_OFFSET             0x0000      /* Data register offset DSP 1 subboard 1  */
+#define MQ_DSP2_DATA_OFFSET             0x0200      /* Data register offset DSP 2 subboard 1  */
+#define MQ_DSP_JUNK_OFFSET              0x0400      /* DSP Data/Addr regs subboard offset     */
+#define MQ_ISAC_DSP_RESET               0x0028      /* ISAC and DSP reset address offset      */
+#define MQ_BOARD_ISAC_DSP_RESET         0x800028    /* ISAC and DSP reset address offset      */
+#define MQ_INSTANCE_COUNT               4           /* 4BRI consists of four instances        */
+#define MQ_MEMORY_SIZE                  0x00400000  /* 4MB on standard 4BRI                   */
+#define MQ_CTRL_SIZE                    0x00002000  /* 8K memory mapped registers             */
+#define MQ_SHARED_RAM_SIZE              0x00010000  /* 64k shared RAM                         */
+#define MQ_ORG_MAX_DSP_CODE_SIZE        0x00050000  /* max 320k DSP-Code (Telindus) */
+#define MQ_V90D_MAX_DSP_CODE_SIZE       0x00060000  /* max 384K DSP-Code if V.90D included */
+#define MQ_VOIP_MAX_DSP_CODE_SIZE       0x00028000  /* max 4*160k = 640K DSP-Code if voice over IP included */
+#define MQ_CACHED_ADDR(x)               (((x) & 0x1fffffffL) | 0x80000000L)
+#define MQ_UNCACHED_ADDR(x)             (((x) & 0x1fffffffL) | 0xa0000000L)
+/*--------------------------------------------------------------------------------------------*/
+/* Additional definitions reflecting the different address map of the  SERVER 4BRI V2          */
+#define MQ2_BREG_RISC                   0x0200      /* RISC Reset ect                         */
+#define MQ2_BREG_IRQ_TEST               0x0400      /* Interrupt request, no CPU interaction  */
+#define MQ2_BOARD_DSP_OFFSET            0x800000    /* PC relative On board DSP regs offset   */
+#define MQ2_DSP1_DATA_OFFSET            0x1800      /* Data register offset DSP 1 subboard 1  */
+#define MQ2_DSP1_ADDR_OFFSET            0x1808      /* Addr register offset DSP 1 subboard 1  */
+#define MQ2_DSP2_DATA_OFFSET            0x1810      /* Data register offset DSP 2 subboard 1  */
+#define MQ2_DSP2_ADDR_OFFSET            0x1818      /* Addr register offset DSP 2 subboard 1  */
+#define MQ2_DSP_JUNK_OFFSET             0x1000      /* DSP Data/Addr regs subboard offset     */
+#define MQ2_ISAC_DSP_RESET              0x0000      /* ISAC and DSP reset address offset      */
+#define MQ2_BOARD_ISAC_DSP_RESET        0x800000    /* ISAC and DSP reset address offset      */
+#define MQ2_IPACX_CONFIG                0x0300      /* IPACX Configuration TE(0)/NT(1)        */
+#define MQ2_BOARD_IPACX_CONFIG          0x800300    /*     ""                                 */
+#define MQ2_MEMORY_SIZE                 0x01000000  /* 16MB code/data memory                  */
+#define MQ2_CTRL_SIZE                   0x00008000  /* 32K memory mapped registers            */
+/*----------------------------------------------------------------------------*/
+/* SERVER BRI 2M/2F as derived from 4BRI V2                                   */
+#define BRI2_MEMORY_SIZE                0x00800000  /* 8MB code/data memory                   */
+#define BRI2_PROTOCOL_MEMORY_SIZE       (MQ2_MEMORY_SIZE >> 2) /*  same as one 4BRI Rev.2 task */
+#define BRI2_CTRL_SIZE                  0x00008000  /* 32K memory mapped registers            */
+#define M_INSTANCE_COUNT                1           /*  BRI consists of one instance          */
+/*
+ * Some useful constants for proper initialization of the GT6401x
+ */
+#define ID_REG        0x0000      /*Pci reg-contain the Dev&Ven ID of the card*/
+#define RAS0_BASEREG  0x0010      /*Ras0 register - contain the base addr Ras0*/
+#define RAS2_BASEREG  0x0014
+#define CS_BASEREG    0x0018
+#define BOOT_BASEREG  0x001c
+#define GTREGS_BASEREG 0x0024   /*GTRegsBase reg-contain the base addr where*/
+                                /*the GT64010 internal regs where mapped    */
+/*
+ *  GT64010 internal registers
+ */
+        /* DRAM device coding  */
+#define LOW_RAS0_DREG 0x0400    /*Ras0 low decode address*/
+#define HI_RAS0_DREG  0x0404    /*Ras0 high decode address*/
+#define LOW_RAS1_DREG 0x0408    /*Ras1 low decode address*/
+#define HI_RAS1_DREG  0x040c    /*Ras1 high decode address*/
+#define LOW_RAS2_DREG 0x0410    /*Ras2 low decode address*/
+#define HI_RAS2_DREG  0x0414    /*Ras2 high decode address*/
+#define LOW_RAS3_DREG 0x0418    /*Ras3 low decode address*/
+#define HI_RAS3_DREG  0x041c    /*Ras3 high decode address*/
+        /* I/O CS device coding  */
+#define LOW_CS0_DREG  0x0420 /* CS0* low decode register */
+#define HI_CS0_DREG   0x0424 /* CS0* high decode register */
+#define LOW_CS1_DREG  0x0428 /* CS1* low decode register */
+#define HI_CS1_DREG   0x042c /* CS1* high decode register */
+#define LOW_CS2_DREG  0x0430 /* CS2* low decode register */
+#define HI_CS2_DREG   0x0434 /* CS2* high decode register */
+#define LOW_CS3_DREG  0x0438 /* CS3* low decode register */
+#define HI_CS3_DREG   0x043c /* CS3* high decode register */
+        /* Boot PROM device coding */
+#define LOW_BOOTCS_DREG 0x0440 /* Boot CS low decode register */
+#define HI_BOOTCS_DREG 0x0444 /* Boot CS High decode register */
+        /* DRAM group coding (for CPU)  */
+#define LO_RAS10_GREG 0x0008    /*Ras1..0 group low decode address*/
+#define HI_RAS10_GREG 0x0010    /*Ras1..0 group high decode address*/
+#define LO_RAS32_GREG 0x0018    /*Ras3..2 group low decode address  */
+#define HI_RAS32_GREG 0x0020    /*Ras3..2 group high decode address  */
+        /* I/O CS group coding for (CPU)  */
+#define LO_CS20_GREG  0x0028 /* CS2..0 group low decode register */
+#define HI_CS20_GREG  0x0030 /* CS2..0 group high decode register */
+#define LO_CS3B_GREG  0x0038 /* CS3 & PROM group low decode register */
+#define HI_CS3B_GREG  0x0040 /* CS3 & PROM group high decode register */
+        /* Galileo specific PCI config. */
+#define PCI_TIMEOUT_RET 0x0c04 /* Time Out and retry register */
+#define RAS10_BANKSIZE 0x0c08 /* RAS 1..0 group PCI bank size */
+#define RAS32_BANKSIZE 0x0c0c /* RAS 3..2 group PCI bank size */
+#define CS20_BANKSIZE 0x0c10 /* CS 2..0 group PCI bank size */
+#define CS3B_BANKSIZE 0x0c14 /* CS 3 & Boot group PCI bank size */
+#define DRAM_SIZE     0x0001      /*Dram size in mega bytes*/
+#define PROM_SIZE     0x08000     /*Prom size in bytes*/
+/*--------------------------------------------------------------------------*/
+#define OFFS_DIVA_INIT_TASK_COUNT 0x68
+#define OFFS_DSP_CODE_BASE_ADDR   0x6c
+#define OFFS_XLOG_BUF_ADDR        0x70
+#define OFFS_XLOG_COUNT_ADDR      0x74
+#define OFFS_XLOG_OUT_ADDR        0x78
+#define OFFS_PROTOCOL_END_ADDR    0x7c
+#define OFFS_PROTOCOL_ID_STRING   0x80
+/*--------------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/mntfunc.c b/drivers/isdn/hardware/eicon/mntfunc.c
new file mode 100644
index 0000000..a564b75
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/mntfunc.c
@@ -0,0 +1,370 @@
+/* $Id: mntfunc.c,v 1.19.6.4 2005/01/31 12:22:20 armin Exp $
+ *
+ * Driver for Eicon DIVA Server ISDN cards.
+ * Maint module
+ *
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de)
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+
+#include "platform.h"
+#include "di_defs.h"
+#include "divasync.h"
+#include "debug_if.h"
+
+extern char *DRIVERRELEASE_MNT;
+
+#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
+#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
+
+extern void DIVA_DIDD_Read(void *, int);
+
+static dword notify_handle;
+static DESCRIPTOR DAdapter;
+static DESCRIPTOR MAdapter;
+static DESCRIPTOR MaintDescriptor =
+    { IDI_DIMAINT, 0, 0, (IDI_CALL) diva_maint_prtComp };
+
+extern int diva_os_copy_to_user(void *os_handle, void __user *dst,
+				const void *src, int length);
+extern int diva_os_copy_from_user(void *os_handle, void *dst,
+				  const void __user *src, int length);
+
+static void no_printf(unsigned char *x, ...)
+{
+	/* dummy debug function */
+}
+
+#include "debuglib.c"
+
+/*
+ *  DIDD callback function
+ */
+static void *didd_callback(void *context, DESCRIPTOR * adapter,
+			   int removal)
+{
+	if (adapter->type == IDI_DADAPTER) {
+		DBG_ERR(("cb: Change in DAdapter ? Oops ?."));
+	} else if (adapter->type == IDI_DIMAINT) {
+		if (removal) {
+			DbgDeregister();
+			memset(&MAdapter, 0, sizeof(MAdapter));
+			dprintf = no_printf;
+		} else {
+			memcpy(&MAdapter, adapter, sizeof(MAdapter));
+			dprintf = (DIVA_DI_PRINTF) MAdapter.request;
+			DbgRegister("MAINT", DRIVERRELEASE_MNT, DBG_DEFAULT);
+		}
+	} else if ((adapter->type > 0) && (adapter->type < 16)) {
+		if (removal) {
+			diva_mnt_remove_xdi_adapter(adapter);
+		} else {
+			diva_mnt_add_xdi_adapter(adapter);
+		}
+	}
+	return (NULL);
+}
+
+/*
+ * connect to didd
+ */
+static int DIVA_INIT_FUNCTION connect_didd(void)
+{
+	int x = 0;
+	int dadapter = 0;
+	IDI_SYNC_REQ req;
+	DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
+
+	DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
+
+	for (x = 0; x < MAX_DESCRIPTORS; x++) {
+		if (DIDD_Table[x].type == IDI_DADAPTER) {	/* DADAPTER found */
+			dadapter = 1;
+			memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
+			req.didd_notify.e.Req = 0;
+			req.didd_notify.e.Rc =
+			    IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
+			req.didd_notify.info.callback = (void *)didd_callback;
+			req.didd_notify.info.context = NULL;
+			DAdapter.request((ENTITY *) & req);
+			if (req.didd_notify.e.Rc != 0xff)
+				return (0);
+			notify_handle = req.didd_notify.info.handle;
+			/* Register MAINT (me) */
+			req.didd_add_adapter.e.Req = 0;
+			req.didd_add_adapter.e.Rc =
+			    IDI_SYNC_REQ_DIDD_ADD_ADAPTER;
+			req.didd_add_adapter.info.descriptor =
+			    (void *) &MaintDescriptor;
+			DAdapter.request((ENTITY *) & req);
+			if (req.didd_add_adapter.e.Rc != 0xff)
+				return (0);
+		} else if ((DIDD_Table[x].type > 0)
+			   && (DIDD_Table[x].type < 16)) {
+			diva_mnt_add_xdi_adapter(&DIDD_Table[x]);
+		}
+	}
+	return (dadapter);
+}
+
+/*
+ * disconnect from didd
+ */
+static void DIVA_EXIT_FUNCTION disconnect_didd(void)
+{
+	IDI_SYNC_REQ req;
+
+	req.didd_notify.e.Req = 0;
+	req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
+	req.didd_notify.info.handle = notify_handle;
+	DAdapter.request((ENTITY *) & req);
+
+	req.didd_remove_adapter.e.Req = 0;
+	req.didd_remove_adapter.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER;
+	req.didd_remove_adapter.info.p_request =
+	    (IDI_CALL) MaintDescriptor.request;
+	DAdapter.request((ENTITY *) & req);
+}
+
+/*
+ * read/write maint
+ */
+int maint_read_write(void __user *buf, int count)
+{
+	byte data[128];
+	dword cmd, id, mask;
+	int ret = 0;
+
+	if (count < (3 * sizeof(dword)))
+		return (-EFAULT);
+
+	if (diva_os_copy_from_user(NULL, (void *) &data[0],
+				   buf, 3 * sizeof(dword))) {
+		return (-EFAULT);
+	}
+
+	cmd = *(dword *) & data[0];	/* command */
+	id = *(dword *) & data[4];	/* driver id */
+	mask = *(dword *) & data[8];	/* mask or size */
+
+	switch (cmd) {
+	case DITRACE_CMD_GET_DRIVER_INFO:
+		if ((ret = diva_get_driver_info(id, data, sizeof(data))) > 0) {
+			if ((count < ret) || diva_os_copy_to_user
+			    (NULL, buf, (void *) &data[0], ret))
+				ret = -EFAULT;
+		} else {
+			ret = -EINVAL;
+		}
+		break;
+
+	case DITRACE_READ_DRIVER_DBG_MASK:
+		if ((ret = diva_get_driver_dbg_mask(id, (byte *) data)) > 0) {
+			if ((count < ret) || diva_os_copy_to_user
+			    (NULL, buf, (void *) &data[0], ret))
+				ret = -EFAULT;
+		} else {
+			ret = -ENODEV;
+		}
+		break;
+
+	case DITRACE_WRITE_DRIVER_DBG_MASK:
+		if ((ret = diva_set_driver_dbg_mask(id, mask)) <= 0) {
+			ret = -ENODEV;
+		}
+		break;
+
+    /*
+       Filter commands will ignore the ID due to fact that filtering affects
+       the B- channel and Audio Tap trace levels only. Also MAINT driver will
+       select the right trace ID by itself
+       */
+	case DITRACE_WRITE_SELECTIVE_TRACE_FILTER:
+		if (!mask) {
+			ret = diva_set_trace_filter (1, "*");
+		} else if (mask < sizeof(data)) {
+			if (diva_os_copy_from_user(NULL, data, (char __user *)buf+12, mask)) {
+				ret = -EFAULT;
+			} else {
+				ret = diva_set_trace_filter ((int)mask, data);
+			}
+		} else {
+			ret = -EINVAL;
+		}
+		break;
+
+	case DITRACE_READ_SELECTIVE_TRACE_FILTER:
+		if ((ret = diva_get_trace_filter (sizeof(data), data)) > 0) {
+			if (diva_os_copy_to_user (NULL, buf, data, ret))
+				ret = -EFAULT;
+		} else {
+			ret = -ENODEV;
+		}
+		break;
+
+	case DITRACE_READ_TRACE_ENTRY:{
+			diva_os_spin_lock_magic_t old_irql;
+			word size;
+			diva_dbg_entry_head_t *pmsg;
+			byte *pbuf;
+
+			if (!(pbuf = diva_os_malloc(0, mask))) {
+				return (-ENOMEM);
+			}
+
+			for(;;) {
+				if (!(pmsg =
+				    diva_maint_get_message(&size, &old_irql))) {
+					break;
+				}
+				if (size > mask) {
+					diva_maint_ack_message(0, &old_irql);
+					ret = -EINVAL;
+					break;
+				}
+				ret = size;
+				memcpy(pbuf, pmsg, size);
+				diva_maint_ack_message(1, &old_irql);
+				if ((count < size) ||
+				     diva_os_copy_to_user (NULL, buf, (void *) pbuf, size))
+							ret = -EFAULT;
+				break;
+			}
+			diva_os_free(0, pbuf);
+		}
+		break;
+
+	case DITRACE_READ_TRACE_ENTRYS:{
+			diva_os_spin_lock_magic_t old_irql;
+			word size;
+			diva_dbg_entry_head_t *pmsg;
+			byte *pbuf = NULL;
+			int written = 0;
+
+			if (mask < 4096) {
+				ret = -EINVAL;
+				break;
+			}
+			if (!(pbuf = diva_os_malloc(0, mask))) {
+				return (-ENOMEM);
+			}
+
+			for (;;) {
+				if (!(pmsg =
+				     diva_maint_get_message(&size, &old_irql))) {
+					break;
+				}
+				if ((size + 8) > mask) {
+					diva_maint_ack_message(0, &old_irql);
+					break;
+				}
+				/*
+				   Write entry length
+				 */
+				pbuf[written++] = (byte) size;
+				pbuf[written++] = (byte) (size >> 8);
+				pbuf[written++] = 0;
+				pbuf[written++] = 0;
+				/*
+				   Write message
+				 */
+				memcpy(&pbuf[written], pmsg, size);
+				diva_maint_ack_message(1, &old_irql);
+				written += size;
+				mask -= (size + 4);
+			}
+			pbuf[written++] = 0;
+			pbuf[written++] = 0;
+			pbuf[written++] = 0;
+			pbuf[written++] = 0;
+
+			if ((count < written) || diva_os_copy_to_user(NULL, buf, (void *) pbuf, written)) {
+				ret = -EFAULT;
+			} else {
+				ret = written;
+			}
+			diva_os_free(0, pbuf);
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	return (ret);
+}
+
+/*
+ *  init
+ */
+int DIVA_INIT_FUNCTION mntfunc_init(int *buffer_length, void **buffer,
+				    unsigned long diva_dbg_mem)
+{
+	if (*buffer_length < 64) {
+		*buffer_length = 64;
+	}
+	if (*buffer_length > 512) {
+		*buffer_length = 512;
+	}
+	*buffer_length *= 1024;
+
+	if (diva_dbg_mem) {
+		*buffer = (void *) diva_dbg_mem;
+	} else {
+		while ((*buffer_length >= (64 * 1024))
+		       &&
+		       (!(*buffer = diva_os_malloc (0, *buffer_length)))) {
+			*buffer_length -= 1024;
+		}
+
+		if (!*buffer) {
+			DBG_ERR(("init: Can not alloc trace buffer"));
+			return (0);
+		}
+	}
+
+	if (diva_maint_init(*buffer, *buffer_length, (diva_dbg_mem == 0))) {
+		if (!diva_dbg_mem) {
+			diva_os_free (0, *buffer);
+		}
+		DBG_ERR(("init: maint init failed"));
+		return (0);
+	}
+
+	if (!connect_didd()) {
+		DBG_ERR(("init: failed to connect to DIDD."));
+		diva_maint_finit();
+		if (!diva_dbg_mem) {
+			diva_os_free (0, *buffer);
+		}
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ *  exit
+ */
+void DIVA_EXIT_FUNCTION mntfunc_finit(void)
+{
+	void *buffer;
+	int i = 100;
+
+	DbgDeregister();
+
+	while (diva_mnt_shutdown_xdi_adapters() && i--) {
+		diva_os_sleep(10);
+	}
+
+	disconnect_didd();
+
+	if ((buffer = diva_maint_finit())) {
+		diva_os_free (0, buffer);
+	}
+
+	memset(&MAdapter, 0, sizeof(MAdapter));
+	dprintf = no_printf;
+}
diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c
new file mode 100644
index 0000000..cccfabc
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_4bri.c
@@ -0,0 +1,1131 @@
+/* $Id: os_4bri.c,v 1.28.4.4 2005/02/11 19:40:25 armin Exp $ */
+
+#include "platform.h"
+#include "debuglib.h"
+#include "cardtype.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "dsp_defs.h"
+#include "di.h"
+#include "io.h"
+
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "os_4bri.h"
+#include "diva_pci.h"
+#include "mi_pc.h"
+#include "dsrv4bri.h"
+
+static void *diva_xdiLoadFileFile = NULL;
+static dword diva_xdiLoadFileLength = 0;
+
+/*
+**  IMPORTS
+*/
+extern void prepare_qBri_functions(PISDN_ADAPTER IoAdapter);
+extern void prepare_qBri2_functions(PISDN_ADAPTER IoAdapter);
+extern void diva_xdi_display_adapter_features(int card);
+extern void diva_add_slave_adapter(diva_os_xdi_adapter_t * a);
+
+extern int qBri_FPGA_download(PISDN_ADAPTER IoAdapter);
+extern void start_qBri_hardware(PISDN_ADAPTER IoAdapter);
+
+extern int diva_card_read_xlog(diva_os_xdi_adapter_t * a);
+
+/*
+**  LOCALS
+*/
+static unsigned long _4bri_bar_length[4] = {
+	0x100,
+	0x100,			/* I/O */
+	MQ_MEMORY_SIZE,
+	0x2000
+};
+static unsigned long _4bri_v2_bar_length[4] = {
+	0x100,
+	0x100,			/* I/O */
+	MQ2_MEMORY_SIZE,
+	0x10000
+};
+static unsigned long _4bri_v2_bri_bar_length[4] = {
+	0x100,
+	0x100,			/* I/O */
+	BRI2_MEMORY_SIZE,
+	0x10000
+};
+
+
+static int diva_4bri_cleanup_adapter(diva_os_xdi_adapter_t * a);
+static int _4bri_get_serial_number(diva_os_xdi_adapter_t * a);
+static int diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
+				   diva_xdi_um_cfg_cmd_t * cmd,
+				   int length);
+static int diva_4bri_cleanup_slave_adapters(diva_os_xdi_adapter_t * a);
+static int diva_4bri_write_fpga_image(diva_os_xdi_adapter_t * a,
+				      byte * data, dword length);
+static int diva_4bri_reset_adapter(PISDN_ADAPTER IoAdapter);
+static int diva_4bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
+				       dword address,
+				       const byte * data,
+				       dword length, dword limit);
+static int diva_4bri_start_adapter(PISDN_ADAPTER IoAdapter,
+				   dword start_address, dword features);
+static int check_qBri_interrupt(PISDN_ADAPTER IoAdapter);
+static int diva_4bri_stop_adapter(diva_os_xdi_adapter_t * a);
+
+static int _4bri_is_rev_2_card(int card_ordinal)
+{
+	switch (card_ordinal) {
+	case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
+	case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
+	case CARDTYPE_DIVASRV_B_2M_V2_PCI:
+	case CARDTYPE_DIVASRV_B_2F_PCI:
+	case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
+		return (1);
+	}
+	return (0);
+}
+
+static int _4bri_is_rev_2_bri_card(int card_ordinal)
+{
+	switch (card_ordinal) {
+	case CARDTYPE_DIVASRV_B_2M_V2_PCI:
+	case CARDTYPE_DIVASRV_B_2F_PCI:
+	case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
+		return (1);
+	}
+	return (0);
+}
+
+static void diva_4bri_set_addresses(diva_os_xdi_adapter_t *a)
+{
+	dword offset = a->resources.pci.qoffset;
+	dword c_offset = offset * a->xdi_adapter.ControllerNumber;
+
+	a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 2;
+	a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 2;
+	a->resources.pci.mem_type_id[MEM_TYPE_CONTROL] = 2;
+	a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 0;
+	a->resources.pci.mem_type_id[MEM_TYPE_CTLREG] = 3;
+	a->resources.pci.mem_type_id[MEM_TYPE_PROM] = 0;
+
+	/*
+	   Set up hardware related pointers
+	 */
+	a->xdi_adapter.Address = a->resources.pci.addr[2];	/* BAR2 SDRAM  */
+	a->xdi_adapter.Address += c_offset;
+
+	a->xdi_adapter.Control = a->resources.pci.addr[2];	/* BAR2 SDRAM  */
+
+	a->xdi_adapter.ram = a->resources.pci.addr[2];	/* BAR2 SDRAM  */
+	a->xdi_adapter.ram += c_offset + (offset - MQ_SHARED_RAM_SIZE);
+	
+	a->xdi_adapter.reset = a->resources.pci.addr[0];	/* BAR0 CONFIG */
+	/*
+	   ctlReg contains the register address for the MIPS CPU reset control
+	 */
+	a->xdi_adapter.ctlReg = a->resources.pci.addr[3];	/* BAR3 CNTRL  */
+	/*
+	   prom contains the register address for FPGA and EEPROM programming
+	 */
+	a->xdi_adapter.prom = &a->xdi_adapter.reset[0x6E];
+}
+
+/*
+**  BAR0 - MEM - 0x100    - CONFIG MEM
+**  BAR1 - I/O - 0x100    - UNUSED
+**  BAR2 - MEM - MQ_MEMORY_SIZE (MQ2_MEMORY_SIZE on Rev.2) - SDRAM
+**  BAR3 - MEM - 0x2000 (0x10000 on Rev.2)   - CNTRL
+**
+**  Called by master adapter, that will initialize and add slave adapters
+*/
+int diva_4bri_init_card(diva_os_xdi_adapter_t * a)
+{
+	int bar, i;
+	byte __iomem *p;
+	PADAPTER_LIST_ENTRY quadro_list;
+	diva_os_xdi_adapter_t *diva_current;
+	diva_os_xdi_adapter_t *adapter_list[4];
+	PISDN_ADAPTER Slave;
+	unsigned long bar_length[sizeof(_4bri_bar_length) /
+				 sizeof(_4bri_bar_length[0])];
+	int v2 = _4bri_is_rev_2_card(a->CardOrdinal);
+	int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT;
+	int factor = (tasks == 1) ? 1 : 2;
+
+	if (v2) {
+		if (_4bri_is_rev_2_bri_card(a->CardOrdinal)) {
+			memcpy(bar_length, _4bri_v2_bri_bar_length,
+			       sizeof(bar_length));
+		} else {
+			memcpy(bar_length, _4bri_v2_bar_length,
+			       sizeof(bar_length));
+		}
+	} else {
+		memcpy(bar_length, _4bri_bar_length, sizeof(bar_length));
+	}
+	DBG_TRC(("SDRAM_LENGTH=%08x, tasks=%d, factor=%d",
+		 bar_length[2], tasks, factor))
+
+	/*
+	   Get Serial Number
+	   The serial number of 4BRI is accessible in accordance with PCI spec
+	   via command register located in configuration space, also we do not
+	   have to map any BAR before we can access it
+	 */
+	if (!_4bri_get_serial_number(a)) {
+		DBG_ERR(("A: 4BRI can't get Serial Number"))
+		diva_4bri_cleanup_adapter(a);
+		return (-1);
+	}
+
+	/*
+	   Set properties
+	 */
+	a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
+	DBG_LOG(("Load %s, SN:%ld, bus:%02x, func:%02x",
+		 a->xdi_adapter.Properties.Name,
+		 a->xdi_adapter.serialNo,
+		 a->resources.pci.bus, a->resources.pci.func))
+
+	/*
+	   First initialization step: get and check hardware resoures.
+	   Do not map resources and do not access card at this step
+	 */
+	for (bar = 0; bar < 4; bar++) {
+		a->resources.pci.bar[bar] =
+		    divasa_get_pci_bar(a->resources.pci.bus,
+				       a->resources.pci.func, bar,
+				       a->resources.pci.hdev);
+		if (!a->resources.pci.bar[bar]
+		    || (a->resources.pci.bar[bar] == 0xFFFFFFF0)) {
+			DBG_ERR(
+				("A: invalid bar[%d]=%08x", bar,
+				 a->resources.pci.bar[bar]))
+			return (-1);
+		}
+	}
+	a->resources.pci.irq =
+	    (byte) divasa_get_pci_irq(a->resources.pci.bus,
+				      a->resources.pci.func,
+				      a->resources.pci.hdev);
+	if (!a->resources.pci.irq) {
+		DBG_ERR(("A: invalid irq"));
+		return (-1);
+	}
+
+	a->xdi_adapter.sdram_bar = a->resources.pci.bar[2];
+
+	/*
+	   Map all MEMORY BAR's
+	 */
+	for (bar = 0; bar < 4; bar++) {
+		if (bar != 1) {	/* ignore I/O */
+			a->resources.pci.addr[bar] =
+			    divasa_remap_pci_bar(a, bar, a->resources.pci.bar[bar],
+						 bar_length[bar]);
+			if (!a->resources.pci.addr[bar]) {
+				DBG_ERR(("A: 4BRI: can't map bar[%d]", bar))
+				diva_4bri_cleanup_adapter(a);
+				return (-1);
+			}
+		}
+	}
+
+	/*
+	   Register I/O port
+	 */
+	sprintf(&a->port_name[0], "DIVA 4BRI %ld", (long) a->xdi_adapter.serialNo);
+
+	if (diva_os_register_io_port(a, 1, a->resources.pci.bar[1],
+				     bar_length[1], &a->port_name[0], 1)) {
+		DBG_ERR(("A: 4BRI: can't register bar[1]"))
+		diva_4bri_cleanup_adapter(a);
+		return (-1);
+	}
+
+	a->resources.pci.addr[1] =
+		(void *) (unsigned long) a->resources.pci.bar[1];
+
+	/*
+	   Set cleanup pointer for base adapter only, so slave adapter
+	   will be unable to get cleanup
+	 */
+	a->interface.cleanup_adapter_proc = diva_4bri_cleanup_adapter;
+
+	/*
+	   Create slave adapters
+	 */
+	if (tasks > 1) {
+		if (!(a->slave_adapters[0] =
+		     (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
+		{
+			diva_4bri_cleanup_adapter(a);
+			return (-1);
+		}
+		if (!(a->slave_adapters[1] =
+		     (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
+		{
+			diva_os_free(0, a->slave_adapters[0]);
+			a->slave_adapters[0] = NULL;
+			diva_4bri_cleanup_adapter(a);
+			return (-1);
+		}
+		if (!(a->slave_adapters[2] =
+		     (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a))))
+		{
+			diva_os_free(0, a->slave_adapters[0]);
+			diva_os_free(0, a->slave_adapters[1]);
+			a->slave_adapters[0] = NULL;
+			a->slave_adapters[1] = NULL;
+			diva_4bri_cleanup_adapter(a);
+			return (-1);
+		}
+		memset(a->slave_adapters[0], 0x00, sizeof(*a));
+		memset(a->slave_adapters[1], 0x00, sizeof(*a));
+		memset(a->slave_adapters[2], 0x00, sizeof(*a));
+	}
+
+	adapter_list[0] = a;
+	adapter_list[1] = a->slave_adapters[0];
+	adapter_list[2] = a->slave_adapters[1];
+	adapter_list[3] = a->slave_adapters[2];
+
+	/*
+	   Allocate slave list
+	 */
+	quadro_list =
+	    (PADAPTER_LIST_ENTRY) diva_os_malloc(0, sizeof(*quadro_list));
+	if (!(a->slave_list = quadro_list)) {
+		for (i = 0; i < (tasks - 1); i++) {
+			diva_os_free(0, a->slave_adapters[i]);
+			a->slave_adapters[i] = NULL;
+		}
+		diva_4bri_cleanup_adapter(a);
+		return (-1);
+	}
+	memset(quadro_list, 0x00, sizeof(*quadro_list));
+
+	/*
+	   Set interfaces
+	 */
+	a->xdi_adapter.QuadroList = quadro_list;
+	for (i = 0; i < tasks; i++) {
+		adapter_list[i]->xdi_adapter.ControllerNumber = i;
+		adapter_list[i]->xdi_adapter.tasks = tasks;
+		quadro_list->QuadroAdapter[i] =
+		    &adapter_list[i]->xdi_adapter;
+	}
+
+	for (i = 0; i < tasks; i++) {
+		diva_current = adapter_list[i];
+
+		diva_current->dsp_mask = 0x00000003;
+
+		diva_current->xdi_adapter.a.io =
+		    &diva_current->xdi_adapter;
+		diva_current->xdi_adapter.DIRequest = request;
+		diva_current->interface.cmd_proc = diva_4bri_cmd_card_proc;
+		diva_current->xdi_adapter.Properties =
+		    CardProperties[a->CardOrdinal];
+		diva_current->CardOrdinal = a->CardOrdinal;
+
+		diva_current->xdi_adapter.Channels =
+		    CardProperties[a->CardOrdinal].Channels;
+		diva_current->xdi_adapter.e_max =
+		    CardProperties[a->CardOrdinal].E_info;
+		diva_current->xdi_adapter.e_tbl =
+		    diva_os_malloc(0,
+				   diva_current->xdi_adapter.e_max *
+				   sizeof(E_INFO));
+
+		if (!diva_current->xdi_adapter.e_tbl) {
+			diva_4bri_cleanup_slave_adapters(a);
+			diva_4bri_cleanup_adapter(a);
+			for (i = 1; i < (tasks - 1); i++) {
+				diva_os_free(0, adapter_list[i]);
+			}
+			return (-1);
+		}
+		memset(diva_current->xdi_adapter.e_tbl, 0x00,
+		       diva_current->xdi_adapter.e_max * sizeof(E_INFO));
+
+		if (diva_os_initialize_spin_lock(&diva_current->xdi_adapter.isr_spin_lock, "isr")) {
+			diva_4bri_cleanup_slave_adapters(a);
+			diva_4bri_cleanup_adapter(a);
+			for (i = 1; i < (tasks - 1); i++) {
+				diva_os_free(0, adapter_list[i]);
+			}
+			return (-1);
+		}
+		if (diva_os_initialize_spin_lock(&diva_current->xdi_adapter.data_spin_lock, "data")) {
+			diva_4bri_cleanup_slave_adapters(a);
+			diva_4bri_cleanup_adapter(a);
+			for (i = 1; i < (tasks - 1); i++) {
+				diva_os_free(0, adapter_list[i]);
+			}
+			return (-1);
+		}
+
+		strcpy(diva_current->xdi_adapter.req_soft_isr. dpc_thread_name, "kdivas4brid");
+
+		if (diva_os_initialize_soft_isr (&diva_current->xdi_adapter.req_soft_isr, DIDpcRoutine,
+		     &diva_current->xdi_adapter)) {
+			diva_4bri_cleanup_slave_adapters(a);
+			diva_4bri_cleanup_adapter(a);
+			for (i = 1; i < (tasks - 1); i++) {
+				diva_os_free(0, adapter_list[i]);
+			}
+			return (-1);
+		}
+
+		/*
+		   Do not initialize second DPC - only one thread will be created
+		 */
+		diva_current->xdi_adapter.isr_soft_isr.object =
+		    diva_current->xdi_adapter.req_soft_isr.object;
+	}
+
+	if (v2) {
+		prepare_qBri2_functions(&a->xdi_adapter);
+	} else {
+		prepare_qBri_functions(&a->xdi_adapter);
+	}
+
+	for (i = 0; i < tasks; i++) {
+		diva_current = adapter_list[i];
+		if (i)
+			memcpy(&diva_current->resources, &a->resources, sizeof(divas_card_resources_t));
+		diva_current->resources.pci.qoffset = (a->xdi_adapter.MemorySize >> factor); 
+	}
+
+	/*
+	   Set up hardware related pointers
+	 */
+	a->xdi_adapter.cfg = (void *) (unsigned long) a->resources.pci.bar[0];	/* BAR0 CONFIG */
+	a->xdi_adapter.port = (void *) (unsigned long) a->resources.pci.bar[1];	/* BAR1        */
+	a->xdi_adapter.ctlReg = (void *) (unsigned long) a->resources.pci.bar[3];	/* BAR3 CNTRL  */
+
+	for (i = 0; i < tasks; i++) {
+		diva_current = adapter_list[i];
+		diva_4bri_set_addresses(diva_current);
+		Slave = a->xdi_adapter.QuadroList->QuadroAdapter[i];
+		Slave->MultiMaster = &a->xdi_adapter;
+		Slave->sdram_bar = a->xdi_adapter.sdram_bar;
+		if (i) {
+			Slave->serialNo = ((dword) (Slave->ControllerNumber << 24)) |
+					a->xdi_adapter.serialNo;
+			Slave->cardType = a->xdi_adapter.cardType;
+		}
+	}
+
+	/*
+	   reset contains the base address for the PLX 9054 register set
+	 */
+	p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
+	WRITE_BYTE(&p[PLX9054_INTCSR], 0x00);	/* disable PCI interrupts */
+	DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
+
+	/*
+	   Set IRQ handler
+	 */
+	a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
+	sprintf(a->xdi_adapter.irq_info.irq_name, "DIVA 4BRI %ld",
+		(long) a->xdi_adapter.serialNo);
+
+	if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr,
+				 a->xdi_adapter.irq_info.irq_name)) {
+		diva_4bri_cleanup_slave_adapters(a);
+		diva_4bri_cleanup_adapter(a);
+		for (i = 1; i < (tasks - 1); i++) {
+			diva_os_free(0, adapter_list[i]);
+		}
+		return (-1);
+	}
+
+	a->xdi_adapter.irq_info.registered = 1;
+
+	/*
+	   Add three slave adapters
+	 */
+	if (tasks > 1) {
+		diva_add_slave_adapter(adapter_list[1]);
+		diva_add_slave_adapter(adapter_list[2]);
+		diva_add_slave_adapter(adapter_list[3]);
+	}
+
+	diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
+		      a->resources.pci.irq, a->xdi_adapter.serialNo);
+
+	return (0);
+}
+
+/*
+**  Cleanup function will be called for master adapter only
+**  this is garanteed by design: cleanup callback is set
+**  by master adapter only
+*/
+static int diva_4bri_cleanup_adapter(diva_os_xdi_adapter_t * a)
+{
+	int bar;
+
+	/*
+	   Stop adapter if running
+	 */
+	if (a->xdi_adapter.Initialized) {
+		diva_4bri_stop_adapter(a);
+	}
+
+	/*
+	   Remove IRQ handler
+	 */
+	if (a->xdi_adapter.irq_info.registered) {
+		diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr);
+	}
+	a->xdi_adapter.irq_info.registered = 0;
+
+	/*
+	   Free DPC's and spin locks on all adapters
+	 */
+	diva_4bri_cleanup_slave_adapters(a);
+
+	/*
+	   Unmap all BARS
+	 */
+	for (bar = 0; bar < 4; bar++) {
+		if (bar != 1) {
+			if (a->resources.pci.bar[bar]
+			    && a->resources.pci.addr[bar]) {
+				divasa_unmap_pci_bar(a->resources.pci.addr[bar]);
+				a->resources.pci.bar[bar] = 0;
+				a->resources.pci.addr[bar] = NULL;
+			}
+		}
+	}
+
+	/*
+	   Unregister I/O
+	 */
+	if (a->resources.pci.bar[1] && a->resources.pci.addr[1]) {
+		diva_os_register_io_port(a, 0, a->resources.pci.bar[1],
+					 _4bri_is_rev_2_card(a->
+							     CardOrdinal) ?
+					 _4bri_v2_bar_length[1] :
+					 _4bri_bar_length[1],
+					 &a->port_name[0], 1);
+		a->resources.pci.bar[1] = 0;
+		a->resources.pci.addr[1] = NULL;
+	}
+
+	if (a->slave_list) {
+		diva_os_free(0, a->slave_list);
+		a->slave_list = NULL;
+	}
+
+	return (0);
+}
+
+static int _4bri_get_serial_number(diva_os_xdi_adapter_t * a)
+{
+	dword data[64];
+	dword serNo;
+	word addr, status, i, j;
+	byte Bus, Slot;
+	void *hdev;
+
+	Bus = a->resources.pci.bus;
+	Slot = a->resources.pci.func;
+	hdev = a->resources.pci.hdev;
+
+	for (i = 0; i < 64; ++i) {
+		addr = i * 4;
+		for (j = 0; j < 5; ++j) {
+			PCIwrite(Bus, Slot, 0x4E, &addr, sizeof(addr),
+				 hdev);
+			diva_os_wait(1);
+			PCIread(Bus, Slot, 0x4E, &status, sizeof(status),
+				hdev);
+			if (status & 0x8000)
+				break;
+		}
+		if (j >= 5) {
+			DBG_ERR(("EEPROM[%d] read failed (0x%x)", i * 4, addr))
+			return (0);
+		}
+		PCIread(Bus, Slot, 0x50, &data[i], sizeof(data[i]), hdev);
+	}
+	DBG_BLK(((char *) &data[0], sizeof(data)))
+
+	serNo = data[32];
+	if (serNo == 0 || serNo == 0xffffffff)
+		serNo = data[63];
+
+	if (!serNo) {
+		DBG_LOG(("W: Serial Number == 0, create one serial number"));
+		serNo = a->resources.pci.bar[1] & 0xffff0000;
+		serNo |= a->resources.pci.bus << 8;
+		serNo |= a->resources.pci.func;
+	}
+
+	a->xdi_adapter.serialNo = serNo;
+
+	DBG_REG(("Serial No.          : %ld", a->xdi_adapter.serialNo))
+
+	return (serNo);
+}
+
+/*
+**  Release resources of slave adapters
+*/
+static int diva_4bri_cleanup_slave_adapters(diva_os_xdi_adapter_t * a)
+{
+	diva_os_xdi_adapter_t *adapter_list[4];
+	diva_os_xdi_adapter_t *diva_current;
+	int i;
+
+	adapter_list[0] = a;
+	adapter_list[1] = a->slave_adapters[0];
+	adapter_list[2] = a->slave_adapters[1];
+	adapter_list[3] = a->slave_adapters[2];
+
+	for (i = 0; i < a->xdi_adapter.tasks; i++) {
+		diva_current = adapter_list[i];
+		if (diva_current) {
+			diva_os_destroy_spin_lock(&diva_current->
+						  xdi_adapter.
+						  isr_spin_lock, "unload");
+			diva_os_destroy_spin_lock(&diva_current->
+						  xdi_adapter.
+						  data_spin_lock,
+						  "unload");
+
+			diva_os_cancel_soft_isr(&diva_current->xdi_adapter.
+						req_soft_isr);
+			diva_os_cancel_soft_isr(&diva_current->xdi_adapter.
+						isr_soft_isr);
+
+			diva_os_remove_soft_isr(&diva_current->xdi_adapter.
+						req_soft_isr);
+			diva_current->xdi_adapter.isr_soft_isr.object = NULL;
+
+			if (diva_current->xdi_adapter.e_tbl) {
+				diva_os_free(0,
+					     diva_current->xdi_adapter.
+					     e_tbl);
+			}
+			diva_current->xdi_adapter.e_tbl = NULL;
+			diva_current->xdi_adapter.e_max = 0;
+			diva_current->xdi_adapter.e_count = 0;
+		}
+	}
+
+	return (0);
+}
+
+static int
+diva_4bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
+			diva_xdi_um_cfg_cmd_t * cmd, int length)
+{
+	int ret = -1;
+
+	if (cmd->adapter != a->controller) {
+		DBG_ERR(("A: 4bri_cmd, invalid controller=%d != %d",
+			 cmd->adapter, a->controller))
+		return (-1);
+	}
+
+	switch (cmd->command) {
+	case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
+		a->xdi_mbox.data_length = sizeof(dword);
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			*(dword *) a->xdi_mbox.data =
+			    (dword) a->CardOrdinal;
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
+		a->xdi_mbox.data_length = sizeof(dword);
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			*(dword *) a->xdi_mbox.data =
+			    (dword) a->xdi_adapter.serialNo;
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
+		if (!a->xdi_adapter.ControllerNumber) {
+			/*
+			   Only master adapter can access hardware config
+			 */
+			a->xdi_mbox.data_length = sizeof(dword) * 9;
+			a->xdi_mbox.data =
+			    diva_os_malloc(0, a->xdi_mbox.data_length);
+			if (a->xdi_mbox.data) {
+				int i;
+				dword *data = (dword *) a->xdi_mbox.data;
+
+				for (i = 0; i < 8; i++) {
+					*data++ = a->resources.pci.bar[i];
+				}
+				*data++ = (dword) a->resources.pci.irq;
+				a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+				ret = 0;
+			}
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_CARD_STATE:
+		if (!a->xdi_adapter.ControllerNumber) {
+			a->xdi_mbox.data_length = sizeof(dword);
+			a->xdi_mbox.data =
+			    diva_os_malloc(0, a->xdi_mbox.data_length);
+			if (a->xdi_mbox.data) {
+				dword *data = (dword *) a->xdi_mbox.data;
+				if (!a->xdi_adapter.ram
+				    || !a->xdi_adapter.reset
+				    || !a->xdi_adapter.cfg) {
+					*data = 3;
+				} else if (a->xdi_adapter.trapped) {
+					*data = 2;
+				} else if (a->xdi_adapter.Initialized) {
+					*data = 1;
+				} else {
+					*data = 0;
+				}
+				a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+				ret = 0;
+			}
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_WRITE_FPGA:
+		if (!a->xdi_adapter.ControllerNumber) {
+			ret =
+			    diva_4bri_write_fpga_image(a,
+						       (byte *) & cmd[1],
+						       cmd->command_data.
+						       write_fpga.
+						       image_length);
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_RESET_ADAPTER:
+		if (!a->xdi_adapter.ControllerNumber) {
+			ret = diva_4bri_reset_adapter(&a->xdi_adapter);
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
+		if (!a->xdi_adapter.ControllerNumber) {
+			ret = diva_4bri_write_sdram_block(&a->xdi_adapter,
+							  cmd->
+							  command_data.
+							  write_sdram.
+							  offset,
+							  (byte *) &
+							  cmd[1],
+							  cmd->
+							  command_data.
+							  write_sdram.
+							  length,
+							  a->xdi_adapter.
+							  MemorySize);
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_START_ADAPTER:
+		if (!a->xdi_adapter.ControllerNumber) {
+			ret = diva_4bri_start_adapter(&a->xdi_adapter,
+						      cmd->command_data.
+						      start.offset,
+						      cmd->command_data.
+						      start.features);
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
+		if (!a->xdi_adapter.ControllerNumber) {
+			a->xdi_adapter.features =
+			    cmd->command_data.features.features;
+			a->xdi_adapter.a.protocol_capabilities =
+			    a->xdi_adapter.features;
+			DBG_TRC(("Set raw protocol features (%08x)",
+				 a->xdi_adapter.features))
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_STOP_ADAPTER:
+		if (!a->xdi_adapter.ControllerNumber) {
+			ret = diva_4bri_stop_adapter(a);
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
+		ret = diva_card_read_xlog(a);
+		break;
+
+	case DIVA_XDI_UM_CMD_READ_SDRAM:
+		if (!a->xdi_adapter.ControllerNumber
+		    && a->xdi_adapter.Address) {
+			if (
+			    (a->xdi_mbox.data_length =
+			     cmd->command_data.read_sdram.length)) {
+				if (
+				    (a->xdi_mbox.data_length +
+				     cmd->command_data.read_sdram.offset) <
+				    a->xdi_adapter.MemorySize) {
+					a->xdi_mbox.data =
+					    diva_os_malloc(0,
+							   a->xdi_mbox.
+							   data_length);
+					if (a->xdi_mbox.data) {
+						byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(&a->xdi_adapter);
+						byte __iomem *src = p;
+						byte *dst = a->xdi_mbox.data;
+						dword len = a->xdi_mbox.data_length;
+
+						src += cmd->command_data.read_sdram.offset;
+
+						while (len--) {
+							*dst++ = READ_BYTE(src++);
+						}
+						DIVA_OS_MEM_DETACH_ADDRESS(&a->xdi_adapter, p);
+						a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+						ret = 0;
+					}
+				}
+			}
+		}
+		break;
+
+	default:
+		DBG_ERR(("A: A(%d) invalid cmd=%d", a->controller,
+			 cmd->command))
+	}
+
+	return (ret);
+}
+
+void *xdiLoadFile(char *FileName, unsigned long *FileLength,
+		  unsigned long lim)
+{
+	void *ret = diva_xdiLoadFileFile;
+
+	if (FileLength) {
+		*FileLength = diva_xdiLoadFileLength;
+	}
+	diva_xdiLoadFileFile = NULL;
+	diva_xdiLoadFileLength = 0;
+
+	return (ret);
+}
+
+void diva_os_set_qBri_functions(PISDN_ADAPTER IoAdapter)
+{
+}
+
+void diva_os_set_qBri2_functions(PISDN_ADAPTER IoAdapter)
+{
+}
+
+static int
+diva_4bri_write_fpga_image(diva_os_xdi_adapter_t * a, byte * data,
+			   dword length)
+{
+	int ret;
+
+	diva_xdiLoadFileFile = data;
+	diva_xdiLoadFileLength = length;
+
+	ret = qBri_FPGA_download(&a->xdi_adapter);
+
+	diva_xdiLoadFileFile = NULL;
+	diva_xdiLoadFileLength = 0;
+
+	return (ret ? 0 : -1);
+}
+
+static int diva_4bri_reset_adapter(PISDN_ADAPTER IoAdapter)
+{
+	PISDN_ADAPTER Slave;
+	int i;
+
+	if (!IoAdapter->Address || !IoAdapter->reset) {
+		return (-1);
+	}
+	if (IoAdapter->Initialized) {
+		DBG_ERR(("A: A(%d) can't reset 4BRI adapter - please stop first",
+			 IoAdapter->ANum))
+		return (-1);
+	}
+
+	/*
+	   Forget all entities on all adapters
+	 */
+	for (i = 0; ((i < IoAdapter->tasks) && IoAdapter->QuadroList); i++) {
+		Slave = IoAdapter->QuadroList->QuadroAdapter[i];
+		Slave->e_count = 0;
+		if (Slave->e_tbl) {
+			memset(Slave->e_tbl, 0x00,
+			       Slave->e_max * sizeof(E_INFO));
+		}
+		Slave->head = 0;
+		Slave->tail = 0;
+		Slave->assign = 0;
+		Slave->trapped = 0;
+
+		memset(&Slave->a.IdTable[0], 0x00,
+		       sizeof(Slave->a.IdTable));
+		memset(&Slave->a.IdTypeTable[0], 0x00,
+		       sizeof(Slave->a.IdTypeTable));
+		memset(&Slave->a.FlowControlIdTable[0], 0x00,
+		       sizeof(Slave->a.FlowControlIdTable));
+		memset(&Slave->a.FlowControlSkipTable[0], 0x00,
+		       sizeof(Slave->a.FlowControlSkipTable));
+		memset(&Slave->a.misc_flags_table[0], 0x00,
+		       sizeof(Slave->a.misc_flags_table));
+		memset(&Slave->a.rx_stream[0], 0x00,
+		       sizeof(Slave->a.rx_stream));
+		memset(&Slave->a.tx_stream[0], 0x00,
+		       sizeof(Slave->a.tx_stream));
+		memset(&Slave->a.tx_pos[0], 0x00, sizeof(Slave->a.tx_pos));
+		memset(&Slave->a.rx_pos[0], 0x00, sizeof(Slave->a.rx_pos));
+	}
+
+	return (0);
+}
+
+
+static int
+diva_4bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
+			    dword address,
+			    const byte * data, dword length, dword limit)
+{
+	byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
+	byte __iomem *mem = p;
+
+	if (((address + length) >= limit) || !mem) {
+		DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
+		DBG_ERR(("A: A(%d) write 4BRI address=0x%08lx",
+			 IoAdapter->ANum, address + length))
+		return (-1);
+	}
+	mem += address;
+
+	while (length--) {
+		WRITE_BYTE(mem++, *data++);
+	}
+
+	DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
+	return (0);
+}
+
+static int
+diva_4bri_start_adapter(PISDN_ADAPTER IoAdapter,
+			dword start_address, dword features)
+{
+	volatile word __iomem *signature;
+	int started = 0;
+	int i;
+	byte __iomem *p;
+
+	/*
+	   start adapter
+	 */
+	start_qBri_hardware(IoAdapter);
+
+	p = DIVA_OS_MEM_ATTACH_RAM(IoAdapter);
+	/*
+	   wait for signature in shared memory (max. 3 seconds)
+	 */
+	signature = (volatile word __iomem *) (&p[0x1E]);
+
+	for (i = 0; i < 300; ++i) {
+		diva_os_wait(10);
+		if (READ_WORD(&signature[0]) == 0x4447) {
+			DBG_TRC(("Protocol startup time %d.%02d seconds",
+				 (i / 100), (i % 100)))
+			started = 1;
+			break;
+		}
+	}
+
+	for (i = 1; i < IoAdapter->tasks; i++) {
+		IoAdapter->QuadroList->QuadroAdapter[i]->features =
+		    IoAdapter->features;
+		IoAdapter->QuadroList->QuadroAdapter[i]->a.
+		    protocol_capabilities = IoAdapter->features;
+	}
+
+	if (!started) {
+		DBG_FTL(("%s: Adapter selftest failed, signature=%04x",
+			 IoAdapter->Properties.Name,
+			 READ_WORD(&signature[0])))
+		DIVA_OS_MEM_DETACH_RAM(IoAdapter, p);
+		(*(IoAdapter->trapFnc)) (IoAdapter);
+		IoAdapter->stop(IoAdapter);
+		return (-1);
+	}
+	DIVA_OS_MEM_DETACH_RAM(IoAdapter, p);
+
+	for (i = 0; i < IoAdapter->tasks; i++) {
+		IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 1;
+		IoAdapter->QuadroList->QuadroAdapter[i]->IrqCount = 0;
+	}
+
+	if (check_qBri_interrupt(IoAdapter)) {
+		DBG_ERR(("A: A(%d) interrupt test failed",
+			 IoAdapter->ANum))
+		for (i = 0; i < IoAdapter->tasks; i++) {
+			IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 0;
+		}
+		IoAdapter->stop(IoAdapter);
+		return (-1);
+	}
+
+	IoAdapter->Properties.Features = (word) features;
+	diva_xdi_display_adapter_features(IoAdapter->ANum);
+
+	for (i = 0; i < IoAdapter->tasks; i++) {
+		DBG_LOG(("A(%d) %s adapter successfull started",
+			 IoAdapter->QuadroList->QuadroAdapter[i]->ANum,
+			 (IoAdapter->tasks == 1) ? "BRI 2.0" : "4BRI"))
+		diva_xdi_didd_register_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
+		IoAdapter->QuadroList->QuadroAdapter[i]->Properties.Features = (word) features;
+	}
+
+	return (0);
+}
+
+static int check_qBri_interrupt(PISDN_ADAPTER IoAdapter)
+{
+#ifdef	SUPPORT_INTERRUPT_TEST_ON_4BRI
+	int i;
+	ADAPTER *a = &IoAdapter->a;
+	byte __iomem *p;
+
+	IoAdapter->IrqCount = 0;
+
+	if (IoAdapter->ControllerNumber > 0)
+		return (-1);
+
+	p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+	WRITE_BYTE(&p[PLX9054_INTCSR], PLX9054_INT_ENABLE);
+	DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+	/*
+	   interrupt test
+	 */
+	a->ReadyInt = 1;
+	a->ram_out(a, &PR_RAM->ReadyInt, 1);
+
+	for (i = 100; !IoAdapter->IrqCount && (i-- > 0); diva_os_wait(10));
+
+	return ((IoAdapter->IrqCount > 0) ? 0 : -1);
+#else
+	dword volatile __iomem *qBriIrq;
+	byte __iomem *p;
+	/*
+	   Reset on-board interrupt register
+	 */
+	IoAdapter->IrqCount = 0;
+	p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+	qBriIrq = (dword volatile __iomem *) (&p[_4bri_is_rev_2_card
+				       (IoAdapter->
+					cardType) ? (MQ2_BREG_IRQ_TEST)
+				       : (MQ_BREG_IRQ_TEST)]);
+
+	WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF);
+	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+
+	p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+	WRITE_BYTE(&p[PLX9054_INTCSR], PLX9054_INT_ENABLE);
+	DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+
+	diva_os_wait(100);
+
+	return (0);
+#endif				/* SUPPORT_INTERRUPT_TEST_ON_4BRI */
+}
+
+static void diva_4bri_clear_interrupts(diva_os_xdi_adapter_t * a)
+{
+	PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+
+	/*
+	   clear any pending interrupt
+	 */
+	IoAdapter->disIrq(IoAdapter);
+
+	IoAdapter->tst_irq(&IoAdapter->a);
+	IoAdapter->clr_irq(&IoAdapter->a);
+	IoAdapter->tst_irq(&IoAdapter->a);
+
+	/*
+	   kill pending dpcs
+	 */
+	diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
+	diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
+}
+
+static int diva_4bri_stop_adapter(diva_os_xdi_adapter_t * a)
+{
+	PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+	int i;
+
+	if (!IoAdapter->ram) {
+		return (-1);
+	}
+
+	if (!IoAdapter->Initialized) {
+		DBG_ERR(("A: A(%d) can't stop PRI adapter - not running",
+			 IoAdapter->ANum))
+		return (-1);	/* nothing to stop */
+	}
+
+	for (i = 0; i < IoAdapter->tasks; i++) {
+		IoAdapter->QuadroList->QuadroAdapter[i]->Initialized = 0;
+	}
+
+	/*
+	   Disconnect Adapters from DIDD
+	 */
+	for (i = 0; i < IoAdapter->tasks; i++) {
+		diva_xdi_didd_remove_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
+	}
+
+	i = 100;
+
+	/*
+	   Stop interrupts
+	 */
+	a->clear_interrupts_proc = diva_4bri_clear_interrupts;
+	IoAdapter->a.ReadyInt = 1;
+	IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
+	do {
+		diva_os_sleep(10);
+	} while (i-- && a->clear_interrupts_proc);
+
+	if (a->clear_interrupts_proc) {
+		diva_4bri_clear_interrupts(a);
+		a->clear_interrupts_proc = NULL;
+		DBG_ERR(("A: A(%d) no final interrupt from 4BRI adapter",
+			 IoAdapter->ANum))
+	}
+	IoAdapter->a.ReadyInt = 0;
+
+	/*
+	   Stop and reset adapter
+	 */
+	IoAdapter->stop(IoAdapter);
+
+	return (0);
+}
diff --git a/drivers/isdn/hardware/eicon/os_4bri.h b/drivers/isdn/hardware/eicon/os_4bri.h
new file mode 100644
index 0000000..665f0af
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_4bri.h
@@ -0,0 +1,8 @@
+/* $Id: os_4bri.h,v 1.1.2.2 2001/02/08 12:25:44 armin Exp $ */
+
+#ifndef __DIVA_OS_4_BRI_H__
+#define __DIVA_OS_4_BRI_H__
+
+int diva_4bri_init_card(diva_os_xdi_adapter_t * a);
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/os_bri.c b/drivers/isdn/hardware/eicon/os_bri.c
new file mode 100644
index 0000000..4cc44a5
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_bri.c
@@ -0,0 +1,813 @@
+/* $Id: os_bri.c,v 1.21 2004/03/21 17:26:01 armin Exp $ */
+
+#include "platform.h"
+#include "debuglib.h"
+#include "cardtype.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "dsp_defs.h"
+#include "di.h"
+#include "io.h"
+
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "os_bri.h"
+#include "diva_pci.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+
+/*
+**  IMPORTS
+*/
+extern void prepare_maestra_functions(PISDN_ADAPTER IoAdapter);
+extern void diva_xdi_display_adapter_features(int card);
+extern int diva_card_read_xlog(diva_os_xdi_adapter_t * a);
+
+/*
+**  LOCALS
+*/
+static int bri_bar_length[3] = {
+	0x80,
+	0x80,
+	0x20
+};
+static int diva_bri_cleanup_adapter(diva_os_xdi_adapter_t * a);
+static dword diva_bri_get_serial_number(diva_os_xdi_adapter_t * a);
+static int diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
+				  diva_xdi_um_cfg_cmd_t * cmd, int length);
+static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a);
+static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter);
+static int diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
+				      dword address,
+				      const byte * data, dword length);
+static int diva_bri_start_adapter(PISDN_ADAPTER IoAdapter,
+				  dword start_address, dword features);
+static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a);
+
+static void diva_bri_set_addresses(diva_os_xdi_adapter_t * a)
+{
+	a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 0;
+	a->resources.pci.mem_type_id[MEM_TYPE_CFG] = 1;
+	a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 2;
+	a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 1;
+	a->resources.pci.mem_type_id[MEM_TYPE_PORT] = 2;
+	a->resources.pci.mem_type_id[MEM_TYPE_CTLREG] = 2;
+	
+	a->xdi_adapter.ram = a->resources.pci.addr[0];
+	a->xdi_adapter.cfg = a->resources.pci.addr[1];
+	a->xdi_adapter.Address = a->resources.pci.addr[2];
+
+	a->xdi_adapter.reset = a->xdi_adapter.cfg;
+	a->xdi_adapter.port = a->xdi_adapter.Address;
+
+	a->xdi_adapter.ctlReg = a->xdi_adapter.port + M_PCI_RESET;
+
+	a->xdi_adapter.reset += 0x4C;	/* PLX 9050 !! */
+}
+
+/*
+**  BAR0 - MEM Addr  - 0x80  - NOT USED
+**  BAR1 - I/O Addr  - 0x80
+**  BAR2 - I/O Addr  - 0x20
+*/
+int diva_bri_init_card(diva_os_xdi_adapter_t * a)
+{
+	int bar;
+	dword bar2 = 0, bar2_length = 0xffffffff;
+	word cmd = 0, cmd_org;
+	byte Bus, Slot;
+	void *hdev;
+	byte __iomem *p;
+
+	/*
+	   Set properties
+	 */
+	a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
+	DBG_LOG(("Load %s", a->xdi_adapter.Properties.Name))
+
+	    /*
+	       Get resources
+	     */
+	    for (bar = 0; bar < 3; bar++) {
+		a->resources.pci.bar[bar] =
+		    divasa_get_pci_bar(a->resources.pci.bus,
+				       a->resources.pci.func, bar,
+				       a->resources.pci.hdev);
+		if (!a->resources.pci.bar[bar]) {
+			DBG_ERR(("A: can't get BAR[%d]", bar))
+			return (-1);
+		}
+	}
+
+	a->resources.pci.irq =
+	    (byte) divasa_get_pci_irq(a->resources.pci.bus,
+				      a->resources.pci.func,
+				      a->resources.pci.hdev);
+	if (!a->resources.pci.irq) {
+		DBG_ERR(("A: invalid irq"));
+		return (-1);
+	}
+
+	/*
+	   Get length of I/O bar 2 - it is different by older
+	   EEPROM version
+	 */
+	Bus = a->resources.pci.bus;
+	Slot = a->resources.pci.func;
+	hdev = a->resources.pci.hdev;
+
+	/*
+	   Get plain original values of the BAR2 CDM registers
+	 */
+	PCIread(Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev);
+	PCIread(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
+	/*
+	   Disable device and get BAR2 length
+	 */
+	PCIwrite(Bus, Slot, 0x04, &cmd, sizeof(cmd), hdev);
+	PCIwrite(Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev);
+	PCIread(Bus, Slot, 0x18, &bar2_length, sizeof(bar2_length), hdev);
+	/*
+	   Restore BAR2 and CMD registers
+	 */
+	PCIwrite(Bus, Slot, 0x18, &bar2, sizeof(bar2), hdev);
+	PCIwrite(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
+
+	/*
+	   Calculate BAR2 length
+	 */
+	bar2_length = (~(bar2_length & ~7)) + 1;
+	DBG_LOG(("BAR[2] length=%lx", bar2_length))
+
+	    /*
+	       Map and register resources
+	     */
+	    if (!(a->resources.pci.addr[0] =
+		 divasa_remap_pci_bar(a, 0, a->resources.pci.bar[0],
+				      bri_bar_length[0]))) {
+		DBG_ERR(("A: BRI, can't map BAR[0]"))
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+
+	sprintf(&a->port_name[0], "BRI %02x:%02x",
+		a->resources.pci.bus, a->resources.pci.func);
+
+	if (diva_os_register_io_port(a, 1, a->resources.pci.bar[1],
+				     bri_bar_length[1], &a->port_name[0], 1)) {
+		DBG_ERR(("A: BRI, can't register BAR[1]"))
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+	a->resources.pci.addr[1] = (void *) (unsigned long) a->resources.pci.bar[1];
+	a->resources.pci.length[1] = bri_bar_length[1];
+
+	if (diva_os_register_io_port(a, 1, a->resources.pci.bar[2],
+				     bar2_length, &a->port_name[0], 2)) {
+		DBG_ERR(("A: BRI, can't register BAR[2]"))
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+	a->resources.pci.addr[2] = (void *) (unsigned long) a->resources.pci.bar[2];
+	a->resources.pci.length[2] = bar2_length;
+
+	/*
+	   Set all memory areas
+	 */
+	diva_bri_set_addresses(a);
+
+	/*
+	   Get Serial Number
+	 */
+	a->xdi_adapter.serialNo = diva_bri_get_serial_number(a);
+
+	/*
+	   Register I/O ports with correct name now
+	 */
+	if (diva_bri_reregister_io(a)) {
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+
+	/*
+	   Initialize OS dependent objects
+	 */
+	if (diva_os_initialize_spin_lock
+	    (&a->xdi_adapter.isr_spin_lock, "isr")) {
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+	if (diva_os_initialize_spin_lock
+	    (&a->xdi_adapter.data_spin_lock, "data")) {
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+
+	strcpy(a->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivasbrid");
+
+	if (diva_os_initialize_soft_isr(&a->xdi_adapter.req_soft_isr,
+					DIDpcRoutine, &a->xdi_adapter)) {
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+	/*
+	   Do not initialize second DPC - only one thread will be created
+	 */
+	a->xdi_adapter.isr_soft_isr.object = a->xdi_adapter.req_soft_isr.object;
+
+	/*
+	   Create entity table
+	 */
+	a->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels;
+	a->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info;
+	a->xdi_adapter.e_tbl = diva_os_malloc(0, a->xdi_adapter.e_max * sizeof(E_INFO));
+	if (!a->xdi_adapter.e_tbl) {
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+	memset(a->xdi_adapter.e_tbl, 0x00, a->xdi_adapter.e_max * sizeof(E_INFO));
+
+	/*
+	   Set up interface
+	 */
+	a->xdi_adapter.a.io = &a->xdi_adapter;
+	a->xdi_adapter.DIRequest = request;
+	a->interface.cleanup_adapter_proc = diva_bri_cleanup_adapter;
+	a->interface.cmd_proc = diva_bri_cmd_card_proc;
+
+	p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
+	outpp(p, 0x41);
+	DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
+
+	prepare_maestra_functions(&a->xdi_adapter);
+
+	a->dsp_mask = 0x00000003;
+
+	/*
+	   Set IRQ handler
+	 */
+	a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
+	sprintf(a->xdi_adapter.irq_info.irq_name, "DIVA BRI %ld",
+		(long) a->xdi_adapter.serialNo);
+	if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr,
+				 a->xdi_adapter.irq_info.irq_name)) {
+		diva_bri_cleanup_adapter(a);
+		return (-1);
+	}
+	a->xdi_adapter.irq_info.registered = 1;
+
+	diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
+		      a->resources.pci.irq, a->xdi_adapter.serialNo);
+
+	return (0);
+}
+
+
+static int diva_bri_cleanup_adapter(diva_os_xdi_adapter_t * a)
+{
+	int i;
+
+	if (a->xdi_adapter.Initialized) {
+		diva_bri_stop_adapter(a);
+	}
+
+	/*
+	   Remove ISR Handler
+	 */
+	if (a->xdi_adapter.irq_info.registered) {
+		diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr);
+	}
+	a->xdi_adapter.irq_info.registered = 0;
+
+	if (a->resources.pci.addr[0] && a->resources.pci.bar[0]) {
+		divasa_unmap_pci_bar(a->resources.pci.addr[0]);
+		a->resources.pci.addr[0] = NULL;
+		a->resources.pci.bar[0] = 0;
+	}
+
+	for (i = 1; i < 3; i++) {
+		if (a->resources.pci.addr[i] && a->resources.pci.bar[i]) {
+			diva_os_register_io_port(a, 0,
+						 a->resources.pci.bar[i],
+						 a->resources.pci.
+						 length[i],
+						 &a->port_name[0], i);
+			a->resources.pci.addr[i] = NULL;
+			a->resources.pci.bar[i] = 0;
+		}
+	}
+
+	/*
+	   Free OS objects
+	 */
+	diva_os_cancel_soft_isr(&a->xdi_adapter.req_soft_isr);
+	diva_os_cancel_soft_isr(&a->xdi_adapter.isr_soft_isr);
+
+	diva_os_remove_soft_isr(&a->xdi_adapter.req_soft_isr);
+	a->xdi_adapter.isr_soft_isr.object = NULL;
+
+	diva_os_destroy_spin_lock(&a->xdi_adapter.isr_spin_lock, "rm");
+	diva_os_destroy_spin_lock(&a->xdi_adapter.data_spin_lock, "rm");
+
+	/*
+	   Free memory
+	 */
+	if (a->xdi_adapter.e_tbl) {
+		diva_os_free(0, a->xdi_adapter.e_tbl);
+		a->xdi_adapter.e_tbl = NULL;
+	}
+
+	return (0);
+}
+
+void diva_os_prepare_maestra_functions(PISDN_ADAPTER IoAdapter)
+{
+}
+
+/*
+**  Get serial number
+*/
+static dword diva_bri_get_serial_number(diva_os_xdi_adapter_t * a)
+{
+	dword serNo = 0;
+	byte __iomem *confIO;
+	word serHi, serLo;
+	word __iomem *confMem;
+
+	confIO = DIVA_OS_MEM_ATTACH_CFG(&a->xdi_adapter);
+	serHi = (word) (inppw(&confIO[0x22]) & 0x0FFF);
+	serLo = (word) (inppw(&confIO[0x26]) & 0x0FFF);
+	serNo = ((dword) serHi << 16) | (dword) serLo;
+	DIVA_OS_MEM_DETACH_CFG(&a->xdi_adapter, confIO);
+
+	if ((serNo == 0) || (serNo == 0xFFFFFFFF)) {
+		DBG_FTL(("W: BRI use BAR[0] to get card serial number"))
+
+		confMem = (word __iomem *)DIVA_OS_MEM_ATTACH_RAM(&a->xdi_adapter);
+		serHi = (word) (READ_WORD(&confMem[0x11]) & 0x0FFF);
+		serLo = (word) (READ_WORD(&confMem[0x13]) & 0x0FFF);
+		serNo = (((dword) serHi) << 16) | ((dword) serLo);
+		DIVA_OS_MEM_DETACH_RAM(&a->xdi_adapter, confMem);
+	}
+
+	DBG_LOG(("Serial Number=%ld", serNo))
+
+	return (serNo);
+}
+
+/*
+**  Unregister I/O and register it with new name,
+**  based on Serial Number
+*/
+static int diva_bri_reregister_io(diva_os_xdi_adapter_t * a)
+{
+	int i;
+
+	for (i = 1; i < 3; i++) {
+		diva_os_register_io_port(a, 0, a->resources.pci.bar[i],
+					 a->resources.pci.length[i],
+					 &a->port_name[0], i);
+		a->resources.pci.addr[i] = NULL;
+	}
+
+	sprintf(a->port_name, "DIVA BRI %ld",
+		(long) a->xdi_adapter.serialNo);
+
+	for (i = 1; i < 3; i++) {
+		if (diva_os_register_io_port(a, 1, a->resources.pci.bar[i],
+					     a->resources.pci.length[i],
+					     &a->port_name[0], i)) {
+			DBG_ERR(("A: failed to reregister BAR[%d]", i))
+			return (-1);
+		}
+		a->resources.pci.addr[i] =
+		    (void *) (unsigned long) a->resources.pci.bar[i];
+	}
+
+	return (0);
+}
+
+/*
+**  Process command from user mode
+*/
+static int
+diva_bri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
+		       diva_xdi_um_cfg_cmd_t * cmd, int length)
+{
+	int ret = -1;
+
+	if (cmd->adapter != a->controller) {
+		DBG_ERR(("A: pri_cmd, invalid controller=%d != %d",
+			 cmd->adapter, a->controller))
+		return (-1);
+	}
+
+	switch (cmd->command) {
+	case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
+		a->xdi_mbox.data_length = sizeof(dword);
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			*(dword *) a->xdi_mbox.data =
+			    (dword) a->CardOrdinal;
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
+		a->xdi_mbox.data_length = sizeof(dword);
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			*(dword *) a->xdi_mbox.data =
+			    (dword) a->xdi_adapter.serialNo;
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
+		a->xdi_mbox.data_length = sizeof(dword) * 9;
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			int i;
+			dword *data = (dword *) a->xdi_mbox.data;
+
+			for (i = 0; i < 8; i++) {
+				*data++ = a->resources.pci.bar[i];
+			}
+			*data++ = (dword) a->resources.pci.irq;
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_CARD_STATE:
+		a->xdi_mbox.data_length = sizeof(dword);
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			dword *data = (dword *) a->xdi_mbox.data;
+			if (!a->xdi_adapter.port) {
+				*data = 3;
+			} else if (a->xdi_adapter.trapped) {
+				*data = 2;
+			} else if (a->xdi_adapter.Initialized) {
+				*data = 1;
+			} else {
+				*data = 0;
+			}
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_RESET_ADAPTER:
+		ret = diva_bri_reset_adapter(&a->xdi_adapter);
+		break;
+
+	case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
+		ret = diva_bri_write_sdram_block(&a->xdi_adapter,
+						 cmd->command_data.
+						 write_sdram.offset,
+						 (byte *) & cmd[1],
+						 cmd->command_data.
+						 write_sdram.length);
+		break;
+
+	case DIVA_XDI_UM_CMD_START_ADAPTER:
+		ret = diva_bri_start_adapter(&a->xdi_adapter,
+					     cmd->command_data.start.
+					     offset,
+					     cmd->command_data.start.
+					     features);
+		break;
+
+	case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
+		a->xdi_adapter.features =
+		    cmd->command_data.features.features;
+		a->xdi_adapter.a.protocol_capabilities =
+		    a->xdi_adapter.features;
+		DBG_TRC(
+			("Set raw protocol features (%08x)",
+			 a->xdi_adapter.features)) ret = 0;
+		break;
+
+	case DIVA_XDI_UM_CMD_STOP_ADAPTER:
+		ret = diva_bri_stop_adapter(a);
+		break;
+
+	case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
+		ret = diva_card_read_xlog(a);
+		break;
+
+	default:
+		DBG_ERR(
+			("A: A(%d) invalid cmd=%d", a->controller,
+			 cmd->command))}
+
+	return (ret);
+}
+
+static int diva_bri_reset_adapter(PISDN_ADAPTER IoAdapter)
+{
+	byte __iomem *addrHi, *addrLo, *ioaddr;
+	dword i;
+	byte __iomem *Port;
+
+	if (!IoAdapter->port) {
+		return (-1);
+	}
+	if (IoAdapter->Initialized) {
+		DBG_ERR(("A: A(%d) can't reset BRI adapter - please stop first",
+			 IoAdapter->ANum)) return (-1);
+	}
+	(*(IoAdapter->rstFnc)) (IoAdapter);
+	diva_os_wait(100);
+	Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
+	addrHi = Port +
+	    ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
+	addrLo = Port + ADDR;
+	ioaddr = Port + DATA;
+	/*
+	   recover
+	 */
+	outpp(addrHi, (byte) 0);
+	outppw(addrLo, (word) 0);
+	outppw(ioaddr, (word) 0);
+	/*
+	   clear shared memory
+	 */
+	outpp(addrHi,
+	      (byte) (
+		      (IoAdapter->MemoryBase + IoAdapter->MemorySize -
+		       BRI_SHARED_RAM_SIZE) >> 16));
+	outppw(addrLo, 0);
+	for (i = 0; i < 0x8000; outppw(ioaddr, 0), ++i);
+	diva_os_wait(100);
+
+	/*
+	   clear signature
+	 */
+	outpp(addrHi,
+	      (byte) (
+		      (IoAdapter->MemoryBase + IoAdapter->MemorySize -
+		       BRI_SHARED_RAM_SIZE) >> 16));
+	outppw(addrLo, 0x1e);
+	outpp(ioaddr, 0);
+	outpp(ioaddr, 0);
+
+	outpp(addrHi, (byte) 0);
+	outppw(addrLo, (word) 0);
+	outppw(ioaddr, (word) 0);
+
+	DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
+
+	/*
+	   Forget all outstanding entities
+	 */
+	IoAdapter->e_count = 0;
+	if (IoAdapter->e_tbl) {
+		memset(IoAdapter->e_tbl, 0x00,
+		       IoAdapter->e_max * sizeof(E_INFO));
+	}
+	IoAdapter->head = 0;
+	IoAdapter->tail = 0;
+	IoAdapter->assign = 0;
+	IoAdapter->trapped = 0;
+
+	memset(&IoAdapter->a.IdTable[0], 0x00,
+	       sizeof(IoAdapter->a.IdTable));
+	memset(&IoAdapter->a.IdTypeTable[0], 0x00,
+	       sizeof(IoAdapter->a.IdTypeTable));
+	memset(&IoAdapter->a.FlowControlIdTable[0], 0x00,
+	       sizeof(IoAdapter->a.FlowControlIdTable));
+	memset(&IoAdapter->a.FlowControlSkipTable[0], 0x00,
+	       sizeof(IoAdapter->a.FlowControlSkipTable));
+	memset(&IoAdapter->a.misc_flags_table[0], 0x00,
+	       sizeof(IoAdapter->a.misc_flags_table));
+	memset(&IoAdapter->a.rx_stream[0], 0x00,
+	       sizeof(IoAdapter->a.rx_stream));
+	memset(&IoAdapter->a.tx_stream[0], 0x00,
+	       sizeof(IoAdapter->a.tx_stream));
+	memset(&IoAdapter->a.tx_pos[0], 0x00, sizeof(IoAdapter->a.tx_pos));
+	memset(&IoAdapter->a.rx_pos[0], 0x00, sizeof(IoAdapter->a.rx_pos));
+
+	return (0);
+}
+
+static int
+diva_bri_write_sdram_block(PISDN_ADAPTER IoAdapter,
+			   dword address, const byte * data, dword length)
+{
+	byte __iomem *addrHi, *addrLo, *ioaddr;
+	byte __iomem *Port;
+
+	if (!IoAdapter->port) {
+		return (-1);
+	}
+
+	Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
+	addrHi = Port +
+	    ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
+	addrLo = Port + ADDR;
+	ioaddr = Port + DATA;
+
+	while (length--) {
+		outpp(addrHi, (word) (address >> 16));
+		outppw(addrLo, (word) (address & 0x0000ffff));
+		outpp(ioaddr, *data++);
+		address++;
+	}
+
+	DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
+	return (0);
+}
+
+static int
+diva_bri_start_adapter(PISDN_ADAPTER IoAdapter,
+		       dword start_address, dword features)
+{
+	byte __iomem *Port;
+	dword i, test;
+	byte __iomem *addrHi, *addrLo, *ioaddr;
+	int started = 0;
+	ADAPTER *a = &IoAdapter->a;
+
+	if (IoAdapter->Initialized) {
+		DBG_ERR(
+			("A: A(%d) bri_start_adapter, adapter already running",
+			 IoAdapter->ANum)) return (-1);
+	}
+	if (!IoAdapter->port) {
+		DBG_ERR(("A: A(%d) bri_start_adapter, adapter not mapped",
+			 IoAdapter->ANum)) return (-1);
+	}
+
+	sprintf(IoAdapter->Name, "A(%d)", (int) IoAdapter->ANum);
+	DBG_LOG(("A(%d) start BRI", IoAdapter->ANum))
+
+	Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
+	addrHi = Port +
+	    ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
+	addrLo = Port + ADDR;
+	ioaddr = Port + DATA;
+
+	outpp(addrHi,
+	      (byte) (
+		      (IoAdapter->MemoryBase + IoAdapter->MemorySize -
+		       BRI_SHARED_RAM_SIZE) >> 16));
+	outppw(addrLo, 0x1e);
+	outppw(ioaddr, 0x00);
+	DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
+
+	/*
+	   start the protocol code
+	 */
+	Port = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+	outpp(Port, 0x08);
+	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, Port);
+
+	Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
+	addrHi = Port +
+	    ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH);
+	addrLo = Port + ADDR;
+	ioaddr = Port + DATA;
+	/*
+	   wait for signature (max. 3 seconds)
+	 */
+	for (i = 0; i < 300; ++i) {
+		diva_os_wait(10);
+		outpp(addrHi,
+		      (byte) (
+			      (IoAdapter->MemoryBase +
+			       IoAdapter->MemorySize -
+			       BRI_SHARED_RAM_SIZE) >> 16));
+		outppw(addrLo, 0x1e);
+		test = (dword) inppw(ioaddr);
+		if (test == 0x4447) {
+			DBG_LOG(
+				("Protocol startup time %d.%02d seconds",
+				 (i / 100), (i % 100)))
+			started = 1;
+			break;
+		}
+	}
+	DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
+
+	if (!started) {
+		DBG_FTL(("A: A(%d) %s: Adapter selftest failed 0x%04X",
+			 IoAdapter->ANum, IoAdapter->Properties.Name,
+			 test))
+		(*(IoAdapter->trapFnc)) (IoAdapter);
+		return (-1);
+	}
+
+	IoAdapter->Initialized = 1;
+
+	/*
+	   Check Interrupt
+	 */
+	IoAdapter->IrqCount = 0;
+	a->ReadyInt = 1;
+
+	if (IoAdapter->reset) {
+		Port = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+		outpp(Port, 0x41);
+		DIVA_OS_MEM_DETACH_RESET(IoAdapter, Port);
+	}
+
+	a->ram_out(a, &PR_RAM->ReadyInt, 1);
+	for (i = 0; ((!IoAdapter->IrqCount) && (i < 100)); i++) {
+		diva_os_wait(10);
+	}
+	if (!IoAdapter->IrqCount) {
+		DBG_ERR(
+			("A: A(%d) interrupt test failed",
+			 IoAdapter->ANum))
+		IoAdapter->Initialized = 0;
+		IoAdapter->stop(IoAdapter);
+		return (-1);
+	}
+
+	IoAdapter->Properties.Features = (word) features;
+	diva_xdi_display_adapter_features(IoAdapter->ANum);
+	DBG_LOG(("A(%d) BRI adapter successfull started", IoAdapter->ANum))
+	    /*
+	       Register with DIDD
+	     */
+	diva_xdi_didd_register_adapter(IoAdapter->ANum);
+
+	return (0);
+}
+
+static void diva_bri_clear_interrupts(diva_os_xdi_adapter_t * a)
+{
+	PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+
+	/*
+	   clear any pending interrupt
+	 */
+	IoAdapter->disIrq(IoAdapter);
+
+	IoAdapter->tst_irq(&IoAdapter->a);
+	IoAdapter->clr_irq(&IoAdapter->a);
+	IoAdapter->tst_irq(&IoAdapter->a);
+
+	/*
+	   kill pending dpcs
+	 */
+	diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
+	diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
+}
+
+/*
+**  Stop card
+*/
+static int diva_bri_stop_adapter(diva_os_xdi_adapter_t * a)
+{
+	PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+	int i = 100;
+
+	if (!IoAdapter->port) {
+		return (-1);
+	}
+	if (!IoAdapter->Initialized) {
+		DBG_ERR(("A: A(%d) can't stop BRI adapter - not running",
+			 IoAdapter->ANum))
+		return (-1);	/* nothing to stop */
+	}
+	IoAdapter->Initialized = 0;
+
+	/*
+	   Disconnect Adapter from DIDD
+	 */
+	diva_xdi_didd_remove_adapter(IoAdapter->ANum);
+
+	/*
+	   Stop interrupts
+	 */
+	a->clear_interrupts_proc = diva_bri_clear_interrupts;
+	IoAdapter->a.ReadyInt = 1;
+	IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
+	do {
+		diva_os_sleep(10);
+	} while (i-- && a->clear_interrupts_proc);
+	if (a->clear_interrupts_proc) {
+		diva_bri_clear_interrupts(a);
+		a->clear_interrupts_proc = NULL;
+		DBG_ERR(("A: A(%d) no final interrupt from BRI adapter",
+			 IoAdapter->ANum))
+	}
+	IoAdapter->a.ReadyInt = 0;
+
+	/*
+	   Stop and reset adapter
+	 */
+	IoAdapter->stop(IoAdapter);
+
+	return (0);
+}
diff --git a/drivers/isdn/hardware/eicon/os_bri.h b/drivers/isdn/hardware/eicon/os_bri.h
new file mode 100644
index 0000000..a54f0ce
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_bri.h
@@ -0,0 +1,8 @@
+/* $Id: os_bri.h,v 1.1.2.2 2001/02/08 12:25:44 armin Exp $ */
+
+#ifndef __DIVA_OS_BRI_REV_1_H__
+#define __DIVA_OS_BRI_REV_1_H__
+
+int diva_bri_init_card(diva_os_xdi_adapter_t * a);
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/os_capi.h b/drivers/isdn/hardware/eicon/os_capi.h
new file mode 100644
index 0000000..726f915
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_capi.h
@@ -0,0 +1,21 @@
+/* $Id: os_capi.h,v 1.7 2003/04/12 21:40:49 schindler Exp $
+ *
+ * ISDN interface module for Eicon active cards DIVA.
+ * CAPI Interface OS include files 
+ * 
+ * Copyright 2000-2003 by Armin Schindler (mac@melware.de) 
+ * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef __OS_CAPI_H__ 
+#define __OS_CAPI_H__
+
+#include <linux/capi.h>
+#include <linux/kernelcapi.h>
+#include <linux/isdn/capiutil.h>
+#include <linux/isdn/capilli.h>
+
+#endif /* __OS_CAPI_H__ */
diff --git a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c
new file mode 100644
index 0000000..8ac207f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_pri.c
@@ -0,0 +1,1051 @@
+/* $Id: os_pri.c,v 1.32 2004/03/21 17:26:01 armin Exp $ */
+
+#include "platform.h"
+#include "debuglib.h"
+#include "cardtype.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di_defs.h"
+#include "dsp_defs.h"
+#include "di.h"
+#include "io.h"
+
+#include "xdi_msg.h"
+#include "xdi_adapter.h"
+#include "os_pri.h"
+#include "diva_pci.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+#include "dsp_tst.h"
+#include "diva_dma.h"
+
+/* --------------------------------------------------------------------------
+   OS Dependent part of XDI driver for DIVA PRI Adapter
+
+   DSP detection/validation by Anthony Booth (Eicon Networks, www.eicon.com)
+-------------------------------------------------------------------------- */
+
+#define DIVA_PRI_NO_PCI_BIOS_WORKAROUND 1
+
+extern int diva_card_read_xlog(diva_os_xdi_adapter_t * a);
+
+/*
+**  IMPORTS
+*/
+extern void prepare_pri_functions(PISDN_ADAPTER IoAdapter);
+extern void prepare_pri2_functions(PISDN_ADAPTER IoAdapter);
+extern void diva_xdi_display_adapter_features(int card);
+
+static int diva_pri_cleanup_adapter(diva_os_xdi_adapter_t * a);
+static int diva_pri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
+				  diva_xdi_um_cfg_cmd_t * cmd, int length);
+static int pri_get_serial_number(diva_os_xdi_adapter_t * a);
+static int diva_pri_stop_adapter(diva_os_xdi_adapter_t * a);
+static dword diva_pri_detect_dsps(diva_os_xdi_adapter_t * a);
+
+/*
+**  Check card revision
+*/
+static int pri_is_rev_2_card(int card_ordinal)
+{
+	switch (card_ordinal) {
+	case CARDTYPE_DIVASRV_P_30M_V2_PCI:
+	case CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI:
+		return (1);
+	}
+	return (0);
+}
+
+static void diva_pri_set_addresses(diva_os_xdi_adapter_t * a)
+{
+	a->resources.pci.mem_type_id[MEM_TYPE_ADDRESS] = 0;
+	a->resources.pci.mem_type_id[MEM_TYPE_CONTROL] = 2;
+	a->resources.pci.mem_type_id[MEM_TYPE_CONFIG] = 4;
+	a->resources.pci.mem_type_id[MEM_TYPE_RAM] = 0;
+	a->resources.pci.mem_type_id[MEM_TYPE_RESET] = 2;
+	a->resources.pci.mem_type_id[MEM_TYPE_CFG] = 4;
+	a->resources.pci.mem_type_id[MEM_TYPE_PROM] = 3;
+	
+	a->xdi_adapter.Address = a->resources.pci.addr[0];
+	a->xdi_adapter.Control = a->resources.pci.addr[2];
+	a->xdi_adapter.Config = a->resources.pci.addr[4];
+
+	a->xdi_adapter.ram = a->resources.pci.addr[0];
+	a->xdi_adapter.ram += MP_SHARED_RAM_OFFSET;
+
+	a->xdi_adapter.reset = a->resources.pci.addr[2];
+	a->xdi_adapter.reset += MP_RESET;
+
+	a->xdi_adapter.cfg = a->resources.pci.addr[4];
+	a->xdi_adapter.cfg += MP_IRQ_RESET;
+
+	a->xdi_adapter.sdram_bar = a->resources.pci.bar[0];
+
+	a->xdi_adapter.prom = a->resources.pci.addr[3];
+}
+
+/*
+**  BAR0 - SDRAM, MP_MEMORY_SIZE, MP2_MEMORY_SIZE by Rev.2
+**  BAR1 - DEVICES,				0x1000
+**  BAR2 - CONTROL (REG), 0x2000
+**  BAR3 - FLASH (REG),		0x8000
+**  BAR4 - CONFIG (CFG),	0x1000
+*/
+int diva_pri_init_card(diva_os_xdi_adapter_t * a)
+{
+	int bar = 0;
+	int pri_rev_2;
+	unsigned long bar_length[5] = {
+		MP_MEMORY_SIZE,
+		0x1000,
+		0x2000,
+		0x8000,
+		0x1000
+	};
+
+	pri_rev_2 = pri_is_rev_2_card(a->CardOrdinal);
+
+	if (pri_rev_2) {
+		bar_length[0] = MP2_MEMORY_SIZE;
+	}
+	/*
+	   Set properties
+	 */
+	a->xdi_adapter.Properties = CardProperties[a->CardOrdinal];
+	DBG_LOG(("Load %s", a->xdi_adapter.Properties.Name))
+
+	/*
+	   First initialization step: get and check hardware resoures.
+	   Do not map resources and do not acecess card at this step
+	 */
+	for (bar = 0; bar < 5; bar++) {
+		a->resources.pci.bar[bar] =
+		    divasa_get_pci_bar(a->resources.pci.bus,
+				       a->resources.pci.func, bar,
+				       a->resources.pci.hdev);
+		if (!a->resources.pci.bar[bar]
+		    || (a->resources.pci.bar[bar] == 0xFFFFFFF0)) {
+			DBG_ERR(("A: invalid bar[%d]=%08x", bar,
+				 a->resources.pci.bar[bar]))
+			return (-1);
+		}
+	}
+	a->resources.pci.irq =
+	    (byte) divasa_get_pci_irq(a->resources.pci.bus,
+				      a->resources.pci.func,
+				      a->resources.pci.hdev);
+	if (!a->resources.pci.irq) {
+		DBG_ERR(("A: invalid irq"));
+		return (-1);
+	}
+
+	/*
+	   Map all BAR's
+	 */
+	for (bar = 0; bar < 5; bar++) {
+		a->resources.pci.addr[bar] =
+		    divasa_remap_pci_bar(a, bar, a->resources.pci.bar[bar],
+					 bar_length[bar]);
+		if (!a->resources.pci.addr[bar]) {
+			DBG_ERR(("A: A(%d), can't map bar[%d]",
+				 a->controller, bar))
+			diva_pri_cleanup_adapter(a);
+			return (-1);
+		}
+	}
+
+	/*
+	   Set all memory areas
+	 */
+	diva_pri_set_addresses(a);
+
+	/*
+	   Get Serial Number of this adapter
+	 */
+	if (pri_get_serial_number(a)) {
+		dword serNo;
+		serNo = a->resources.pci.bar[1] & 0xffff0000;
+		serNo |= ((dword) a->resources.pci.bus) << 8;
+		serNo += (a->resources.pci.func + a->controller + 1);
+		a->xdi_adapter.serialNo = serNo & ~0xFF000000;
+		DBG_ERR(("A: A(%d) can't get Serial Number, generated serNo=%ld",
+			 a->controller, a->xdi_adapter.serialNo))
+	}
+
+
+	/*
+	   Initialize os objects
+	 */
+	if (diva_os_initialize_spin_lock(&a->xdi_adapter.isr_spin_lock, "isr")) {
+		diva_pri_cleanup_adapter(a);
+		return (-1);
+	}
+	if (diva_os_initialize_spin_lock
+	    (&a->xdi_adapter.data_spin_lock, "data")) {
+		diva_pri_cleanup_adapter(a);
+		return (-1);
+	}
+
+	strcpy(a->xdi_adapter.req_soft_isr.dpc_thread_name, "kdivasprid");
+
+	if (diva_os_initialize_soft_isr(&a->xdi_adapter.req_soft_isr,
+					DIDpcRoutine, &a->xdi_adapter)) {
+		diva_pri_cleanup_adapter(a);
+		return (-1);
+	}
+
+	/*
+	   Do not initialize second DPC - only one thread will be created
+	 */
+	a->xdi_adapter.isr_soft_isr.object =
+	    a->xdi_adapter.req_soft_isr.object;
+
+	/*
+	   Next step of card initialization:
+	   set up all interface pointers
+	 */
+	a->xdi_adapter.Channels = CardProperties[a->CardOrdinal].Channels;
+	a->xdi_adapter.e_max = CardProperties[a->CardOrdinal].E_info;
+
+	a->xdi_adapter.e_tbl =
+	    diva_os_malloc(0, a->xdi_adapter.e_max * sizeof(E_INFO));
+	if (!a->xdi_adapter.e_tbl) {
+		diva_pri_cleanup_adapter(a);
+		return (-1);
+	}
+	memset(a->xdi_adapter.e_tbl, 0x00, a->xdi_adapter.e_max * sizeof(E_INFO));
+
+	a->xdi_adapter.a.io = &a->xdi_adapter;
+	a->xdi_adapter.DIRequest = request;
+	a->interface.cleanup_adapter_proc = diva_pri_cleanup_adapter;
+	a->interface.cmd_proc = diva_pri_cmd_card_proc;
+
+	if (pri_rev_2) {
+		prepare_pri2_functions(&a->xdi_adapter);
+	} else {
+		prepare_pri_functions(&a->xdi_adapter);
+	}
+
+	a->dsp_mask = diva_pri_detect_dsps(a);
+
+	/*
+	   Allocate DMA map
+	 */
+	if (pri_rev_2) {
+		diva_init_dma_map(a->resources.pci.hdev,
+				  (struct _diva_dma_map_entry **) &a->xdi_adapter.dma_map, 32);
+	}
+
+	/*
+	   Set IRQ handler
+	 */
+	a->xdi_adapter.irq_info.irq_nr = a->resources.pci.irq;
+	sprintf(a->xdi_adapter.irq_info.irq_name,
+		"DIVA PRI %ld", (long) a->xdi_adapter.serialNo);
+
+	if (diva_os_register_irq(a, a->xdi_adapter.irq_info.irq_nr,
+				 a->xdi_adapter.irq_info.irq_name)) {
+		diva_pri_cleanup_adapter(a);
+		return (-1);
+	}
+	a->xdi_adapter.irq_info.registered = 1;
+
+	diva_log_info("%s IRQ:%d SerNo:%d", a->xdi_adapter.Properties.Name,
+		      a->resources.pci.irq, a->xdi_adapter.serialNo);
+
+	return (0);
+}
+
+static int diva_pri_cleanup_adapter(diva_os_xdi_adapter_t * a)
+{
+	int bar = 0;
+
+	/*
+	   Stop Adapter if adapter is running
+	 */
+	if (a->xdi_adapter.Initialized) {
+		diva_pri_stop_adapter(a);
+	}
+
+	/*
+	   Remove ISR Handler
+	 */
+	if (a->xdi_adapter.irq_info.registered) {
+		diva_os_remove_irq(a, a->xdi_adapter.irq_info.irq_nr);
+	}
+	a->xdi_adapter.irq_info.registered = 0;
+
+	/*
+	   Step 1: unmap all BAR's, if any was mapped
+	 */
+	for (bar = 0; bar < 5; bar++) {
+		if (a->resources.pci.bar[bar]
+		    && a->resources.pci.addr[bar]) {
+			divasa_unmap_pci_bar(a->resources.pci.addr[bar]);
+			a->resources.pci.bar[bar] = 0;
+			a->resources.pci.addr[bar] = NULL;
+		}
+	}
+
+	/*
+	   Free OS objects
+	 */
+	diva_os_cancel_soft_isr(&a->xdi_adapter.isr_soft_isr);
+	diva_os_cancel_soft_isr(&a->xdi_adapter.req_soft_isr);
+
+	diva_os_remove_soft_isr(&a->xdi_adapter.req_soft_isr);
+	a->xdi_adapter.isr_soft_isr.object = NULL;
+
+	diva_os_destroy_spin_lock(&a->xdi_adapter.isr_spin_lock, "rm");
+	diva_os_destroy_spin_lock(&a->xdi_adapter.data_spin_lock, "rm");
+
+	/*
+	   Free memory accupied by XDI adapter
+	 */
+	if (a->xdi_adapter.e_tbl) {
+		diva_os_free(0, a->xdi_adapter.e_tbl);
+		a->xdi_adapter.e_tbl = NULL;
+	}
+	a->xdi_adapter.Channels = 0;
+	a->xdi_adapter.e_max = 0;
+
+
+	/*
+	   Free adapter DMA map
+	 */
+	diva_free_dma_map(a->resources.pci.hdev,
+			  (struct _diva_dma_map_entry *) a->xdi_adapter.
+			  dma_map);
+	a->xdi_adapter.dma_map = NULL;
+
+
+	/*
+	   Detach this adapter from debug driver
+	 */
+
+	return (0);
+}
+
+/*
+**  Activate On Board Boot Loader
+*/
+static int diva_pri_reset_adapter(PISDN_ADAPTER IoAdapter)
+{
+	dword i;
+	struct mp_load __iomem *boot;
+
+	if (!IoAdapter->Address || !IoAdapter->reset) {
+		return (-1);
+	}
+	if (IoAdapter->Initialized) {
+		DBG_ERR(("A: A(%d) can't reset PRI adapter - please stop first",
+			 IoAdapter->ANum))
+		return (-1);
+	}
+
+	boot = (struct mp_load __iomem *) DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
+	WRITE_DWORD(&boot->err, 0);
+	DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
+
+	IoAdapter->rstFnc(IoAdapter);
+
+	diva_os_wait(10);
+
+	boot = (struct mp_load __iomem *) DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
+	i = READ_DWORD(&boot->live);
+
+	diva_os_wait(10);
+	if (i == READ_DWORD(&boot->live)) {
+		DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
+		DBG_ERR(("A: A(%d) CPU on PRI %ld is not alive!",
+			 IoAdapter->ANum, IoAdapter->serialNo))
+		return (-1);
+	}
+	if (READ_DWORD(&boot->err)) {
+		DBG_ERR(("A: A(%d) PRI %ld Board Selftest failed, error=%08lx",
+			 IoAdapter->ANum, IoAdapter->serialNo,
+			 READ_DWORD(&boot->err)))
+		DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
+		return (-1);
+	}
+	DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
+
+	/*
+	   Forget all outstanding entities
+	 */
+	IoAdapter->e_count = 0;
+	if (IoAdapter->e_tbl) {
+		memset(IoAdapter->e_tbl, 0x00,
+		       IoAdapter->e_max * sizeof(E_INFO));
+	}
+	IoAdapter->head = 0;
+	IoAdapter->tail = 0;
+	IoAdapter->assign = 0;
+	IoAdapter->trapped = 0;
+
+	memset(&IoAdapter->a.IdTable[0], 0x00,
+	       sizeof(IoAdapter->a.IdTable));
+	memset(&IoAdapter->a.IdTypeTable[0], 0x00,
+	       sizeof(IoAdapter->a.IdTypeTable));
+	memset(&IoAdapter->a.FlowControlIdTable[0], 0x00,
+	       sizeof(IoAdapter->a.FlowControlIdTable));
+	memset(&IoAdapter->a.FlowControlSkipTable[0], 0x00,
+	       sizeof(IoAdapter->a.FlowControlSkipTable));
+	memset(&IoAdapter->a.misc_flags_table[0], 0x00,
+	       sizeof(IoAdapter->a.misc_flags_table));
+	memset(&IoAdapter->a.rx_stream[0], 0x00,
+	       sizeof(IoAdapter->a.rx_stream));
+	memset(&IoAdapter->a.tx_stream[0], 0x00,
+	       sizeof(IoAdapter->a.tx_stream));
+	memset(&IoAdapter->a.tx_pos[0], 0x00, sizeof(IoAdapter->a.tx_pos));
+	memset(&IoAdapter->a.rx_pos[0], 0x00, sizeof(IoAdapter->a.rx_pos));
+
+	return (0);
+}
+
+static int
+diva_pri_write_sdram_block(PISDN_ADAPTER IoAdapter,
+			   dword address,
+			   const byte * data, dword length, dword limit)
+{
+	byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
+	byte __iomem *mem = p;
+
+	if (((address + length) >= limit) || !mem) {
+		DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
+		DBG_ERR(("A: A(%d) write PRI address=0x%08lx",
+			 IoAdapter->ANum, address + length))
+		return (-1);
+	}
+	mem += address;
+
+	/* memcpy_toio(), maybe? */
+	while (length--) {
+		WRITE_BYTE(mem++, *data++);
+	}
+
+	DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, p);
+	return (0);
+}
+
+static int
+diva_pri_start_adapter(PISDN_ADAPTER IoAdapter,
+		       dword start_address, dword features)
+{
+	dword i;
+	int started = 0;
+	byte __iomem *p;
+	struct mp_load __iomem *boot = (struct mp_load __iomem *) DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
+	ADAPTER *a = &IoAdapter->a;
+
+	if (IoAdapter->Initialized) {
+		DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
+		DBG_ERR(("A: A(%d) pri_start_adapter, adapter already running",
+			 IoAdapter->ANum))
+		return (-1);
+	}
+	if (!boot) {
+		DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
+		DBG_ERR(("A: PRI %ld can't start, adapter not mapped",
+			 IoAdapter->serialNo))
+		return (-1);
+	}
+
+	sprintf(IoAdapter->Name, "A(%d)", (int) IoAdapter->ANum);
+	DBG_LOG(("A(%d) start PRI at 0x%08lx", IoAdapter->ANum,
+		 start_address))
+
+	WRITE_DWORD(&boot->addr, start_address);
+	WRITE_DWORD(&boot->cmd, 3);
+
+	for (i = 0; i < 300; ++i) {
+		diva_os_wait(10);
+		if ((READ_DWORD(&boot->signature) >> 16) == 0x4447) {
+			DBG_LOG(("A(%d) Protocol startup time %d.%02d seconds",
+				 IoAdapter->ANum, (i / 100), (i % 100)))
+			started = 1;
+			break;
+		}
+	}
+
+	if (!started) {
+		byte __iomem *p = (byte __iomem *)boot;
+		dword TrapId;
+		dword debug;
+		TrapId = READ_DWORD(&p[0x80]);
+		debug = READ_DWORD(&p[0x1c]);
+		DBG_ERR(("A(%d) Adapter start failed 0x%08lx, TrapId=%08lx, debug=%08lx",
+			 IoAdapter->ANum, READ_DWORD(&boot->signature),
+			 TrapId, debug))
+		DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
+		if (IoAdapter->trapFnc) {
+			(*(IoAdapter->trapFnc)) (IoAdapter);
+		}
+		IoAdapter->stop(IoAdapter);
+		return (-1);
+	}
+	DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
+
+	IoAdapter->Initialized = TRUE;
+
+	/*
+	   Check Interrupt
+	 */
+	IoAdapter->IrqCount = 0;
+	p = DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
+	WRITE_DWORD(p, (dword) ~ 0x03E00000);
+	DIVA_OS_MEM_DETACH_CFG(IoAdapter, p);
+	a->ReadyInt = 1;
+	a->ram_out(a, &PR_RAM->ReadyInt, 1);
+
+	for (i = 100; !IoAdapter->IrqCount && (i-- > 0); diva_os_wait(10));
+
+	if (!IoAdapter->IrqCount) {
+		DBG_ERR(("A: A(%d) interrupt test failed",
+			 IoAdapter->ANum))
+		IoAdapter->Initialized = FALSE;
+		IoAdapter->stop(IoAdapter);
+		return (-1);
+	}
+
+	IoAdapter->Properties.Features = (word) features;
+
+	diva_xdi_display_adapter_features(IoAdapter->ANum);
+
+	DBG_LOG(("A(%d) PRI adapter successfull started", IoAdapter->ANum))
+	/*
+	   Register with DIDD
+	 */
+	diva_xdi_didd_register_adapter(IoAdapter->ANum);
+
+	return (0);
+}
+
+static void diva_pri_clear_interrupts(diva_os_xdi_adapter_t * a)
+{
+	PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+
+	/*
+	   clear any pending interrupt
+	 */
+	IoAdapter->disIrq(IoAdapter);
+
+	IoAdapter->tst_irq(&IoAdapter->a);
+	IoAdapter->clr_irq(&IoAdapter->a);
+	IoAdapter->tst_irq(&IoAdapter->a);
+
+	/*
+	   kill pending dpcs
+	 */
+	diva_os_cancel_soft_isr(&IoAdapter->req_soft_isr);
+	diva_os_cancel_soft_isr(&IoAdapter->isr_soft_isr);
+}
+
+/*
+**  Stop Adapter, but do not unmap/unregister - adapter
+**  will be restarted later
+*/
+static int diva_pri_stop_adapter(diva_os_xdi_adapter_t * a)
+{
+	PISDN_ADAPTER IoAdapter = &a->xdi_adapter;
+	int i = 100;
+
+	if (!IoAdapter->ram) {
+		return (-1);
+	}
+	if (!IoAdapter->Initialized) {
+		DBG_ERR(("A: A(%d) can't stop PRI adapter - not running",
+			 IoAdapter->ANum))
+		return (-1);	/* nothing to stop */
+	}
+	IoAdapter->Initialized = 0;
+
+	/*
+	   Disconnect Adapter from DIDD
+	 */
+	diva_xdi_didd_remove_adapter(IoAdapter->ANum);
+
+	/*
+	   Stop interrupts
+	 */
+	a->clear_interrupts_proc = diva_pri_clear_interrupts;
+	IoAdapter->a.ReadyInt = 1;
+	IoAdapter->a.ram_inc(&IoAdapter->a, &PR_RAM->ReadyInt);
+	do {
+		diva_os_sleep(10);
+	} while (i-- && a->clear_interrupts_proc);
+
+	if (a->clear_interrupts_proc) {
+		diva_pri_clear_interrupts(a);
+		a->clear_interrupts_proc = NULL;
+		DBG_ERR(("A: A(%d) no final interrupt from PRI adapter",
+			 IoAdapter->ANum))
+	}
+	IoAdapter->a.ReadyInt = 0;
+
+	/*
+	   Stop and reset adapter
+	 */
+	IoAdapter->stop(IoAdapter);
+
+	return (0);
+}
+
+/*
+**  Process commands form configuration/download framework and from
+**  user mode
+**
+**  return 0 on success
+*/
+static int
+diva_pri_cmd_card_proc(struct _diva_os_xdi_adapter *a,
+		       diva_xdi_um_cfg_cmd_t * cmd, int length)
+{
+	int ret = -1;
+
+	if (cmd->adapter != a->controller) {
+		DBG_ERR(("A: pri_cmd, invalid controller=%d != %d",
+			 cmd->adapter, a->controller))
+		return (-1);
+	}
+
+	switch (cmd->command) {
+	case DIVA_XDI_UM_CMD_GET_CARD_ORDINAL:
+		a->xdi_mbox.data_length = sizeof(dword);
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			*(dword *) a->xdi_mbox.data =
+			    (dword) a->CardOrdinal;
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_SERIAL_NR:
+		a->xdi_mbox.data_length = sizeof(dword);
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			*(dword *) a->xdi_mbox.data =
+			    (dword) a->xdi_adapter.serialNo;
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG:
+		a->xdi_mbox.data_length = sizeof(dword) * 9;
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			int i;
+			dword *data = (dword *) a->xdi_mbox.data;
+
+			for (i = 0; i < 8; i++) {
+				*data++ = a->resources.pci.bar[i];
+			}
+			*data++ = (dword) a->resources.pci.irq;
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_RESET_ADAPTER:
+		ret = diva_pri_reset_adapter(&a->xdi_adapter);
+		break;
+
+	case DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK:
+		ret = diva_pri_write_sdram_block(&a->xdi_adapter,
+						 cmd->command_data.
+						 write_sdram.offset,
+						 (byte *) & cmd[1],
+						 cmd->command_data.
+						 write_sdram.length,
+						 pri_is_rev_2_card(a->
+								   CardOrdinal)
+						 ? MP2_MEMORY_SIZE :
+						 MP_MEMORY_SIZE);
+		break;
+
+	case DIVA_XDI_UM_CMD_STOP_ADAPTER:
+		ret = diva_pri_stop_adapter(a);
+		break;
+
+	case DIVA_XDI_UM_CMD_START_ADAPTER:
+		ret = diva_pri_start_adapter(&a->xdi_adapter,
+					     cmd->command_data.start.
+					     offset,
+					     cmd->command_data.start.
+					     features);
+		break;
+
+	case DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES:
+		a->xdi_adapter.features =
+		    cmd->command_data.features.features;
+		a->xdi_adapter.a.protocol_capabilities =
+		    a->xdi_adapter.features;
+		DBG_TRC(("Set raw protocol features (%08x)",
+			 a->xdi_adapter.features))
+		ret = 0;
+		break;
+
+	case DIVA_XDI_UM_CMD_GET_CARD_STATE:
+		a->xdi_mbox.data_length = sizeof(dword);
+		a->xdi_mbox.data =
+		    diva_os_malloc(0, a->xdi_mbox.data_length);
+		if (a->xdi_mbox.data) {
+			dword *data = (dword *) a->xdi_mbox.data;
+			if (!a->xdi_adapter.ram ||
+				!a->xdi_adapter.reset ||
+			    !a->xdi_adapter.cfg) {
+				*data = 3;
+			} else if (a->xdi_adapter.trapped) {
+				*data = 2;
+			} else if (a->xdi_adapter.Initialized) {
+				*data = 1;
+			} else {
+				*data = 0;
+			}
+			a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+			ret = 0;
+		}
+		break;
+
+	case DIVA_XDI_UM_CMD_READ_XLOG_ENTRY:
+		ret = diva_card_read_xlog(a);
+		break;
+
+	case DIVA_XDI_UM_CMD_READ_SDRAM:
+		if (a->xdi_adapter.Address) {
+			if (
+			    (a->xdi_mbox.data_length =
+			     cmd->command_data.read_sdram.length)) {
+				if (
+				    (a->xdi_mbox.data_length +
+				     cmd->command_data.read_sdram.offset) <
+				    a->xdi_adapter.MemorySize) {
+					a->xdi_mbox.data =
+					    diva_os_malloc(0,
+							   a->xdi_mbox.
+							   data_length);
+					if (a->xdi_mbox.data) {
+						byte __iomem *p = DIVA_OS_MEM_ATTACH_ADDRESS(&a->xdi_adapter);
+						byte __iomem *src = p;
+						byte *dst = a->xdi_mbox.data;
+						dword len = a->xdi_mbox.data_length;
+
+						src += cmd->command_data.read_sdram.offset;
+
+						while (len--) {
+							*dst++ = READ_BYTE(src++);
+						}
+						a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;
+						DIVA_OS_MEM_DETACH_ADDRESS(&a->xdi_adapter, p);
+						ret = 0;
+					}
+				}
+			}
+		}
+		break;
+
+	default:
+		DBG_ERR(("A: A(%d) invalid cmd=%d", a->controller,
+			 cmd->command))
+	}
+
+	return (ret);
+}
+
+/*
+**  Get Serial Number
+*/
+static int pri_get_serial_number(diva_os_xdi_adapter_t * a)
+{
+	byte data[64];
+	int i;
+	dword len = sizeof(data);
+	volatile byte __iomem *config;
+	volatile byte __iomem *flash;
+	byte c;
+
+/*
+ *  First set some GT6401x config registers before accessing the BOOT-ROM
+ */
+ 	config = DIVA_OS_MEM_ATTACH_CONFIG(&a->xdi_adapter);
+	c = READ_BYTE(&config[0xc3c]);
+	if (!(c & 0x08)) {
+		WRITE_BYTE(&config[0xc3c], c);	/* Base Address enable register */
+	}
+	WRITE_BYTE(&config[LOW_BOOTCS_DREG], 0x00);
+	WRITE_BYTE(&config[HI_BOOTCS_DREG], 0xFF);
+ 	DIVA_OS_MEM_DETACH_CONFIG(&a->xdi_adapter, config);
+/*
+ *  Read only the last 64 bytes of manufacturing data
+ */
+	memset(data, '\0', len);
+ 	flash = DIVA_OS_MEM_ATTACH_PROM(&a->xdi_adapter);
+	for (i = 0; i < len; i++) {
+		data[i] = READ_BYTE(&flash[0x8000 - len + i]);
+	}
+ 	DIVA_OS_MEM_DETACH_PROM(&a->xdi_adapter, flash);
+
+ 	config = DIVA_OS_MEM_ATTACH_CONFIG(&a->xdi_adapter);
+	WRITE_BYTE(&config[LOW_BOOTCS_DREG], 0xFC);	/* Disable FLASH EPROM access */
+	WRITE_BYTE(&config[HI_BOOTCS_DREG], 0xFF);
+ 	DIVA_OS_MEM_DETACH_CONFIG(&a->xdi_adapter, config);
+
+	if (memcmp(&data[48], "DIVAserverPR", 12)) {
+#if !defined(DIVA_PRI_NO_PCI_BIOS_WORKAROUND)	/* { */
+		word cmd = 0, cmd_org;
+		void *addr;
+		dword addr1, addr3, addr4;
+		byte Bus, Slot;
+		void *hdev;
+		addr4 = a->resources.pci.bar[4];
+		addr3 = a->resources.pci.bar[3];	/* flash  */
+		addr1 = a->resources.pci.bar[1];	/* unused */
+
+		DBG_ERR(("A: apply Compaq BIOS workaround"))
+		DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			     data[0], data[1], data[2], data[3],
+			     data[4], data[5], data[6], data[7]))
+
+		Bus = a->resources.pci.bus;
+		Slot = a->resources.pci.func;
+		hdev = a->resources.pci.hdev;
+		PCIread(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
+		PCIwrite(Bus, Slot, 0x04, &cmd, sizeof(cmd), hdev);
+
+		PCIwrite(Bus, Slot, 0x14, &addr4, sizeof(addr4), hdev);
+		PCIwrite(Bus, Slot, 0x20, &addr1, sizeof(addr1), hdev);
+
+		PCIwrite(Bus, Slot, 0x04, &cmd_org, sizeof(cmd_org), hdev);
+
+		addr = a->resources.pci.addr[1];
+		a->resources.pci.addr[1] = a->resources.pci.addr[4];
+		a->resources.pci.addr[4] = addr;
+
+		addr1 = a->resources.pci.bar[1];
+		a->resources.pci.bar[1] = a->resources.pci.bar[4];
+		a->resources.pci.bar[4] = addr1;
+
+		/*
+		   Try to read Flash again
+		 */
+		len = sizeof(data);
+
+ 		config = DIVA_OS_MEM_ATTACH_CONFIG(&a->xdi_adapter);
+		if (!(config[0xc3c] & 0x08)) {
+			config[0xc3c] |= 0x08;	/* Base Address enable register */
+		}
+		config[LOW_BOOTCS_DREG] = 0x00;
+		config[HI_BOOTCS_DREG] = 0xFF;
+ 		DIVA_OS_MEM_DETACH_CONFIG(&a->xdi_adapter, config);
+
+		memset(data, '\0', len);
+ 		flash = DIVA_OS_MEM_ATTACH_PROM(&a->xdi_adapter);
+		for (i = 0; i < len; i++) {
+			data[i] = flash[0x8000 - len + i];
+		}
+ 		DIVA_OS_MEM_ATTACH_PROM(&a->xdi_adapter, flash);
+ 		config = DIVA_OS_MEM_ATTACH_CONFIG(&a->xdi_adapter);
+		config[LOW_BOOTCS_DREG] = 0xFC;
+		config[HI_BOOTCS_DREG] = 0xFF;
+ 		DIVA_OS_MEM_DETACH_CONFIG(&a->xdi_adapter, config);
+
+		if (memcmp(&data[48], "DIVAserverPR", 12)) {
+			DBG_ERR(("A: failed to read serial number"))
+			DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+				     data[0], data[1], data[2], data[3],
+				     data[4], data[5], data[6], data[7]))
+			return (-1);
+		}
+#else				/* } { */
+		DBG_ERR(("A: failed to read DIVA signature word"))
+		DBG_LOG(("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			     data[0], data[1], data[2], data[3],
+			     data[4], data[5], data[6], data[7]))
+		DBG_LOG(("%02x:%02x:%02x:%02x", data[47], data[46],
+			     data[45], data[44]))
+#endif				/* } */
+	}
+
+	a->xdi_adapter.serialNo =
+	    (data[47] << 24) | (data[46] << 16) | (data[45] << 8) |
+	    data[44];
+	if (!a->xdi_adapter.serialNo
+	    || (a->xdi_adapter.serialNo == 0xffffffff)) {
+		a->xdi_adapter.serialNo = 0;
+		DBG_ERR(("A: failed to read serial number"))
+		return (-1);
+	}
+
+	DBG_LOG(("Serial No.          : %ld", a->xdi_adapter.serialNo))
+	DBG_TRC(("Board Revision      : %d.%02d", (int) data[41],
+		     (int) data[40]))
+	DBG_TRC(("PLD revision        : %d.%02d", (int) data[33],
+		     (int) data[32]))
+	DBG_TRC(("Boot loader version : %d.%02d", (int) data[37],
+		     (int) data[36]))
+
+	DBG_TRC(("Manufacturing Date  : %d/%02d/%02d  (yyyy/mm/dd)",
+		     (int) ((data[28] > 90) ? 1900 : 2000) +
+		     (int) data[28], (int) data[29], (int) data[30]))
+
+	return (0);
+}
+
+void diva_os_prepare_pri2_functions(PISDN_ADAPTER IoAdapter)
+{
+}
+
+void diva_os_prepare_pri_functions(PISDN_ADAPTER IoAdapter)
+{
+}
+
+/*
+**  Checks presence of DSP on board
+*/
+static int
+dsp_check_presence(volatile byte __iomem * addr, volatile byte __iomem * data, int dsp)
+{
+	word pattern;
+
+	WRITE_WORD(addr, 0x4000);
+	WRITE_WORD(data, DSP_SIGNATURE_PROBE_WORD);
+
+	WRITE_WORD(addr, 0x4000);
+	pattern = READ_WORD(data);
+
+	if (pattern != DSP_SIGNATURE_PROBE_WORD) {
+		DBG_TRC(("W: DSP[%d] %04x(is) != %04x(should)",
+			 dsp, pattern, DSP_SIGNATURE_PROBE_WORD))
+		return (-1);
+	}
+
+	WRITE_WORD(addr, 0x4000);
+	WRITE_WORD(data, ~DSP_SIGNATURE_PROBE_WORD);
+
+	WRITE_WORD(addr, 0x4000);
+	pattern = READ_WORD(data);
+
+	if (pattern != (word) ~ DSP_SIGNATURE_PROBE_WORD) {
+		DBG_ERR(("A: DSP[%d] %04x(is) != %04x(should)",
+			 dsp, pattern, (word) ~ DSP_SIGNATURE_PROBE_WORD))
+		return (-2);
+	}
+
+	DBG_TRC(("DSP[%d] present", dsp))
+
+	return (0);
+}
+
+
+/*
+**  Check if DSP's are present and operating
+**  Information about detected DSP's is returned as bit mask
+**  Bit 0  - DSP1
+**  ...
+**  ...
+**  ...
+**  Bit 29 - DSP30
+*/
+static dword diva_pri_detect_dsps(diva_os_xdi_adapter_t * a)
+{
+	byte __iomem *base;
+	byte __iomem *p;
+	dword ret = 0;
+	dword row_offset[7] = {
+		0x00000000,
+		0x00000800,	/* 1 - ROW 1 */
+		0x00000840,	/* 2 - ROW 2 */
+		0x00001000,	/* 3 - ROW 3 */
+		0x00001040,	/* 4 - ROW 4 */
+		0x00000000	/* 5 - ROW 0 */
+	};
+
+	byte __iomem *dsp_addr_port;
+	byte __iomem *dsp_data_port;
+	byte row_state;
+	int dsp_row = 0, dsp_index, dsp_num;
+
+	if (!a->xdi_adapter.Control || !a->xdi_adapter.reset) {
+		return (0);
+	}
+
+	p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
+	WRITE_BYTE(p, _MP_RISC_RESET | _MP_DSP_RESET);
+	DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
+	diva_os_wait(5);
+
+	base = DIVA_OS_MEM_ATTACH_CONTROL(&a->xdi_adapter);
+
+	for (dsp_num = 0; dsp_num < 30; dsp_num++) {
+		dsp_row = dsp_num / 7 + 1;
+		dsp_index = dsp_num % 7;
+
+		dsp_data_port = base;
+		dsp_addr_port = base;
+
+		dsp_data_port += row_offset[dsp_row];
+		dsp_addr_port += row_offset[dsp_row];
+
+		dsp_data_port += (dsp_index * 8);
+		dsp_addr_port += (dsp_index * 8) + 0x80;
+
+		if (!dsp_check_presence
+		    (dsp_addr_port, dsp_data_port, dsp_num + 1)) {
+			ret |= (1 << dsp_num);
+		}
+	}
+	DIVA_OS_MEM_DETACH_CONTROL(&a->xdi_adapter, base);
+
+	p = DIVA_OS_MEM_ATTACH_RESET(&a->xdi_adapter);
+	WRITE_BYTE(p, _MP_RISC_RESET | _MP_LED1 | _MP_LED2);
+	DIVA_OS_MEM_DETACH_RESET(&a->xdi_adapter, p);
+	diva_os_wait(5);
+
+	/*
+	   Verify modules
+	 */
+	for (dsp_row = 0; dsp_row < 4; dsp_row++) {
+		row_state = ((ret >> (dsp_row * 7)) & 0x7F);
+		if (row_state && (row_state != 0x7F)) {
+			for (dsp_index = 0; dsp_index < 7; dsp_index++) {
+				if (!(row_state & (1 << dsp_index))) {
+					DBG_ERR(("A: MODULE[%d]-DSP[%d] failed",
+						 dsp_row + 1,
+						 dsp_index + 1))
+				}
+			}
+		}
+	}
+
+	if (!(ret & 0x10000000)) {
+		DBG_ERR(("A: ON BOARD-DSP[1] failed"))
+	}
+	if (!(ret & 0x20000000)) {
+		DBG_ERR(("A: ON BOARD-DSP[2] failed"))
+	}
+
+	/*
+	   Print module population now
+	 */
+	DBG_LOG(("+-----------------------+"))
+	DBG_LOG(("| DSP MODULE POPULATION |"))
+	DBG_LOG(("+-----------------------+"))
+	DBG_LOG(("|  1  |  2  |  3  |  4  |"))
+	DBG_LOG(("+-----------------------+"))
+	DBG_LOG(("|  %s  |  %s  |  %s  |  %s  |",
+		 ((ret >> (0 * 7)) & 0x7F) ? "Y" : "N",
+		 ((ret >> (1 * 7)) & 0x7F) ? "Y" : "N",
+		 ((ret >> (2 * 7)) & 0x7F) ? "Y" : "N",
+		 ((ret >> (3 * 7)) & 0x7F) ? "Y" : "N"))
+	DBG_LOG(("+-----------------------+"))
+
+	DBG_LOG(("DSP's(present-absent):%08x-%08x", ret,
+		 ~ret & 0x3fffffff))
+
+	return (ret);
+}
diff --git a/drivers/isdn/hardware/eicon/os_pri.h b/drivers/isdn/hardware/eicon/os_pri.h
new file mode 100644
index 0000000..a7c42f9
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/os_pri.h
@@ -0,0 +1,8 @@
+/* $Id: os_pri.h,v 1.1.2.2 2001/02/08 12:25:44 armin Exp $ */
+
+#ifndef __DIVA_OS_PRI_REV_1_H__
+#define __DIVA_OS_PRI_REV_1_H__
+
+int diva_pri_init_card(diva_os_xdi_adapter_t * a);
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/pc.h b/drivers/isdn/hardware/eicon/pc.h
new file mode 100644
index 0000000..1c69457
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pc.h
@@ -0,0 +1,738 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef PC_H_INCLUDED  /* { */
+#define PC_H_INCLUDED
+/*------------------------------------------------------------------*/
+/* buffer definition                                                */
+/*------------------------------------------------------------------*/
+typedef struct {
+  word length;          /* length of data/parameter field           */
+  byte P[270];          /* data/parameter field                     */
+} PBUFFER;
+/*------------------------------------------------------------------*/
+/* dual port ram structure                                          */
+/*------------------------------------------------------------------*/
+struct dual
+{
+  byte Req;             /* request register                         */
+  byte ReqId;           /* request task/entity identification       */
+  byte Rc;              /* return code register                     */
+  byte RcId;            /* return code task/entity identification   */
+  byte Ind;             /* Indication register                      */
+  byte IndId;           /* Indication task/entity identification    */
+  byte IMask;           /* Interrupt Mask Flag                      */
+  byte RNR;             /* Receiver Not Ready (set by PC)           */
+  byte XLock;           /* XBuffer locked Flag                      */
+  byte Int;             /* ISDN-S interrupt                         */
+  byte ReqCh;           /* Channel field for layer-3 Requests       */
+  byte RcCh;            /* Channel field for layer-3 Returncodes    */
+  byte IndCh;           /* Channel field for layer-3 Indications    */
+  byte MInd;            /* more data indication field               */
+  word MLength;         /* more data total packet length            */
+  byte ReadyInt;        /* request field for ready interrupt        */
+  byte SWReg;           /* Software register for special purposes   */
+  byte Reserved[11];    /* reserved space                           */
+  byte InterfaceType;   /* interface type 1=16K interface           */
+  word Signature;       /* ISDN-S adapter Signature (GD)            */
+  PBUFFER XBuffer;      /* Transmit Buffer                          */
+  PBUFFER RBuffer;      /* Receive Buffer                           */
+};
+/*------------------------------------------------------------------*/
+/* SWReg Values (0 means no command)                                */
+/*------------------------------------------------------------------*/
+#define SWREG_DIE_WITH_LEDON  0x01
+#define SWREG_HALT_CPU        0x02 /* Push CPU into a while(1) loop */
+/*------------------------------------------------------------------*/
+/* Id Fields Coding                                                 */
+/*------------------------------------------------------------------*/
+#define ID_MASK 0xe0    /* Mask for the ID field                    */
+#define GL_ERR_ID 0x1f  /* ID for error reporting on global requests*/
+#define DSIG_ID  0x00   /* ID for D-channel signaling               */
+#define NL_ID    0x20   /* ID for network-layer access (B or D)     */
+#define BLLC_ID  0x60   /* ID for B-channel link level access       */
+#define TASK_ID  0x80   /* ID for dynamic user tasks                */
+#define TIMER_ID 0xa0   /* ID for timer task                        */
+#define TEL_ID   0xc0   /* ID for telephone support                 */
+#define MAN_ID   0xe0   /* ID for management                        */
+/*------------------------------------------------------------------*/
+/* ASSIGN and REMOVE requests are the same for all entities         */
+/*------------------------------------------------------------------*/
+#define ASSIGN  0x01
+#define UREMOVE 0xfe /* without return code */
+#define REMOVE  0xff
+/*------------------------------------------------------------------*/
+/* Timer Interrupt Task Interface                                   */
+/*------------------------------------------------------------------*/
+#define ASSIGN_TIM 0x01
+#define REMOVE_TIM 0xff
+/*------------------------------------------------------------------*/
+/* dynamic user task interface                                      */
+/*------------------------------------------------------------------*/
+#define ASSIGN_TSK 0x01
+#define REMOVE_TSK 0xff
+#define LOAD 0xf0
+#define RELOCATE 0xf1
+#define START 0xf2
+#define LOAD2 0xf3
+#define RELOCATE2 0xf4
+/*------------------------------------------------------------------*/
+/* dynamic user task messages                                       */
+/*------------------------------------------------------------------*/
+#define TSK_B2          0x0000
+#define TSK_WAKEUP      0x2000
+#define TSK_TIMER       0x4000
+#define TSK_TSK         0x6000
+#define TSK_PC          0xe000
+/*------------------------------------------------------------------*/
+/* LL management primitives                                         */
+/*------------------------------------------------------------------*/
+#define ASSIGN_LL 1     /* assign logical link                      */
+#define REMOVE_LL 0xff  /* remove logical link                      */
+/*------------------------------------------------------------------*/
+/* LL service primitives                                            */
+/*------------------------------------------------------------------*/
+#define LL_UDATA 1      /* link unit data request/indication        */
+#define LL_ESTABLISH 2  /* link establish request/indication        */
+#define LL_RELEASE 3    /* link release request/indication          */
+#define LL_DATA 4       /* data request/indication                  */
+#define LL_LOCAL 5      /* switch to local operation (COM only)     */
+#define LL_DATA_PEND 5  /* data pending indication (SDLC SHM only)  */
+#define LL_REMOTE 6     /* switch to remote operation (COM only)    */
+#define LL_TEST 8       /* link test request                        */
+#define LL_MDATA 9      /* more data request/indication             */
+#define LL_BUDATA 10    /* broadcast unit data request/indication   */
+#define LL_XID 12       /* XID command request/indication           */
+#define LL_XID_R 13     /* XID response request/indication          */
+/*------------------------------------------------------------------*/
+/* NL service primitives                                            */
+/*------------------------------------------------------------------*/
+#define N_MDATA         1       /* more data to come REQ/IND        */
+#define N_CONNECT       2       /* OSI N-CONNECT REQ/IND            */
+#define N_CONNECT_ACK   3       /* OSI N-CONNECT CON/RES            */
+#define N_DISC          4       /* OSI N-DISC REQ/IND               */
+#define N_DISC_ACK      5       /* OSI N-DISC CON/RES               */
+#define N_RESET         6       /* OSI N-RESET REQ/IND              */
+#define N_RESET_ACK     7       /* OSI N-RESET CON/RES              */
+#define N_DATA          8       /* OSI N-DATA REQ/IND               */
+#define N_EDATA         9       /* OSI N-EXPEDITED DATA REQ/IND     */
+#define N_UDATA         10      /* OSI D-UNIT-DATA REQ/IND          */
+#define N_BDATA         11      /* BROADCAST-DATA REQ/IND           */
+#define N_DATA_ACK      12      /* data ack ind for D-bit procedure */
+#define N_EDATA_ACK     13      /* data ack ind for INTERRUPT       */
+#define N_XON           15      /* clear RNR state */
+#define N_COMBI_IND     N_XON   /* combined indication              */
+#define N_Q_BIT         0x10    /* Q-bit for req/ind                */
+#define N_M_BIT         0x20    /* M-bit for req/ind                */
+#define N_D_BIT         0x40    /* D-bit for req/ind                */
+/*------------------------------------------------------------------*/
+/* Signaling management primitives                                  */
+/*------------------------------------------------------------------*/
+#define ASSIGN_SIG  1    /* assign signaling task                    */
+#define UREMOVE_SIG 0xfe /* remove signaling task without return code*/
+#define REMOVE_SIG  0xff /* remove signaling task                    */
+/*------------------------------------------------------------------*/
+/* Signaling service primitives                                     */
+/*------------------------------------------------------------------*/
+#define CALL_REQ 1      /* call request                             */
+#define CALL_CON 1      /* call confirmation                        */
+#define CALL_IND 2      /* incoming call connected                  */
+#define LISTEN_REQ 2    /* listen request                           */
+#define HANGUP 3        /* hangup request/indication                */
+#define SUSPEND 4       /* call suspend request/confirm             */
+#define RESUME 5        /* call resume request/confirm              */
+#define SUSPEND_REJ 6   /* suspend rejected indication              */
+#define USER_DATA 8     /* user data for user to user signaling     */
+#define CONGESTION 9    /* network congestion indication            */
+#define INDICATE_REQ 10 /* request to indicate an incoming call     */
+#define INDICATE_IND 10 /* indicates that there is an incoming call */
+#define CALL_RES 11     /* accept an incoming call                  */
+#define CALL_ALERT 12   /* send ALERT for incoming call             */
+#define INFO_REQ 13     /* INFO request                             */
+#define INFO_IND 13     /* INFO indication                          */
+#define REJECT 14       /* reject an incoming call                  */
+#define RESOURCES 15    /* reserve B-Channel hardware resources     */
+#define HW_CTRL 16      /* B-Channel hardware IOCTL req/ind         */
+#define TEL_CTRL 16     /* Telephone control request/indication     */
+#define STATUS_REQ 17   /* Request D-State (returned in INFO_IND)   */
+#define FAC_REG_REQ 18  /* 1TR6 connection independent fac reg      */
+#define FAC_REG_ACK 19  /* 1TR6 fac registration acknowledge        */
+#define FAC_REG_REJ 20  /* 1TR6 fac registration reject             */
+#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call       */
+#define SW_CTRL 22      /* extended software features               */
+#define REGISTER_REQ 23 /* Q.931 connection independent reg req     */
+#define REGISTER_IND 24 /* Q.931 connection independent reg ind     */
+#define FACILITY_REQ 25 /* Q.931 connection independent fac req     */
+#define FACILITY_IND 26 /* Q.931 connection independent fac ind     */
+#define NCR_INFO_REQ 27 /* INFO_REQ with NULL CR                    */
+#define GCR_MIM_REQ 28  /* MANAGEMENT_INFO_REQ with global CR       */
+#define SIG_CTRL    29  /* Control for Signalling Hardware          */
+#define DSP_CTRL    30  /* Control for DSPs                         */
+#define LAW_REQ      31 /* Law config request for (returns info_i)  */
+#define SPID_CTRL    32 /* Request/indication SPID related          */
+#define NCR_FACILITY 33 /* Request/indication with NULL/DUMMY CR    */
+#define CALL_HOLD    34 /* Request/indication to hold a CALL        */
+#define CALL_RETRIEVE 35 /* Request/indication to retrieve a CALL   */
+#define CALL_HOLD_ACK 36 /* OK of                hold a CALL        */
+#define CALL_RETRIEVE_ACK 37 /* OK of             retrieve a CALL   */
+#define CALL_HOLD_REJ 38 /* Reject of            hold a CALL        */
+#define CALL_RETRIEVE_REJ 39 /* Reject of         retrieve a call   */
+#define GCR_RESTART   40 /* Send/Receive Restart message            */
+#define S_SERVICE     41 /* Send/Receive Supplementary Service      */
+#define S_SERVICE_REJ 42 /* Reject Supplementary Service indication */
+#define S_SUPPORTED   43 /* Req/Ind to get Supported Services       */
+#define STATUS_ENQ    44 /* Req to send the D-ch request if !state0 */
+#define CALL_GUARD    45 /* Req/Ind to use the FLAGS_CALL_OUTCHECK  */
+#define CALL_GUARD_HP 46 /* Call Guard function to reject a call    */
+#define CALL_GUARD_IF 47 /* Call Guard function, inform the appl    */
+#define SSEXT_REQ     48 /* Supplem.Serv./QSIG specific request     */
+#define SSEXT_IND     49 /* Supplem.Serv./QSIG specific indication  */
+/* reserved commands for the US protocols */
+#define INT_3PTY_NIND 50 /* US       specific indication            */
+#define INT_CF_NIND   51 /* US       specific indication            */
+#define INT_3PTY_DROP 52 /* US       specific indication            */
+#define INT_MOVE_CONF 53 /* US       specific indication            */
+#define INT_MOVE_RC   54 /* US       specific indication            */
+#define INT_MOVE_FLIPPED_CONF 55 /* US specific indication          */
+#define INT_X5NI_OK   56 /* internal transfer OK indication         */
+#define INT_XDMS_START 57 /* internal transfer OK indication        */
+#define INT_XDMS_STOP 58 /* internal transfer finish indication     */
+#define INT_XDMS_STOP2 59 /* internal transfer send FA              */
+#define INT_CUSTCONF_REJ 60 /* internal conference reject           */
+#define INT_CUSTXFER 61 /* internal transfer request                */
+#define INT_CUSTX_NIND 62 /* internal transfer ack                  */
+#define INT_CUSTXREJ_NIND 63 /* internal transfer rej               */
+#define INT_X5NI_CF_XFER  64 /* internal transfer OK indication     */
+#define VSWITCH_REQ 65        /* communication between protocol and */
+#define VSWITCH_IND 66        /* capifunctions for D-CH-switching   */
+#define MWI_POLL 67     /* Message Waiting Status Request fkt */
+#define CALL_PEND_NOTIFY 68 /* notify capi to set new listen        */
+#define DO_NOTHING 69       /* dont do somethin if you get this     */
+#define INT_CT_REJ 70       /* ECT rejected internal command        */
+#define CALL_HOLD_COMPLETE 71 /* In NT Mode indicate hold complete  */
+#define CALL_RETRIEVE_COMPLETE 72 /* In NT Mode indicate retrieve complete  */
+/*------------------------------------------------------------------*/
+/* management service primitives                                    */
+/*------------------------------------------------------------------*/
+#define MAN_READ        2
+#define MAN_WRITE       3
+#define MAN_EXECUTE     4
+#define MAN_EVENT_ON    5
+#define MAN_EVENT_OFF   6
+#define MAN_LOCK        7
+#define MAN_UNLOCK      8
+#define MAN_INFO_IND    2
+#define MAN_EVENT_IND   3
+#define MAN_TRACE_IND   4
+#define MAN_COMBI_IND   9
+#define MAN_ESC         0x80
+/*------------------------------------------------------------------*/
+/* return code coding                                               */
+/*------------------------------------------------------------------*/
+#define UNKNOWN_COMMAND         0x01    /* unknown command          */
+#define WRONG_COMMAND           0x02    /* wrong command            */
+#define WRONG_ID                0x03    /* unknown task/entity id   */
+#define WRONG_CH                0x04    /* wrong task/entity id     */
+#define UNKNOWN_IE              0x05    /* unknown information el.  */
+#define WRONG_IE                0x06    /* wrong information el.    */
+#define OUT_OF_RESOURCES        0x07    /* ISDN-S card out of res.  */
+#define ISDN_GUARD_REJ          0x09    /* ISDN-Guard SuppServ rej  */
+#define N_FLOW_CONTROL          0x10    /* Flow-Control, retry      */
+#define ASSIGN_RC               0xe0    /* ASSIGN acknowledgement   */
+#define ASSIGN_OK               0xef    /* ASSIGN OK                */
+#define OK_FC                   0xfc    /* Flow-Control RC          */
+#define READY_INT               0xfd    /* Ready interrupt          */
+#define TIMER_INT               0xfe    /* timer interrupt          */
+#define OK                      0xff    /* command accepted         */
+/*------------------------------------------------------------------*/
+/* information elements                                             */
+/*------------------------------------------------------------------*/
+#define SHIFT 0x90              /* codeset shift                    */
+#define MORE 0xa0               /* more data                        */
+#define SDNCMPL 0xa1            /* sending complete                 */
+#define CL 0xb0                 /* congestion level                 */
+        /* codeset 0                                                */
+#define SMSG 0x00               /* segmented message                */
+#define BC  0x04                /* Bearer Capability                */
+#define CAU 0x08                /* cause                            */
+#define CAD 0x0c                /* Connected address                */
+#define CAI 0x10                /* call identity                    */
+#define CHI 0x18                /* channel identification           */
+#define LLI 0x19                /* logical link id                  */
+#define CHA 0x1a                /* charge advice                    */
+#define FTY 0x1c                /* Facility                         */
+#define DT  0x29                /* ETSI date/time                   */
+#define KEY 0x2c                /* keypad information element       */
+#define UID 0x2d                /* User id information element      */
+#define DSP 0x28                /* display                          */
+#define SIG 0x34                /* signalling hardware control      */
+#define OAD 0x6c                /* origination address              */
+#define OSA 0x6d                /* origination sub-address          */
+#define CPN 0x70                /* called party number              */
+#define DSA 0x71                /* destination sub-address          */
+#define RDX 0x73                /* redirecting number extended      */
+#define RDN 0x74                /* redirecting number               */
+#define RIN 0x76                /* redirection number               */
+#define IUP 0x76                /* VN6 rerouter->PCS (codeset 6)    */
+#define IPU 0x77                /* VN6 PCS->rerouter (codeset 6)    */
+#define RI  0x79                /* restart indicator                */
+#define MIE 0x7a                /* management info element          */
+#define LLC 0x7c                /* low layer compatibility          */
+#define HLC 0x7d                /* high layer compatibility         */
+#define UUI 0x7e                /* user user information            */
+#define ESC 0x7f                /* escape extension                 */
+#define DLC 0x20                /* data link layer configuration    */
+#define NLC 0x21                /* network layer configuration      */
+#define REDIRECT_IE     0x22    /* redirection request/indication data */
+#define REDIRECT_NET_IE 0x23    /* redirection network override data   */
+        /* codeset 6                                                */
+#define SIN 0x01                /* service indicator                */
+#define CIF 0x02                /* charging information             */
+#define DATE 0x03               /* date                             */
+#define CPS 0x07                /* called party status              */
+/*------------------------------------------------------------------*/
+/* ESC information elements                                         */
+/*------------------------------------------------------------------*/
+#define MSGTYPEIE        0x7a   /* Messagetype info element         */
+#define CRIE             0x7b   /* INFO info element                */
+#define CODESET6IE       0xec   /* Tunnel for Codeset 6 IEs         */
+#define VSWITCHIE        0xed   /* VSwitch info element             */
+#define SSEXTIE          0xee   /* Supplem. Service info element    */
+#define PROFILEIE        0xef   /* Profile info element             */
+/*------------------------------------------------------------------*/
+/* TEL_CTRL contents                                                */
+/*------------------------------------------------------------------*/
+#define RING_ON         0x01
+#define RING_OFF        0x02
+#define HANDS_FREE_ON   0x03
+#define HANDS_FREE_OFF  0x04
+#define ON_HOOK         0x80
+#define OFF_HOOK        0x90
+/* operation values used by ETSI supplementary services */
+#define THREE_PTY_BEGIN           0x04
+#define THREE_PTY_END             0x05
+#define ECT_EXECUTE               0x06
+#define ACTIVATION_DIVERSION      0x07
+#define DEACTIVATION_DIVERSION    0x08
+#define CALL_DEFLECTION           0x0D
+#define INTERROGATION_DIVERSION   0x0B
+#define INTERROGATION_SERV_USR_NR 0x11
+#define ACTIVATION_MWI            0x20
+#define DEACTIVATION_MWI          0x21
+#define MWI_INDICATION            0x22
+#define MWI_RESPONSE              0x23
+#define CONF_BEGIN                0x28
+#define CONF_ADD                  0x29
+#define CONF_SPLIT                0x2a
+#define CONF_DROP                 0x2b
+#define CONF_ISOLATE              0x2c
+#define CONF_REATTACH             0x2d
+#define CONF_PARTYDISC            0x2e
+#define CCBS_INFO_RETAIN          0x2f
+#define CCBS_ERASECALLLINKAGEID   0x30
+#define CCBS_STOP_ALERTING        0x31
+#define CCBS_REQUEST              0x32
+#define CCBS_DEACTIVATE           0x33
+#define CCBS_INTERROGATE          0x34
+#define CCBS_STATUS               0x35
+#define CCBS_ERASE                0x36
+#define CCBS_B_FREE               0x37
+#define CCNR_INFO_RETAIN          0x38
+#define CCBS_REMOTE_USER_FREE     0x39
+#define CCNR_REQUEST              0x3a
+#define CCNR_INTERROGATE          0x3b
+#define GET_SUPPORTED_SERVICES    0xff
+#define DIVERSION_PROCEDURE_CFU     0x70
+#define DIVERSION_PROCEDURE_CFB     0x71
+#define DIVERSION_PROCEDURE_CFNR    0x72
+#define DIVERSION_DEACTIVATION_CFU  0x80
+#define DIVERSION_DEACTIVATION_CFB  0x81
+#define DIVERSION_DEACTIVATION_CFNR 0x82
+#define DIVERSION_INTERROGATE_NUM   0x11
+#define DIVERSION_INTERROGATE_CFU   0x60
+#define DIVERSION_INTERROGATE_CFB   0x61
+#define DIVERSION_INTERROGATE_CFNR  0x62
+/* Service Masks */
+#define SMASK_HOLD_RETRIEVE        0x00000001
+#define SMASK_TERMINAL_PORTABILITY 0x00000002
+#define SMASK_ECT                  0x00000004
+#define SMASK_3PTY                 0x00000008
+#define SMASK_CALL_FORWARDING      0x00000010
+#define SMASK_CALL_DEFLECTION      0x00000020
+#define SMASK_MCID                 0x00000040
+#define SMASK_CCBS                 0x00000080
+#define SMASK_MWI                  0x00000100
+#define SMASK_CCNR                 0x00000200
+#define SMASK_CONF                 0x00000400
+/* ----------------------------------------------
+    Types of transfers used to transfer the
+    information in the 'struct RC->Reserved2[8]'
+    The information is transferred as 2 dwords
+    (2 4Byte unsigned values)
+    First of them is the transfer type.
+    2^32-1 possible messages are possible in this way.
+    The context of the second one had no meaning
+   ---------------------------------------------- */
+#define DIVA_RC_TYPE_NONE              0x00000000
+#define DIVA_RC_TYPE_REMOVE_COMPLETE   0x00000008
+#define DIVA_RC_TYPE_STREAM_PTR        0x00000009
+#define DIVA_RC_TYPE_CMA_PTR           0x0000000a
+#define DIVA_RC_TYPE_OK_FC             0x0000000b
+#define DIVA_RC_TYPE_RX_DMA            0x0000000c
+/* ------------------------------------------------------
+      IO Control codes for IN BAND SIGNALING
+   ------------------------------------------------------ */
+#define CTRL_L1_SET_SIG_ID        5
+#define CTRL_L1_SET_DAD           6
+#define CTRL_L1_RESOURCES         7
+/* ------------------------------------------------------ */
+/* ------------------------------------------------------
+      Layer 2 types
+   ------------------------------------------------------ */
+#define X75T            1       /* x.75 for ttx                     */
+#define TRF             2       /* transparent with hdlc framing    */
+#define TRF_IN          3       /* transparent with hdlc fr. inc.   */
+#define SDLC            4       /* sdlc, sna layer-2                */
+#define X75             5       /* x.75 for btx                     */
+#define LAPD            6       /* lapd (Q.921)                     */
+#define X25_L2          7       /* x.25 layer-2                     */
+#define V120_L2         8       /* V.120 layer-2 protocol           */
+#define V42_IN          9       /* V.42 layer-2 protocol, incomming */
+#define V42            10       /* V.42 layer-2 protocol            */
+#define MDM_ATP        11       /* AT Parser built in the L2        */
+#define X75_V42BIS     12       /* x.75 with V.42bis                */
+#define RTPL2_IN       13       /* RTP layer-2 protocol, incomming  */
+#define RTPL2          14       /* RTP layer-2 protocol             */
+#define V120_V42BIS    15       /* V.120 asynchronous mode supporting V.42bis compression */
+#define LISTENER       27       /* Layer 2 to listen line */
+#define MTP2           28       /* MTP2 Layer 2 */
+#define PIAFS_CRC      29       /* PIAFS Layer 2 with CRC calculation at L2 */
+/* ------------------------------------------------------
+   PIAFS DLC DEFINITIONS
+   ------------------------------------------------------ */
+#define PIAFS_64K            0x01
+#define PIAFS_VARIABLE_SPEED 0x02
+#define PIAFS_CHINESE_SPEED    0x04
+#define PIAFS_UDATA_ABILITY_ID    0x80
+#define PIAFS_UDATA_ABILITY_DCDON 0x01
+#define PIAFS_UDATA_ABILITY_DDI   0x80
+/*
+DLC of PIAFS :
+Byte | 8 7 6 5 4 3 2 1
+-----+--------------------------------------------------------
+   0 | 0 0 1 0 0 0 0 0  Data Link Configuration
+   1 | X X X X X X X X  Length of IE (at least 15 Bytes)
+   2 | 0 0 0 0 0 0 0 0  max. information field, LOW  byte (not used, fix 73 Bytes)
+   3 | 0 0 0 0 0 0 0 0  max. information field, HIGH byte (not used, fix 73 Bytes)
+   4 | 0 0 0 0 0 0 0 0  address A (not used)
+   5 | 0 0 0 0 0 0 0 0  address B (not used)
+   6 | 0 0 0 0 0 0 0 0  Mode (not used, fix 128)
+   7 | 0 0 0 0 0 0 0 0  Window Size (not used, fix 127)
+   8 | X X X X X X X X  XID Length, Low Byte (at least 7 Bytes)
+   9 | X X X X X X X X  XID Length, High Byte
+  10 | 0 0 0 0 0 C V S  PIAFS Protocol Speed configuration -> Note(1)
+     |                  S = 0 -> Protocol Speed is 32K
+     |                  S = 1 -> Protocol Speed is 64K
+     |                  V = 0 -> Protocol Speed is fixed
+     |                  V = 1 -> Protocol Speed is variable
+     |                  C = 0 -> speed setting according to standard
+     |                  C = 1 -> speed setting for chinese implementation
+  11 | 0 0 0 0 0 0 R T  P0 - V42bis Compression enable/disable, Low Byte
+     |                  T = 0 -> Transmit Direction enable
+     |                  T = 1 -> Transmit Direction disable
+     |                  R = 0 -> Receive  Direction enable
+     |                  R = 1 -> Receive  Direction disable
+  13 | 0 0 0 0 0 0 0 0  P0 - V42bis Compression enable/disable, High Byte
+  14 | X X X X X X X X  P1 - V42bis Dictionary Size, Low Byte
+  15 | X X X X X X X X  P1 - V42bis Dictionary Size, High Byte
+  16 | X X X X X X X X  P2 - V42bis String Length, Low Byte
+  17 | X X X X X X X X  P2 - V42bis String Length, High Byte
+  18 | X X X X X X X X  PIAFS extension length
+  19 | 1 0 0 0 0 0 0 0  PIAFS extension Id (0x80) - UDATA abilities
+  20 | U 0 0 0 0 0 0 D  UDATA abilities -> Note (2)
+     |                  up to now the following Bits are defined:
+     |                  D - signal DCD ON
+     |                  U - use extensive UDATA control communication
+     |                      for DDI test application
++ Note (1): ----------+------+-----------------------------------------+
+| PIAFS Protocol      | Bit  |                                         |
+| Speed configuration |    S | Bit 1 - Protocol Speed                  |
+|                     |      |         0 - 32K                         |
+|                     |      |         1 - 64K (default)               |
+|                     |    V | Bit 2 - Variable Protocol Speed         |
+|                     |      |         0 - Speed is fix                |
+|                     |      |         1 - Speed is variable (default) |
+|                     |      |             OVERWRITES 32k Bit 1        |
+|                     |    C | Bit 3   0 - Speed Settings according to |
+|                     |      |             PIAFS specification         |
+|                     |      |         1 - Speed setting for chinese   |
+|                     |      |             PIAFS implementation        |
+|                     |      | Explanation for chinese speed settings: |
+|                     |      |         if Bit 3 is set the following   |
+|                     |      |         rules apply:                    |
+|                     |      |         Bit1=0 Bit2=0: 32k fix          |
+|                     |      |         Bit1=1 Bit2=0: 64k fix          |
+|                     |      |         Bit1=0 Bit2=1: PIAFS is trying  |
+|                     |      |             to negotiate 32k is that is |
+|                     |      |             not possible it tries to    |
+|                     |      |             negotiate 64k               |
+|                     |      |         Bit1=1 Bit2=1: PIAFS is trying  |
+|                     |      |             to negotiate 64k is that is |
+|                     |      |             not possible it tries to    |
+|                     |      |             negotiate 32k               |
++ Note (2): ----------+------+-----------------------------------------+
+| PIAFS               | Bit  | this byte defines the usage of UDATA    |
+| Implementation      |      | control communication                   |
+| UDATA usage         |    D | Bit 1 - DCD-ON signalling               |
+|                     |      |         0 - no DCD-ON is signalled      |
+|                     |      |             (default)                   |
+|                     |      |         1 - DCD-ON will be signalled    |
+|                     |    U | Bit 8 - DDI test application UDATA      |
+|                     |      |         control communication           |
+|                     |      |         0 - no UDATA control            |
+|                     |      |             communication (default)     |
+|                     |      |             sets as well the DCD-ON     |
+|                     |      |             signalling                  |
+|                     |      |         1 - UDATA control communication |
+|                     |      |             ATTENTION: Do not use these |
+|                     |      |                        setting if you   |
+|                     |      |                        are not really   |
+|                     |      |                        that you need it |
+|                     |      |                        and you know     |
+|                     |      |                        exactly what you |
+|                     |      |                        are doing.       |
+|                     |      |                        You can easily   |
+|                     |      |                        disable any      |
+|                     |      |                        data transfer.   |
++---------------------+------+-----------------------------------------+
+*/
+/* ------------------------------------------------------
+   LISTENER DLC DEFINITIONS
+   ------------------------------------------------------ */
+#define LISTENER_FEATURE_MASK_CUMMULATIVE            0x0001
+/* ------------------------------------------------------
+   LISTENER META-FRAME CODE/PRIMITIVE DEFINITIONS
+   ------------------------------------------------------ */
+#define META_CODE_LL_UDATA_RX 0x01
+#define META_CODE_LL_UDATA_TX 0x02
+#define META_CODE_LL_DATA_RX  0x03
+#define META_CODE_LL_DATA_TX  0x04
+#define META_CODE_LL_MDATA_RX 0x05
+#define META_CODE_LL_MDATA_TX 0x06
+#define META_CODE_EMPTY       0x10
+#define META_CODE_LOST_FRAMES 0x11
+#define META_FLAG_TRUNCATED   0x0001
+/*------------------------------------------------------------------*/
+/* CAPI-like profile to indicate features on LAW_REQ                */
+/*------------------------------------------------------------------*/
+#define GL_INTERNAL_CONTROLLER_SUPPORTED     0x00000001L
+#define GL_EXTERNAL_EQUIPMENT_SUPPORTED      0x00000002L
+#define GL_HANDSET_SUPPORTED                 0x00000004L
+#define GL_DTMF_SUPPORTED                    0x00000008L
+#define GL_SUPPLEMENTARY_SERVICES_SUPPORTED  0x00000010L
+#define GL_CHANNEL_ALLOCATION_SUPPORTED      0x00000020L
+#define GL_BCHANNEL_OPERATION_SUPPORTED      0x00000040L
+#define GL_LINE_INTERCONNECT_SUPPORTED       0x00000080L
+#define B1_HDLC_SUPPORTED                    0x00000001L
+#define B1_TRANSPARENT_SUPPORTED             0x00000002L
+#define B1_V110_ASYNC_SUPPORTED              0x00000004L
+#define B1_V110_SYNC_SUPPORTED               0x00000008L
+#define B1_T30_SUPPORTED                     0x00000010L
+#define B1_HDLC_INVERTED_SUPPORTED           0x00000020L
+#define B1_TRANSPARENT_R_SUPPORTED           0x00000040L
+#define B1_MODEM_ALL_NEGOTIATE_SUPPORTED     0x00000080L
+#define B1_MODEM_ASYNC_SUPPORTED             0x00000100L
+#define B1_MODEM_SYNC_HDLC_SUPPORTED         0x00000200L
+#define B2_X75_SUPPORTED                     0x00000001L
+#define B2_TRANSPARENT_SUPPORTED             0x00000002L
+#define B2_SDLC_SUPPORTED                    0x00000004L
+#define B2_LAPD_SUPPORTED                    0x00000008L
+#define B2_T30_SUPPORTED                     0x00000010L
+#define B2_PPP_SUPPORTED                     0x00000020L
+#define B2_TRANSPARENT_NO_CRC_SUPPORTED      0x00000040L
+#define B2_MODEM_EC_COMPRESSION_SUPPORTED    0x00000080L
+#define B2_X75_V42BIS_SUPPORTED              0x00000100L
+#define B2_V120_ASYNC_SUPPORTED              0x00000200L
+#define B2_V120_ASYNC_V42BIS_SUPPORTED       0x00000400L
+#define B2_V120_BIT_TRANSPARENT_SUPPORTED    0x00000800L
+#define B2_LAPD_FREE_SAPI_SEL_SUPPORTED      0x00001000L
+#define B3_TRANSPARENT_SUPPORTED             0x00000001L
+#define B3_T90NL_SUPPORTED                   0x00000002L
+#define B3_ISO8208_SUPPORTED                 0x00000004L
+#define B3_X25_DCE_SUPPORTED                 0x00000008L
+#define B3_T30_SUPPORTED                     0x00000010L
+#define B3_T30_WITH_EXTENSIONS_SUPPORTED     0x00000020L
+#define B3_RESERVED_SUPPORTED                0x00000040L
+#define B3_MODEM_SUPPORTED                   0x00000080L
+#define MANUFACTURER_FEATURE_SLAVE_CODEC          0x00000001L
+#define MANUFACTURER_FEATURE_FAX_MORE_DOCUMENTS   0x00000002L
+#define MANUFACTURER_FEATURE_HARDDTMF             0x00000004L
+#define MANUFACTURER_FEATURE_SOFTDTMF_SEND        0x00000008L
+#define MANUFACTURER_FEATURE_DTMF_PARAMETERS      0x00000010L
+#define MANUFACTURER_FEATURE_SOFTDTMF_RECEIVE     0x00000020L
+#define MANUFACTURER_FEATURE_FAX_SUB_SEP_PWD      0x00000040L
+#define MANUFACTURER_FEATURE_V18                  0x00000080L
+#define MANUFACTURER_FEATURE_MIXER_CH_CH          0x00000100L
+#define MANUFACTURER_FEATURE_MIXER_CH_PC          0x00000200L
+#define MANUFACTURER_FEATURE_MIXER_PC_CH          0x00000400L
+#define MANUFACTURER_FEATURE_MIXER_PC_PC          0x00000800L
+#define MANUFACTURER_FEATURE_ECHO_CANCELLER       0x00001000L
+#define MANUFACTURER_FEATURE_RTP                  0x00002000L
+#define MANUFACTURER_FEATURE_T38                  0x00004000L
+#define MANUFACTURER_FEATURE_TRANSP_DELIVERY_CONF 0x00008000L
+#define MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL  0x00010000L
+#define MANUFACTURER_FEATURE_OOB_CHANNEL          0x00020000L
+#define MANUFACTURER_FEATURE_IN_BAND_CHANNEL      0x00040000L
+#define MANUFACTURER_FEATURE_IN_BAND_FEATURE      0x00080000L
+#define MANUFACTURER_FEATURE_PIAFS                0x00100000L
+#define MANUFACTURER_FEATURE_DTMF_TONE            0x00200000L
+#define MANUFACTURER_FEATURE_FAX_PAPER_FORMATS    0x00400000L
+#define MANUFACTURER_FEATURE_OK_FC_LABEL          0x00800000L
+#define MANUFACTURER_FEATURE_VOWN                 0x01000000L
+#define MANUFACTURER_FEATURE_XCONNECT             0x02000000L
+#define MANUFACTURER_FEATURE_DMACONNECT           0x04000000L
+#define MANUFACTURER_FEATURE_AUDIO_TAP            0x08000000L
+#define MANUFACTURER_FEATURE_FAX_NONSTANDARD      0x10000000L
+#define MANUFACTURER_FEATURE_SS7                  0x20000000L
+#define MANUFACTURER_FEATURE_MADAPTER             0x40000000L
+#define MANUFACTURER_FEATURE_MEASURE              0x80000000L
+#define MANUFACTURER_FEATURE2_LISTENING           0x00000001L
+#define MANUFACTURER_FEATURE2_SS_DIFFCONTPOSSIBLE 0x00000002L
+#define MANUFACTURER_FEATURE2_GENERIC_TONE        0x00000004L
+#define MANUFACTURER_FEATURE2_COLOR_FAX           0x00000008L
+#define MANUFACTURER_FEATURE2_SS_ECT_DIFFCONTPOSSIBLE 0x00000010L
+#define RTP_PRIM_PAYLOAD_PCMU_8000     0
+#define RTP_PRIM_PAYLOAD_1016_8000     1
+#define RTP_PRIM_PAYLOAD_G726_32_8000  2
+#define RTP_PRIM_PAYLOAD_GSM_8000      3
+#define RTP_PRIM_PAYLOAD_G723_8000     4
+#define RTP_PRIM_PAYLOAD_DVI4_8000     5
+#define RTP_PRIM_PAYLOAD_DVI4_16000    6
+#define RTP_PRIM_PAYLOAD_LPC_8000      7
+#define RTP_PRIM_PAYLOAD_PCMA_8000     8
+#define RTP_PRIM_PAYLOAD_G722_16000    9
+#define RTP_PRIM_PAYLOAD_QCELP_8000    12
+#define RTP_PRIM_PAYLOAD_G728_8000     14
+#define RTP_PRIM_PAYLOAD_G729_8000     18
+#define RTP_PRIM_PAYLOAD_GSM_HR_8000   30
+#define RTP_PRIM_PAYLOAD_GSM_EFR_8000  31
+#define RTP_ADD_PAYLOAD_BASE           32
+#define RTP_ADD_PAYLOAD_RED            32
+#define RTP_ADD_PAYLOAD_CN_8000        33
+#define RTP_ADD_PAYLOAD_DTMF           34
+#define RTP_PRIM_PAYLOAD_PCMU_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_PCMU_8000)
+#define RTP_PRIM_PAYLOAD_1016_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_1016_8000)
+#define RTP_PRIM_PAYLOAD_G726_32_8000_SUPPORTED  (1L << RTP_PRIM_PAYLOAD_G726_32_8000)
+#define RTP_PRIM_PAYLOAD_GSM_8000_SUPPORTED      (1L << RTP_PRIM_PAYLOAD_GSM_8000)
+#define RTP_PRIM_PAYLOAD_G723_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_G723_8000)
+#define RTP_PRIM_PAYLOAD_DVI4_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_DVI4_8000)
+#define RTP_PRIM_PAYLOAD_DVI4_16000_SUPPORTED    (1L << RTP_PRIM_PAYLOAD_DVI4_16000)
+#define RTP_PRIM_PAYLOAD_LPC_8000_SUPPORTED      (1L << RTP_PRIM_PAYLOAD_LPC_8000)
+#define RTP_PRIM_PAYLOAD_PCMA_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_PCMA_8000)
+#define RTP_PRIM_PAYLOAD_G722_16000_SUPPORTED    (1L << RTP_PRIM_PAYLOAD_G722_16000)
+#define RTP_PRIM_PAYLOAD_QCELP_8000_SUPPORTED    (1L << RTP_PRIM_PAYLOAD_QCELP_8000)
+#define RTP_PRIM_PAYLOAD_G728_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_G728_8000)
+#define RTP_PRIM_PAYLOAD_G729_8000_SUPPORTED     (1L << RTP_PRIM_PAYLOAD_G729_8000)
+#define RTP_PRIM_PAYLOAD_GSM_HR_8000_SUPPORTED   (1L << RTP_PRIM_PAYLOAD_GSM_HR_8000)
+#define RTP_PRIM_PAYLOAD_GSM_EFR_8000_SUPPORTED  (1L << RTP_PRIM_PAYLOAD_GSM_EFR_8000)
+#define RTP_ADD_PAYLOAD_RED_SUPPORTED            (1L << (RTP_ADD_PAYLOAD_RED - RTP_ADD_PAYLOAD_BASE))
+#define RTP_ADD_PAYLOAD_CN_8000_SUPPORTED        (1L << (RTP_ADD_PAYLOAD_CN_8000 - RTP_ADD_PAYLOAD_BASE))
+#define RTP_ADD_PAYLOAD_DTMF_SUPPORTED           (1L << (RTP_ADD_PAYLOAD_DTMF - RTP_ADD_PAYLOAD_BASE))
+/* virtual switching definitions */
+#define VSJOIN         1
+#define VSTRANSPORT    2
+#define VSGETPARAMS    3
+#define VSCAD          1
+#define VSRXCPNAME     2
+#define VSCALLSTAT     3
+#define VSINVOKEID    4
+#define VSCLMRKS       5
+#define VSTBCTIDENT    6
+#define VSETSILINKID   7
+#define VSSAMECONTROLLER 8
+/* Errorcodes for VSETSILINKID begin */
+#define VSETSILINKIDRRWC      1
+#define VSETSILINKIDREJECT    2
+#define VSETSILINKIDTIMEOUT   3
+#define VSETSILINKIDFAILCOUNT 4
+#define VSETSILINKIDERROR     5
+/* Errorcodes for VSETSILINKID end */
+/* -----------------------------------------------------------**
+** The PROTOCOL_FEATURE_STRING in feature.h (included         **
+** in prstart.sx and astart.sx) defines capabilities and      **
+** features of the actual protocol code. It's used as a bit   **
+** mask.                                                      **
+** The following Bits are defined:                            **
+** -----------------------------------------------------------*/
+#define PROTCAP_TELINDUS  0x0001  /* Telindus Variant of protocol code   */
+#define PROTCAP_MAN_IF    0x0002  /* Management interface implemented    */
+#define PROTCAP_V_42      0x0004  /* V42 implemented                     */
+#define PROTCAP_V90D      0x0008  /* V.90D (implies up to 384k DSP code) */
+#define PROTCAP_EXTD_FAX  0x0010  /* Extended FAX (ECM, 2D, T6, Polling) */
+#define PROTCAP_EXTD_RXFC 0x0020  /* RxFC (Extd Flow Control), OOB Chnl  */
+#define PROTCAP_VOIP      0x0040  /* VoIP (implies up to 512k DSP code)  */
+#define PROTCAP_CMA_ALLPR 0x0080  /* CMA support for all NL primitives   */
+#define PROTCAP_FREE8     0x0100  /* not used                            */
+#define PROTCAP_FREE9     0x0200  /* not used                            */
+#define PROTCAP_FREE10    0x0400  /* not used                            */
+#define PROTCAP_FREE11    0x0800  /* not used                            */
+#define PROTCAP_FREE12    0x1000  /* not used                            */
+#define PROTCAP_FREE13    0x2000  /* not used                            */
+#define PROTCAP_FREE14    0x4000  /* not used                            */
+#define PROTCAP_EXTENSION 0x8000  /* used for future extentions          */
+/* -----------------------------------------------------------* */
+/* Onhook data transmission ETS30065901 */
+/* Message Type */
+/*#define RESERVED4                 0x4*/
+#define CALL_SETUP                0x80
+#define MESSAGE_WAITING_INDICATOR 0x82
+/*#define RESERVED84                0x84*/
+/*#define RESERVED85                0x85*/
+#define ADVICE_OF_CHARGE          0x86
+/*1111 0001
+to
+1111 1111
+F1H - Reserved for network operator use
+to
+FFH*/
+/* Parameter Types */
+#define DATE_AND_TIME                                           1
+#define CLI_PARAMETER_TYPE                                      2
+#define CALLED_DIRECTORY_NUMBER_PARAMETER_TYPE                  3
+#define REASON_FOR_ABSENCE_OF_CLI_PARAMETER_TYPE                4
+#define NAME_PARAMETER_TYPE                                     7
+#define REASON_FOR_ABSENCE_OF_CALLING_PARTY_NAME_PARAMETER_TYPE 8
+#define VISUAL_INDICATOR_PARAMETER_TYPE                         0xb
+#define COMPLEMENTARY_CLI_PARAMETER_TYPE                        0x10
+#define CALL_TYPE_PARAMETER_TYPE                                0x11
+#define FIRST_CALLED_LINE_DIRECTORY_NUMBER_PARAMETER_TYPE       0x12
+#define NETWORK_MESSAGE_SYSTEM_STATUS_PARAMETER_TYPE            0x13
+#define FORWARDED_CALL_TYPE_PARAMETER_TYPE                      0x15
+#define TYPE_OF_CALLING_USER_PARAMETER_TYPE                     0x16
+#define REDIRECTING_NUMBER_PARAMETER_TYPE                       0x1a
+#define EXTENSION_FOR_NETWORK_OPERATOR_USE_PARAMETER_TYPE       0xe0
+/* -----------------------------------------------------------* */
+#else
+#endif /* PC_H_INCLUDED  } */
diff --git a/drivers/isdn/hardware/eicon/pc_init.h b/drivers/isdn/hardware/eicon/pc_init.h
new file mode 100644
index 0000000..a616fc9
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pc_init.h
@@ -0,0 +1,267 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef PC_INIT_H_
+#define PC_INIT_H_
+/*------------------------------------------------------------------*/
+/*
+  Initialisation parameters for the card
+  0x0008 <byte> TEI
+  0x0009 <byte> NT2 flag
+  0x000a <byte> Default DID length
+  0x000b <byte> Disable watchdog flag
+  0x000c <byte> Permanent connection flag
+  0x000d <byte> Bit 3-8: L1 Hunt Group/Tristate
+  0x000d <byte> Bit 1: QSig small CR length if set to 1
+  0x000d <byte> Bit 2: QSig small CHI length if set to 1
+  0x000e <byte> Bit 1-3: Stable L2, 0=OnDemand,1=NoDisc,2=permanent
+  0x000e <byte> Bit 4: NT mode
+  0x000e <byte> Bit 5: QSig Channel ID format
+  0x000e <byte> Bit 6: QSig Call Forwarding Allowed Flag
+  0x000e <byte> Bit 7: Disable AutoSPID Flag
+  0x000f <byte> No order check flag
+  0x0010 <byte> Force companding type:0=default,1=a-law,2=u-law
+  0x0012 <byte> Low channel flag
+  0x0013 <byte> Protocol version
+  0x0014 <byte> CRC4 option:0=default,1=double_frm,2=multi_frm,3=auto
+  0x0015 <byte> Bit 0: NoHscx30, Bit 1: Loopback flag, Bit 2: ForceHscx30
+  0x0016 <byte> DSP info
+  0x0017-0x0019 Serial number
+  0x001a <byte> Card type
+  0x0020 <string> OAD 0
+  0x0040 <string> OSA 0
+  0x0060 <string> SPID 0 (if not T.1)
+  0x0060 <struct> if T.1: Robbed Bit Configuration
+  0x0060          length (8)
+  0x0061          RBS Answer Delay
+  0x0062          RBS Config Bit 3, 4:
+                             0  0 -> Wink Start
+                             1  0 -> Loop Start
+                             0  1 -> Ground Start
+                             1  1 -> reserved
+                             Bit 5, 6:
+                             0  0 -> Pulse Dial -> Rotary
+                             1  0 -> DTMF
+                             0  1 -> MF
+                             1  1 -> reserved
+  0x0063          RBS RX Digit Timeout
+  0x0064          RBS Bearer Capability
+  0x0065-0x0069   RBS Debug Mask
+  0x0080 <string> OAD 1
+  0x00a0 <string> OSA 1
+  0x00c0 <string> SPID 1
+  0x00e0 <w-element list> Additional configuration
+*/
+#define PCINIT_END_OF_LIST                0x00
+#define PCINIT_MODEM_GUARD_TONE           0x01
+#define PCINIT_MODEM_MIN_SPEED            0x02
+#define PCINIT_MODEM_MAX_SPEED            0x03
+#define PCINIT_MODEM_PROTOCOL_OPTIONS     0x04
+#define PCINIT_FAX_OPTIONS                0x05
+#define PCINIT_FAX_MAX_SPEED              0x06
+#define PCINIT_MODEM_OPTIONS              0x07
+#define PCINIT_MODEM_NEGOTIATION_MODE     0x08
+#define PCINIT_MODEM_MODULATIONS_MASK     0x09
+#define PCINIT_MODEM_TRANSMIT_LEVEL       0x0a
+#define PCINIT_FAX_DISABLED_RESOLUTIONS   0x0b
+#define PCINIT_FAX_MAX_RECORDING_WIDTH    0x0c
+#define PCINIT_FAX_MAX_RECORDING_LENGTH   0x0d
+#define PCINIT_FAX_MIN_SCANLINE_TIME      0x0e
+#define PCINIT_US_EKTS_CACH_HANDLES       0x0f
+#define PCINIT_US_EKTS_BEGIN_CONF         0x10
+#define PCINIT_US_EKTS_DROP_CONF          0x11
+#define PCINIT_US_EKTS_CALL_TRANSFER      0x12
+#define PCINIT_RINGERTONE_OPTION          0x13
+#define PCINIT_CARD_ADDRESS               0x14
+#define PCINIT_FPGA_FEATURES              0x15
+#define PCINIT_US_EKTS_MWI                0x16
+#define PCINIT_MODEM_SPEAKER_CONTROL      0x17
+#define PCINIT_MODEM_SPEAKER_VOLUME       0x18
+#define PCINIT_MODEM_CARRIER_WAIT_TIME    0x19
+#define PCINIT_MODEM_CARRIER_LOSS_TIME    0x1a
+#define PCINIT_UNCHAN_B_MASK              0x1b
+#define PCINIT_PART68_LIMITER             0x1c
+#define PCINIT_XDI_FEATURES               0x1d
+#define PCINIT_QSIG_DIALECT               0x1e
+#define PCINIT_DISABLE_AUTOSPID_FLAG      0x1f
+#define PCINIT_FORCE_VOICE_MAIL_ALERT     0x20
+#define PCINIT_PIAFS_TURNAROUND_FRAMES    0x21
+#define PCINIT_L2_COUNT                   0x22
+#define PCINIT_QSIG_FEATURES              0x23
+#define PCINIT_NO_SIGNALLING              0x24
+#define PCINIT_CARD_SN                    0x25
+#define PCINIT_CARD_PORT                  0x26
+#define PCINIT_ALERTTO                    0x27
+#define PCINIT_MODEM_EYE_SETUP            0x28
+#define PCINIT_FAX_V34_OPTIONS            0x29
+/*------------------------------------------------------------------*/
+#define PCINIT_MODEM_GUARD_TONE_NONE            0x00
+#define PCINIT_MODEM_GUARD_TONE_550HZ           0x01
+#define PCINIT_MODEM_GUARD_TONE_1800HZ          0x02
+#define PCINIT_MODEM_GUARD_TONE_CHOICES         0x03
+#define PCINIT_MODEMPROT_DISABLE_V42_V42BIS     0x0001
+#define PCINIT_MODEMPROT_DISABLE_MNP_MNP5       0x0002
+#define PCINIT_MODEMPROT_REQUIRE_PROTOCOL       0x0004
+#define PCINIT_MODEMPROT_DISABLE_V42_DETECT     0x0008
+#define PCINIT_MODEMPROT_DISABLE_COMPRESSION    0x0010
+#define PCINIT_MODEMPROT_REQUIRE_PROTOCOL_V34UP 0x0020
+#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_1200    0x0100
+#define PCINIT_MODEMPROT_BUFFER_IN_V42_DETECT   0x0200
+#define PCINIT_MODEMPROT_DISABLE_V42_SREJ       0x0400
+#define PCINIT_MODEMPROT_DISABLE_MNP3           0x0800
+#define PCINIT_MODEMPROT_DISABLE_MNP4           0x1000
+#define PCINIT_MODEMPROT_DISABLE_MNP10          0x2000
+#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_V22BIS  0x4000
+#define PCINIT_MODEMPROT_NO_PROTOCOL_IF_V32BIS  0x8000
+#define PCINIT_MODEMCONFIG_LEASED_LINE_MODE     0x00000001L
+#define PCINIT_MODEMCONFIG_4_WIRE_OPERATION     0x00000002L
+#define PCINIT_MODEMCONFIG_DISABLE_BUSY_DETECT  0x00000004L
+#define PCINIT_MODEMCONFIG_DISABLE_CALLING_TONE 0x00000008L
+#define PCINIT_MODEMCONFIG_DISABLE_ANSWER_TONE  0x00000010L
+#define PCINIT_MODEMCONFIG_ENABLE_DIAL_TONE_DET 0x00000020L
+#define PCINIT_MODEMCONFIG_USE_POTS_INTERFACE   0x00000040L
+#define PCINIT_MODEMCONFIG_FORCE_RAY_TAYLOR_FAX 0x00000080L
+#define PCINIT_MODEMCONFIG_DISABLE_RETRAIN      0x00000100L
+#define PCINIT_MODEMCONFIG_DISABLE_STEPDOWN     0x00000200L
+#define PCINIT_MODEMCONFIG_DISABLE_SPLIT_SPEED  0x00000400L
+#define PCINIT_MODEMCONFIG_DISABLE_TRELLIS      0x00000800L
+#define PCINIT_MODEMCONFIG_ALLOW_RDL_TEST_LOOP  0x00001000L
+#define PCINIT_MODEMCONFIG_DISABLE_STEPUP       0x00002000L
+#define PCINIT_MODEMCONFIG_DISABLE_FLUSH_TIMER  0x00004000L
+#define PCINIT_MODEMCONFIG_REVERSE_DIRECTION    0x00008000L
+#define PCINIT_MODEMCONFIG_DISABLE_TX_REDUCTION 0x00010000L
+#define PCINIT_MODEMCONFIG_DISABLE_PRECODING    0x00020000L
+#define PCINIT_MODEMCONFIG_DISABLE_PREEMPHASIS  0x00040000L
+#define PCINIT_MODEMCONFIG_DISABLE_SHAPING      0x00080000L
+#define PCINIT_MODEMCONFIG_DISABLE_NONLINEAR_EN 0x00100000L
+#define PCINIT_MODEMCONFIG_DISABLE_MANUALREDUCT 0x00200000L
+#define PCINIT_MODEMCONFIG_DISABLE_16_POINT_TRN 0x00400000L
+#define PCINIT_MODEMCONFIG_DISABLE_2400_SYMBOLS 0x01000000L
+#define PCINIT_MODEMCONFIG_DISABLE_2743_SYMBOLS 0x02000000L
+#define PCINIT_MODEMCONFIG_DISABLE_2800_SYMBOLS 0x04000000L
+#define PCINIT_MODEMCONFIG_DISABLE_3000_SYMBOLS 0x08000000L
+#define PCINIT_MODEMCONFIG_DISABLE_3200_SYMBOLS 0x10000000L
+#define PCINIT_MODEMCONFIG_DISABLE_3429_SYMBOLS 0x20000000L
+#define PCINIT_MODEM_NEGOTIATE_HIGHEST          0x00
+#define PCINIT_MODEM_NEGOTIATE_DISABLED         0x01
+#define PCINIT_MODEM_NEGOTIATE_IN_CLASS         0x02
+#define PCINIT_MODEM_NEGOTIATE_V100             0x03
+#define PCINIT_MODEM_NEGOTIATE_V8               0x04
+#define PCINIT_MODEM_NEGOTIATE_V8BIS            0x05
+#define PCINIT_MODEM_NEGOTIATE_CHOICES          0x06
+#define PCINIT_MODEMMODULATION_DISABLE_V21      0x00000001L
+#define PCINIT_MODEMMODULATION_DISABLE_V23      0x00000002L
+#define PCINIT_MODEMMODULATION_DISABLE_V22      0x00000004L
+#define PCINIT_MODEMMODULATION_DISABLE_V22BIS   0x00000008L
+#define PCINIT_MODEMMODULATION_DISABLE_V32      0x00000010L
+#define PCINIT_MODEMMODULATION_DISABLE_V32BIS   0x00000020L
+#define PCINIT_MODEMMODULATION_DISABLE_V34      0x00000040L
+#define PCINIT_MODEMMODULATION_DISABLE_V90      0x00000080L
+#define PCINIT_MODEMMODULATION_DISABLE_BELL103  0x00000100L
+#define PCINIT_MODEMMODULATION_DISABLE_BELL212A 0x00000200L
+#define PCINIT_MODEMMODULATION_DISABLE_VFC      0x00000400L
+#define PCINIT_MODEMMODULATION_DISABLE_K56FLEX  0x00000800L
+#define PCINIT_MODEMMODULATION_DISABLE_X2       0x00001000L
+#define PCINIT_MODEMMODULATION_ENABLE_V29FDX    0x00010000L
+#define PCINIT_MODEMMODULATION_ENABLE_V33       0x00020000L
+#define PCINIT_MODEMMODULATION_ENABLE_V90A      0x00040000L
+#define PCINIT_MODEM_TRANSMIT_LEVEL_CHOICES     0x10
+#define PCINIT_MODEM_SPEAKER_OFF                0x00
+#define PCINIT_MODEM_SPEAKER_DURING_TRAIN       0x01
+#define PCINIT_MODEM_SPEAKER_TIL_CONNECT        0x02
+#define PCINIT_MODEM_SPEAKER_ALWAYS_ON          0x03
+#define PCINIT_MODEM_SPEAKER_CHOICES            0x04
+#define PCINIT_MODEM_SPEAKER_VOLUME_MIN         0x00
+#define PCINIT_MODEM_SPEAKER_VOLUME_LOW         0x01
+#define PCINIT_MODEM_SPEAKER_VOLUME_HIGH        0x02
+#define PCINIT_MODEM_SPEAKER_VOLUME_MAX         0x03
+#define PCINIT_MODEM_SPEAKER_VOLUME_CHOICES     0x04
+/*------------------------------------------------------------------*/
+#define PCINIT_FAXCONFIG_DISABLE_FINE           0x0001
+#define PCINIT_FAXCONFIG_DISABLE_ECM            0x0002
+#define PCINIT_FAXCONFIG_ECM_64_BYTES           0x0004
+#define PCINIT_FAXCONFIG_DISABLE_2D_CODING      0x0008
+#define PCINIT_FAXCONFIG_DISABLE_T6_CODING      0x0010
+#define PCINIT_FAXCONFIG_DISABLE_UNCOMPR        0x0020
+#define PCINIT_FAXCONFIG_REFUSE_POLLING         0x0040
+#define PCINIT_FAXCONFIG_HIDE_TOTAL_PAGES       0x0080
+#define PCINIT_FAXCONFIG_HIDE_ALL_HEADLINE      0x0100
+#define PCINIT_FAXCONFIG_HIDE_PAGE_INFO         0x0180
+#define PCINIT_FAXCONFIG_HEADLINE_OPTIONS_MASK  0x0180
+#define PCINIT_FAXCONFIG_DISABLE_FEATURE_FALLBACK 0x0200
+#define PCINIT_FAXCONFIG_V34FAX_CONTROL_RATE_1200 0x0800
+#define PCINIT_FAXCONFIG_DISABLE_V34FAX         0x1000
+#define PCINIT_FAXCONFIG_DISABLE_R8_0770_OR_200 0x01
+#define PCINIT_FAXCONFIG_DISABLE_R8_1540        0x02
+#define PCINIT_FAXCONFIG_DISABLE_R16_1540_OR_400 0x04
+#define PCINIT_FAXCONFIG_DISABLE_R4_0385_OR_100 0x08
+#define PCINIT_FAXCONFIG_DISABLE_300_300        0x10
+#define PCINIT_FAXCONFIG_DISABLE_INCH_BASED     0x40
+#define PCINIT_FAXCONFIG_DISABLE_METRIC_BASED   0x80
+#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_A3       0
+#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_B4       1
+#define PCINIT_FAXCONFIG_REC_WIDTH_ISO_A4       2
+#define PCINIT_FAXCONFIG_REC_WIDTH_COUNT        3
+#define PCINIT_FAXCONFIG_REC_LENGTH_UNLIMITED   0
+#define PCINIT_FAXCONFIG_REC_LENGTH_ISO_B4      1
+#define PCINIT_FAXCONFIG_REC_LENGTH_ISO_A4      2
+#define PCINIT_FAXCONFIG_REC_LENGTH_COUNT       3
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_00_00_00 0
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_05_05_05 1
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_05_05 2
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_10_10 3
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_10_10 4
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_20_20 5
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_20_20 6
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_40_40 7
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_8    8
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_9    9
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_RES_10   10
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_10_10_05 11
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_10_05 12
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_20_20_10 13
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_20_10 14
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_40_40_20 15
+#define PCINIT_FAXCONFIG_SCANLINE_TIME_COUNT    16
+#define PCINIT_FAXCONFIG_DISABLE_TX_REDUCTION   0x00010000L
+#define PCINIT_FAXCONFIG_DISABLE_PRECODING      0x00020000L
+#define PCINIT_FAXCONFIG_DISABLE_PREEMPHASIS    0x00040000L
+#define PCINIT_FAXCONFIG_DISABLE_SHAPING        0x00080000L
+#define PCINIT_FAXCONFIG_DISABLE_NONLINEAR_EN   0x00100000L
+#define PCINIT_FAXCONFIG_DISABLE_MANUALREDUCT   0x00200000L
+#define PCINIT_FAXCONFIG_DISABLE_16_POINT_TRN   0x00400000L
+#define PCINIT_FAXCONFIG_DISABLE_2400_SYMBOLS   0x01000000L
+#define PCINIT_FAXCONFIG_DISABLE_2743_SYMBOLS   0x02000000L
+#define PCINIT_FAXCONFIG_DISABLE_2800_SYMBOLS   0x04000000L
+#define PCINIT_FAXCONFIG_DISABLE_3000_SYMBOLS   0x08000000L
+#define PCINIT_FAXCONFIG_DISABLE_3200_SYMBOLS   0x10000000L
+#define PCINIT_FAXCONFIG_DISABLE_3429_SYMBOLS   0x20000000L
+/*--------------------------------------------------------------------------*/
+#define PCINIT_XDI_CMA_FOR_ALL_NL_PRIMITIVES    0x01
+/*--------------------------------------------------------------------------*/
+#define PCINIT_FPGA_PLX_ACCESS_SUPPORTED        0x01
+/*--------------------------------------------------------------------------*/
+#endif
+/*--------------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/pc_maint.h b/drivers/isdn/hardware/eicon/pc_maint.h
new file mode 100644
index 0000000..352ab8d
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pc_maint.h
@@ -0,0 +1,160 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifdef PLATFORM_GT_32BIT
+/* #define POINTER_32BIT byte * __ptr32 */
+#define POINTER_32BIT dword 
+#else
+#define POINTER_32BIT byte *
+#endif
+#if !defined(MIPS_SCOM)
+#define BUFFER_SZ  48
+#define MAINT_OFFS 0x380
+#else
+#define BUFFER_SZ  128
+#if defined(PRI)
+#define MAINT_OFFS 0xef00
+#else
+#define MAINT_OFFS 0xff00
+#endif
+#endif
+#define MIPS_BUFFER_SZ  128
+#if defined(PRI)
+#define MIPS_MAINT_OFFS 0xef00
+#else
+#define MIPS_MAINT_OFFS 0xff00
+#endif
+#define LOG                     1
+#define MEMR                    2
+#define MEMW                    3
+#define IOR                     4
+#define IOW                     5
+#define B1TEST                  6
+#define B2TEST                  7
+#define BTESTOFF                8
+#define DSIG_STATS              9
+#define B_CH_STATS              10
+#define D_CH_STATS              11
+#define BL1_STATS               12
+#define BL1_STATS_C             13
+#define GET_VERSION             14
+#define OS_STATS                15
+#define XLOG_SET_MASK           16
+#define XLOG_GET_MASK           17
+#define DSP_READ                20
+#define DSP_WRITE               21
+#define OK 0xff
+#define MORE_EVENTS 0xfe
+#define NO_EVENT 1
+struct DSigStruc
+{
+  byte Id;
+  byte u;
+  byte listen;
+  byte active;
+  byte sin[3];
+  byte bc[6];
+  byte llc[6];
+  byte hlc[6];
+  byte oad[20];
+};
+struct BL1Struc {
+  dword cx_b1;
+  dword cx_b2;
+  dword cr_b1;
+  dword cr_b2;
+  dword px_b1;
+  dword px_b2;
+  dword pr_b1;
+  dword pr_b2;
+  word er_b1;
+  word er_b2;
+};
+struct L2Struc {
+  dword XTotal;
+  dword RTotal;
+  word XError;
+  word RError;
+};
+struct OSStruc {
+  dword free_n;
+};
+typedef union
+{
+  struct DSigStruc DSigStats;
+  struct BL1Struc BL1Stats;
+  struct L2Struc L2Stats;
+  struct OSStruc OSStats;
+  byte   b[BUFFER_SZ];
+  word   w[BUFFER_SZ>>1];
+  word   l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+  dword  d[BUFFER_SZ>>2];
+} BUFFER;
+typedef union
+{
+  struct DSigStruc DSigStats;
+  struct BL1Struc BL1Stats;
+  struct L2Struc L2Stats;
+  struct OSStruc OSStats;
+  byte   b[MIPS_BUFFER_SZ];
+  word   w[MIPS_BUFFER_SZ>>1];
+  word   l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+  dword  d[MIPS_BUFFER_SZ>>2];
+} MIPS_BUFFER;
+#if !defined(MIPS_SCOM)
+struct pc_maint
+{
+  byte req;
+  byte rc;
+  POINTER_32BIT mem;
+  short length;
+  word port;
+  byte fill[6];
+  BUFFER data;
+};
+#else
+struct pc_maint
+{
+  byte req;
+  byte rc;
+  byte reserved[2];     /* R3000 alignment ... */
+  POINTER_32BIT mem;
+  short length;
+  word port;
+  byte fill[4];         /* data at offset 16   */
+  BUFFER data;
+};
+#endif
+struct mi_pc_maint
+{
+  byte req;
+  byte rc;
+  byte reserved[2];     /* R3000 alignment ... */
+  POINTER_32BIT mem;
+  short length;
+  word port;
+  byte fill[4];         /* data at offset 16   */
+  MIPS_BUFFER data;
+};
diff --git a/drivers/isdn/hardware/eicon/pkmaint.h b/drivers/isdn/hardware/eicon/pkmaint.h
new file mode 100644
index 0000000..722f85f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pkmaint.h
@@ -0,0 +1,44 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_XDI_OS_DEPENDENT_PACK_MAIN_ON_BYTE_INC__
+#define __DIVA_XDI_OS_DEPENDENT_PACK_MAIN_ON_BYTE_INC__
+
+
+/*
+	Only one purpose of this compiler dependent file to pack
+	structures, described in pc_maint.h so that no padding
+	will be included.
+
+	With microsoft compile it is done by "pshpack1.h" and
+	after is restored by "poppack.h"
+	*/
+
+
+#include "pc_maint.h"
+
+
+#endif
+
diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
new file mode 100644
index 0000000..12b8ff2
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/platform.h
@@ -0,0 +1,394 @@
+/* $Id: platform.h,v 1.37.4.6 2005/01/31 12:22:20 armin Exp $
+ *
+ * platform.h
+ * 
+ *
+ * Copyright 2000-2003  by Armin Schindler (mac@melware.de)
+ * Copyright 2000  Eicon Networks 
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+
+#ifndef	__PLATFORM_H__
+#define	__PLATFORM_H__
+
+#if !defined(DIVA_BUILD)
+#define DIVA_BUILD "local"
+#endif
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+#include "cardtype.h"
+
+/* activate debuglib for modules only */
+#ifndef MODULE
+#define DIVA_NO_DEBUGLIB
+#endif
+
+#define DIVA_INIT_FUNCTION  __init
+#define DIVA_EXIT_FUNCTION  __exit
+
+#define DIVA_USER_MODE_CARD_CONFIG 1
+#define	USE_EXTENDED_DEBUGS 1
+
+#define MAX_ADAPTER     32
+
+#define DIVA_ISTREAM 1
+
+#define MEMORY_SPACE_TYPE  0
+#define PORT_SPACE_TYPE    1
+
+
+#include <linux/string.h>
+
+#ifndef	byte
+#define	byte   u8
+#endif
+
+#ifndef	word
+#define	word   u16
+#endif
+
+#ifndef	dword
+#define	dword  u32
+#endif
+
+#ifndef	qword
+#define	qword  u64
+#endif
+
+#ifndef	TRUE
+#define	TRUE	1
+#endif
+
+#ifndef	FALSE
+#define	FALSE	0
+#endif
+
+#ifndef	NULL
+#define	NULL	((void *) 0)
+#endif
+
+#ifndef	MIN
+#define MIN(a,b)	((a)>(b) ? (b) : (a))
+#endif
+
+#ifndef	MAX
+#define MAX(a,b)	((a)>(b) ? (a) : (b))
+#endif
+
+#ifndef	far
+#define far
+#endif
+
+#ifndef	_pascal
+#define _pascal
+#endif
+
+#ifndef	_loadds
+#define _loadds
+#endif
+
+#ifndef	_cdecl
+#define _cdecl
+#endif
+
+#define MEM_TYPE_RAM		0
+#define MEM_TYPE_PORT		1
+#define MEM_TYPE_PROM		2
+#define MEM_TYPE_CTLREG		3
+#define MEM_TYPE_RESET		4
+#define MEM_TYPE_CFG		5
+#define MEM_TYPE_ADDRESS	6
+#define MEM_TYPE_CONFIG		7
+#define MEM_TYPE_CONTROL	8
+
+#define MAX_MEM_TYPE		10
+
+#define DIVA_OS_MEM_ATTACH_RAM(a)	((a)->ram)
+#define DIVA_OS_MEM_ATTACH_PORT(a)	((a)->port)
+#define DIVA_OS_MEM_ATTACH_PROM(a)	((a)->prom)
+#define DIVA_OS_MEM_ATTACH_CTLREG(a)	((a)->ctlReg)
+#define DIVA_OS_MEM_ATTACH_RESET(a)	((a)->reset)
+#define DIVA_OS_MEM_ATTACH_CFG(a)	((a)->cfg)
+#define DIVA_OS_MEM_ATTACH_ADDRESS(a)	((a)->Address)
+#define DIVA_OS_MEM_ATTACH_CONFIG(a)	((a)->Config)
+#define DIVA_OS_MEM_ATTACH_CONTROL(a)	((a)->Control)
+
+#define DIVA_OS_MEM_DETACH_RAM(a, x)	do { } while(0)
+#define DIVA_OS_MEM_DETACH_PORT(a, x)	do { } while(0)
+#define DIVA_OS_MEM_DETACH_PROM(a, x)	do { } while(0)
+#define DIVA_OS_MEM_DETACH_CTLREG(a, x)	do { } while(0)
+#define DIVA_OS_MEM_DETACH_RESET(a, x)	do { } while(0)
+#define DIVA_OS_MEM_DETACH_CFG(a, x)	do { } while(0)
+#define DIVA_OS_MEM_DETACH_ADDRESS(a, x)	do { } while(0)
+#define DIVA_OS_MEM_DETACH_CONFIG(a, x)	do { } while(0)
+#define DIVA_OS_MEM_DETACH_CONTROL(a, x)	do { } while(0)
+
+#if !defined(DIM)
+#define DIM(array)  (sizeof (array)/sizeof ((array)[0]))
+#endif
+
+#define DIVA_INVALID_FILE_HANDLE  ((dword)(-1))
+
+#define DIVAS_CONTAINING_RECORD(address, type, field) \
+        ((type *)((char*)(address) - (char*)(&((type *)0)->field)))
+
+extern int sprintf(char *, const char*, ...);
+
+typedef void* LIST_ENTRY;
+
+typedef char    DEVICE_NAME[64];
+typedef struct _ISDN_ADAPTER   ISDN_ADAPTER;
+typedef struct _ISDN_ADAPTER* PISDN_ADAPTER;
+
+typedef void (* DIVA_DI_PRINTF) (unsigned char *, ...);
+#include "debuglib.h"
+
+#define dtrc(p) DBG_PRV0(p)
+#define dbug(a,p) DBG_PRV1(p)
+
+
+typedef struct e_info_s E_INFO ;
+
+typedef char diva_os_dependent_devica_name_t[64];
+typedef void* PDEVICE_OBJECT;
+
+struct _diva_os_soft_isr;
+struct _diva_os_timer;
+struct _ISDN_ADAPTER;
+
+void diva_log_info(unsigned char *, ...);
+
+/*
+**  XDI DIDD Interface
+*/
+void diva_xdi_didd_register_adapter (int card);
+void diva_xdi_didd_remove_adapter (int card);
+
+/*
+** memory allocation
+*/
+static __inline__ void* diva_os_malloc (unsigned long flags, unsigned long size)
+{
+	void *ret = NULL;
+
+	if (size) {
+		ret = (void *) vmalloc((unsigned int) size);
+	}
+	return (ret);
+}
+static __inline__ void  diva_os_free   (unsigned long flags, void* ptr)
+{
+	vfree(ptr);
+}
+
+/*
+** use skbuffs for message buffer
+*/
+typedef struct sk_buff diva_os_message_buffer_s;
+diva_os_message_buffer_s *diva_os_alloc_message_buffer(unsigned long size, void **data_buf);
+void diva_os_free_message_buffer(diva_os_message_buffer_s *dmb);
+#define DIVA_MESSAGE_BUFFER_LEN(x) x->len
+#define DIVA_MESSAGE_BUFFER_DATA(x) x->data
+
+/*
+** mSeconds waiting
+*/
+static __inline__ void diva_os_sleep(dword mSec)
+{
+	msleep(mSec);
+}
+static __inline__ void diva_os_wait(dword mSec)
+{
+	mdelay(mSec);
+}
+
+/*
+**  PCI Configuration space access
+*/
+void PCIwrite (byte bus, byte func, int offset, void* data, int length, void* pci_dev_handle);
+void PCIread (byte bus, byte func, int offset, void* data, int length, void* pci_dev_handle);
+
+/*
+**  I/O Port utilities
+*/
+int diva_os_register_io_port (void *adapter, int register, unsigned long port,
+				unsigned long length, const char* name, int id);
+/*
+**  I/O port access abstraction
+*/
+byte inpp (void __iomem *);
+word inppw (void __iomem *);
+void inppw_buffer (void __iomem *, void*, int);
+void outppw (void __iomem *, word);
+void outppw_buffer (void __iomem * , void*, int);
+void outpp (void __iomem *, word);
+
+/*
+**  IRQ 
+*/
+typedef struct _diva_os_adapter_irq_info {
+        byte irq_nr;
+        int  registered;
+        char irq_name[24];
+} diva_os_adapter_irq_info_t;
+int diva_os_register_irq (void* context, byte irq, const char* name);
+void diva_os_remove_irq (void* context, byte irq);
+
+#define diva_os_in_irq() in_irq()
+
+/*
+**  Spin Lock framework
+*/
+typedef long diva_os_spin_lock_magic_t;
+typedef spinlock_t diva_os_spin_lock_t;
+static __inline__ int diva_os_initialize_spin_lock (spinlock_t *lock, void * unused) { \
+  spin_lock_init (lock); return(0); }
+static __inline__ void diva_os_enter_spin_lock (diva_os_spin_lock_t* a, \
+                              diva_os_spin_lock_magic_t* old_irql, \
+                              void* dbg) { spin_lock_bh(a); }
+static __inline__ void diva_os_leave_spin_lock (diva_os_spin_lock_t* a, \
+                              diva_os_spin_lock_magic_t* old_irql, \
+                              void* dbg) { spin_unlock_bh(a); }
+
+#define diva_os_destroy_spin_lock(a,b) do { } while(0)
+
+/*
+**  Deffered processing framework
+*/
+typedef int (*diva_os_isr_callback_t)(struct _ISDN_ADAPTER*);
+typedef void (*diva_os_soft_isr_callback_t)(struct _diva_os_soft_isr* psoft_isr, void* context);
+
+typedef struct _diva_os_soft_isr {
+  void* object;
+  diva_os_soft_isr_callback_t callback;
+  void* callback_context;
+  char dpc_thread_name[24];
+} diva_os_soft_isr_t;
+
+int diva_os_initialize_soft_isr (diva_os_soft_isr_t* psoft_isr, diva_os_soft_isr_callback_t callback, void*   callback_context);
+int diva_os_schedule_soft_isr (diva_os_soft_isr_t* psoft_isr);
+int diva_os_cancel_soft_isr (diva_os_soft_isr_t* psoft_isr);
+void diva_os_remove_soft_isr (diva_os_soft_isr_t* psoft_isr);
+
+/*
+  Get time service
+  */
+void diva_os_get_time (dword* sec, dword* usec);
+
+/*
+**  atomic operation, fake because we use threads
+*/
+typedef int diva_os_atomic_t;
+static diva_os_atomic_t __inline__
+diva_os_atomic_increment(diva_os_atomic_t* pv)
+{
+  *pv += 1;
+  return (*pv);
+}
+static diva_os_atomic_t __inline__
+diva_os_atomic_decrement(diva_os_atomic_t* pv)
+{
+  *pv -= 1;
+  return (*pv);
+}
+
+/* 
+**  CAPI SECTION
+*/
+#define NO_CORNETN
+#define IMPLEMENT_DTMF 1
+#define IMPLEMENT_ECHO_CANCELLER 1
+#define IMPLEMENT_RTP 1
+#define IMPLEMENT_T38 1
+#define IMPLEMENT_FAX_SUB_SEP_PWD 1
+#define IMPLEMENT_V18 1
+#define IMPLEMENT_DTMF_TONE 1
+#define IMPLEMENT_PIAFS 1
+#define IMPLEMENT_FAX_PAPER_FORMATS 1
+#define IMPLEMENT_VOWN 1
+#define IMPLEMENT_CAPIDTMF 1
+#define IMPLEMENT_FAX_NONSTANDARD 1
+#define VSWITCH_SUPPORT 1
+
+#define IMPLEMENT_MARKED_OK_AFTER_FC 1
+
+#define DIVA_IDI_RX_DMA 1
+
+/*
+** endian macros
+**
+** If only...  In some cases we did use them for endianness conversion;
+** unfortunately, other uses were real iomem accesses.
+*/
+#define READ_BYTE(addr)   readb(addr)
+#define READ_WORD(addr)   readw(addr)
+#define READ_DWORD(addr)  readl(addr)
+
+#define WRITE_BYTE(addr,v)  writeb(v,addr)
+#define WRITE_WORD(addr,v)  writew(v,addr)
+#define WRITE_DWORD(addr,v) writel(v,addr)
+
+static inline __u16 GET_WORD(void *addr)
+{
+	return le16_to_cpu(*(__le16 *)addr);
+}
+static inline __u32 GET_DWORD(void *addr)
+{
+	return le32_to_cpu(*(__le32 *)addr);
+}
+static inline void PUT_WORD(void *addr, __u16 v)
+{
+	*(__le16 *)addr = cpu_to_le16(v);
+}
+static inline void PUT_DWORD(void *addr, __u32 v)
+{
+	*(__le32 *)addr = cpu_to_le32(v);
+}
+
+/*
+** 32/64 bit macors
+*/
+#ifdef BITS_PER_LONG
+ #if BITS_PER_LONG > 32 
+  #define PLATFORM_GT_32BIT
+  #define ULongToPtr(x) (void *)(unsigned long)(x)
+ #endif
+#endif
+
+/*
+** undef os definitions of macros we use
+*/
+#undef ID_MASK
+#undef N_DATA
+#undef ADDR
+
+/*
+** dump file
+*/
+#define diva_os_dump_file_t char
+#define diva_os_board_trace_t char
+#define diva_os_dump_file(__x__) do { } while(0)
+
+/*
+** size of internal arrays
+*/
+#define MAX_DESCRIPTORS 64
+
+#endif	/* __PLATFORM_H__ */
diff --git a/drivers/isdn/hardware/eicon/pr_pc.h b/drivers/isdn/hardware/eicon/pr_pc.h
new file mode 100644
index 0000000..bf49a5a
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/pr_pc.h
@@ -0,0 +1,76 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+struct pr_ram {
+  word NextReq;         /* pointer to next Req Buffer               */
+  word NextRc;          /* pointer to next Rc Buffer                */
+  word NextInd;         /* pointer to next Ind Buffer               */
+  byte ReqInput;        /* number of Req Buffers sent               */
+  byte ReqOutput;       /* number of Req Buffers returned           */
+  byte ReqReserved;     /* number of Req Buffers reserved           */
+  byte Int;             /* ISDN-P interrupt                         */
+  byte XLock;           /* Lock field for arbitration               */
+  byte RcOutput;        /* number of Rc buffers received            */
+  byte IndOutput;       /* number of Ind buffers received           */
+  byte IMask;           /* Interrupt Mask Flag                      */
+  byte Reserved1[2];    /* reserved field, do not use               */
+  byte ReadyInt;        /* request field for ready interrupt        */
+  byte Reserved2[12];   /* reserved field, do not use               */
+  byte InterfaceType;   /* interface type 1=16K interface           */
+  word Signature;       /* ISDN-P initialized indication            */
+  byte B[1];            /* buffer space for Req,Ind and Rc          */
+};
+typedef struct {
+  word next;
+  byte Req;
+  byte ReqId;
+  byte ReqCh;
+  byte Reserved1;
+  word Reference;
+  byte Reserved[8];
+  PBUFFER XBuffer;
+} REQ;
+typedef struct {
+  word next;
+  byte Rc;
+  byte RcId;
+  byte RcCh;
+  byte Reserved1;
+  word Reference;
+  byte Reserved2[8];
+} RC;
+typedef struct {
+  word next;
+  byte Ind;
+  byte IndId;
+  byte IndCh;
+  byte MInd;
+  word MLength;
+  word Reference;
+  byte RNR;
+  byte Reserved;
+  dword Ack;
+  PBUFFER RBuffer;
+} IND;
diff --git a/drivers/isdn/hardware/eicon/s_4bri.c b/drivers/isdn/hardware/eicon/s_4bri.c
new file mode 100644
index 0000000..25c5d7f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/s_4bri.c
@@ -0,0 +1,510 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+#include "divasync.h"
+#include "pc_init.h"
+#include "io.h"
+#include "helpers.h"
+#include "dsrv4bri.h"
+#include "dsp_defs.h"
+#include "sdp_hdr.h"
+
+/*****************************************************************************/
+#define	MAX_XLOG_SIZE	(64 * 1024)
+
+/* --------------------------------------------------------------------------
+		Recovery XLOG from QBRI Card
+	 -------------------------------------------------------------------------- */
+static void qBri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
+	byte  __iomem *base ;
+	word *Xlog ;
+	dword   regs[4], TrapID, offset, size ;
+	Xdesc   xlogDesc ;
+	int factor = (IoAdapter->tasks == 1) ? 1 : 2;
+
+/*
+ *	check for trapped MIPS 46xx CPU, dump exception frame
+ */
+
+	base = DIVA_OS_MEM_ATTACH_CONTROL(IoAdapter);
+	offset = IoAdapter->ControllerNumber * (IoAdapter->MemorySize >> factor) ;
+
+	TrapID = READ_DWORD(&base[0x80]) ;
+
+	if ( (TrapID == 0x99999999) || (TrapID == 0x99999901) )
+	{
+		dump_trap_frame (IoAdapter, &base[0x90]) ;
+		IoAdapter->trapped = 1 ;
+	}
+
+	regs[0] = READ_DWORD((base + offset) + 0x70);
+	regs[1] = READ_DWORD((base + offset) + 0x74);
+	regs[2] = READ_DWORD((base + offset) + 0x78);
+	regs[3] = READ_DWORD((base + offset) + 0x7c);
+	regs[0] &= IoAdapter->MemorySize - 1 ;
+
+	if ( (regs[0] >= offset)
+	  && (regs[0] < offset + (IoAdapter->MemorySize >> factor) - 1) )
+	{
+		if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) ) {
+			DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
+			return ;
+		}
+
+		size = offset + (IoAdapter->MemorySize >> factor) - regs[0] ;
+		if ( size > MAX_XLOG_SIZE )
+			size = MAX_XLOG_SIZE ;
+		memcpy_fromio (Xlog, &base[regs[0]], size) ;
+		xlogDesc.buf = Xlog ;
+		xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
+		xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
+		dump_xlog_buffer (IoAdapter, &xlogDesc) ;
+		diva_os_free (0, Xlog) ;
+		IoAdapter->trapped = 2 ;
+	}
+	DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
+}
+
+/* --------------------------------------------------------------------------
+		Reset QBRI Hardware
+	 -------------------------------------------------------------------------- */
+static void reset_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	word volatile __iomem *qBriReset ;
+	byte  volatile __iomem *qBriCntrl ;
+	byte  volatile __iomem *p ;
+
+	qBriReset = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
+	WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_SOFT_RESET) ;
+	diva_os_wait (1) ;
+	WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_SOFT_RESET) ;
+	diva_os_wait (1);
+	WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_RELOAD_EEPROM) ;
+	diva_os_wait (1) ;
+	WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_RELOAD_EEPROM) ;
+	diva_os_wait (1);
+	DIVA_OS_MEM_DETACH_PROM(IoAdapter, qBriReset);
+
+	qBriCntrl = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+	p = &qBriCntrl[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
+	WRITE_DWORD(p, 0) ;
+	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, qBriCntrl);
+
+	DBG_TRC(("resetted board @ reset addr 0x%08lx", qBriReset))
+	DBG_TRC(("resetted board @ cntrl addr 0x%08lx", p))
+}
+
+/* --------------------------------------------------------------------------
+		Start Card CPU
+	 -------------------------------------------------------------------------- */
+void start_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	byte volatile __iomem *qBriReset ;
+	byte volatile __iomem *p ;
+
+	p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+	qBriReset = &p[(DIVA_4BRI_REVISION(IoAdapter)) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
+	WRITE_DWORD(qBriReset, MQ_RISC_COLD_RESET_MASK) ;
+	diva_os_wait (2) ;
+	WRITE_DWORD(qBriReset, MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK) ;
+	diva_os_wait (10) ;
+	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+
+	DBG_TRC(("started processor @ addr 0x%08lx", qBriReset))
+}
+
+/* --------------------------------------------------------------------------
+		Stop Card CPU
+	 -------------------------------------------------------------------------- */
+static void stop_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	byte volatile __iomem *p ;
+	dword volatile __iomem *qBriReset ;
+	dword volatile __iomem *qBriIrq ;
+	dword volatile __iomem *qBriIsacDspReset ;
+	int rev2 = DIVA_4BRI_REVISION(IoAdapter);
+	int reset_offset = rev2 ? (MQ2_BREG_RISC)      : (MQ_BREG_RISC);
+	int irq_offset   = rev2 ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST);
+	int hw_offset    = rev2 ? (MQ2_ISAC_DSP_RESET) : (MQ_ISAC_DSP_RESET);
+
+	if ( IoAdapter->ControllerNumber > 0 )
+		return ;
+	p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+	qBriReset = (dword volatile __iomem *)&p[reset_offset];
+	qBriIsacDspReset = (dword volatile __iomem *)&p[hw_offset];
+/*
+ *	clear interrupt line (reset Local Interrupt Test Register)
+ */
+	WRITE_DWORD(qBriReset, 0) ;
+ 	WRITE_DWORD(qBriIsacDspReset, 0) ;
+	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+	
+	p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+	WRITE_BYTE(&p[PLX9054_INTCSR], 0x00);	/* disable PCI interrupts */
+	DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+	
+	p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+	qBriIrq   = (dword volatile __iomem *)&p[irq_offset];
+	WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
+	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+
+	DBG_TRC(("stopped processor @ addr 0x%08lx", qBriReset))
+
+}
+
+/* --------------------------------------------------------------------------
+		FPGA download
+	 -------------------------------------------------------------------------- */
+#define FPGA_NAME_OFFSET         0x10
+
+static byte * qBri_check_FPGAsrc (PISDN_ADAPTER IoAdapter, char *FileName,
+                                  dword *Length, dword *code) {
+	byte *File ;
+	char  *fpgaFile, *fpgaType, *fpgaDate, *fpgaTime ;
+	dword  fpgaFlen,  fpgaTlen,  fpgaDlen, cnt, year, i ;
+
+	if (!(File = (byte *)xdiLoadFile (FileName, Length, 0))) {
+		return (NULL) ;
+	}
+/*
+ *	 scan file until FF and put id string into buffer
+ */
+	for ( i = 0 ; File[i] != 0xff ; )
+	{
+		if ( ++i >= *Length )
+		{
+			DBG_FTL(("FPGA download: start of data header not found"))
+			xdiFreeFile (File) ;
+			return (NULL) ;
+		}
+	}
+	*code = i++ ;
+
+	if ( (File[i] & 0xF0) != 0x20 )
+	{
+		DBG_FTL(("FPGA download: data header corrupted"))
+		xdiFreeFile (File) ;
+		return (NULL) ;
+	}
+	fpgaFlen = (dword)  File[FPGA_NAME_OFFSET - 1] ;
+	if ( fpgaFlen == 0 )
+		fpgaFlen = 12 ;
+	fpgaFile = (char *)&File[FPGA_NAME_OFFSET] ;
+	fpgaTlen = (dword)  fpgaFile[fpgaFlen + 2] ;
+	if ( fpgaTlen == 0 )
+		fpgaTlen = 10 ;
+	fpgaType = (char *)&fpgaFile[fpgaFlen + 3] ;
+	fpgaDlen = (dword)  fpgaType[fpgaTlen + 2] ;
+	if ( fpgaDlen == 0 )
+		fpgaDlen = 11 ;
+	fpgaDate = (char *)&fpgaType[fpgaTlen + 3] ;
+	fpgaTime = (char *)&fpgaDate[fpgaDlen + 3] ;
+	cnt = (dword)(((File[  i  ] & 0x0F) << 20) + (File[i + 1] << 12)
+	             + (File[i + 2]         <<  4) + (File[i + 3] >>  4)) ;
+
+	if ( (dword)(i + (cnt / 8)) > *Length )
+	{
+		DBG_FTL(("FPGA download: '%s' file too small (%ld < %ld)",
+		         FileName, *Length, code + ((cnt + 7) / 8) ))
+		xdiFreeFile (File) ;
+		return (NULL) ;
+	}
+	i = 0 ;
+	do
+	{
+		while ( (fpgaDate[i] != '\0')
+		     && ((fpgaDate[i] < '0') || (fpgaDate[i] > '9')) )
+		{
+			i++;
+		}
+		year = 0 ;
+		while ( (fpgaDate[i] >= '0') && (fpgaDate[i] <= '9') )
+			year = year * 10 + (fpgaDate[i++] - '0') ;
+	} while ( (year < 2000) && (fpgaDate[i] != '\0') );
+
+	switch (IoAdapter->cardType) {
+		case CARDTYPE_DIVASRV_B_2F_PCI:
+			break;
+
+		default:
+	    if ( year >= 2001 ) {
+				IoAdapter->fpga_features |= PCINIT_FPGA_PLX_ACCESS_SUPPORTED ;
+			}
+	}
+
+	DBG_LOG(("FPGA[%s] file %s (%s %s) len %d",
+	         fpgaType, fpgaFile, fpgaDate, fpgaTime, cnt))
+	return (File) ;
+}
+
+/******************************************************************************/
+
+#define FPGA_PROG   0x0001		/* PROG enable low */
+#define FPGA_BUSY   0x0002		/* BUSY high, DONE low */
+#define	FPGA_CS     0x000C		/* Enable I/O pins */
+#define FPGA_CCLK   0x0100
+#define FPGA_DOUT   0x0400
+#define FPGA_DIN    FPGA_DOUT   /* bidirectional I/O */
+
+int qBri_FPGA_download (PISDN_ADAPTER IoAdapter) {
+	int            bit ;
+	byte           *File ;
+	dword          code, FileLength ;
+	word volatile __iomem *addr = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
+	word           val, baseval = FPGA_CS | FPGA_PROG ;
+
+
+
+	if (DIVA_4BRI_REVISION(IoAdapter))
+	{
+		char* name;
+
+		switch (IoAdapter->cardType) {
+			case CARDTYPE_DIVASRV_B_2F_PCI:
+				name = "dsbri2f.bit";
+				break;
+
+			case CARDTYPE_DIVASRV_B_2M_V2_PCI:
+			case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
+				name = "dsbri2m.bit";
+				break;
+
+			default:
+				name = "ds4bri2.bit";
+		}
+
+		File = qBri_check_FPGAsrc (IoAdapter, name,
+	                           		&FileLength, &code);
+	}
+	else
+	{
+		File = qBri_check_FPGAsrc (IoAdapter, "ds4bri.bit",
+		                           &FileLength, &code) ;
+	}
+	if ( !File ) {
+		DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
+		return (0) ;
+	}
+/*
+ *	prepare download, pulse PROGRAM pin down.
+ */
+	WRITE_WORD(addr, baseval & ~FPGA_PROG) ; /* PROGRAM low pulse */
+	WRITE_WORD(addr, baseval) ;              /* release */
+	diva_os_wait (50) ;  /* wait until FPGA finished internal memory clear */
+/*
+ *	check done pin, must be low
+ */
+	if ( READ_WORD(addr) & FPGA_BUSY )
+	{
+		DBG_FTL(("FPGA download: acknowledge for FPGA memory clear missing"))
+		xdiFreeFile (File) ;
+		DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
+		return (0) ;
+	}
+/*
+ *	put data onto the FPGA
+ */
+	while ( code < FileLength )
+	{
+		val = ((word)File[code++]) << 3 ;
+
+		for ( bit = 8 ; bit-- > 0 ; val <<= 1 ) /* put byte onto FPGA */
+		{
+			baseval &= ~FPGA_DOUT ;             /* clr  data bit */
+			baseval |= (val & FPGA_DOUT) ;      /* copy data bit */
+			WRITE_WORD(addr, baseval) ;
+			WRITE_WORD(addr, baseval | FPGA_CCLK) ;     /* set CCLK hi */
+			WRITE_WORD(addr, baseval | FPGA_CCLK) ;     /* set CCLK hi */
+			WRITE_WORD(addr, baseval) ;                 /* set CCLK lo */
+		}
+	}
+	xdiFreeFile (File) ;
+	diva_os_wait (100) ;
+	val = READ_WORD(addr) ;
+
+	DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
+
+	if ( !(val & FPGA_BUSY) )
+	{
+		DBG_FTL(("FPGA download: chip remains in busy state (0x%04x)", val))
+		return (0) ;
+	}
+
+	return (1) ;
+}
+
+static int load_qBri_hardware (PISDN_ADAPTER IoAdapter) {
+	return (0);
+}
+
+/* --------------------------------------------------------------------------
+		Card ISR
+	 -------------------------------------------------------------------------- */
+static int qBri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
+	dword volatile     __iomem *qBriIrq ;
+
+	PADAPTER_LIST_ENTRY QuadroList = IoAdapter->QuadroList ;
+
+	word              	i ;
+	int             	serviced = 0 ;
+	byte __iomem *p;
+
+	p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+
+	if ( !(READ_BYTE(&p[PLX9054_INTCSR]) & 0x80) ) {
+		DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+		return (0) ;
+	}
+	DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+
+/*
+ *	clear interrupt line (reset Local Interrupt Test Register)
+ */
+	p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+	qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
+	WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
+	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+
+	for ( i = 0 ; i < IoAdapter->tasks; ++i )
+	{
+		IoAdapter = QuadroList->QuadroAdapter[i] ;
+
+		if ( IoAdapter && IoAdapter->Initialized
+		  && IoAdapter->tst_irq (&IoAdapter->a) )
+		{
+			IoAdapter->IrqCount++ ;
+			serviced = 1 ;
+			diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
+		}
+	}
+
+	return (serviced) ;
+}
+
+/* --------------------------------------------------------------------------
+		Does disable the interrupt on the card
+	 -------------------------------------------------------------------------- */
+static void disable_qBri_interrupt (PISDN_ADAPTER IoAdapter) {
+	dword volatile __iomem *qBriIrq ;
+	byte __iomem *p;
+
+	if ( IoAdapter->ControllerNumber > 0 )
+		return ;
+/*
+ *	clear interrupt line (reset Local Interrupt Test Register)
+ */
+	p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+	WRITE_BYTE(&p[PLX9054_INTCSR], 0x00);	/* disable PCI interrupts */
+	DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+
+	p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+	qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
+	WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
+	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+}
+
+/* --------------------------------------------------------------------------
+		Install Adapter Entry Points
+	 -------------------------------------------------------------------------- */
+static void set_common_qBri_functions (PISDN_ADAPTER IoAdapter) {
+	ADAPTER *a;
+
+	a = &IoAdapter->a ;
+
+	a->ram_in           = mem_in ;
+	a->ram_inw          = mem_inw ;
+	a->ram_in_buffer    = mem_in_buffer ;
+	a->ram_look_ahead   = mem_look_ahead ;
+	a->ram_out          = mem_out ;
+	a->ram_outw         = mem_outw ;
+	a->ram_out_buffer   = mem_out_buffer ;
+	a->ram_inc          = mem_inc ;
+
+	IoAdapter->out      = pr_out ;
+	IoAdapter->dpc      = pr_dpc ;
+	IoAdapter->tst_irq  = scom_test_int ;
+	IoAdapter->clr_irq  = scom_clear_int ;
+	IoAdapter->pcm      = (struct pc_maint *)MIPS_MAINT_OFFS ;
+
+	IoAdapter->load     = load_qBri_hardware ;
+
+	IoAdapter->disIrq   = disable_qBri_interrupt ;
+	IoAdapter->rstFnc   = reset_qBri_hardware ;
+	IoAdapter->stop     = stop_qBri_hardware ;
+	IoAdapter->trapFnc  = qBri_cpu_trapped ;
+
+	IoAdapter->diva_isr_handler = qBri_ISR;
+
+	IoAdapter->a.io       = (void*)IoAdapter ;
+}
+
+static void set_qBri_functions (PISDN_ADAPTER IoAdapter) {
+	if (!IoAdapter->tasks) {
+		IoAdapter->tasks = MQ_INSTANCE_COUNT;
+	}
+	IoAdapter->MemorySize = MQ_MEMORY_SIZE ;
+	set_common_qBri_functions (IoAdapter) ;
+	diva_os_set_qBri_functions (IoAdapter) ;
+}
+
+static void set_qBri2_functions (PISDN_ADAPTER IoAdapter) {
+	if (!IoAdapter->tasks) {
+		IoAdapter->tasks = MQ_INSTANCE_COUNT;
+	}
+	IoAdapter->MemorySize = (IoAdapter->tasks == 1) ? BRI2_MEMORY_SIZE : MQ2_MEMORY_SIZE;
+	set_common_qBri_functions (IoAdapter) ;
+	diva_os_set_qBri2_functions (IoAdapter) ;
+}
+
+/******************************************************************************/
+
+void prepare_qBri_functions (PISDN_ADAPTER IoAdapter) {
+
+	set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[0]) ;
+	set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[1]) ;
+	set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[2]) ;
+	set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[3]) ;
+
+}
+
+void prepare_qBri2_functions (PISDN_ADAPTER IoAdapter) {
+	if (!IoAdapter->tasks) {
+		IoAdapter->tasks = MQ_INSTANCE_COUNT;
+	}
+
+	set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[0]) ;
+	if (IoAdapter->tasks > 1) {
+		set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[1]) ;
+		set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[2]) ;
+		set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[3]) ;
+	}
+
+}
+
+/* -------------------------------------------------------------------------- */
diff --git a/drivers/isdn/hardware/eicon/s_bri.c b/drivers/isdn/hardware/eicon/s_bri.c
new file mode 100644
index 0000000..5c87552
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/s_bri.c
@@ -0,0 +1,191 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+#include "divasync.h"
+#include "io.h"
+#include "helpers.h"
+#include "dsrv_bri.h"
+#include "dsp_defs.h"
+/*****************************************************************************/
+#define MAX_XLOG_SIZE (64 * 1024)
+/* --------------------------------------------------------------------------
+  Investigate card state, recovery trace buffer
+  -------------------------------------------------------------------------- */
+static void bri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
+ byte  __iomem *addrHi, *addrLo, *ioaddr ;
+ word *Xlog ;
+ dword   regs[4], i, size ;
+ Xdesc   xlogDesc ;
+ byte __iomem *Port;
+/*
+ * first read pointers and trap frame
+ */
+ if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) )
+  return ;
+ Port = DIVA_OS_MEM_ATTACH_PORT(IoAdapter);
+ addrHi =   Port + ((IoAdapter->Properties.Bus == BUS_PCI) ? M_PCI_ADDRH : ADDRH) ;
+ addrLo = Port + ADDR ;
+ ioaddr = Port + DATA ;
+ outpp (addrHi,  0) ;
+ outppw (addrLo, 0) ;
+ for ( i = 0 ; i < 0x100 ; Xlog[i++] = inppw(ioaddr) ) ;
+/*
+ * check for trapped MIPS 3xxx CPU, dump only exception frame
+ */
+ if ( GET_DWORD(&Xlog[0x80 / sizeof(Xlog[0])]) == 0x99999999 )
+ {
+  dump_trap_frame (IoAdapter, &((byte *)Xlog)[0x90]) ;
+  IoAdapter->trapped = 1 ;
+ }
+ regs[0] = GET_DWORD(&((byte *)Xlog)[0x70]);
+ regs[1] = GET_DWORD(&((byte *)Xlog)[0x74]);
+ regs[2] = GET_DWORD(&((byte *)Xlog)[0x78]);
+ regs[3] = GET_DWORD(&((byte *)Xlog)[0x7c]);
+ outpp (addrHi, (regs[1] >> 16) & 0x7F) ;
+ outppw (addrLo, regs[1] & 0xFFFF) ;
+ xlogDesc.cnt = inppw(ioaddr) ;
+ outpp (addrHi, (regs[2] >> 16) & 0x7F) ;
+ outppw (addrLo, regs[2] & 0xFFFF) ;
+ xlogDesc.out = inppw(ioaddr) ;
+ xlogDesc.buf = Xlog ;
+ regs[0] &= IoAdapter->MemorySize - 1 ;
+ if ( (regs[0] < IoAdapter->MemorySize - 1) )
+ {
+  size = IoAdapter->MemorySize - regs[0] ;
+  if ( size > MAX_XLOG_SIZE )
+   size = MAX_XLOG_SIZE ;
+  for ( i = 0 ; i < (size / sizeof(*Xlog)) ; regs[0] += 2 )
+  {
+   outpp (addrHi, (regs[0] >> 16) & 0x7F) ;
+   outppw (addrLo, regs[0] & 0xFFFF) ;
+   Xlog[i++] = inppw(ioaddr) ;
+  }
+  dump_xlog_buffer (IoAdapter, &xlogDesc) ;
+  diva_os_free (0, Xlog) ;
+  IoAdapter->trapped = 2 ;
+ }
+ outpp  (addrHi, (byte)((BRI_UNCACHED_ADDR (IoAdapter->MemoryBase + IoAdapter->MemorySize -
+                                            BRI_SHARED_RAM_SIZE)) >> 16)) ;
+ outppw (addrLo, 0x00) ;
+ DIVA_OS_MEM_DETACH_PORT(IoAdapter, Port);
+}
+/* ---------------------------------------------------------------------
+   Reset hardware
+  --------------------------------------------------------------------- */
+static void reset_bri_hardware (PISDN_ADAPTER IoAdapter) {
+ byte __iomem *p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+ outpp (p, 0x00) ;
+ DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+}
+/* ---------------------------------------------------------------------
+   Halt system
+  --------------------------------------------------------------------- */
+static void stop_bri_hardware (PISDN_ADAPTER IoAdapter) {
+ byte __iomem *p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+ if (p) {
+  outpp (p, 0x00) ; /* disable interrupts ! */
+ }
+ DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+ p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+ outpp (p, 0x00) ;    /* clear int, halt cpu */
+ DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+}
+static int load_bri_hardware (PISDN_ADAPTER IoAdapter) {
+ return (0);
+}
+/******************************************************************************/
+static int bri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
+ byte __iomem *p;
+
+ p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+ if ( !(inpp (p) & 0x01) ) {
+  DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+  return (0) ;
+ }
+ /*
+  clear interrupt line
+  */
+ outpp (p, 0x08) ;
+ DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+ IoAdapter->IrqCount++ ;
+ if ( IoAdapter->Initialized ) {
+  diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
+ }
+ return (1) ;
+}
+/* --------------------------------------------------------------------------
+  Disable IRQ in the card hardware
+  -------------------------------------------------------------------------- */
+static void disable_bri_interrupt (PISDN_ADAPTER IoAdapter) {
+ byte __iomem *p;
+ p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+ if ( p )
+ {
+  outpp (p, 0x00) ; /* disable interrupts ! */
+ }
+ DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+ p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
+ outpp (p, 0x00) ; /* clear int, halt cpu */
+ DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
+}
+/* -------------------------------------------------------------------------
+  Fill card entry points
+  ------------------------------------------------------------------------- */
+void prepare_maestra_functions (PISDN_ADAPTER IoAdapter) {
+ ADAPTER *a = &IoAdapter->a ;
+ a->ram_in             = io_in ;
+ a->ram_inw            = io_inw ;
+ a->ram_in_buffer      = io_in_buffer ;
+ a->ram_look_ahead     = io_look_ahead ;
+ a->ram_out            = io_out ;
+ a->ram_outw           = io_outw ;
+ a->ram_out_buffer     = io_out_buffer ;
+ a->ram_inc            = io_inc ;
+ IoAdapter->MemoryBase = BRI_MEMORY_BASE ;
+ IoAdapter->MemorySize = BRI_MEMORY_SIZE ;
+ IoAdapter->out        = pr_out ;
+ IoAdapter->dpc        = pr_dpc ;
+ IoAdapter->tst_irq    = scom_test_int ;
+ IoAdapter->clr_irq    = scom_clear_int ;
+ IoAdapter->pcm        = (struct pc_maint *)MIPS_MAINT_OFFS ;
+ IoAdapter->load       = load_bri_hardware ;
+ IoAdapter->disIrq     = disable_bri_interrupt ;
+ IoAdapter->rstFnc     = reset_bri_hardware ;
+ IoAdapter->stop       = stop_bri_hardware ;
+ IoAdapter->trapFnc    = bri_cpu_trapped ;
+ IoAdapter->diva_isr_handler = bri_ISR;
+ /*
+  Prepare OS dependent functions
+  */
+ diva_os_prepare_maestra_functions (IoAdapter);
+}
+/* -------------------------------------------------------------------------- */
diff --git a/drivers/isdn/hardware/eicon/s_pri.c b/drivers/isdn/hardware/eicon/s_pri.c
new file mode 100644
index 0000000..18f2878
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/s_pri.c
@@ -0,0 +1,205 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "di.h"
+#include "mi_pc.h"
+#include "pc_maint.h"
+#include "divasync.h"
+#include "io.h"
+#include "helpers.h"
+#include "dsrv_pri.h"
+#include "dsp_defs.h"
+/*****************************************************************************/
+#define MAX_XLOG_SIZE  (64 * 1024)
+/* -------------------------------------------------------------------------
+  Does return offset between ADAPTER->ram and real begin of memory
+  ------------------------------------------------------------------------- */
+static dword pri_ram_offset (ADAPTER* a) {
+ return ((dword)MP_SHARED_RAM_OFFSET);
+}
+/* -------------------------------------------------------------------------
+  Recovery XLOG buffer from the card
+  ------------------------------------------------------------------------- */
+static void pri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
+ byte  __iomem *base ;
+ word *Xlog ;
+ dword   regs[4], TrapID, size ;
+ Xdesc   xlogDesc ;
+/*
+ * check for trapped MIPS 46xx CPU, dump exception frame
+ */
+ base   = DIVA_OS_MEM_ATTACH_ADDRESS(IoAdapter);
+ TrapID = READ_DWORD(&base[0x80]) ;
+ if ( (TrapID == 0x99999999) || (TrapID == 0x99999901) )
+ {
+  dump_trap_frame (IoAdapter, &base[0x90]) ;
+  IoAdapter->trapped = 1 ;
+ }
+ regs[0] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x70]);
+ regs[1] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x74]);
+ regs[2] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x78]);
+ regs[3] = READ_DWORD(&base[MP_PROTOCOL_OFFSET + 0x7c]);
+ regs[0] &= IoAdapter->MemorySize - 1 ;
+ if ( (regs[0] < IoAdapter->MemorySize - 1) )
+ {
+  if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) ) {
+   DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, base);
+   return ;
+  }
+  size = IoAdapter->MemorySize - regs[0] ;
+  if ( size > MAX_XLOG_SIZE )
+   size = MAX_XLOG_SIZE ;
+  memcpy_fromio(Xlog, &base[regs[0]], size) ;
+  xlogDesc.buf = Xlog ;
+  xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
+  xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
+  dump_xlog_buffer (IoAdapter, &xlogDesc) ;
+  diva_os_free (0, Xlog) ;
+  IoAdapter->trapped = 2 ;
+ }
+ DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, base);
+}
+/* -------------------------------------------------------------------------
+  Hardware reset of PRI card
+  ------------------------------------------------------------------------- */
+static void reset_pri_hardware (PISDN_ADAPTER IoAdapter) {
+ byte __iomem *p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+ WRITE_BYTE(p, _MP_RISC_RESET | _MP_LED1 | _MP_LED2);
+ diva_os_wait (50) ;
+ WRITE_BYTE(p, 0x00);
+ diva_os_wait (50) ;
+ DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+}
+/* -------------------------------------------------------------------------
+  Stop Card Hardware
+  ------------------------------------------------------------------------- */
+static void stop_pri_hardware (PISDN_ADAPTER IoAdapter) {
+ dword i;
+ byte __iomem *p;
+ dword volatile __iomem *cfgReg = (void __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
+ WRITE_DWORD(&cfgReg[3], 0);
+ WRITE_DWORD(&cfgReg[1], 0);
+ DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
+ IoAdapter->a.ram_out (&IoAdapter->a, &RAM->SWReg, SWREG_HALT_CPU) ;
+ i = 0 ;
+ while ( (i < 100) && (IoAdapter->a.ram_in (&IoAdapter->a, &RAM->SWReg) != 0) )
+ {
+  diva_os_wait (1) ;
+  i++ ;
+ }
+ DBG_TRC(("%s: PRI stopped (%d)", IoAdapter->Name, i))
+ cfgReg = (void __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
+ WRITE_DWORD(&cfgReg[0],((dword)(~0x03E00000)));
+ DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
+ diva_os_wait (1) ;
+ p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
+ WRITE_BYTE(p, _MP_RISC_RESET | _MP_LED1 | _MP_LED2);
+ DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
+}
+static int load_pri_hardware (PISDN_ADAPTER IoAdapter) {
+ return (0);
+}
+/* --------------------------------------------------------------------------
+  PRI Adapter interrupt Service Routine
+   -------------------------------------------------------------------------- */
+static int pri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
+ byte __iomem *cfg = DIVA_OS_MEM_ATTACH_CFG(IoAdapter);
+ if ( !(READ_DWORD(cfg) & 0x80000000) ) {
+  DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfg);
+  return (0) ;
+ }
+ /*
+  clear interrupt line
+  */
+ WRITE_DWORD(cfg, (dword)~0x03E00000) ;
+ DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfg);
+ IoAdapter->IrqCount++ ;
+ if ( IoAdapter->Initialized )
+ {
+  diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
+ }
+ return (1) ;
+}
+/* -------------------------------------------------------------------------
+  Disable interrupt in the card hardware
+  ------------------------------------------------------------------------- */
+static void disable_pri_interrupt (PISDN_ADAPTER IoAdapter) {
+ dword volatile __iomem *cfgReg = (dword volatile __iomem *)DIVA_OS_MEM_ATTACH_CFG(IoAdapter) ;
+ WRITE_DWORD(&cfgReg[3], 0);
+ WRITE_DWORD(&cfgReg[1], 0);
+ WRITE_DWORD(&cfgReg[0], (dword)(~0x03E00000)) ;
+ DIVA_OS_MEM_DETACH_CFG(IoAdapter, cfgReg);
+}
+/* -------------------------------------------------------------------------
+  Install entry points for PRI Adapter
+  ------------------------------------------------------------------------- */
+static void prepare_common_pri_functions (PISDN_ADAPTER IoAdapter) {
+ ADAPTER *a = &IoAdapter->a ;
+ a->ram_in           = mem_in ;
+ a->ram_inw          = mem_inw ;
+ a->ram_in_buffer    = mem_in_buffer ;
+ a->ram_look_ahead   = mem_look_ahead ;
+ a->ram_out          = mem_out ;
+ a->ram_outw         = mem_outw ;
+ a->ram_out_buffer   = mem_out_buffer ;
+ a->ram_inc          = mem_inc ;
+ a->ram_offset       = pri_ram_offset ;
+ a->ram_out_dw    = mem_out_dw;
+ a->ram_in_dw    = mem_in_dw;
+  a->istream_wakeup   = pr_stream;
+ IoAdapter->out      = pr_out ;
+ IoAdapter->dpc      = pr_dpc ;
+ IoAdapter->tst_irq  = scom_test_int ;
+ IoAdapter->clr_irq  = scom_clear_int ;
+ IoAdapter->pcm      = (struct pc_maint *)(MIPS_MAINT_OFFS
+                                        - MP_SHARED_RAM_OFFSET) ;
+ IoAdapter->load     = load_pri_hardware ;
+ IoAdapter->disIrq   = disable_pri_interrupt ;
+ IoAdapter->rstFnc   = reset_pri_hardware ;
+ IoAdapter->stop     = stop_pri_hardware ;
+ IoAdapter->trapFnc  = pri_cpu_trapped ;
+ IoAdapter->diva_isr_handler = pri_ISR;
+}
+/* -------------------------------------------------------------------------
+  Install entry points for PRI Adapter
+  ------------------------------------------------------------------------- */
+void prepare_pri_functions (PISDN_ADAPTER IoAdapter) {
+ IoAdapter->MemorySize = MP_MEMORY_SIZE ;
+ prepare_common_pri_functions (IoAdapter) ;
+ diva_os_prepare_pri_functions (IoAdapter);
+}
+/* -------------------------------------------------------------------------
+  Install entry points for PRI Rev.2 Adapter
+  ------------------------------------------------------------------------- */
+void prepare_pri2_functions (PISDN_ADAPTER IoAdapter) {
+ IoAdapter->MemorySize = MP2_MEMORY_SIZE ;
+ prepare_common_pri_functions (IoAdapter) ;
+ diva_os_prepare_pri2_functions (IoAdapter);
+}
+/* ------------------------------------------------------------------------- */
diff --git a/drivers/isdn/hardware/eicon/sdp_hdr.h b/drivers/isdn/hardware/eicon/sdp_hdr.h
new file mode 100644
index 0000000..8f61c69
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/sdp_hdr.h
@@ -0,0 +1,117 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#ifndef __DIVA_SOFT_DSP_TASK_ENTRY_H__
+#define __DIVA_SOFT_DSP_TASK_ENTRY_H__
+/*
+ The soft DSP image is described by binary header contained on begin of this
+ image:
+OFFSET FROM IMAGE START |  VARIABLE
+------------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_LINK_OFFS   |  link to the next image
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_GP_OFFS    |  image gp register value, void*
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_ENTRY_OFFS   |  diva_mips_sdp_task_entry_t*
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_LOAD_ADDR_OFFS |  image image start address (void*)
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_END_ADDR_OFFS |  image image end address   (void*)
+  ----------------------------------------------------------------------
+ DIVA_MIPS_TASK_IMAGE_ID_STRING_OFFS |  image id string char[...];
+  ----------------------------------------------------------------------
+ */
+#define DIVA_MIPS_TASK_IMAGE_LINK_OFFS   0x6C
+#define DIVA_MIPS_TASK_IMAGE_GP_OFFS    0x70
+#define DIVA_MIPS_TASK_IMAGE_ENTRY_OFFS   0x74
+#define DIVA_MIPS_TASK_IMAGE_LOAD_ADDR_OFFS 0x78
+#define DIVA_MIPS_TASK_IMAGE_END_ADDR_OFFS 0x7c
+#define DIVA_MIPS_TASK_IMAGE_ID_STRING_OFFS 0x80
+/*
+ This function is called in order to set GP register of this task
+ This function should be always called before any function of the
+ task is called
+ */
+typedef void (*diva_task_set_prog_gp_proc_t)(void* new_gp);
+/*
+ This function is called to clear .bss at task initialization step
+ */
+typedef void  (*diva_task_sys_reset_proc_t)(void);
+/*
+ This function is called in order to provide GP of master call to
+ task, that will be used by calls from the task to the master
+ */
+typedef void (*diva_task_set_main_gp_proc_t)(void* main_gp);
+/*
+ This function is called to provide address of 'dprintf' function
+ to the task
+ */
+typedef word (*diva_prt_proc_t)(char *, ...);
+typedef void (*diva_task_set_prt_proc_t)(diva_prt_proc_t fn);
+/*
+ This function is called to set task PID
+ */
+typedef void (*diva_task_set_pid_proc_t)(dword id);
+/*
+ This function is called for run-time task init
+ */
+typedef int (*diva_task_run_time_init_proc_t)(void*, dword);
+/*
+ This function is called from system scheduler or from timer
+ */
+typedef void (*diva_task_callback_proc_t)(void);
+/*
+ This callback is used by task to get current time im mS
+  */
+typedef dword (*diva_task_get_tick_count_proc_t)(void);
+typedef void (*diva_task_set_get_time_proc_t)(\
+                diva_task_get_tick_count_proc_t fn);
+typedef struct _diva_mips_sdp_task_entry {
+ diva_task_set_prog_gp_proc_t  set_gp_proc;
+ diva_task_sys_reset_proc_t   sys_reset_proc;
+ diva_task_set_main_gp_proc_t  set_main_gp_proc;
+ diva_task_set_prt_proc_t    set_dprintf_proc;
+ diva_task_set_pid_proc_t    set_pid_proc;
+ diva_task_run_time_init_proc_t run_time_init_proc;
+ diva_task_callback_proc_t    task_callback_proc;
+ diva_task_callback_proc_t    timer_callback_proc;
+ diva_task_set_get_time_proc_t  set_get_time_proc;
+ void*              last_entry_proc;
+} diva_mips_sdp_task_entry_t;
+/*
+ 'last_entry_proc' should be set to zero and is used for future extensuios
+ */
+typedef struct _diva_mips_sw_task {
+  diva_mips_sdp_task_entry_t  sdp_entry;
+  void*                       sdp_gp_reg;
+  void*                       own_gp_reg;
+} diva_mips_sw_task_t;
+#if !defined(DIVA_BRI2F_SDP_1_NAME)
+#define DIVA_BRI2F_SDP_1_NAME "sdp0.2q0"
+#endif
+#if !defined(DIVA_BRI2F_SDP_2_NAME)
+#define DIVA_BRI2F_SDP_2_NAME "sdp1.2q0"
+#endif
+#endif
diff --git a/drivers/isdn/hardware/eicon/um_idi.c b/drivers/isdn/hardware/eicon/um_idi.c
new file mode 100644
index 0000000..6563db9
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/um_idi.c
@@ -0,0 +1,885 @@
+/* $Id: um_idi.c,v 1.14 2004/03/21 17:54:37 armin Exp $ */
+
+#include "platform.h"
+#include "di_defs.h"
+#include "pc.h"
+#include "dqueue.h"
+#include "adapter.h"
+#include "entity.h"
+#include "um_xdi.h"
+#include "um_idi.h"
+#include "debuglib.h"
+#include "divasync.h"
+
+#define DIVAS_MAX_XDI_ADAPTERS	64
+
+/* --------------------------------------------------------------------------
+		IMPORTS
+   -------------------------------------------------------------------------- */
+extern void diva_os_wakeup_read(void *os_context);
+extern void diva_os_wakeup_close(void *os_context);
+/* --------------------------------------------------------------------------
+		LOCALS
+   -------------------------------------------------------------------------- */
+static LIST_HEAD(adapter_q);
+static diva_os_spin_lock_t adapter_lock;
+
+static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr);
+static void cleanup_adapter(diva_um_idi_adapter_t * a);
+static void cleanup_entity(divas_um_idi_entity_t * e);
+static int diva_user_mode_idi_adapter_features(diva_um_idi_adapter_t * a,
+					       diva_um_idi_adapter_features_t
+					       * features);
+static int process_idi_request(divas_um_idi_entity_t * e,
+			       const diva_um_idi_req_hdr_t * req);
+static int process_idi_rc(divas_um_idi_entity_t * e, byte rc);
+static int process_idi_ind(divas_um_idi_entity_t * e, byte ind);
+static int write_return_code(divas_um_idi_entity_t * e, byte rc);
+
+/* --------------------------------------------------------------------------
+		MAIN
+   -------------------------------------------------------------------------- */
+int diva_user_mode_idi_init(void)
+{
+	diva_os_initialize_spin_lock(&adapter_lock, "adapter");
+	return (0);
+}
+
+/* --------------------------------------------------------------------------
+		Copy adapter features to user supplied buffer
+   -------------------------------------------------------------------------- */
+static int
+diva_user_mode_idi_adapter_features(diva_um_idi_adapter_t * a,
+				    diva_um_idi_adapter_features_t *
+				    features)
+{
+	IDI_SYNC_REQ sync_req;
+
+	if ((a) && (a->d.request)) {
+		features->type = a->d.type;
+		features->features = a->d.features;
+		features->channels = a->d.channels;
+		memset(features->name, 0, sizeof(features->name));
+
+		sync_req.GetName.Req = 0;
+		sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;
+		(*(a->d.request)) ((ENTITY *) & sync_req);
+		strlcpy(features->name, sync_req.GetName.name,
+			sizeof(features->name));
+
+		sync_req.GetSerial.Req = 0;
+		sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
+		sync_req.GetSerial.serial = 0;
+		(*(a->d.request)) ((ENTITY *) & sync_req);
+		features->serial_number = sync_req.GetSerial.serial;
+	}
+
+	return ((a) ? 0 : -1);
+}
+
+/* --------------------------------------------------------------------------
+		REMOVE ADAPTER
+   -------------------------------------------------------------------------- */
+void diva_user_mode_idi_remove_adapter(int adapter_nr)
+{
+	struct list_head *tmp;
+	diva_um_idi_adapter_t *a;
+
+	list_for_each(tmp, &adapter_q) {
+		a = list_entry(tmp, diva_um_idi_adapter_t, link);
+		if (a->adapter_nr == adapter_nr) {
+			list_del(tmp);
+			cleanup_adapter(a);
+			DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr));
+			diva_os_free(0, a);
+			break;
+		}
+	}
+}
+
+/* --------------------------------------------------------------------------
+		CALLED ON DRIVER EXIT (UNLOAD)
+   -------------------------------------------------------------------------- */
+void diva_user_mode_idi_finit(void)
+{
+	struct list_head *tmp, *safe;
+	diva_um_idi_adapter_t *a;
+
+	list_for_each_safe(tmp, safe, &adapter_q) {
+		a = list_entry(tmp, diva_um_idi_adapter_t, link);
+		list_del(tmp);
+		cleanup_adapter(a);
+		DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr));
+		diva_os_free(0, a);
+	}
+	diva_os_destroy_spin_lock(&adapter_lock, "adapter");
+}
+
+/* -------------------------------------------------------------------------
+		CREATE AND INIT IDI ADAPTER
+	 ------------------------------------------------------------------------- */
+int diva_user_mode_idi_create_adapter(const DESCRIPTOR * d, int adapter_nr)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	diva_um_idi_adapter_t *a =
+	    (diva_um_idi_adapter_t *) diva_os_malloc(0,
+						     sizeof
+						     (diva_um_idi_adapter_t));
+
+	if (!a) {
+		return (-1);
+	}
+	memset(a, 0x00, sizeof(*a));
+	INIT_LIST_HEAD(&a->entity_q);
+
+	a->d = *d;
+	a->adapter_nr = adapter_nr;
+
+	DBG_LOG(("DIDD_ADD A(%d), type:%02x, features:%04x, channels:%d",
+		 adapter_nr, a->d.type, a->d.features, a->d.channels));
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_adapter");
+	list_add_tail(&a->link, &adapter_q);
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_adapter");
+	return (0);
+}
+
+/* ------------------------------------------------------------------------
+			Find adapter by Adapter number
+   ------------------------------------------------------------------------ */
+static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr)
+{
+	diva_um_idi_adapter_t *a = NULL;
+	struct list_head *tmp;
+
+	list_for_each(tmp, &adapter_q) {
+		a = list_entry(tmp, diva_um_idi_adapter_t, link);
+		DBG_TRC(("find_adapter: (%d)-(%d)", nr, a->adapter_nr));
+		if (a->adapter_nr == (int)nr)
+			break;
+		a = NULL;
+	}
+	return(a);
+}
+
+/* ------------------------------------------------------------------------
+		Cleanup this adapter and cleanup/delete all entities assigned
+		to this adapter
+   ------------------------------------------------------------------------ */
+static void cleanup_adapter(diva_um_idi_adapter_t * a)
+{
+	struct list_head *tmp, *safe;
+	divas_um_idi_entity_t *e;
+
+	list_for_each_safe(tmp, safe, &a->entity_q) {
+		e = list_entry(tmp, divas_um_idi_entity_t, link);
+		list_del(tmp);
+		cleanup_entity(e);
+		if (e->os_context) {
+			diva_os_wakeup_read(e->os_context);
+			diva_os_wakeup_close(e->os_context);
+		}
+	}
+	memset(&a->d, 0x00, sizeof(DESCRIPTOR));
+}
+
+/* ------------------------------------------------------------------------
+		Cleanup, but NOT delete this entity
+   ------------------------------------------------------------------------ */
+static void cleanup_entity(divas_um_idi_entity_t * e)
+{
+	e->os_ref = NULL;
+	e->status = 0;
+	e->adapter = NULL;
+	e->e.Id = 0;
+	e->rc_count = 0;
+
+	e->status |= DIVA_UM_IDI_REMOVED;
+	e->status |= DIVA_UM_IDI_REMOVE_PENDING;
+
+	diva_data_q_finit(&e->data);
+	diva_data_q_finit(&e->rc);
+}
+
+
+/* ------------------------------------------------------------------------
+		Create ENTITY, link it to the adapter and remove pointer to entity
+   ------------------------------------------------------------------------ */
+void *divas_um_idi_create_entity(dword adapter_nr, void *file)
+{
+	divas_um_idi_entity_t *e;
+	diva_um_idi_adapter_t *a;
+	diva_os_spin_lock_magic_t old_irql;
+
+	if ((e = (divas_um_idi_entity_t *) diva_os_malloc(0, sizeof(*e)))) {
+		memset(e, 0x00, sizeof(*e));
+		if (!
+		    (e->os_context =
+		     diva_os_malloc(0, diva_os_get_context_size()))) {
+			DBG_LOG(("E(%08x) no memory for os context", e));
+			diva_os_free(0, e);
+			return NULL;
+		}
+		memset(e->os_context, 0x00, diva_os_get_context_size());
+
+		if ((diva_data_q_init(&e->data, 2048 + 512, 16))) {
+			diva_os_free(0, e->os_context);
+			diva_os_free(0, e);
+			return NULL;
+		}
+		if ((diva_data_q_init(&e->rc, sizeof(diva_um_idi_ind_hdr_t), 2))) {
+			diva_data_q_finit(&e->data);
+			diva_os_free(0, e->os_context);
+			diva_os_free(0, e);
+			return NULL;
+		}
+
+		diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_entity");
+		/*
+		   Look for Adapter requested
+		 */
+		if (!(a = diva_um_idi_find_adapter(adapter_nr))) {
+			/*
+			   No adapter was found, or this adapter was removed
+			 */
+			diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_entity");
+
+			DBG_LOG(("A: no adapter(%ld)", adapter_nr));
+
+			cleanup_entity(e);
+			diva_os_free(0, e->os_context);
+			diva_os_free(0, e);
+
+			return NULL;
+		}
+
+		e->os_ref = file;	/* link to os handle */
+		e->adapter = a;	/* link to adapter   */
+
+		list_add_tail(&e->link, &a->entity_q);	/* link from adapter */
+
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_entity");
+
+		DBG_LOG(("A(%ld), create E(%08x)", adapter_nr, e));
+	}
+
+	return (e);
+}
+
+/* ------------------------------------------------------------------------
+		Unlink entity and free memory 
+   ------------------------------------------------------------------------ */
+int divas_um_idi_delete_entity(int adapter_nr, void *entity)
+{
+	divas_um_idi_entity_t *e;
+	diva_um_idi_adapter_t *a;
+	diva_os_spin_lock_magic_t old_irql;
+
+	if (!(e = (divas_um_idi_entity_t *) entity))
+		return (-1);
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "delete_entity");
+	if ((a = e->adapter)) {
+		list_del(&e->link);
+	}
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "delete_entity");
+
+	diva_um_idi_stop_wdog(entity);
+	cleanup_entity(e);
+	diva_os_free(0, e->os_context);
+	memset(e, 0x00, sizeof(*e));
+	diva_os_free(0, e);
+
+	DBG_LOG(("A(%d) remove E:%08x", adapter_nr, e));
+
+	return (0);
+}
+
+/* --------------------------------------------------------------------------
+		Called by application to read data from IDI
+	 -------------------------------------------------------------------------- */
+int diva_um_idi_read(void *entity,
+		     void *os_handle,
+		     void *dst,
+		     int max_length, divas_um_idi_copy_to_user_fn_t cp_fn)
+{
+	divas_um_idi_entity_t *e;
+	diva_um_idi_adapter_t *a;
+	const void *data;
+	int length, ret = 0;
+	diva_um_idi_data_queue_t *q;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "read");
+
+	e = (divas_um_idi_entity_t *) entity;
+	if (!e || (!(a = e->adapter)) ||
+	    (e->status & DIVA_UM_IDI_REMOVE_PENDING) ||
+	    (e->status & DIVA_UM_IDI_REMOVED) ||
+	    (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "read");
+		DBG_ERR(("E(%08x) read failed - adapter removed", e))
+		return (-1);
+	}
+
+	DBG_TRC(("A(%d) E(%08x) read(%d)", a->adapter_nr, e, max_length));
+
+	/*
+	   Try to read return code first
+	 */
+	data = diva_data_q_get_segment4read(&e->rc);
+	q = &e->rc;
+
+	/*
+	   No return codes available, read indications now
+	 */
+	if (!data) {
+		if (!(e->status & DIVA_UM_IDI_RC_PENDING)) {
+			DBG_TRC(("A(%d) E(%08x) read data", a->adapter_nr, e));
+			data = diva_data_q_get_segment4read(&e->data);
+			q = &e->data;
+		}
+	} else {
+		e->status &= ~DIVA_UM_IDI_RC_PENDING;
+		DBG_TRC(("A(%d) E(%08x) read rc", a->adapter_nr, e));
+	}
+
+	if (data) {
+		if ((length = diva_data_q_get_segment_length(q)) >
+		    max_length) {
+			/*
+			   Not enough space to read message
+			 */
+			DBG_ERR(("A: A(%d) E(%08x) read small buffer",
+				 a->adapter_nr, e, ret));
+			diva_os_leave_spin_lock(&adapter_lock, &old_irql,
+						"read");
+			return (-2);
+		}
+		/*
+		   Copy it to user, this function does access ONLY locked an verified
+		   memory, also we can access it witch spin lock held
+		 */
+
+		if ((ret = (*cp_fn) (os_handle, dst, data, length)) >= 0) {
+			/*
+			   Acknowledge only if read was successfull
+			 */
+			diva_data_q_ack_segment4read(q);
+		}
+	}
+
+
+	DBG_TRC(("A(%d) E(%08x) read=%d", a->adapter_nr, e, ret));
+
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "read");
+
+	return (ret);
+}
+
+
+int diva_um_idi_write(void *entity,
+		      void *os_handle,
+		      const void *src,
+		      int length, divas_um_idi_copy_from_user_fn_t cp_fn)
+{
+	divas_um_idi_entity_t *e;
+	diva_um_idi_adapter_t *a;
+	diva_um_idi_req_hdr_t *req;
+	void *data;
+	int ret = 0;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "write");
+
+	e = (divas_um_idi_entity_t *) entity;
+	if (!e || (!(a = e->adapter)) ||
+	    (e->status & DIVA_UM_IDI_REMOVE_PENDING) ||
+	    (e->status & DIVA_UM_IDI_REMOVED) ||
+	    (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+		DBG_ERR(("E(%08x) write failed - adapter removed", e))
+		return (-1);
+	}
+
+	DBG_TRC(("A(%d) E(%08x) write(%d)", a->adapter_nr, e, length));
+
+	if ((length < sizeof(*req)) || (length > sizeof(e->buffer))) {
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+		return (-2);
+	}
+
+	if (e->status & DIVA_UM_IDI_RC_PENDING) {
+		DBG_ERR(("A: A(%d) E(%08x) rc pending", a->adapter_nr, e));
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+		return (-1);	/* should wait for RC code first */
+	}
+
+	/*
+	   Copy function does access only locked verified memory,
+	   also it can be called with spin lock held
+	 */
+	if ((ret = (*cp_fn) (os_handle, e->buffer, src, length)) < 0) {
+		DBG_TRC(("A: A(%d) E(%08x) write error=%d", a->adapter_nr,
+			 e, ret));
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+		return (ret);
+	}
+
+	req = (diva_um_idi_req_hdr_t *) & e->buffer[0];
+
+	switch (req->type) {
+	case DIVA_UM_IDI_GET_FEATURES:{
+			DBG_LOG(("A(%d) get_features", a->adapter_nr));
+			if (!(data =
+			     diva_data_q_get_segment4write(&e->data))) {
+				DBG_ERR(("A(%d) get_features, no free buffer",
+					 a->adapter_nr));
+				diva_os_leave_spin_lock(&adapter_lock,
+							&old_irql,
+							"write");
+				return (0);
+			}
+			diva_user_mode_idi_adapter_features(a, &(((diva_um_idi_ind_hdr_t
+								*) data)->hdr.features));
+			((diva_um_idi_ind_hdr_t *) data)->type =
+			    DIVA_UM_IDI_IND_FEATURES;
+			((diva_um_idi_ind_hdr_t *) data)->data_length = 0;
+			diva_data_q_ack_segment4write(&e->data,
+						      sizeof(diva_um_idi_ind_hdr_t));
+
+			diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+
+			diva_os_wakeup_read(e->os_context);
+		}
+		break;
+
+	case DIVA_UM_IDI_REQ:
+	case DIVA_UM_IDI_REQ_MAN:
+	case DIVA_UM_IDI_REQ_SIG:
+	case DIVA_UM_IDI_REQ_NET:
+		DBG_TRC(("A(%d) REQ(%02d)-(%02d)-(%08x)", a->adapter_nr,
+			 req->Req, req->ReqCh,
+			 req->type & DIVA_UM_IDI_REQ_TYPE_MASK));
+		switch (process_idi_request(e, req)) {
+		case -1:
+			diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+			return (-1);
+		case -2:
+			diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+			diva_os_wakeup_read(e->os_context);
+			break;
+		default:
+			diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+			break;
+		}
+		break;
+
+	default:
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "write");
+		return (-1);
+	}
+
+	DBG_TRC(("A(%d) E(%08x) write=%d", a->adapter_nr, e, ret));
+
+	return (ret);
+}
+
+/* --------------------------------------------------------------------------
+			CALLBACK FROM XDI
+	 -------------------------------------------------------------------------- */
+static void diva_um_idi_xdi_callback(ENTITY * entity)
+{
+	divas_um_idi_entity_t *e = DIVAS_CONTAINING_RECORD(entity,
+							   divas_um_idi_entity_t,
+							   e);
+	diva_os_spin_lock_magic_t old_irql;
+	int call_wakeup = 0;
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
+
+	if (e->e.complete == 255) {
+		if (!(e->status & DIVA_UM_IDI_REMOVE_PENDING)) {
+			diva_um_idi_stop_wdog(e);
+		}
+		if ((call_wakeup = process_idi_rc(e, e->e.Rc))) {
+			if (e->rc_count) {
+				e->rc_count--;
+			}
+		}
+		e->e.Rc = 0;
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
+
+		if (call_wakeup) {
+			diva_os_wakeup_read(e->os_context);
+			diva_os_wakeup_close(e->os_context);
+		}
+	} else {
+		if (e->status & DIVA_UM_IDI_REMOVE_PENDING) {
+			e->e.RNum = 0;
+			e->e.RNR = 2;
+		} else {
+			call_wakeup = process_idi_ind(e, e->e.Ind);
+		}
+		e->e.Ind = 0;
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "xdi_callback");
+		if (call_wakeup) {
+			diva_os_wakeup_read(e->os_context);
+		}
+	}
+}
+
+static int process_idi_request(divas_um_idi_entity_t * e,
+			       const diva_um_idi_req_hdr_t * req)
+{
+	int assign = 0;
+	byte Req = (byte) req->Req;
+	dword type = req->type & DIVA_UM_IDI_REQ_TYPE_MASK;
+
+	if (!e->e.Id || !e->e.callback) {	/* not assigned */
+		if (Req != ASSIGN) {
+			DBG_ERR(("A: A(%d) E(%08x) not assigned",
+				 e->adapter->adapter_nr, e));
+			return (-1);	/* NOT ASSIGNED */
+		} else {
+			switch (type) {
+			case DIVA_UM_IDI_REQ_TYPE_MAN:
+				e->e.Id = MAN_ID;
+				DBG_TRC(("A(%d) E(%08x) assign MAN",
+					 e->adapter->adapter_nr, e));
+				break;
+
+			case DIVA_UM_IDI_REQ_TYPE_SIG:
+				e->e.Id = DSIG_ID;
+				DBG_TRC(("A(%d) E(%08x) assign SIG",
+					 e->adapter->adapter_nr, e));
+				break;
+
+			case DIVA_UM_IDI_REQ_TYPE_NET:
+				e->e.Id = NL_ID;
+				DBG_TRC(("A(%d) E(%08x) assign NET",
+					 e->adapter->adapter_nr, e));
+				break;
+
+			default:
+				DBG_ERR(("A: A(%d) E(%08x) unknown type=%08x",
+					 e->adapter->adapter_nr, e,
+					 type));
+				return (-1);
+			}
+		}
+		e->e.XNum = 1;
+		e->e.RNum = 1;
+		e->e.callback = diva_um_idi_xdi_callback;
+		e->e.X = &e->XData;
+		e->e.R = &e->RData;
+		assign = 1;
+	}
+	e->status |= DIVA_UM_IDI_RC_PENDING;
+	e->e.Req = Req;
+	e->e.ReqCh = (byte) req->ReqCh;
+	e->e.X->PLength = (word) req->data_length;
+	e->e.X->P = (byte *) & req[1];	/* Our buffer is safe */
+
+	DBG_TRC(("A(%d) E(%08x) request(%02x-%02x-%02x (%d))",
+		 e->adapter->adapter_nr, e, e->e.Id, e->e.Req,
+		 e->e.ReqCh, e->e.X->PLength));
+
+	e->rc_count++;
+
+	if (e->adapter && e->adapter->d.request) {
+		diva_um_idi_start_wdog(e);
+		(*(e->adapter->d.request)) (&e->e);
+	}
+
+	if (assign) {
+		if (e->e.Rc == OUT_OF_RESOURCES) {
+			/*
+			   XDI has no entities more, call was not forwarded to the card,
+			   no callback will be scheduled
+			 */
+			DBG_ERR(("A: A(%d) E(%08x) XDI out of entities",
+				 e->adapter->adapter_nr, e));
+
+			e->e.Id = 0;
+			e->e.ReqCh = 0;
+			e->e.RcCh = 0;
+			e->e.Ind = 0;
+			e->e.IndCh = 0;
+			e->e.XNum = 0;
+			e->e.RNum = 0;
+			e->e.callback = NULL;
+			e->e.X = NULL;
+			e->e.R = NULL;
+			write_return_code(e, ASSIGN_RC | OUT_OF_RESOURCES);
+			return (-2);
+		} else {
+			e->status |= DIVA_UM_IDI_ASSIGN_PENDING;
+		}
+	}
+
+	return (0);
+}
+
+static int process_idi_rc(divas_um_idi_entity_t * e, byte rc)
+{
+	DBG_TRC(("A(%d) E(%08x) rc(%02x-%02x-%02x)",
+		 e->adapter->adapter_nr, e, e->e.Id, rc, e->e.RcCh));
+
+	if (e->status & DIVA_UM_IDI_ASSIGN_PENDING) {
+		e->status &= ~DIVA_UM_IDI_ASSIGN_PENDING;
+		if (rc != ASSIGN_OK) {
+			DBG_ERR(("A: A(%d) E(%08x) ASSIGN failed",
+				 e->adapter->adapter_nr, e));
+			e->e.callback = NULL;
+			e->e.Id = 0;
+			e->e.Req = 0;
+			e->e.ReqCh = 0;
+			e->e.Rc = 0;
+			e->e.RcCh = 0;
+			e->e.Ind = 0;
+			e->e.IndCh = 0;
+			e->e.X = NULL;
+			e->e.R = NULL;
+			e->e.XNum = 0;
+			e->e.RNum = 0;
+		}
+	}
+	if ((e->e.Req == REMOVE) && e->e.Id && (rc == 0xff)) {
+		DBG_ERR(("A: A(%d) E(%08x)  discard OK in REMOVE",
+			 e->adapter->adapter_nr, e));
+		return (0);	/* let us do it in the driver */
+	}
+	if ((e->e.Req == REMOVE) && (!e->e.Id)) {	/* REMOVE COMPLETE */
+		e->e.callback = NULL;
+		e->e.Id = 0;
+		e->e.Req = 0;
+		e->e.ReqCh = 0;
+		e->e.Rc = 0;
+		e->e.RcCh = 0;
+		e->e.Ind = 0;
+		e->e.IndCh = 0;
+		e->e.X = NULL;
+		e->e.R = NULL;
+		e->e.XNum = 0;
+		e->e.RNum = 0;
+		e->rc_count = 0;
+	}
+	if ((e->e.Req == REMOVE) && (rc != 0xff)) {	/* REMOVE FAILED */
+		DBG_ERR(("A: A(%d) E(%08x)  REMOVE FAILED",
+			 e->adapter->adapter_nr, e));
+	}
+	write_return_code(e, rc);
+
+	return (1);
+}
+
+static int process_idi_ind(divas_um_idi_entity_t * e, byte ind)
+{
+	int do_wakeup = 0;
+
+	if (e->e.complete != 0x02) {
+		diva_um_idi_ind_hdr_t *pind =
+		    (diva_um_idi_ind_hdr_t *)
+		    diva_data_q_get_segment4write(&e->data);
+		if (pind) {
+			e->e.RNum = 1;
+			e->e.R->P = (byte *) & pind[1];
+			e->e.R->PLength =
+			    (word) (diva_data_q_get_max_length(&e->data) -
+				    sizeof(*pind));
+			DBG_TRC(("A(%d) E(%08x) ind_1(%02x-%02x-%02x)-[%d-%d]",
+				 e->adapter->adapter_nr, e, e->e.Id, ind,
+				 e->e.IndCh, e->e.RLength,
+				 e->e.R->PLength));
+
+		} else {
+			DBG_TRC(("A(%d) E(%08x) ind(%02x-%02x-%02x)-RNR",
+				 e->adapter->adapter_nr, e, e->e.Id, ind,
+				 e->e.IndCh));
+			e->e.RNum = 0;
+			e->e.RNR = 1;
+			do_wakeup = 1;
+		}
+	} else {
+		diva_um_idi_ind_hdr_t *pind =
+		    (diva_um_idi_ind_hdr_t *) (e->e.R->P);
+
+		DBG_TRC(("A(%d) E(%08x) ind(%02x-%02x-%02x)-[%d]",
+			 e->adapter->adapter_nr, e, e->e.Id, ind,
+			 e->e.IndCh, e->e.R->PLength));
+
+		pind--;
+		pind->type = DIVA_UM_IDI_IND;
+		pind->hdr.ind.Ind = ind;
+		pind->hdr.ind.IndCh = e->e.IndCh;
+		pind->data_length = e->e.R->PLength;
+		diva_data_q_ack_segment4write(&e->data,
+					      (int) (sizeof(*pind) +
+						     e->e.R->PLength));
+		do_wakeup = 1;
+	}
+
+	if ((e->status & DIVA_UM_IDI_RC_PENDING) && !e->rc.count) {
+		do_wakeup = 0;
+	}
+
+	return (do_wakeup);
+}
+
+/* --------------------------------------------------------------------------
+		Write return code to the return code queue of entity
+	 -------------------------------------------------------------------------- */
+static int write_return_code(divas_um_idi_entity_t * e, byte rc)
+{
+	diva_um_idi_ind_hdr_t *prc;
+
+	if (!(prc =
+	     (diva_um_idi_ind_hdr_t *) diva_data_q_get_segment4write(&e->rc)))
+	{
+		DBG_ERR(("A: A(%d) E(%08x) rc(%02x) lost",
+			 e->adapter->adapter_nr, e, rc));
+		e->status &= ~DIVA_UM_IDI_RC_PENDING;
+		return (-1);
+	}
+
+	prc->type = DIVA_UM_IDI_IND_RC;
+	prc->hdr.rc.Rc = rc;
+	prc->hdr.rc.RcCh = e->e.RcCh;
+	prc->data_length = 0;
+	diva_data_q_ack_segment4write(&e->rc, sizeof(*prc));
+
+	return (0);
+}
+
+/* --------------------------------------------------------------------------
+		Return amount of entries that can be bead from this entity or
+		-1 if adapter was removed
+	 -------------------------------------------------------------------------- */
+int diva_user_mode_idi_ind_ready(void *entity, void *os_handle)
+{
+	divas_um_idi_entity_t *e;
+	diva_um_idi_adapter_t *a;
+	diva_os_spin_lock_magic_t old_irql;
+	int ret;
+
+	if (!entity)
+		return (-1);
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "ind_ready");
+	e = (divas_um_idi_entity_t *) entity;
+	a = e->adapter;
+
+	if ((!a) || (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+		/*
+		   Adapter was unloaded
+		 */
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
+		return (-1);	/* adapter was removed */
+	}
+	if (e->status & DIVA_UM_IDI_REMOVED) {
+		/*
+		   entity was removed as result of adapter removal
+		   user should assign this entity again
+		 */
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
+		return (-1);
+	}
+
+	ret = e->rc.count + e->data.count;
+
+	if ((e->status & DIVA_UM_IDI_RC_PENDING) && !e->rc.count) {
+		ret = 0;
+	}
+
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "ind_ready");
+
+	return (ret);
+}
+
+void *diva_um_id_get_os_context(void *entity)
+{
+	return (((divas_um_idi_entity_t *) entity)->os_context);
+}
+
+int divas_um_idi_entity_assigned(void *entity)
+{
+	divas_um_idi_entity_t *e;
+	diva_um_idi_adapter_t *a;
+	int ret;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "assigned?");
+
+
+	e = (divas_um_idi_entity_t *) entity;
+	if (!e || (!(a = e->adapter)) ||
+	    (e->status & DIVA_UM_IDI_REMOVED) ||
+	    (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "assigned?");
+		return (0);
+	}
+
+	e->status |= DIVA_UM_IDI_REMOVE_PENDING;
+
+	ret = (e->e.Id || e->rc_count
+	       || (e->status & DIVA_UM_IDI_ASSIGN_PENDING));
+
+	DBG_TRC(("Id:%02x, rc_count:%d, status:%08x", e->e.Id, e->rc_count,
+		 e->status))
+
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "assigned?");
+
+	return (ret);
+}
+
+int divas_um_idi_entity_start_remove(void *entity)
+{
+	divas_um_idi_entity_t *e;
+	diva_um_idi_adapter_t *a;
+	diva_os_spin_lock_magic_t old_irql;
+
+	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "start_remove");
+
+	e = (divas_um_idi_entity_t *) entity;
+	if (!e || (!(a = e->adapter)) ||
+	    (e->status & DIVA_UM_IDI_REMOVED) ||
+	    (a->status & DIVA_UM_IDI_ADAPTER_REMOVED)) {
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
+		return (0);
+	}
+
+	if (e->rc_count) {
+		/*
+		   Entity BUSY
+		 */
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
+		return (1);
+	}
+
+	if (!e->e.Id) {
+		/*
+		   Remove request was already pending, and arrived now
+		 */
+		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
+		return (0);	/* REMOVE was pending */
+	}
+
+	/*
+	   Now send remove request
+	 */
+	e->e.Req = REMOVE;
+	e->e.ReqCh = 0;
+
+	e->rc_count++;
+
+	DBG_TRC(("A(%d) E(%08x) request(%02x-%02x-%02x (%d))",
+		 e->adapter->adapter_nr, e, e->e.Id, e->e.Req,
+		 e->e.ReqCh, e->e.X->PLength));
+
+	if (a->d.request)
+		(*(a->d.request)) (&e->e);
+
+	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "start_remove");
+
+	return (0);
+}
diff --git a/drivers/isdn/hardware/eicon/um_idi.h b/drivers/isdn/hardware/eicon/um_idi.h
new file mode 100644
index 0000000..141072f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/um_idi.h
@@ -0,0 +1,43 @@
+/* $Id: um_idi.h,v 1.6 2004/03/21 17:26:01 armin Exp $ */
+
+#ifndef __DIVA_USER_MODE_IDI_CORE_H__
+#define __DIVA_USER_MODE_IDI_CORE_H__
+
+
+/*
+  interface between UM IDI core and OS dependent part
+  */
+int diva_user_mode_idi_init(void);
+void diva_user_mode_idi_finit(void);
+void *divas_um_idi_create_entity(dword adapter_nr, void *file);
+int divas_um_idi_delete_entity(int adapter_nr, void *entity);
+
+typedef int (*divas_um_idi_copy_to_user_fn_t) (void *os_handle,
+					       void *dst,
+					       const void *src,
+					       int length);
+typedef int (*divas_um_idi_copy_from_user_fn_t) (void *os_handle,
+						 void *dst,
+						 const void *src,
+						 int length);
+
+int diva_um_idi_read(void *entity,
+		     void *os_handle,
+		     void *dst,
+		     int max_length, divas_um_idi_copy_to_user_fn_t cp_fn);
+
+int diva_um_idi_write(void *entity,
+		      void *os_handle,
+		      const void *src,
+		      int length, divas_um_idi_copy_from_user_fn_t cp_fn);
+
+int diva_user_mode_idi_ind_ready(void *entity, void *os_handle);
+void *diva_um_id_get_os_context(void *entity);
+int diva_os_get_context_size(void);
+int divas_um_idi_entity_assigned(void *entity);
+int divas_um_idi_entity_start_remove(void *entity);
+
+void diva_um_idi_start_wdog(void *entity);
+void diva_um_idi_stop_wdog(void *entity);
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/um_xdi.h b/drivers/isdn/hardware/eicon/um_xdi.h
new file mode 100644
index 0000000..b48fc04
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/um_xdi.h
@@ -0,0 +1,68 @@
+/* $Id: um_xdi.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+
+#ifndef __DIVA_USER_MODE_XDI_H__
+#define __DIVA_USER_MODE_XDI_H__
+
+/*
+  Contains declaratiom of structures shared between application
+  and user mode idi driver
+*/
+
+typedef struct _diva_um_idi_adapter_features {
+	dword type;
+	dword features;
+	dword channels;
+	dword serial_number;
+	char name[128];
+} diva_um_idi_adapter_features_t;
+
+#define DIVA_UM_IDI_REQ_MASK			0x0000FFFF
+#define DIVA_UM_IDI_REQ_TYPE_MASK		(~(DIVA_UM_IDI_REQ_MASK))
+#define DIVA_UM_IDI_GET_FEATURES		1	/* trigger features indication */
+#define DIVA_UM_IDI_REQ				2
+#define DIVA_UM_IDI_REQ_TYPE_MAN		0x10000000
+#define DIVA_UM_IDI_REQ_TYPE_SIG		0x20000000
+#define DIVA_UM_IDI_REQ_TYPE_NET		0x30000000
+#define DIVA_UM_IDI_REQ_MAN			(DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_MAN)
+#define DIVA_UM_IDI_REQ_SIG			(DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_SIG)
+#define DIVA_UM_IDI_REQ_NET			(DIVA_UM_IDI_REQ | DIVA_UM_IDI_REQ_TYPE_NET)
+/*
+  data_length  bytes will follow this structure
+*/
+typedef struct _diva_um_idi_req_hdr {
+	dword type;
+	dword Req;
+	dword ReqCh;
+	dword data_length;
+} diva_um_idi_req_hdr_t;
+
+typedef struct _diva_um_idi_ind_parameters {
+	dword Ind;
+	dword IndCh;
+} diva_um_idi_ind_parameters_t;
+
+typedef struct _diva_um_idi_rc_parameters {
+	dword Rc;
+	dword RcCh;
+} diva_um_idi_rc_parameters_t;
+
+typedef union _diva_um_idi_ind {
+	diva_um_idi_adapter_features_t features;
+	diva_um_idi_ind_parameters_t ind;
+	diva_um_idi_rc_parameters_t rc;
+} diva_um_idi_ind_t;
+
+#define DIVA_UM_IDI_IND_FEATURES  1	/* features indication */
+#define DIVA_UM_IDI_IND           2
+#define DIVA_UM_IDI_IND_RC        3
+/*
+  data_length bytes of data follow
+  this structure
+*/
+typedef struct _diva_um_idi_ind_hdr {
+	dword type;
+	diva_um_idi_ind_t hdr;
+	dword data_length;
+} diva_um_idi_ind_hdr_t;
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/xdi_adapter.h b/drivers/isdn/hardware/eicon/xdi_adapter.h
new file mode 100644
index 0000000..a3bd163
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/xdi_adapter.h
@@ -0,0 +1,70 @@
+/* $Id: xdi_adapter.h,v 1.7 2004/03/21 17:26:01 armin Exp $ */
+
+#ifndef __DIVA_OS_XDI_ADAPTER_H__
+#define __DIVA_OS_XDI_ADAPTER_H__
+
+#define DIVAS_XDI_ADAPTER_BUS_PCI  0
+#define DIVAS_XDI_ADAPTER_BUS_ISA  1
+
+typedef struct _divas_pci_card_resources {
+	byte bus;
+	byte func;
+	void *hdev;
+
+	dword bar[8];		/* contains context of appropriate BAR Register */
+	void __iomem *addr[8];		/* same bar, but mapped into memory */
+	dword length[8];	/* bar length */
+	int mem_type_id[MAX_MEM_TYPE];
+	unsigned int qoffset;
+	byte irq;
+} divas_pci_card_resources_t;
+
+typedef union _divas_card_resources {
+	divas_pci_card_resources_t pci;
+} divas_card_resources_t;
+
+struct _diva_os_xdi_adapter;
+typedef int (*diva_init_card_proc_t) (struct _diva_os_xdi_adapter * a);
+typedef int (*diva_cmd_card_proc_t) (struct _diva_os_xdi_adapter * a,
+				     diva_xdi_um_cfg_cmd_t * data,
+				     int length);
+typedef void (*diva_xdi_clear_interrupts_proc_t) (struct
+						  _diva_os_xdi_adapter *);
+
+#define DIVA_XDI_MBOX_BUSY			1
+#define DIVA_XDI_MBOX_WAIT_XLOG	2
+
+typedef struct _xdi_mbox_t {
+	dword status;
+	diva_xdi_um_cfg_cmd_data_t cmd_data;
+	dword data_length;
+	void *data;
+} xdi_mbox_t;
+
+typedef struct _diva_os_idi_adapter_interface {
+	diva_init_card_proc_t cleanup_adapter_proc;
+	diva_cmd_card_proc_t cmd_proc;
+} diva_os_idi_adapter_interface_t;
+
+typedef struct _diva_os_xdi_adapter {
+	struct list_head link;
+	int CardIndex;
+	int CardOrdinal;
+	int controller;		/* number of this controller */
+	int Bus;		/* PCI, ISA, ... */
+	divas_card_resources_t resources;
+	char port_name[24];
+	ISDN_ADAPTER xdi_adapter;
+	xdi_mbox_t xdi_mbox;
+	diva_os_idi_adapter_interface_t interface;
+	struct _diva_os_xdi_adapter *slave_adapters[3];
+	void *slave_list;
+	void *proc_adapter_dir;	/* adapterX proc entry */
+	void *proc_info;	/* info proc entry     */
+	void *proc_grp_opt;	/* group_optimization  */
+	void *proc_d_l1_down;	/* dynamic_l1_down     */
+	volatile diva_xdi_clear_interrupts_proc_t clear_interrupts_proc;
+	dword dsp_mask;
+} diva_os_xdi_adapter_t;
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/xdi_msg.h b/drivers/isdn/hardware/eicon/xdi_msg.h
new file mode 100644
index 0000000..3ade28f
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/xdi_msg.h
@@ -0,0 +1,127 @@
+/* $Id: xdi_msg.h,v 1.1.2.2 2001/02/16 08:40:36 armin Exp $ */
+
+#ifndef __DIVA_XDI_UM_CFG_MESSSGE_H__
+#define __DIVA_XDI_UM_CFG_MESSAGE_H__
+
+/*
+  Definition of messages used to communicate between
+  XDI device driver and user mode configuration utility
+*/
+
+/*
+  As acknowledge one DWORD - card ordinal will be read from the card
+*/
+#define DIVA_XDI_UM_CMD_GET_CARD_ORDINAL	0
+
+/*
+  no acknowledge will be generated, memory block will be written in the
+  memory at given offset
+*/
+#define DIVA_XDI_UM_CMD_WRITE_SDRAM_BLOCK	1
+
+/*
+  no acknowledge will be genatated, FPGA will be programmed
+*/
+#define DIVA_XDI_UM_CMD_WRITE_FPGA				2
+
+/*
+  As acknowledge block of SDRAM will be read in the user buffer
+*/
+#define DIVA_XDI_UM_CMD_READ_SDRAM				3
+
+/*
+  As acknowledge dword with serial number will be read in the user buffer
+*/
+#define DIVA_XDI_UM_CMD_GET_SERIAL_NR			4
+
+/*
+  As acknowledge struct consisting from 9 dwords with PCI info.
+  dword[0...7] = 8 PCI BARS
+  dword[9]		 = IRQ
+*/
+#define DIVA_XDI_UM_CMD_GET_PCI_HW_CONFIG	5
+
+/*
+  Reset of the board + activation of primary
+  boot loader
+*/
+#define DIVA_XDI_UM_CMD_RESET_ADAPTER			6
+
+/*
+  Called after code download to start adapter
+  at specified address
+  Start does set new set of features due to fact that we not know
+  if protocol features have changed
+*/
+#define DIVA_XDI_UM_CMD_START_ADAPTER			7
+
+/*
+  Stop adapter, called if user
+  wishes to stop adapter without unload
+  of the driver, to reload adapter with
+  different protocol
+*/
+#define DIVA_XDI_UM_CMD_STOP_ADAPTER			8
+
+/*
+  Get state of current adapter
+  Acknowledge is one dword with following values:
+  0 - adapter ready for download
+  1 - adapter running
+  2 - adapter dead
+  3 - out of service, driver should be restarted or hardware problem
+*/
+#define DIVA_XDI_UM_CMD_GET_CARD_STATE		9
+
+/*
+  Reads XLOG entry from the card
+*/
+#define DIVA_XDI_UM_CMD_READ_XLOG_ENTRY		10
+
+/*
+  Set untranslated protocol code features
+  */
+#define DIVA_XDI_UM_CMD_SET_PROTOCOL_FEATURES	11
+
+typedef struct _diva_xdi_um_cfg_cmd_data_set_features {
+	dword features;
+} diva_xdi_um_cfg_cmd_data_set_features_t;
+
+typedef struct _diva_xdi_um_cfg_cmd_data_start {
+	dword offset;
+	dword features;
+} diva_xdi_um_cfg_cmd_data_start_t;
+
+typedef struct _diva_xdi_um_cfg_cmd_data_write_sdram {
+	dword ram_number;
+	dword offset;
+	dword length;
+} diva_xdi_um_cfg_cmd_data_write_sdram_t;
+
+typedef struct _diva_xdi_um_cfg_cmd_data_write_fpga {
+	dword fpga_number;
+	dword image_length;
+} diva_xdi_um_cfg_cmd_data_write_fpga_t;
+
+typedef struct _diva_xdi_um_cfg_cmd_data_read_sdram {
+	dword ram_number;
+	dword offset;
+	dword length;
+} diva_xdi_um_cfg_cmd_data_read_sdram_t;
+
+typedef union _diva_xdi_um_cfg_cmd_data {
+	diva_xdi_um_cfg_cmd_data_write_sdram_t write_sdram;
+	diva_xdi_um_cfg_cmd_data_write_fpga_t write_fpga;
+	diva_xdi_um_cfg_cmd_data_read_sdram_t read_sdram;
+	diva_xdi_um_cfg_cmd_data_start_t start;
+	diva_xdi_um_cfg_cmd_data_set_features_t features;
+} diva_xdi_um_cfg_cmd_data_t;
+
+typedef struct _diva_xdi_um_cfg_cmd {
+	dword adapter;		/* Adapter number 1...N */
+	dword command;
+	diva_xdi_um_cfg_cmd_data_t command_data;
+	dword data_length;	/* Plain binary data will follow */
+} diva_xdi_um_cfg_cmd_t;
+
+#endif
diff --git a/drivers/isdn/hardware/eicon/xdi_vers.h b/drivers/isdn/hardware/eicon/xdi_vers.h
new file mode 100644
index 0000000..cf34941
--- /dev/null
+++ b/drivers/isdn/hardware/eicon/xdi_vers.h
@@ -0,0 +1,26 @@
+
+/*
+ *
+  Copyright (c) Eicon Networks, 2002.
+ *
+  This source file is supplied for the use with
+  Eicon Networks range of DIVA Server Adapters.
+ *
+  Eicon File Revision :    2.1
+ *
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2, or (at your option)
+  any later version.
+ *
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the GNU General Public License for more details.
+ *
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+static char diva_xdi_common_code_build[] = "102-52";